From 31b0050c82d10e7e26c4a43cddaa3dad692ff74b Mon Sep 17 00:00:00 2001 From: JunJangE Date: Mon, 22 Jul 2024 21:18:48 +0900 Subject: [PATCH 1/5] =?UTF-8?q?fix:=20=EC=B9=B4=EC=B9=B4=EC=98=A4=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=84=B1=EA=B3=B5=EC=8B=9C=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=95=84=20=EB=A7=8C=EB=93=A4=EA=B8=B0=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friendogly/presentation/ui/register/RegisterViewModel.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterViewModel.kt b/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterViewModel.kt index 22746e97d..e2b05c60f 100644 --- a/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterViewModel.kt +++ b/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterViewModel.kt @@ -21,8 +21,9 @@ class RegisterViewModel( fun executeKakaoLogin(context: Context) { viewModelScope.launch { - kakaoLoginUseCase(context = context).onSuccess { - _navigateAction.emit(RegisterNavigationAction.NavigateToGoogleLogin) + kakaoLoginUseCase(context = context).onSuccess { kakaAccessToken -> + kakaAccessToken.idToken ?: return@onSuccess + _navigateAction.emit(RegisterNavigationAction.NavigateToProfileSetting(idToken = kakaAccessToken.idToken)) }.onFailure { } } } From bbb35b5dc40550548ccdbd73aaa39b844c95493d Mon Sep 17 00:00:00 2001 From: JunJangE Date: Mon, 22 Jul 2024 22:35:14 +0900 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20API=20=EC=97=B0=EA=B2=B0=20=EB=B0=8F=20memberId=20l?= =?UTF-8?q?ocal=EC=97=90=EC=84=9C=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friendogly/application/di/AppModule.kt | 14 ++++++ .../friendogly/data/mapper/MemberMapper.kt | 10 +++++ .../friendogly/data/model/MemberDto.kt | 5 +++ .../data/repository/MemberRepositoryImpl.kt | 15 +++++++ .../data/source/MemberDataSource.kt | 10 +++++ .../friendogly/domain/model/Member.kt | 5 +++ .../domain/repository/MemberRepository.kt | 10 +++++ .../domain/usecase/PostMemberUseCase.kt | 13 ++++++ .../profilesetting/ProfileSettingActivity.kt | 8 +++- .../profilesetting/ProfileSettingViewModel.kt | 45 ++++++++++++++++++- .../friendogly/remote/api/ApiClient.kt | 5 ++- .../friendogly/remote/api/MemberService.kt | 13 ++++++ .../friendogly/remote/di/RemoteModule.kt | 19 +++++++- .../remote/mapper/MemberDtoMapper.kt | 12 +++++ .../model/request/PostMembersRequest.kt | 9 ++++ .../remote/model/response/BaseResponse.kt | 3 ++ .../remote/model/response/MemberResponse.kt | 11 +++++ .../remote/source/MemberDataSourceImpl.kt | 20 +++++++++ 18 files changed, 222 insertions(+), 5 deletions(-) create mode 100644 android/app/src/main/java/com/woowacourse/friendogly/data/mapper/MemberMapper.kt create mode 100644 android/app/src/main/java/com/woowacourse/friendogly/data/model/MemberDto.kt create mode 100644 android/app/src/main/java/com/woowacourse/friendogly/data/repository/MemberRepositoryImpl.kt create mode 100644 android/app/src/main/java/com/woowacourse/friendogly/data/source/MemberDataSource.kt create mode 100644 android/app/src/main/java/com/woowacourse/friendogly/domain/model/Member.kt create mode 100644 android/app/src/main/java/com/woowacourse/friendogly/domain/repository/MemberRepository.kt create mode 100644 android/app/src/main/java/com/woowacourse/friendogly/domain/usecase/PostMemberUseCase.kt create mode 100644 android/app/src/main/java/com/woowacourse/friendogly/remote/api/MemberService.kt create mode 100644 android/app/src/main/java/com/woowacourse/friendogly/remote/mapper/MemberDtoMapper.kt create mode 100644 android/app/src/main/java/com/woowacourse/friendogly/remote/model/request/PostMembersRequest.kt create mode 100644 android/app/src/main/java/com/woowacourse/friendogly/remote/model/response/MemberResponse.kt create mode 100644 android/app/src/main/java/com/woowacourse/friendogly/remote/source/MemberDataSourceImpl.kt diff --git a/android/app/src/main/java/com/woowacourse/friendogly/application/di/AppModule.kt b/android/app/src/main/java/com/woowacourse/friendogly/application/di/AppModule.kt index 99f2a90d7..b02da50df 100644 --- a/android/app/src/main/java/com/woowacourse/friendogly/application/di/AppModule.kt +++ b/android/app/src/main/java/com/woowacourse/friendogly/application/di/AppModule.kt @@ -6,14 +6,17 @@ import com.woowacourse.friendogly.data.repository.ClubRepositoryImpl import com.woowacourse.friendogly.data.repository.FootprintRepositoryImpl import com.woowacourse.friendogly.data.repository.KakaoLoginRepositoryImpl import com.woowacourse.friendogly.data.repository.LocalRepositoryImpl +import com.woowacourse.friendogly.data.repository.MemberRepositoryImpl import com.woowacourse.friendogly.data.source.ClubDataSource import com.woowacourse.friendogly.data.source.FootprintDataSource import com.woowacourse.friendogly.data.source.KakaoLoginDataSource import com.woowacourse.friendogly.data.source.LocalDataSource +import com.woowacourse.friendogly.data.source.MemberDataSource import com.woowacourse.friendogly.domain.repository.ClubRepository import com.woowacourse.friendogly.domain.repository.FootprintRepository import com.woowacourse.friendogly.domain.repository.KakaoLoginRepository import com.woowacourse.friendogly.domain.repository.LocalRepository +import com.woowacourse.friendogly.domain.repository.MemberRepository import com.woowacourse.friendogly.domain.usecase.DeleteClubUseCase import com.woowacourse.friendogly.domain.usecase.DeleteLocalDataUseCase import com.woowacourse.friendogly.domain.usecase.GetClubMineUseCase @@ -23,6 +26,7 @@ import com.woowacourse.friendogly.domain.usecase.KakaoLoginUseCase import com.woowacourse.friendogly.domain.usecase.PostClubParticipationUseCase import com.woowacourse.friendogly.domain.usecase.PostClubUseCase import com.woowacourse.friendogly.domain.usecase.PostFootprintUseCase +import com.woowacourse.friendogly.domain.usecase.PostMemberUseCase import com.woowacourse.friendogly.domain.usecase.SaveJwtTokenUseCase import com.woowacourse.friendogly.kakao.source.KakaoLoginDataSourceImpl import com.woowacourse.friendogly.local.di.LocalModule @@ -31,6 +35,7 @@ import com.woowacourse.friendogly.remote.api.BaseUrl import com.woowacourse.friendogly.remote.di.RemoteModule import com.woowacourse.friendogly.remote.source.ClubDataSourceImpl import com.woowacourse.friendogly.remote.source.FootprintDataSourceImpl +import com.woowacourse.friendogly.remote.source.MemberDataSourceImpl class AppModule(context: Context) { private val baseUrl = BaseUrl(BuildConfig.base_url) @@ -49,12 +54,19 @@ class AppModule(context: Context) { localModule = localModule, ) + private val memberService = + RemoteModule.createMemberService( + baseUrl = baseUrl, + localModule = localModule, + ) + // data source private val clubDataSource: ClubDataSource = ClubDataSourceImpl(service = clubService) private val footprintDataSource: FootprintDataSource = FootprintDataSourceImpl(service = footprintService) private val localDataSource: LocalDataSource = LocalDataSourceImpl(localModule = localModule) private val kakaoLoginDataSource: KakaoLoginDataSource = KakaoLoginDataSourceImpl() + private val memberDataSource: MemberDataSource = MemberDataSourceImpl(service = memberService) // repository private val clubRepository: ClubRepository = ClubRepositoryImpl(source = clubDataSource) @@ -63,6 +75,7 @@ class AppModule(context: Context) { private val localRepository: LocalRepository = LocalRepositoryImpl(source = localDataSource) private val kakaoLoginRepository: KakaoLoginRepository = KakaoLoginRepositoryImpl(dataSource = kakaoLoginDataSource) + private val memberRepository: MemberRepository = MemberRepositoryImpl(source = memberDataSource) // use case val kakaoLoginUseCase: KakaoLoginUseCase = KakaoLoginUseCase(repository = kakaoLoginRepository) @@ -79,6 +92,7 @@ class AppModule(context: Context) { val saveJwtTokenUseCase: SaveJwtTokenUseCase = SaveJwtTokenUseCase(repository = localRepository) val deleteLocalDataUseCase: DeleteLocalDataUseCase = DeleteLocalDataUseCase(repository = localRepository) + val postMemberUseCase: PostMemberUseCase = PostMemberUseCase(repository = memberRepository) companion object { private var instance: AppModule? = null diff --git a/android/app/src/main/java/com/woowacourse/friendogly/data/mapper/MemberMapper.kt b/android/app/src/main/java/com/woowacourse/friendogly/data/mapper/MemberMapper.kt new file mode 100644 index 000000000..39741887d --- /dev/null +++ b/android/app/src/main/java/com/woowacourse/friendogly/data/mapper/MemberMapper.kt @@ -0,0 +1,10 @@ +package com.woowacourse.friendogly.data.mapper + +import com.woowacourse.friendogly.data.model.MemberDto +import com.woowacourse.friendogly.domain.model.Member + +fun MemberDto.toDomain(): Member { + return Member( + id = id, + ) +} diff --git a/android/app/src/main/java/com/woowacourse/friendogly/data/model/MemberDto.kt b/android/app/src/main/java/com/woowacourse/friendogly/data/model/MemberDto.kt new file mode 100644 index 000000000..de2739104 --- /dev/null +++ b/android/app/src/main/java/com/woowacourse/friendogly/data/model/MemberDto.kt @@ -0,0 +1,5 @@ +package com.woowacourse.friendogly.data.model + +data class MemberDto( + val id: Long, +) diff --git a/android/app/src/main/java/com/woowacourse/friendogly/data/repository/MemberRepositoryImpl.kt b/android/app/src/main/java/com/woowacourse/friendogly/data/repository/MemberRepositoryImpl.kt new file mode 100644 index 000000000..bcaad33c5 --- /dev/null +++ b/android/app/src/main/java/com/woowacourse/friendogly/data/repository/MemberRepositoryImpl.kt @@ -0,0 +1,15 @@ +package com.woowacourse.friendogly.data.repository + +import com.woowacourse.friendogly.data.mapper.toDomain +import com.woowacourse.friendogly.data.source.MemberDataSource +import com.woowacourse.friendogly.domain.model.Member +import com.woowacourse.friendogly.domain.repository.MemberRepository + +class MemberRepositoryImpl( + private val source: MemberDataSource, +) : MemberRepository { + override suspend fun postMember( + name: String, + email: String, + ): Result = source.postMember(name = name, email = email).mapCatching { result -> result.toDomain() } +} diff --git a/android/app/src/main/java/com/woowacourse/friendogly/data/source/MemberDataSource.kt b/android/app/src/main/java/com/woowacourse/friendogly/data/source/MemberDataSource.kt new file mode 100644 index 000000000..1942ec0fa --- /dev/null +++ b/android/app/src/main/java/com/woowacourse/friendogly/data/source/MemberDataSource.kt @@ -0,0 +1,10 @@ +package com.woowacourse.friendogly.data.source + +import com.woowacourse.friendogly.data.model.MemberDto + +interface MemberDataSource { + suspend fun postMember( + name: String, + email: String, + ): Result +} diff --git a/android/app/src/main/java/com/woowacourse/friendogly/domain/model/Member.kt b/android/app/src/main/java/com/woowacourse/friendogly/domain/model/Member.kt new file mode 100644 index 000000000..059742170 --- /dev/null +++ b/android/app/src/main/java/com/woowacourse/friendogly/domain/model/Member.kt @@ -0,0 +1,5 @@ +package com.woowacourse.friendogly.domain.model + +data class Member( + val id: Long, +) diff --git a/android/app/src/main/java/com/woowacourse/friendogly/domain/repository/MemberRepository.kt b/android/app/src/main/java/com/woowacourse/friendogly/domain/repository/MemberRepository.kt new file mode 100644 index 000000000..69b25e659 --- /dev/null +++ b/android/app/src/main/java/com/woowacourse/friendogly/domain/repository/MemberRepository.kt @@ -0,0 +1,10 @@ +package com.woowacourse.friendogly.domain.repository + +import com.woowacourse.friendogly.domain.model.Member + +interface MemberRepository { + suspend fun postMember( + name: String, + email: String, + ): Result +} diff --git a/android/app/src/main/java/com/woowacourse/friendogly/domain/usecase/PostMemberUseCase.kt b/android/app/src/main/java/com/woowacourse/friendogly/domain/usecase/PostMemberUseCase.kt new file mode 100644 index 000000000..05ac48169 --- /dev/null +++ b/android/app/src/main/java/com/woowacourse/friendogly/domain/usecase/PostMemberUseCase.kt @@ -0,0 +1,13 @@ +package com.woowacourse.friendogly.domain.usecase + +import com.woowacourse.friendogly.domain.model.Member +import com.woowacourse.friendogly.domain.repository.MemberRepository + +class PostMemberUseCase( + private val repository: MemberRepository, +) { + suspend operator fun invoke( + name: String, + email: String, + ): Result = repository.postMember(name = name, email = email) +} diff --git a/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/profilesetting/ProfileSettingActivity.kt b/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/profilesetting/ProfileSettingActivity.kt index a2980d076..5587b6a8f 100644 --- a/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/profilesetting/ProfileSettingActivity.kt +++ b/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/profilesetting/ProfileSettingActivity.kt @@ -12,6 +12,7 @@ import com.canhub.cropper.CropImageContract import com.canhub.cropper.CropImageContractOptions import com.canhub.cropper.CropImageOptions import com.woowacourse.friendogly.R +import com.woowacourse.friendogly.application.di.AppModule import com.woowacourse.friendogly.databinding.ActivityProfileSettingBinding import com.woowacourse.friendogly.presentation.base.BaseActivity import com.woowacourse.friendogly.presentation.base.observeEvent @@ -25,7 +26,12 @@ import com.woowacourse.friendogly.presentation.utils.toMultipartBody class ProfileSettingActivity : BaseActivity(R.layout.activity_profile_setting) { - private val viewModel: ProfileSettingViewModel by viewModels() + private val viewModel: ProfileSettingViewModel by viewModels { + ProfileSettingViewModel.factory( + postMemberUseCase = AppModule.getInstance().postMemberUseCase, + saveJwtTokenUseCase = AppModule.getInstance().saveJwtTokenUseCase, + ) + } private lateinit var imagePickerLauncher: ActivityResultLauncher private lateinit var imageCropLauncher: ActivityResultLauncher diff --git a/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/profilesetting/ProfileSettingViewModel.kt b/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/profilesetting/ProfileSettingViewModel.kt index d50d41e4a..61209dc2a 100644 --- a/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/profilesetting/ProfileSettingViewModel.kt +++ b/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/profilesetting/ProfileSettingViewModel.kt @@ -3,12 +3,22 @@ package com.woowacourse.friendogly.presentation.ui.profilesetting import android.graphics.Bitmap import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import com.woowacourse.friendogly.domain.model.JwtToken +import com.woowacourse.friendogly.domain.usecase.PostMemberUseCase +import com.woowacourse.friendogly.domain.usecase.SaveJwtTokenUseCase import com.woowacourse.friendogly.presentation.base.BaseViewModel +import com.woowacourse.friendogly.presentation.base.BaseViewModelFactory import com.woowacourse.friendogly.presentation.base.Event import com.woowacourse.friendogly.presentation.base.emit +import kotlinx.coroutines.launch import okhttp3.MultipartBody -class ProfileSettingViewModel : BaseViewModel() { +class ProfileSettingViewModel( + private val postMemberUseCase: PostMemberUseCase, + private val saveJwtTokenUseCase: SaveJwtTokenUseCase, +) : BaseViewModel() { private val _uiState: MutableLiveData = MutableLiveData(ProfileSettingUiState()) val uiState: LiveData get() = _uiState @@ -24,7 +34,24 @@ class ProfileSettingViewModel : BaseViewModel() { } fun submitProfileSelection() { - _navigateAction.emit(ProfileSettingNavigationAction.NavigateToHome) + val nickname = nickname.value ?: return + if (nickname.isBlank()) return + viewModelScope.launch { + postMemberUseCase(name = nickname, email = "wnswkd486@gmail.com").onSuccess { member -> + saveJwaToken(member.id) + }.onFailure { + // TODO 예외처리 + } + } + } + + private suspend fun saveJwaToken(memberId: Long) { + val jwtToken = JwtToken(accessToken = memberId.toString(), refreshToken = null) + saveJwtTokenUseCase(jwtToken = jwtToken).onSuccess { + _navigateAction.emit(ProfileSettingNavigationAction.NavigateToHome) + }.onFailure { + // TODO 예외처리 + } } fun updateProfileImage(bitmap: Bitmap) { @@ -41,4 +68,18 @@ class ProfileSettingViewModel : BaseViewModel() { val state = _uiState.value ?: return _uiState.value = state.copy(profilePath = file) } + + companion object { + fun factory( + postMemberUseCase: PostMemberUseCase, + saveJwtTokenUseCase: SaveJwtTokenUseCase, + ): ViewModelProvider.Factory { + return BaseViewModelFactory { _ -> + ProfileSettingViewModel( + postMemberUseCase = postMemberUseCase, + saveJwtTokenUseCase = saveJwtTokenUseCase, + ) + } + } + } } diff --git a/android/app/src/main/java/com/woowacourse/friendogly/remote/api/ApiClient.kt b/android/app/src/main/java/com/woowacourse/friendogly/remote/api/ApiClient.kt index 7e168c8ea..e11a326f6 100644 --- a/android/app/src/main/java/com/woowacourse/friendogly/remote/api/ApiClient.kt +++ b/android/app/src/main/java/com/woowacourse/friendogly/remote/api/ApiClient.kt @@ -8,7 +8,10 @@ class ApiClient { const val GET_FOOTPRINT_MINE_LATEST = "$BASE_URL/mine/latest" } - object Member + object Member { + private const val BASE_URL = "/members" + const val POST_MEMBER = BASE_URL + } object Pet diff --git a/android/app/src/main/java/com/woowacourse/friendogly/remote/api/MemberService.kt b/android/app/src/main/java/com/woowacourse/friendogly/remote/api/MemberService.kt new file mode 100644 index 000000000..945d28e46 --- /dev/null +++ b/android/app/src/main/java/com/woowacourse/friendogly/remote/api/MemberService.kt @@ -0,0 +1,13 @@ +package com.woowacourse.friendogly.remote.api + +import com.woowacourse.friendogly.remote.model.request.PostMembersRequest +import com.woowacourse.friendogly.remote.model.response.MemberResponse +import retrofit2.http.Body +import retrofit2.http.POST + +interface MemberService { + @POST(ApiClient.Member.POST_MEMBER) + suspend fun postMember( + @Body body: PostMembersRequest, + ): MemberResponse +} diff --git a/android/app/src/main/java/com/woowacourse/friendogly/remote/di/RemoteModule.kt b/android/app/src/main/java/com/woowacourse/friendogly/remote/di/RemoteModule.kt index e92a81c39..46eb1061c 100644 --- a/android/app/src/main/java/com/woowacourse/friendogly/remote/di/RemoteModule.kt +++ b/android/app/src/main/java/com/woowacourse/friendogly/remote/di/RemoteModule.kt @@ -5,6 +5,7 @@ import com.woowacourse.friendogly.local.di.LocalModule import com.woowacourse.friendogly.remote.api.BaseUrl import com.woowacourse.friendogly.remote.api.ClubService import com.woowacourse.friendogly.remote.api.FootprintService +import com.woowacourse.friendogly.remote.api.MemberService import com.woowacourse.friendogly.remote.interceptor.AuthorizationInterceptor import com.woowacourse.friendogly.remote.interceptor.ErrorResponseInterceptor import kotlinx.serialization.json.Json @@ -35,6 +36,22 @@ object RemoteModule { ).create(ClubService::class.java) } + fun createMemberService( + baseUrl: BaseUrl, + localModule: LocalModule, + ): MemberService { + return createRetrofit( + baseUrl, + localModule, + ).create(MemberService::class.java) + } + + private val json = + Json { + ignoreUnknownKeys = true + coerceInputValues = true + } + private fun createRetrofit( baseUrl: BaseUrl, localModule: LocalModule, @@ -44,7 +61,7 @@ object RemoteModule { addInterceptor(AuthorizationInterceptor(localModule = localModule)) addInterceptor(ErrorResponseInterceptor()) }, - ).addConverterFactory(Json.asConverterFactory(contentType)).build() + ).addConverterFactory(json.asConverterFactory(contentType)).build() } private fun createOkHttpClient(interceptors: OkHttpClient.Builder.() -> Unit = { }): OkHttpClient = diff --git a/android/app/src/main/java/com/woowacourse/friendogly/remote/mapper/MemberDtoMapper.kt b/android/app/src/main/java/com/woowacourse/friendogly/remote/mapper/MemberDtoMapper.kt new file mode 100644 index 000000000..22c100ade --- /dev/null +++ b/android/app/src/main/java/com/woowacourse/friendogly/remote/mapper/MemberDtoMapper.kt @@ -0,0 +1,12 @@ +package com.woowacourse.friendogly.remote.mapper + +import android.util.Log +import com.woowacourse.friendogly.data.model.MemberDto +import com.woowacourse.friendogly.remote.model.response.MemberResponse + +fun MemberResponse.toData(): MemberDto { + Log.d("ttt this", this.toString()) + return MemberDto( + id = id, + ) +} diff --git a/android/app/src/main/java/com/woowacourse/friendogly/remote/model/request/PostMembersRequest.kt b/android/app/src/main/java/com/woowacourse/friendogly/remote/model/request/PostMembersRequest.kt new file mode 100644 index 000000000..5a5d4d792 --- /dev/null +++ b/android/app/src/main/java/com/woowacourse/friendogly/remote/model/request/PostMembersRequest.kt @@ -0,0 +1,9 @@ +package com.woowacourse.friendogly.remote.model.request + +import kotlinx.serialization.Serializable + +@Serializable +data class PostMembersRequest( + val name: String, + val email: String, +) diff --git a/android/app/src/main/java/com/woowacourse/friendogly/remote/model/response/BaseResponse.kt b/android/app/src/main/java/com/woowacourse/friendogly/remote/model/response/BaseResponse.kt index 5e84d1955..d19a1df04 100644 --- a/android/app/src/main/java/com/woowacourse/friendogly/remote/model/response/BaseResponse.kt +++ b/android/app/src/main/java/com/woowacourse/friendogly/remote/model/response/BaseResponse.kt @@ -1,5 +1,8 @@ package com.woowacourse.friendogly.remote.model.response +import kotlinx.serialization.Serializable + +@Serializable data class BaseResponse( val data: T, val errorCode: String, diff --git a/android/app/src/main/java/com/woowacourse/friendogly/remote/model/response/MemberResponse.kt b/android/app/src/main/java/com/woowacourse/friendogly/remote/model/response/MemberResponse.kt new file mode 100644 index 000000000..c13596ee7 --- /dev/null +++ b/android/app/src/main/java/com/woowacourse/friendogly/remote/model/response/MemberResponse.kt @@ -0,0 +1,11 @@ +package com.woowacourse.friendogly.remote.model.response + +import kotlinx.serialization.Serializable + +@Serializable +data class MemberResponse( + val id: Long, + val name: String, + val tag: String = "", + val email: String, +) diff --git a/android/app/src/main/java/com/woowacourse/friendogly/remote/source/MemberDataSourceImpl.kt b/android/app/src/main/java/com/woowacourse/friendogly/remote/source/MemberDataSourceImpl.kt new file mode 100644 index 000000000..d2e595173 --- /dev/null +++ b/android/app/src/main/java/com/woowacourse/friendogly/remote/source/MemberDataSourceImpl.kt @@ -0,0 +1,20 @@ +package com.woowacourse.friendogly.remote.source + +import com.woowacourse.friendogly.data.model.MemberDto +import com.woowacourse.friendogly.data.source.MemberDataSource +import com.woowacourse.friendogly.remote.api.MemberService +import com.woowacourse.friendogly.remote.mapper.toData +import com.woowacourse.friendogly.remote.model.request.PostMembersRequest + +class MemberDataSourceImpl( + private val service: MemberService, +) : MemberDataSource { + override suspend fun postMember( + name: String, + email: String, + ): Result = + runCatching { + val body = PostMembersRequest(name = name, email = email) + service.postMember(body = body).toData() + } +} From 401d4cf9e87b6be940a306b6630232948259290a Mon Sep 17 00:00:00 2001 From: JunJangE Date: Tue, 23 Jul 2024 11:02:05 +0900 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20=EC=8A=A4=ED=94=8C=EB=9E=98?= =?UTF-8?q?=EC=8B=9C=20=EB=B0=8F=20=EC=9E=90=EB=8F=99=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/src/main/AndroidManifest.xml | 10 +++-- .../ui/register/RegisterActivity.kt | 41 ++++++++++++++++--- .../ui/register/RegisterNavigationAction.kt | 2 + .../ui/register/RegisterViewModel.kt | 32 ++++++++++++++- android/app/src/main/res/values/themes.xml | 7 ++++ android/gradle/libs.versions.toml | 5 ++- 6 files changed, 84 insertions(+), 13 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 3ebc03512..7f5baf63b 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -20,18 +20,20 @@ tools:targetApi="31"> + android:exported="false" /> - + + android:exported="true" + android:theme="@style/Theme.Friendogly.Splash"> diff --git a/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterActivity.kt b/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterActivity.kt index 38299ca21..54a5de29f 100644 --- a/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterActivity.kt +++ b/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterActivity.kt @@ -1,17 +1,25 @@ package com.woowacourse.friendogly.presentation.ui.register +import android.os.Bundle import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import com.google.android.gms.common.api.ApiException -import com.woowacourse.friendogly.R import com.woowacourse.friendogly.application.di.AppModule import com.woowacourse.friendogly.databinding.ActivityRegisterBinding -import com.woowacourse.friendogly.presentation.base.BaseActivity import com.woowacourse.friendogly.presentation.base.observeEvent +import com.woowacourse.friendogly.presentation.ui.MainActivity import com.woowacourse.friendogly.presentation.ui.profilesetting.ProfileSettingActivity -class RegisterActivity : BaseActivity(R.layout.activity_register) { +class RegisterActivity : AppCompatActivity() { + private var _binding: ActivityRegisterBinding? = null + val binding get() = requireNotNull(_binding) + private val viewModel: RegisterViewModel by viewModels { - RegisterViewModel.factory(kakaoLoginUseCase = AppModule.getInstance().kakaoLoginUseCase) + RegisterViewModel.factory( + kakaoLoginUseCase = AppModule.getInstance().kakaoLoginUseCase, + getJwtTokenUseCase = AppModule.getInstance().getJwtTokenUseCase, + ) } private val googleSignInLauncher = @@ -22,18 +30,39 @@ class RegisterActivity : BaseActivity(R.layout.activity viewModel.handleGoogleLogin(idToken = idToken) } - override fun initCreateView() { + override fun onCreate(savedInstanceState: Bundle?) { + val splashScreen = installSplashScreen() + super.onCreate(savedInstanceState) + + _binding = ActivityRegisterBinding.inflate(layoutInflater) + setContentView(binding.root) + + initCreateView() + splashScreen.setKeepOnScreenCondition { + viewModel.splashLoading.value == true + } + } + + private fun initCreateView() { initDataBinding() initObserve() } private fun initDataBinding() { - binding.vm = viewModel + binding.apply { + vm = viewModel + lifecycleOwner = this@RegisterActivity + } } private fun initObserve() { viewModel.navigateAction.observeEvent(this) { action -> when (action) { + is RegisterNavigationAction.NavigateToAlreadyLogin -> { + startActivity(MainActivity.getIntent(this)) + finish() + } + is RegisterNavigationAction.NavigateToGoogleLogin -> googleSignInLauncher.launch( SIGN_IN_REQUEST_CODE, diff --git a/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterNavigationAction.kt b/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterNavigationAction.kt index 5ffd00ea7..46be24232 100644 --- a/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterNavigationAction.kt +++ b/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterNavigationAction.kt @@ -1,6 +1,8 @@ package com.woowacourse.friendogly.presentation.ui.register sealed interface RegisterNavigationAction { + data object NavigateToAlreadyLogin : RegisterNavigationAction + data object NavigateToGoogleLogin : RegisterNavigationAction data class NavigateToProfileSetting(val idToken: String) : RegisterNavigationAction diff --git a/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterViewModel.kt b/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterViewModel.kt index e2b05c60f..a0ef18574 100644 --- a/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterViewModel.kt +++ b/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/register/RegisterViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope +import com.woowacourse.friendogly.domain.usecase.GetJwtTokenUseCase import com.woowacourse.friendogly.domain.usecase.KakaoLoginUseCase import com.woowacourse.friendogly.presentation.base.BaseViewModel import com.woowacourse.friendogly.presentation.base.BaseViewModelFactory @@ -14,11 +15,32 @@ import kotlinx.coroutines.launch class RegisterViewModel( private val kakaoLoginUseCase: KakaoLoginUseCase, + private val getJwtTokenUseCase: GetJwtTokenUseCase, ) : BaseViewModel() { private val _navigateAction: MutableLiveData> = MutableLiveData(null) val navigateAction: LiveData> get() = _navigateAction + val splashLoading = MutableLiveData(true) + + init { + handleTokenState() + } + + private fun handleTokenState() { + viewModelScope.launch { + getJwtTokenUseCase().onSuccess { jwtToken -> + if (jwtToken?.accessToken.isNullOrBlank()) { + splashLoading.value = false + return@onSuccess + } + _navigateAction.emit(RegisterNavigationAction.NavigateToAlreadyLogin) + }.onFailure { + // TODO 예외처리 + } + } + } + fun executeKakaoLogin(context: Context) { viewModelScope.launch { kakaoLoginUseCase(context = context).onSuccess { kakaAccessToken -> @@ -37,9 +59,15 @@ class RegisterViewModel( } companion object { - fun factory(kakaoLoginUseCase: KakaoLoginUseCase): ViewModelProvider.Factory { + fun factory( + kakaoLoginUseCase: KakaoLoginUseCase, + getJwtTokenUseCase: GetJwtTokenUseCase, + ): ViewModelProvider.Factory { return BaseViewModelFactory { _ -> - RegisterViewModel(kakaoLoginUseCase = kakaoLoginUseCase) + RegisterViewModel( + kakaoLoginUseCase = kakaoLoginUseCase, + getJwtTokenUseCase = getJwtTokenUseCase, + ) } } } diff --git a/android/app/src/main/res/values/themes.xml b/android/app/src/main/res/values/themes.xml index 40cb7a90d..9036c4756 100644 --- a/android/app/src/main/res/values/themes.xml +++ b/android/app/src/main/res/values/themes.xml @@ -8,6 +8,13 @@ + + diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index ced8b21bf..7e17a57e6 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -54,6 +54,8 @@ serialization = "1.6.0" # paging paging = "3.3.0" +splashscreen = "1.0.1" + [libraries] # test junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -85,6 +87,7 @@ androidx-navigation-ui = { group = "androidx.navigation", name = "navigation-ui- glide = { group = "com.github.bumptech.glide", name = "glide", version.ref = "glide" } paging-runtime-ktx = { group = "androidx.paging", name = "paging-runtime-ktx", version.ref = "paging" } flextbox = { group = "com.google.android.flexbox", name = "flexbox", version.ref = "flexbox" } +splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "splashscreen" } # kakao kakao-user = { group = "com.kakao.sdk", name = "v2-user", version.ref = "kakao-user" } @@ -109,7 +112,7 @@ okhttp-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-i retrofit2-kotlinx-serialization-converter = { module = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter", version.ref = "retrofit2-kotlinx-serialization-converter" } [bundles] -android = ["androidx-constraintlayout", "androidx-activity", "androidx-appcompat", "androidx-core-ktx", "material", "image-cropper", "glide", "flextbox", "paging-runtime-ktx"] +android = ["androidx-constraintlayout", "androidx-activity", "androidx-appcompat", "androidx-core-ktx", "material", "image-cropper", "glide", "flextbox", "paging-runtime-ktx", "splashscreen"] kotlin = ["lifecycle-runtime-ktx", "lifecycle-extensions", "coroutines-core", "kotlinx-serialization"] navigation = ["androidx-navigation-fragemnt", "androidx-navigation-ui"] google = ["google-services", "firebase-auth", "firebase-messaging", "firebase-bom", "google-auth"] From 2d6054ec65f7343b09cc541acd1b0d8e0506c478 Mon Sep 17 00:00:00 2001 From: JunJangE Date: Tue, 23 Jul 2024 14:01:04 +0900 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20=EB=8B=89=EB=84=A4=EC=9E=84=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/profilesetting/ProfileSettingViewModel.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/profilesetting/ProfileSettingViewModel.kt b/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/profilesetting/ProfileSettingViewModel.kt index 61209dc2a..de9effd9b 100644 --- a/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/profilesetting/ProfileSettingViewModel.kt +++ b/android/app/src/main/java/com/woowacourse/friendogly/presentation/ui/profilesetting/ProfileSettingViewModel.kt @@ -36,8 +36,13 @@ class ProfileSettingViewModel( fun submitProfileSelection() { val nickname = nickname.value ?: return if (nickname.isBlank()) return + if (regex.matches(nickname)) return viewModelScope.launch { - postMemberUseCase(name = nickname, email = "wnswkd486@gmail.com").onSuccess { member -> + // TODO email 필드는 임시로 넣어두었습니다. + postMemberUseCase( + name = nickname, + email = "test@banggapge.com", + ).onSuccess { member -> saveJwaToken(member.id) }.onFailure { // TODO 예외처리 @@ -70,6 +75,8 @@ class ProfileSettingViewModel( } companion object { + private val regex = "^[ㄱ-ㅎㅏ-ㅣ]+$".toRegex() + fun factory( postMemberUseCase: PostMemberUseCase, saveJwtTokenUseCase: SaveJwtTokenUseCase, From 5635602617f4af332d304588c3fdb1b8a575f7da Mon Sep 17 00:00:00 2001 From: JunJangE Date: Tue, 23 Jul 2024 14:47:58 +0900 Subject: [PATCH 5/5] =?UTF-8?q?chore:=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/woowacourse/friendogly/remote/mapper/MemberDtoMapper.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/android/app/src/main/java/com/woowacourse/friendogly/remote/mapper/MemberDtoMapper.kt b/android/app/src/main/java/com/woowacourse/friendogly/remote/mapper/MemberDtoMapper.kt index 22c100ade..9ac4cdfb4 100644 --- a/android/app/src/main/java/com/woowacourse/friendogly/remote/mapper/MemberDtoMapper.kt +++ b/android/app/src/main/java/com/woowacourse/friendogly/remote/mapper/MemberDtoMapper.kt @@ -1,11 +1,9 @@ package com.woowacourse.friendogly.remote.mapper -import android.util.Log import com.woowacourse.friendogly.data.model.MemberDto import com.woowacourse.friendogly.remote.model.response.MemberResponse fun MemberResponse.toData(): MemberDto { - Log.d("ttt this", this.toString()) return MemberDto( id = id, )