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

[Week4] 4주차 필수 과제 #12

Open
wants to merge 21 commits into
base: develop
Choose a base branch
from
Open

[Week4] 4주차 필수 과제 #12

wants to merge 21 commits into from

Conversation

hyeeum
Copy link
Contributor

@hyeeum hyeeum commented Nov 14, 2024

Related issue 🛠

Work Description ✏️

[유저 등록]
- 회원가입 페이지에 진행해주세요.
- 기존에 이메일, 비밀번호를 받는 구조에서 username, password, hobby를 입력하는 구조로 변경해주세요.
- username, password, hobby가 조건을 만족하지 않는 경우 (8자 이상인 경우) 조건을 만족하지 않았다는 것을 화면에 표시해주세요. (방식은 자율입니다.)

[로그인]
- 로그인 페이지에 진행해주세요.
- 기존 이메일, 비밀번호를 받는 구조에서 username, password를 받는 구조로 변경해주세요.
- 로그인 실패, 성공 시에 알맞은 안내 문구를 유저에게 제시해주세요. (방식은 자율입니다.)

[내 취미 조회]
- MY 페이지에 진행해주세요
- 기존에 이메일을 표시했던 부분에 내 취미가 표시되도록 해주세요.

Screenshot 📸

이름 오류 비밀번호 오류 취미 오류 정상 회원가입
이름 오류 비밀번호 오류 취미 오류 정상 회원가입
로그인 오류 정상 로그인
로그인 오류 정상 로그인

취미 불러오기

To Reviewers 📢

  • 네이밍 붙이는게 참어려운 것 같아요 , signup signin을 data layer코드에 넣는게 맞는지 뭔가 하면서도 이건 아닌 것 같다는 느낌이 드는데 다른 분들의 코드를 많이 참고하면서 더 좋은 네이밍을 알아보도록 하겠습니다 : - )
  • 그리고 서버통신은 한 번 하면 감이 잡히기는하는데 체화를 하는 과정이 참 오래 걸리는 것 같아요 패키지를 분리하는 과정에서 다시 한 번 아키텍처 정리를 할 수 있었습니다..! 까먹지않도록 계속 봐야할 것 같네요

@hyeeum hyeeum added the enhancement New feature or request label Nov 14, 2024
@hyeeum hyeeum self-assigned this Nov 14, 2024
Copy link

@greedy0110 greedy0110 left a comment

Choose a reason for hiding this comment

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

네트워크 연결 과제 고생 많으셧습니다 혜음님, 간단히 코멘트 남겨두었어요.

Comment on lines +58 to +61
return OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.addInterceptor(authInterceptor)
.build()

Choose a reason for hiding this comment

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

릴리즈에는 필요없는 interceptor이므로 디버그 앱에만 추가해주심이 어떨까요

Suggested change
return OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.addInterceptor(authInterceptor)
.build()
val builder = OkHttpClient.Builder()
if (BuildConfig.DEBUG) builder.addInterceptor(loggingInterceptor)
builder.addInterceptor(authInterceptor)
return builder.build()

Comment on lines +22 to +27
viewModelScope.launch {
wavveRepository.getHobby().onSuccess { hobbyEntity ->
_state.value = _state.value.copy(
hobby = hobbyEntity.hobby
)
}.onFailure { }

Choose a reason for hiding this comment

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

실패하면 사용자는 아무런 피드백을 받지 못하고 빈 화면을 보게 될 것 같습니다.
앱을 사용하는 사람 입장으로 생각하면 피하고 싶은 상황일 것 같아요.
최소한 토스트로 문제가 생겼음을 보여주거나 뭔가 문제가 있으니 재시도 하라는 화면이 있으면 좋을 것 같습니다.

import javax.inject.Singleton

@Singleton
class User @Inject constructor(

Choose a reason for hiding this comment

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

모듈이 분리된 이 시점에서 이 객체는 다분히 data 혹은 repository 수준에서 관리될 친구로 보이네요.

data로 관리한다면 UserToken 정보를 디바이스에 저장하는 객체로 변모할 것이고 (현재 프로젝트 구조 상 이름은 UserDataSource, TokenDataSource ?)

repository로 관리한다면 UserToken 정보를 저장하고, 필요한 시점에 초기화 하는 인터페이스를 제공하는 객체로 활용되겠네요. (현재 프로젝트 구조에 맞는 이름은 아마도 UserRepository? AuthRepository? SignRepository)

Copy link

@kamja0510 kamja0510 left a comment

Choose a reason for hiding this comment

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

역시 혜음.. 저같은 사람도 코드를 알아볼 수 있게 짜셨네요(mvi는 살짝 이해못함 ㅎ)
항상 코드리뷰 시간이 아니라 보면서 공부하는 느낌

@Provides
fun provideLoggingInterceptor(): HttpLoggingInterceptor {
return HttpLoggingInterceptor { message ->
Log.d("Retrofit2", "CONNECTION INFO -> $message")

Choose a reason for hiding this comment

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

세미나에서 배운것은 이 중괄호 블럭이 없는데 이 블럭이 추가되면서 어떤 추가적인 정보를 볼 수 있나요?


@Serializable
data class RequestSignUpDto(
@SerialName("username")

Choose a reason for hiding this comment

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

변수명과 json key명이 같은데도 SerialName 어노테이션을 굳이 써야하나요?

@SerialName("hobby")
val hobby: String
){
fun toEntity() = ResponseHobbyEntity(

Choose a reason for hiding this comment

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

신기한 문법들


fun NavController.navigateSearch(
navOptions: NavOptions
) {
navigate(Search, navOptions)
navigate(org.sopt.and.feature.search.Search, navOptions)

Choose a reason for hiding this comment

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

오잉 왜 갑자기 경로 다 줘야되는걸로 바뀌었나요

val password: String = "",
var isPasswordVisible: Boolean = false,
) {
val isButtonEnabled: Boolean = username.isNotEmpty() && password.isNotEmpty()

Choose a reason for hiding this comment

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

이 줄이 왜 중괄호 블럭으로 따로 빠져 있나요? 저 username이랑 password를 쓰려면 따로 빼야하는 건가요?

@@ -72,9 +94,8 @@ class SignUpViewModel @Inject constructor() : ViewModel() {
}

companion object {
private const val MIN_PASSWORD = 8
private const val MAX_PASSWORD = 20
private const val MIN_SIGNUP_LENGTH = 1

Choose a reason for hiding this comment

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

와 저는 상수화도 안하고 최소값1로 두지도 않았네요 혼나겠다

@Singleton
class User @Inject constructor(
@ApplicationContext private val context: Context
) {
private val sharedPreferences: SharedPreferences =

Choose a reason for hiding this comment

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

호옥시 datastore 안쓰시고 sharedPreferences 쓰시는 이유가 있나요!

Choose a reason for hiding this comment

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

사소한 부분들도 string들을 다 바꾸셨네요!

) {
val state by viewModel.state.collectAsStateWithLifecycle()

LaunchedEffect(true) {

Choose a reason for hiding this comment

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

이런거 보면 Route를 쓰는게 좋을 거 같다는 생각이 드네요

Copy link

@HAJIEUN02 HAJIEUN02 left a comment

Choose a reason for hiding this comment

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

고생많았서요 혜음이~~ 클린아키텍처 적용을 해서 그런지 저랑 비슷한 부분이 많아서 보기 편했습니다 ㅎㅎ 유스케이스도 한번 사용해보셔요!


// Network
implementation(platform(libs.okhttp.bom))
implementation(libs.okhttp)

Choose a reason for hiding this comment

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

okhttp랑 retrofit처럼 같은 카테고리인 친구들은 각각 libs.versions.toml 내부에서 bundles로 묶어서 한번에 디펜던시 추가해줄 수 있서요! 그러면 더 보기 깔끔할 듯합니당

tools:targetApi="31">
<activity
android:name=".main.MainActivity"
android:name=".feature.main.MainActivity"

Choose a reason for hiding this comment

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

오호 ui가 아니라 feature로 패키지를 구성하셨군요
새로운 네이밍 좋네요

@Provides
fun provideLoggingInterceptor(): HttpLoggingInterceptor {
return HttpLoggingInterceptor { message ->
Log.d("Retrofit2", "CONNECTION INFO -> $message")

Choose a reason for hiding this comment

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

로그는 PR 올릴 때 삭제해주시거나 Timber로 바꿔주시면 좋을 것 같아요!!

val password: String,
)

fun RequestSignInEntity.toDto() = RequestSignInDto(

Choose a reason for hiding this comment

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

요거는 엔티티를 디티오로 바꾸는 거니까 엔티티가 주체잖아요!! 그래서 저라면 엔티티에 해당함수를 구현할 것 같아요

Copy link
Contributor

@1971123-seongmin 1971123-seongmin left a comment

Choose a reason for hiding this comment

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

고생하셨습니다. 항상 잘하셔서 리뷰라기보단 많이 배워가는 것 같아요.

override suspend fun getUserHobby(): BaseResponse<ResponseUserHobbyDto> =
wavveService.getUserHobby()

}
Copy link
Contributor

Choose a reason for hiding this comment

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

깔끔 그 자체에요. 코드 너무 좋아요

@Binds
@Singleton
abstract fun bindsDataSource(myDataSourceImpl: WavveDataSourceImpl): WavveDataSource
}
Copy link
Contributor

Choose a reason for hiding this comment

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

데이터스토어 모듈을 따로 만드셨네요. 저도 분리해야겠어요.

@SerialName("token")
val token: String
){
fun toEntity() = ResponseSignInEntity(
Copy link
Contributor

Choose a reason for hiding this comment

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

objcect에 Mapper를 모아두는 방식을 안쓰고 데이터 클래스에 바로 정의하신 이유 알려주실 수 있나요??


import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import kotlinx.serialization.Serializable
import org.sopt.and.main.MainTabRoute
import org.sopt.and.feature.main.MainTabRoute

fun NavController.navigateSignUp() {
navigate(SignUp)
Copy link
Contributor

Choose a reason for hiding this comment

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

컴포즈도 보통 이렇게 네비게이션 함수를 확장으로 두고 쓰나요??

val hobby: String = "",
var isPasswordVisible: Boolean = false,
) {
val isButtonEnabled: Boolean = username.isNotEmpty() && password.isNotEmpty()
Copy link
Contributor

Choose a reason for hiding this comment

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

이렇게 하면 버튼 활성화/비활성화를 관리할 때 훨씬 편할까요??

<string name="not_valid_input">유효하지 않은 입력입니다.</string>

<!--signin-->
<string name="signin">로그인</string>
<string name="signin_placeholder">이메일 주소 또는 아이디</string>
<string name="signin_username_placeholder">이름</string>
<string name="signin_password_placeholder">비밀번호</string>
<string name="find_id">아이디 찾기</string>
<string name="reset_password">비밀번호 재설정</string>
<string name="join">회원가입</string>
Copy link
Contributor

Choose a reason for hiding this comment

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

string 이름들이 정말 깔끔하고 직관적이네요..

Copy link
Contributor

@jihyunniiii jihyunniiii left a comment

Choose a reason for hiding this comment

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

역시 참 깔끔하네요! 고생하셨습니다! 우리 혜음이 합세도 파이팅!

import javax.inject.Inject

class WavveDataSourceImpl @Inject constructor(
val wavveService: WavveService
Copy link
Contributor

Choose a reason for hiding this comment

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

private를 붙여줘도 좋을 듯,,!! 합니다

Comment on lines +5 to +6


Copy link
Contributor

Choose a reason for hiding this comment

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

요기는 2줄 공백이당 크크

import javax.inject.Inject

@HiltViewModel
class SignInViewModel @Inject constructor() : ViewModel() {
class SignInViewModel @Inject constructor(
private val user:User,
Copy link
Contributor

Choose a reason for hiding this comment

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

정렬이 제대로 안 된 것 같숨다

Copy link
Contributor

Choose a reason for hiding this comment

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

그리고 여기 user를 매개변수로 넣어주는 이유가 뭔가요? ㅜ 찾고 싶은데 졸려서 그런가 안 보여잉 ㅠㅠㅠ

import javax.inject.Singleton

@Singleton
class User @Inject constructor(
Copy link
Contributor

Choose a reason for hiding this comment

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

아 위에 있는 user가 이러한 역할을 하는 친구였군요!
승민님 리뷰처럼 조금 더 직관적으로 네이밍하는 게 필요할 것 같아요!
id랑 비밀번호 등을 저장하는 user data class인 줄 알았서요

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature] 4주차 필수 과제
6 participants