Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Week6 essential #7

Open
wants to merge 47 commits into
base: develop/view
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
72a2211
인터넷 권한 추가
briandr97 Nov 5, 2022
7e8c872
retrofit2, kotlinx-serialization 의존성 추가
briandr97 Nov 5, 2022
c8564d4
Merge branch 'develop/view' of https://github.com/IN-SOPT-ANDROID/Yon…
briandr97 Nov 5, 2022
08d95de
okhttp3 의존성 추가
briandr97 Nov 5, 2022
492b431
retrofit service creator 생성
briandr97 Nov 5, 2022
c091778
refactor(splash): 로컬 저장소 접근 방식 수정
briandr97 Nov 10, 2022
9726d40
refactor(auth): id -> email로 수정
briandr97 Nov 10, 2022
492ad8d
feat(manifest): 인터넷 연결 권한 추가
briandr97 Nov 10, 2022
e375027
feat(auth): 로그인, 회원가입 DTO 생성
briandr97 Nov 10, 2022
852345b
feat(auth): 로그인, 회원가입 서버통신 함수 설계
briandr97 Nov 10, 2022
a5a0013
feat(auth): Retrofit2 객체 생성을 따로 구분
briandr97 Nov 10, 2022
46caf62
feat(auth): 회원가입 정보 전달을 위한 데이터 클래스 생성
briandr97 Nov 10, 2022
2deac32
feat(auth): 회원가입 서버통신 로직 구현
briandr97 Nov 10, 2022
49e32d2
feat(auth): 로그인 서버통신 로직 구현
briandr97 Nov 10, 2022
4cb433e
refactor(auth): 코드 정렬 (ctrl + alt + L)
briandr97 Nov 10, 2022
1c49452
refactor(auth): package 구조 변경
briandr97 Nov 10, 2022
d028069
feat(reqres): Reqres 서버통신 응답값을 위한 DTO 생성
briandr97 Nov 10, 2022
21ec506
feat(reqres): Reqres 서버통신 함수 설계
briandr97 Nov 10, 2022
a6b625a
feat(reqres): Reqres 서버통신을 위한 Retrofit 객체 생성
briandr97 Nov 10, 2022
cf6778d
feat(reqres): Fragment 이름 변경(Search -> Reqres) 및 binding 객체 생성
briandr97 Nov 10, 2022
13cc35e
feat(reqres): Reqres 서버통신 로직 구현
briandr97 Nov 10, 2022
af10a27
feat(reqres): ReqresAdpater 뼈대 완성
briandr97 Nov 10, 2022
d76ff72
feat(reqres): reqres item layout 완성
briandr97 Nov 10, 2022
aa4f280
fix(reqres): ReqresAdapter 오류 수정
briandr97 Nov 10, 2022
3f7a157
build(glide): glide 의존성 추가
briandr97 Nov 10, 2022
74e078b
feat(reqres): Reqres item layout 수정
briandr97 Nov 10, 2022
0e6f55c
feat(reqres): ReqresViewHolder 로직 작성
briandr97 Nov 10, 2022
e07dbc7
refactor(reqres): reqres item layout 수정
briandr97 Nov 10, 2022
a59effc
feat(reqres): ReqresFragment recyclerview xml 추가
briandr97 Nov 10, 2022
da35a8a
feat(reqres): ReqresFragment recyclerview adapter 연결
briandr97 Nov 10, 2022
d8c2333
build(lottie): lottie animation을 쓰기 위해 의존성 추가
briandr97 Nov 10, 2022
62d3792
style(lottie): lottie animation 파일 추가
briandr97 Nov 10, 2022
3c5cddf
feat(reqres): lottie animation view추가
briandr97 Nov 10, 2022
e592c82
feat(reqres): loading 로직 추가
briandr97 Nov 10, 2022
2f06c36
feat(ServerConnectResult): 서버통신 결과를 나타내는 enum 클래스 생성
briandr97 Nov 22, 2022
f1892f4
feat(SignIn): 로그인 서버통신 로직을 액티비티에서 뷰모델로 분리
briandr97 Nov 22, 2022
99b5678
feat(ToastSnackBarExt): string파일의 id값이 아닌 그냥 String으로도 입력할 수 있도록 함수를 …
briandr97 Nov 22, 2022
cab3425
체크아웃을 위한 임시 커밋
briandr97 Nov 26, 2022
1ce3e66
databinding 삭제
briandr97 Nov 30, 2022
b7a5b87
코드 정렬
briandr97 Nov 30, 2022
aadb1b3
databinding 삭제에 따른 viewModel 수정
briandr97 Nov 30, 2022
cf77ae0
edittext 상태에 관련된 enum 클래스 생성
briandr97 Nov 30, 2022
db3bbbd
아이디, 비밀번호, 이름, mbti의 형식 검사 도메인 로직
briandr97 Nov 30, 2022
e96d769
strings 수정
briandr97 Nov 30, 2022
9914e5d
colors 추가
briandr97 Nov 30, 2022
2507ac6
회원가입 뷰 완성
briandr97 Nov 30, 2022
105ac43
필요없는거 삭제
briandr97 Nov 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'org.jetbrains.kotlin.plugin.serialization' version('1.7.10')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
id 'org.jetbrains.kotlin.plugin.serialization' version('1.7.10')
id 'org.jetbrains.kotlin.plugin.serialization' version('1.7.10')
id 'kotlin-kapt'

아래에 kapt 기능 사용해야되니까 이거 추가해야됨

}

android {
Expand Down Expand Up @@ -49,4 +50,20 @@ dependencies {
// ViewModel 생성함수를 편하게 사용하고 싶다면?
implementation "androidx.fragment:fragment-ktx:1.5.3"
implementation "androidx.activity:activity-ktx:1.5.1"

//레트로핏
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1'
implementation 'com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0'

implementation(platform("com.squareup.okhttp3:okhttp-bom:4.10.0"))
implementation("com.squareup.okhttp3:okhttp")
implementation("com.squareup.okhttp3:logging-interceptor")

//글라이드
implementation 'com.github.bumptech.glide:glide:4.14.2'
annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2'
kapt 'com.github.bumptech.glide:compiler:4.14.2'


//로티 뷰
implementation "com.airbnb.android:lottie:5.2.0"
}
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
xmlns:tools="http://schemas.android.com/tools"
package="org.sopt.sample">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
Expand All @@ -12,6 +14,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.INSOPTAndroidPractice"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".ui.main.HomeActivity"
Expand Down
6 changes: 3 additions & 3 deletions app/src/main/java/org/sopt/sample/data/MySharedPreferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ class MySharedPreferences(context: Context) {
get() = loginPreferences.getBoolean("AUTO_LOGIN", false)
set(value) = editor.putBoolean("AUTO_LOGIN", value).apply()

var loginId: String?
get() = loginPreferences.getString("LOGIN_ID", null)
set(value) = editor.putString("LOGIN_ID", value).apply()
var loginEmail: String?
get() = loginPreferences.getString("LOGIN_EMAIL", null)
set(value) = editor.putString("LOGIN_EMAIL", value).apply()
Comment on lines +19 to +21
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

데이터타입이 nullable한 이유가 있을까유?!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이렇게 처리해도 될 것 같은게 어차피 빈 스트링이나 null이나 저장이 안된값으로 인식하면 되어서 처리 로직은 거의 비슷할 듯. 다만 '?.' 연산자를 항상 써야되냐 말아야되나 차이인데 그정도는 취향차이라고 봐도 될 것 같아용


var loginPw: String?
get() = loginPreferences.getString("LOGIN_PW", null)
Expand Down
14 changes: 14 additions & 0 deletions app/src/main/java/org/sopt/sample/data/remote/AuthInterceptor.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.sopt.sample.data.remote

import okhttp3.Interceptor
import okhttp3.Response

class AuthInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originRequest = chain.request()
val headerRequest = originRequest.newBuilder()
.header("token", "")
.build()
return chain.proceed(headerRequest)
}
}
21 changes: 21 additions & 0 deletions app/src/main/java/org/sopt/sample/data/remote/AuthService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.sopt.sample.data.remote

import org.sopt.sample.data.remote.entity.auth.RequestSignInDTO
import org.sopt.sample.data.remote.entity.auth.RequestSignUpDTO
import org.sopt.sample.data.remote.entity.auth.ResponseSignInDTO
import org.sopt.sample.data.remote.entity.auth.ResponseSignUpDTO
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.POST

interface AuthService {
@POST("api/user/signin")
fun postSignIn(
@Body body: RequestSignInDTO
): Call<ResponseSignInDTO>

@POST("api/user/signup")
fun postSignUp(
@Body body: RequestSignUpDTO
) : Call<ResponseSignUpDTO>
}
13 changes: 13 additions & 0 deletions app/src/main/java/org/sopt/sample/data/remote/ReqresService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.sopt.sample.data.remote

import org.sopt.sample.data.remote.entity.reqres.ResponseReqresDTO
import retrofit2.http.GET
import retrofit2.http.Query
import retrofit2.Call

interface ReqresService {
@GET("users")
fun getUsers(
@Query("page") page : Int
) : Call<ResponseReqresDTO>
}
32 changes: 32 additions & 0 deletions app/src/main/java/org/sopt/sample/data/remote/ServiceFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.sopt.sample.data.remote

import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import retrofit2.Retrofit

object ServiceFactory {
private const val AUTH_BASE_URL = "http://3.39.169.52:3000/"
private const val REQRES_BASE_URL = "https://reqres.in/api/"

val retrofitAuth: Retrofit by lazy {
Retrofit.Builder()
.baseUrl(AUTH_BASE_URL)
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
}

val retrofitReqres: Retrofit by lazy {
Retrofit.Builder()
.baseUrl(REQRES_BASE_URL)
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
}

//inline fun <reified T> create(): T = retrofitAuth.create<T>(T::class.java)
}

object ServicePool {
val authService: AuthService = ServiceFactory.retrofitAuth.create(AuthService::class.java)
val reqresService : ReqresService = ServiceFactory.retrofitReqres.create(ReqresService::class.java)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.sopt.sample.data.remote.entity.auth

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class RequestSignInDTO(
@SerialName("email")
val email: String,
@SerialName("password")
val password: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.sopt.sample.data.remote.entity.auth

import kotlinx.serialization.Serializable

@Serializable
data class RequestSignUpDTO(
val email: String,
val password: String,
val name: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.sopt.sample.data.remote.entity.auth

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ResponseSignInDTO(
@SerialName("status")
val status: Int,
@SerialName("message")
val message: String,
@SerialName("result")
val result: User
) {
@Serializable
data class User(
@SerialName("id")
val id: Int,
@SerialName("name")
val name: String,
@SerialName("profileImage")
val profileImage: String?,
@SerialName("bio")
val bio: String?,
@SerialName("email")
val email: String,
@SerialName("password")
val password: String
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.sopt.sample.data.remote.entity.auth

import kotlinx.serialization.Serializable

@Serializable
data class ResponseSignUpDTO(
val message: String,
val newUser: NewUser,
val status: Int
) {
@Serializable
data class NewUser(
val bio: String?,
val email: String,
val id: Int,
val name: String,
val password: String,
val profileImage: String?
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.sopt.sample.data.remote.entity.reqres

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ResponseReqresDTO(
val data: List<Data>,
val page: Int,
@SerialName("per_page")
val perPage: Int,
val support: Support,
val total: Int,
@SerialName("total_pages")
val totalPages: Int
) {
@Serializable
data class Data(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이것도 플러그인이 만들어주신 이름 같다만 Data라는 이름은 최대한 피해주는게 좋을 것 같아. 가독성/직관성이 떨어져보여

val avatar: String,
val email: String,
@SerialName("first_name")
val firstName: String,
val id: Int,
@SerialName("last_name")
val lastName: String
)

@Serializable
data class Support(
val text: String,
val url: String
)
}
5 changes: 2 additions & 3 deletions app/src/main/java/org/sopt/sample/ui/SplashActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ class SplashActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySplashBinding.inflate(layoutInflater)
sharedPref = MySharedPreferences()
sharedPref.init(this)
sharedPref = MySharedPreferences(this)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Application 클래스 만들어서 거기서 한번만 init하고 사용하는걸 추천할게용

setName()
setContentView(binding.root)

Expand All @@ -34,7 +33,7 @@ class SplashActivity : AppCompatActivity() {
}

private fun checkAutoLogin() {
val id = sharedPref.loginId
val id = sharedPref.loginEmail
val autoLogin = sharedPref.autoLogin
if (id == null) startLogin()
else if (autoLogin) startHome()
Expand Down
105 changes: 67 additions & 38 deletions app/src/main/java/org/sopt/sample/ui/auth/AuthChecking.kt
Original file line number Diff line number Diff line change
@@ -1,52 +1,81 @@
package org.sopt.sample.ui.auth

import android.content.Context
import org.sopt.sample.R
import org.sopt.sample.shortToast

class AuthChecking {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

클래스로 따로 빼서 관리해주는 거 좋네요

fun isSignUpIdValid(id: String): Boolean = (id.length in 6..10)

fun isSignUpPwValid(pw: String): Boolean = (pw.length in 8..12)

fun isSignUpNameValid(name : String) : Boolean = (name.length in 1..3)

fun isSignUpMbtiValid(mbti: String): Int {
if (mbti.length < 4) return SHORT
else if (mbti in mbtiList) return CORRECT
else return STRANGE
}

fun isSignInValid(
context: Context, id: String?, pw: String?, inputId: String, inputPw: String
): Boolean {
if (id == null) {
context.shortToast(R.string.needSignUp)
return false
} else if ((inputId != id) and (inputPw != pw)) {
context.shortToast(R.string.checkIdPw)
return false
} else if (inputId != id) {
context.shortToast(R.string.checkId)
return false
} else if (inputPw != pw) {
context.shortToast(R.string.checkPw)
return false
} else {
context.shortToast(R.string.succeedSignIn)

fun validateId(id: String): EditTextUiState {
if (haveNumber(id) and haveAlphabet(id) and checkLength(id, ID_RANGE)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 미친 가독성 좋은데?

return EditTextUiState.CORRECT
}
if (id.isEmpty()) {
return EditTextUiState.NOT_FOCUSED
}
return EditTextUiState.INCORRECT
}

fun validatePw(pw: String): EditTextUiState {
if (haveNumber(pw) and haveAlphabet(pw) and haveSpecialCharacter(pw) and checkLength(pw, PW_RANGE)
) {
return EditTextUiState.CORRECT
}
if (pw.isEmpty()) {
return EditTextUiState.NOT_FOCUSED
}
return EditTextUiState.INCORRECT
}

private fun haveSpecialCharacter(input: String): Boolean {
return !input.all { Character.isLetterOrDigit(it) }
}

private fun haveNumber(input: String): Boolean {
return input.any { Character.isDigit(it) }
}

private fun haveAlphabet(input: String): Boolean {
if (input.any { it.toString() in "a".."z" }) {
return true
}
if (input.any { it.toString() in "A".."Z" }) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (input.any { it.toString() in "A".."Z" }) {
val isValidated = input.any { it.toString() in "A".."Z" }
if (isValidated) {

조금더 직관성있게...!!

return true
}
return false
}

private fun checkLength(input: String, range: IntRange): Boolean {
if (input.length in range) {
return true
}
return false
}

fun validateMbti(input: String): EditTextUiState {
if (input in mbtiList) {
return EditTextUiState.CORRECT
}
if (input.isEmpty()) {
return EditTextUiState.NOT_FOCUSED
}
return EditTextUiState.INCORRECT
}

fun validateName(input: String): EditTextUiState {
if (input.length in 2..4) {
return EditTextUiState.CORRECT
}
if (input.isEmpty()) {
return EditTextUiState.NOT_FOCUSED
}
return EditTextUiState.INCORRECT
}

private val mbtiList: List<String> = listOf(
private val mbtiList: Set<String> = setOf(
"ESTJ", "ESTP", "ESFJ", "ESFP", "ENTJ", "ENTP", "ENFJ", "ENFP",
"ISTJ", "ISTP", "ISFJ", "ISFP", "INTJ", "INTP", "INFJ", "INFP",
"CUTE", "SEXY"
)

companion object {
const val SHORT = 0
const val STRANGE = 1
const val CORRECT = 2
val ID_RANGE = IntRange(6, 10)
val PW_RANGE = IntRange(6, 12)
Comment on lines +78 to +79
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀

}
}
}
Loading