From 8ae94632858d49e9e90d7b3a749332a2de915268 Mon Sep 17 00:00:00 2001 From: yeonjeen Date: Sat, 15 Feb 2025 19:58:13 +0900 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20=EC=95=BD=EA=B4=80=EB=8F=99?= =?UTF-8?q?=EC=9D=98=20Entity=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/into/websoso/data/model/TermsAgreementEntity.kt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 app/src/main/java/com/into/websoso/data/model/TermsAgreementEntity.kt diff --git a/app/src/main/java/com/into/websoso/data/model/TermsAgreementEntity.kt b/app/src/main/java/com/into/websoso/data/model/TermsAgreementEntity.kt new file mode 100644 index 000000000..ea976c779 --- /dev/null +++ b/app/src/main/java/com/into/websoso/data/model/TermsAgreementEntity.kt @@ -0,0 +1,7 @@ +package com.into.websoso.data.model + +data class TermsAgreementEntity( + val serviceAgreed: Boolean, + val privacyAgreed: Boolean, + val marketingAgreed: Boolean, +) From a80cafef035ea7968e86f84bc4b1a3c9c2f2d28c Mon Sep 17 00:00:00 2001 From: yeonjeen Date: Sun, 16 Feb 2025 09:29:52 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20=EC=95=BD=EA=B4=80=EB=8F=99?= =?UTF-8?q?=EC=9D=98=20=EC=9D=91=EB=8B=B5=20dto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../remote/response/TermsAgreementResponseDto.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 app/src/main/java/com/into/websoso/data/remote/response/TermsAgreementResponseDto.kt diff --git a/app/src/main/java/com/into/websoso/data/remote/response/TermsAgreementResponseDto.kt b/app/src/main/java/com/into/websoso/data/remote/response/TermsAgreementResponseDto.kt new file mode 100644 index 000000000..eace932b4 --- /dev/null +++ b/app/src/main/java/com/into/websoso/data/remote/response/TermsAgreementResponseDto.kt @@ -0,0 +1,14 @@ +package com.into.websoso.data.remote.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class TermsAgreementResponseDto( + @SerialName("serviceAgreed") + val serviceAgreed: Boolean, + @SerialName("privacyAgreed") + val privacyAgreed: Boolean, + @SerialName("marketingAgreed") + val marketingAgreed: Boolean, +) From 369197119a8481b63a39dc1dd1cc08eda3e00f3f Mon Sep 17 00:00:00 2001 From: yeonjeen Date: Sun, 16 Feb 2025 09:30:00 +0900 Subject: [PATCH 03/11] =?UTF-8?q?feat:=20=EC=95=BD=EA=B4=80=EB=8F=99?= =?UTF-8?q?=EC=9D=98=20=EC=9A=94=EC=B2=AD=20dto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../remote/request/TermsAgreementRequestDto.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 app/src/main/java/com/into/websoso/data/remote/request/TermsAgreementRequestDto.kt diff --git a/app/src/main/java/com/into/websoso/data/remote/request/TermsAgreementRequestDto.kt b/app/src/main/java/com/into/websoso/data/remote/request/TermsAgreementRequestDto.kt new file mode 100644 index 000000000..58cfe6f03 --- /dev/null +++ b/app/src/main/java/com/into/websoso/data/remote/request/TermsAgreementRequestDto.kt @@ -0,0 +1,14 @@ +package com.into.websoso.data.remote.request + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class TermsAgreementRequestDto( + @SerialName("serviceAgreed") + val serviceAgreed: Boolean, + @SerialName("privacyAgreed") + val privacyAgreed: Boolean, + @SerialName("marketingAgreed") + val marketingAgreed: Boolean, +) From bf92ef015cf0660cbe56bd4f7193f55152b680fe Mon Sep 17 00:00:00 2001 From: yeonjeen Date: Sun, 16 Feb 2025 09:30:36 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20=EC=95=BD=EA=B4=80=EB=8F=99?= =?UTF-8?q?=EC=9D=98=20patch/get=20api=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/into/websoso/data/remote/api/UserApi.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/java/com/into/websoso/data/remote/api/UserApi.kt b/app/src/main/java/com/into/websoso/data/remote/api/UserApi.kt index 2632fd5ed..8a1994dfe 100644 --- a/app/src/main/java/com/into/websoso/data/remote/api/UserApi.kt +++ b/app/src/main/java/com/into/websoso/data/remote/api/UserApi.kt @@ -1,5 +1,6 @@ package com.into.websoso.data.remote.api +import com.into.websoso.data.remote.request.TermsAgreementRequestDto import com.into.websoso.data.remote.request.UserInfoRequestDto import com.into.websoso.data.remote.request.UserProfileEditRequestDto import com.into.websoso.data.remote.request.UserProfileStatusRequestDto @@ -8,6 +9,7 @@ import com.into.websoso.data.remote.response.GenrePreferenceResponseDto import com.into.websoso.data.remote.response.MyProfileResponseDto import com.into.websoso.data.remote.response.NovelPreferenceResponseDto import com.into.websoso.data.remote.response.OtherUserProfileResponseDto +import com.into.websoso.data.remote.response.TermsAgreementResponseDto import com.into.websoso.data.remote.response.UserFeedsResponseDto import com.into.websoso.data.remote.response.UserInfoDetailResponseDto import com.into.websoso.data.remote.response.UserInfoResponseDto @@ -106,4 +108,12 @@ interface UserApi { @Query("lastFeedId") lastFeedId: Long, @Query("size") size: Int, ): UserFeedsResponseDto + + @PATCH("users/terms-settings") + suspend fun patchTermsAgreement( + @Body termsAgreementRequestDto: TermsAgreementRequestDto, + ) + + @GET("users/terms-settings") + suspend fun getTermsAgreement(): TermsAgreementResponseDto } From 450b0a3aad217e62c3772f6fa373946210c54885 Mon Sep 17 00:00:00 2001 From: yeonjeen Date: Sun, 16 Feb 2025 09:31:05 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20=EC=95=BD=EA=B4=80=EB=8F=99?= =?UTF-8?q?=EC=9D=98=20dto=EC=99=80=20entity=20=EB=A7=A4=ED=95=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/into/websoso/data/mapper/UserMapper.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/into/websoso/data/mapper/UserMapper.kt b/app/src/main/java/com/into/websoso/data/mapper/UserMapper.kt index 94ea7de30..d31a64026 100644 --- a/app/src/main/java/com/into/websoso/data/mapper/UserMapper.kt +++ b/app/src/main/java/com/into/websoso/data/mapper/UserMapper.kt @@ -6,6 +6,7 @@ import com.into.websoso.data.model.GenrePreferenceEntity import com.into.websoso.data.model.MyProfileEntity import com.into.websoso.data.model.NovelPreferenceEntity import com.into.websoso.data.model.OtherUserProfileEntity +import com.into.websoso.data.model.TermsAgreementEntity import com.into.websoso.data.model.UserFeedsEntity import com.into.websoso.data.model.UserFeedsEntity.UserFeedEntity import com.into.websoso.data.model.UserInfoDetailEntity @@ -19,6 +20,7 @@ import com.into.websoso.data.remote.response.GenrePreferenceResponseDto import com.into.websoso.data.remote.response.MyProfileResponseDto import com.into.websoso.data.remote.response.NovelPreferenceResponseDto import com.into.websoso.data.remote.response.OtherUserProfileResponseDto +import com.into.websoso.data.remote.response.TermsAgreementResponseDto import com.into.websoso.data.remote.response.UserFeedsResponseDto import com.into.websoso.data.remote.response.UserFeedsResponseDto.UserFeedResponseDto import com.into.websoso.data.remote.response.UserInfoDetailResponseDto @@ -156,4 +158,12 @@ fun UserFeedResponseDto.toData(): UserFeedEntity { novelRating = this.novelRating, relevantCategories = this.relevantCategories, ) -} \ No newline at end of file +} + +fun TermsAgreementResponseDto.toData(): TermsAgreementEntity { + return TermsAgreementEntity( + serviceAgreed = this.serviceAgreed, + privacyAgreed = this.privacyAgreed, + marketingAgreed = this.marketingAgreed, + ) +} From 7366446b1607146ece5c95e960631b7a2af3c4d0 Mon Sep 17 00:00:00 2001 From: yeonjeen Date: Sun, 16 Feb 2025 09:36:58 +0900 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=84=B0=EB=A6=AC=20api=20=EC=97=B0=EA=B2=B0=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../websoso/data/repository/UserRepository.kt | 258 ++++++++++-------- 1 file changed, 138 insertions(+), 120 deletions(-) diff --git a/app/src/main/java/com/into/websoso/data/repository/UserRepository.kt b/app/src/main/java/com/into/websoso/data/repository/UserRepository.kt index faf813b4d..b9fb99168 100644 --- a/app/src/main/java/com/into/websoso/data/repository/UserRepository.kt +++ b/app/src/main/java/com/into/websoso/data/repository/UserRepository.kt @@ -11,6 +11,7 @@ import com.into.websoso.data.model.GenrePreferenceEntity import com.into.websoso.data.model.MyProfileEntity import com.into.websoso.data.model.NovelPreferenceEntity import com.into.websoso.data.model.OtherUserProfileEntity +import com.into.websoso.data.model.TermsAgreementEntity import com.into.websoso.data.model.UserFeedsEntity import com.into.websoso.data.model.UserInfoDetailEntity import com.into.websoso.data.model.UserInfoEntity @@ -18,6 +19,7 @@ import com.into.websoso.data.model.UserNovelStatsEntity import com.into.websoso.data.model.UserProfileStatusEntity import com.into.websoso.data.model.UserStorageEntity import com.into.websoso.data.remote.api.UserApi +import com.into.websoso.data.remote.request.TermsAgreementRequestDto import com.into.websoso.data.remote.request.UserInfoRequestDto import com.into.websoso.data.remote.request.UserProfileEditRequestDto import com.into.websoso.data.remote.request.UserProfileStatusRequestDto @@ -25,152 +27,168 @@ import kotlinx.coroutines.flow.first import javax.inject.Inject class UserRepository - @Inject - constructor( - private val userApi: UserApi, - private val userStorage: DataStore, +@Inject +constructor( + private val userApi: UserApi, + private val userStorage: DataStore, +) { + suspend fun fetchUserInfo(): UserInfoEntity { + val userInfo = userApi.getUserInfo().toData() + saveUserInfo(userInfo.userId, userInfo.nickname, userInfo.gender) + return userInfo + } + + private suspend fun saveUserInfo( + userId: Long, + nickname: String, + gender: String, ) { - suspend fun fetchUserInfo(): UserInfoEntity { - val userInfo = userApi.getUserInfo().toData() - saveUserInfo(userInfo.userId, userInfo.nickname, userInfo.gender) - return userInfo + userStorage.edit { preferences -> + preferences[USER_ID_KEY] = userId.toString() + preferences[USER_NICKNAME_KEY] = nickname + preferences[USER_GENDER_KEY] = gender } + } - private suspend fun saveUserInfo( - userId: Long, - nickname: String, - gender: String, - ) { - userStorage.edit { preferences -> - preferences[USER_ID_KEY] = userId.toString() - preferences[USER_NICKNAME_KEY] = nickname - preferences[USER_GENDER_KEY] = gender - } - } + suspend fun fetchUserInfoDetail(): UserInfoDetailEntity = userApi.getUserInfoDetail().toData() - suspend fun fetchUserInfoDetail(): UserInfoDetailEntity = userApi.getUserInfoDetail().toData() + suspend fun fetchBlockedUsers(): BlockedUsersEntity = userApi.getBlockedUser().toData() - suspend fun fetchBlockedUsers(): BlockedUsersEntity = userApi.getBlockedUser().toData() + suspend fun deleteBlockedUser(blockId: Long) { + userApi.deleteBlockedUser(blockId) + } - suspend fun deleteBlockedUser(blockId: Long) { - userApi.deleteBlockedUser(blockId) - } + suspend fun saveBlockUser(userId: Long) { + userApi.postBlockUser(userId) + } - suspend fun saveBlockUser(userId: Long) { - userApi.postBlockUser(userId) - } + suspend fun fetchUserNovelStats(userId: Long): UserNovelStatsEntity = + userApi.getUserNovelStats(userId).toData() - suspend fun fetchUserNovelStats(userId: Long): UserNovelStatsEntity = userApi.getUserNovelStats(userId).toData() + suspend fun fetchUserProfileStatus(): UserProfileStatusEntity = + userApi.getProfileStatus().toData() - suspend fun fetchUserProfileStatus(): UserProfileStatusEntity = userApi.getProfileStatus().toData() + suspend fun saveUserProfileStatus(isProfilePublic: Boolean) { + userApi.patchProfileStatus(UserProfileStatusRequestDto(isProfilePublic)) + } - suspend fun saveUserProfileStatus(isProfilePublic: Boolean) { - userApi.patchProfileStatus(UserProfileStatusRequestDto(isProfilePublic)) - } + suspend fun saveUserInfoDetail( + gender: String, + birthYear: Int, + ) { + userApi.putUserInfo(UserInfoRequestDto(gender, birthYear)) + } - suspend fun saveUserInfoDetail( - gender: String, - birthYear: Int, - ) { - userApi.putUserInfo(UserInfoRequestDto(gender, birthYear)) - } + suspend fun fetchMyProfile(): MyProfileEntity = userApi.getMyProfile().toData() - suspend fun fetchMyProfile(): MyProfileEntity = userApi.getMyProfile().toData() + suspend fun fetchGenrePreference(userId: Long): List = + userApi.getGenrePreference(userId).genrePreferences.map { + it.toData() + } - suspend fun fetchGenrePreference(userId: Long): List = - userApi.getGenrePreference(userId).genrePreferences.map { - it.toData() - } + suspend fun fetchNovelPreferences(userId: Long): NovelPreferenceEntity = + userApi.getNovelPreferences(userId).toData() - suspend fun fetchNovelPreferences(userId: Long): NovelPreferenceEntity = userApi.getNovelPreferences(userId).toData() + suspend fun fetchOtherUserProfile(userId: Long): OtherUserProfileEntity = + userApi.getOtherUserProfile(userId).toData() - suspend fun fetchOtherUserProfile(userId: Long): OtherUserProfileEntity = userApi.getOtherUserProfile(userId).toData() + suspend fun saveEditingUserProfile( + avatarId: Int?, + nickname: String?, + intro: String?, + genrePreferences: List, + ) { + userApi.patchProfile(UserProfileEditRequestDto(avatarId, nickname, intro, genrePreferences)) + } - suspend fun saveEditingUserProfile( - avatarId: Int?, - nickname: String?, - intro: String?, - genrePreferences: List, - ) { - userApi.patchProfile(UserProfileEditRequestDto(avatarId, nickname, intro, genrePreferences)) + suspend fun saveNovelDetailFirstLaunched(value: Boolean) { + userStorage.edit { preferences -> + preferences[NOVEL_DETAIL_FIRST_LAUNCHED_KEY] = value } + } - suspend fun saveNovelDetailFirstLaunched(value: Boolean) { - userStorage.edit { preferences -> - preferences[NOVEL_DETAIL_FIRST_LAUNCHED_KEY] = value - } - } + suspend fun fetchUserId(): Long { + val preferences = userStorage.data.first() + return preferences[USER_ID_KEY]?.toLongOrNull() ?: DEFAULT_USER_ID + } - suspend fun fetchUserId(): Long { - val preferences = userStorage.data.first() - return preferences[USER_ID_KEY]?.toLongOrNull() ?: DEFAULT_USER_ID - } + suspend fun fetchIsLogin(): Boolean = fetchUserId() != DEFAULT_USER_ID - suspend fun fetchIsLogin(): Boolean = fetchUserId() != DEFAULT_USER_ID + suspend fun fetchGender(): String { + val preferences = userStorage.data.first() + return preferences[USER_GENDER_KEY] ?: DEFAULT_USER_GENDER + } - suspend fun fetchGender(): String { - val preferences = userStorage.data.first() - return preferences[USER_GENDER_KEY] ?: DEFAULT_USER_GENDER + suspend fun saveGender(gender: String) { + userStorage.edit { preferences -> + preferences[USER_GENDER_KEY] = gender } + } - suspend fun saveGender(gender: String) { - userStorage.edit { preferences -> - preferences[USER_GENDER_KEY] = gender - } - } + suspend fun fetchNovelDetailFirstLaunched() = + userStorage.data.first()[NOVEL_DETAIL_FIRST_LAUNCHED_KEY] ?: true + + suspend fun fetchNicknameValidity(nickname: String): Boolean = + userApi.getNicknameValidity(nickname).isValid + + suspend fun fetchUserStorage( + userId: Long, + readStatus: String, + lastUserNovelId: Long, + size: Int, + sortType: String, + ): UserStorageEntity = + userApi + .getUserStorage( + userId = userId, + readStatus = readStatus, + lastUserNovelId = lastUserNovelId, + size = size, + sortType = sortType, + ).toData() + + suspend fun fetchUserFeeds( + userId: Long, + lastFeedId: Long, + size: Int, + ): UserFeedsEntity = userApi.getUserFeeds(userId, lastFeedId, size).toData() + + suspend fun fetchMyActivities( + lastFeedId: Long, + size: Int, + ): UserFeedsEntity { + val myUserId = fetchUserId() + return fetchUserFeeds(myUserId, lastFeedId, size) + } - suspend fun fetchNovelDetailFirstLaunched() = userStorage.data.first()[NOVEL_DETAIL_FIRST_LAUNCHED_KEY] ?: true - - suspend fun fetchNicknameValidity(nickname: String): Boolean = userApi.getNicknameValidity(nickname).isValid - - suspend fun fetchUserStorage( - userId: Long, - readStatus: String, - lastUserNovelId: Long, - size: Int, - sortType: String, - ): UserStorageEntity = - userApi - .getUserStorage( - userId = userId, - readStatus = readStatus, - lastUserNovelId = lastUserNovelId, - size = size, - sortType = sortType, - ).toData() - - suspend fun fetchUserFeeds( - userId: Long, - lastFeedId: Long, - size: Int, - ): UserFeedsEntity = userApi.getUserFeeds(userId, lastFeedId, size).toData() - - suspend fun fetchMyActivities( - lastFeedId: Long, - size: Int, - ): UserFeedsEntity { - val myUserId = fetchUserId() - return fetchUserFeeds(myUserId, lastFeedId, size) - } + suspend fun fetchUserDeviceIdentifier(): String { + val preferences = userStorage.data.first() + return preferences[USER_DEVICE_IDENTIFIER_KEY] ?: "" + } - suspend fun fetchUserDeviceIdentifier(): String { - val preferences = userStorage.data.first() - return preferences[USER_DEVICE_IDENTIFIER_KEY] ?: "" + suspend fun saveUserDeviceIdentifier(deviceIdentifier: String) { + userStorage.edit { preferences -> + preferences[USER_DEVICE_IDENTIFIER_KEY] = deviceIdentifier } + } - suspend fun saveUserDeviceIdentifier(deviceIdentifier: String) { - userStorage.edit { preferences -> - preferences[USER_DEVICE_IDENTIFIER_KEY] = deviceIdentifier - } - } + suspend fun saveTermsAgreements( + serviceAgreed: Boolean, + privacyAgreed: Boolean, + marketingAgreed: Boolean, + ) { + userApi.patchTermsAgreement(TermsAgreementRequestDto( serviceAgreed,privacyAgreed,marketingAgreed)) + } - companion object { - val NOVEL_DETAIL_FIRST_LAUNCHED_KEY = booleanPreferencesKey("NOVEL_DETAIL_FIRST_LAUNCHED") - val USER_ID_KEY = stringPreferencesKey("USER_ID") - val USER_NICKNAME_KEY = stringPreferencesKey("USER_NICKNAME") - val USER_GENDER_KEY = stringPreferencesKey("USER_GENDER") - val USER_DEVICE_IDENTIFIER_KEY = stringPreferencesKey("USER_DEVICE_IDENTIFIER") - const val DEFAULT_USER_ID = -1L - const val DEFAULT_USER_GENDER = "F" - } + suspend fun fetchTermsAgreements(): TermsAgreementEntity = userApi.getTermsAgreement().toData() + + companion object { + val NOVEL_DETAIL_FIRST_LAUNCHED_KEY = booleanPreferencesKey("NOVEL_DETAIL_FIRST_LAUNCHED") + val USER_ID_KEY = stringPreferencesKey("USER_ID") + val USER_NICKNAME_KEY = stringPreferencesKey("USER_NICKNAME") + val USER_GENDER_KEY = stringPreferencesKey("USER_GENDER") + val USER_DEVICE_IDENTIFIER_KEY = stringPreferencesKey("USER_DEVICE_IDENTIFIER") + const val DEFAULT_USER_ID = -1L + const val DEFAULT_USER_GENDER = "F" } +} From 5083b8bbd08232d0ccd41136f0a3db27e351b499 Mon Sep 17 00:00:00 2001 From: yeonjeen Date: Sun, 16 Feb 2025 09:38:47 +0900 Subject: [PATCH 07/11] =?UTF-8?q?feat:=20=EC=95=BD=EA=B4=80=EB=8F=99?= =?UTF-8?q?=EC=9D=98=20=EB=B3=B4=EB=82=B4=EA=B8=B0=20api=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../termsAgreement/TermsAgreementViewModel.kt | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/into/websoso/ui/termsAgreement/TermsAgreementViewModel.kt b/app/src/main/java/com/into/websoso/ui/termsAgreement/TermsAgreementViewModel.kt index b91f3b9a2..ccfcc8e90 100644 --- a/app/src/main/java/com/into/websoso/ui/termsAgreement/TermsAgreementViewModel.kt +++ b/app/src/main/java/com/into/websoso/ui/termsAgreement/TermsAgreementViewModel.kt @@ -2,6 +2,8 @@ package com.into.websoso.ui.termsAgreement import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.into.websoso.data.remote.request.TermsAgreementRequestDto +import com.into.websoso.data.repository.UserRepository import com.into.websoso.ui.termsAgreement.model.AgreementType import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow @@ -11,11 +13,13 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel -class TermsAgreementViewModel @Inject constructor() : ViewModel() { - +class TermsAgreementViewModel @Inject constructor( + private val userRepository: UserRepository, +) : ViewModel() { private val _agreementStatus = MutableStateFlow( mapOf( AgreementType.SERVICE to false, @@ -25,9 +29,11 @@ class TermsAgreementViewModel @Inject constructor() : ViewModel() { ) val agreementStatus: StateFlow> = _agreementStatus.asStateFlow() - val isAllChecked: StateFlow = agreementStatus - .map { it.values.all { checked -> checked } } - .stateIn(viewModelScope, SharingStarted.Lazily, false) + private val _isLoading = MutableStateFlow(false) + val isLoading: StateFlow = _isLoading.asStateFlow() + + private val _saveAgreementResult = MutableStateFlow?>(null) + val saveAgreementResult: StateFlow?> = _saveAgreementResult.asStateFlow() val isRequiredAgreementsChecked: StateFlow = agreementStatus .map { isRequiredAgreementChecked(it) } @@ -49,4 +55,28 @@ class TermsAgreementViewModel @Inject constructor() : ViewModel() { } } } + + fun saveTermsAgreements() { + if (!isRequiredAgreementsChecked.value) return + + viewModelScope.launch { + _isLoading.value = true + + val agreementRequest = TermsAgreementRequestDto( + serviceAgreed = _agreementStatus.value[AgreementType.SERVICE] == true, + privacyAgreed = _agreementStatus.value[AgreementType.PRIVACY] == true, + marketingAgreed = _agreementStatus.value[AgreementType.MARKETING] == true, + ) + + _saveAgreementResult.value = runCatching { + userRepository.saveTermsAgreements( + agreementRequest.serviceAgreed, + agreementRequest.privacyAgreed, + agreementRequest.marketingAgreed, + ) + } + + _isLoading.value = false + } + } } From 595cedd10aaf38d55fa64cc52f4163fb2c6359c9 Mon Sep 17 00:00:00 2001 From: yeonjeen Date: Sun, 16 Feb 2025 09:40:04 +0900 Subject: [PATCH 08/11] =?UTF-8?q?feat:=20=EC=95=BD=EA=B4=80=EB=8F=99?= =?UTF-8?q?=EC=9D=98=20=EC=84=B1=EA=B3=B5=20=ED=9B=84=20=EB=B0=94=ED=85=80?= =?UTF-8?q?=EC=8B=9C=ED=8A=B8=20=EB=8B=AB=EA=B8=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TermsAgreementDialogBottomSheet.kt | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/into/websoso/ui/termsAgreement/TermsAgreementDialogBottomSheet.kt b/app/src/main/java/com/into/websoso/ui/termsAgreement/TermsAgreementDialogBottomSheet.kt index a476cd5ad..ecb11c798 100644 --- a/app/src/main/java/com/into/websoso/ui/termsAgreement/TermsAgreementDialogBottomSheet.kt +++ b/app/src/main/java/com/into/websoso/ui/termsAgreement/TermsAgreementDialogBottomSheet.kt @@ -4,6 +4,7 @@ import android.content.Intent import android.net.Uri import android.os.Bundle import android.view.View +import android.widget.Toast import androidx.core.os.bundleOf import androidx.fragment.app.viewModels import com.google.android.material.bottomsheet.BottomSheetBehavior @@ -94,13 +95,13 @@ class TermsAgreementDialogBottomSheet : } private fun onTermsAgreementCompleteButtonClick() { - binding.btnTermsAgreementComplete.setOnClickListener { dismissIfAgreementsCompleted() } + binding.btnTermsAgreementComplete.setOnClickListener { sendTermsAgreement() } } - private fun dismissIfAgreementsCompleted() { - if (termsAgreementViewModel.isRequiredAgreementsChecked.value) { - dismiss() - } + private fun sendTermsAgreement() { + if (!termsAgreementViewModel.isRequiredAgreementsChecked.value) return // 필수 항목 미체크 시 요청 안 함 + + termsAgreementViewModel.saveTermsAgreements() } private fun setupViewModel() { @@ -112,6 +113,12 @@ class TermsAgreementDialogBottomSheet : termsAgreementViewModel.isRequiredAgreementsChecked.collectWithLifecycle(viewLifecycleOwner) { updateCompleteButtonState(it) } + + termsAgreementViewModel.saveAgreementResult.collectWithLifecycle(viewLifecycleOwner) { result -> + result?.onSuccess { + dismiss() + } + } } private fun updateAgreementIcons(status: Map) { From 52f77c12fbfcc0a846e4456b5a7cfcf5f11bca14 Mon Sep 17 00:00:00 2001 From: yeonjeen Date: Sun, 16 Feb 2025 10:04:40 +0900 Subject: [PATCH 09/11] =?UTF-8?q?feat:=20=EC=95=BD=EA=B4=80=EB=8F=99?= =?UTF-8?q?=EC=9D=98=20=ED=99=95=EC=9D=B8=20api=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../websoso/ui/main/home/HomeViewModel.kt | 363 ++++++++++-------- 1 file changed, 199 insertions(+), 164 deletions(-) diff --git a/app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt b/app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt index 9ee6339c3..67f30eedd 100644 --- a/app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt +++ b/app/src/main/java/com/into/websoso/ui/main/home/HomeViewModel.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope import com.into.websoso.data.model.PopularFeedsEntity import com.into.websoso.data.model.PopularNovelsEntity import com.into.websoso.data.model.RecommendedNovelsByUserTasteEntity +import com.into.websoso.data.model.TermsAgreementEntity import com.into.websoso.data.model.UserInterestFeedMessage import com.into.websoso.data.model.UserInterestFeedMessage.NO_INTEREST_NOVELS import com.into.websoso.data.model.UserInterestFeedsEntity @@ -14,208 +15,242 @@ import com.into.websoso.data.repository.FeedRepository import com.into.websoso.data.repository.NotificationRepository import com.into.websoso.data.repository.NovelRepository import com.into.websoso.data.repository.PushMessageRepository +import com.into.websoso.data.repository.UserRepository import com.into.websoso.ui.main.home.model.HomeUiState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class HomeViewModel - @Inject - constructor( - private val novelRepository: NovelRepository, - private val feedRepository: FeedRepository, - private val pushMessageRepository: PushMessageRepository, - private val notificationRepository: NotificationRepository, - ) : ViewModel() { - private val _uiState: MutableLiveData = MutableLiveData(HomeUiState()) - val uiState: LiveData get() = _uiState - - private val _isNotificationPermissionFirstLaunched: MutableLiveData = MutableLiveData() - val isNotificationPermissionFirstLaunched: LiveData get() = _isNotificationPermissionFirstLaunched - - init { - updateHomeData(true) - updateNotificationUnread() - } +@Inject +constructor( + private val novelRepository: NovelRepository, + private val feedRepository: FeedRepository, + private val pushMessageRepository: PushMessageRepository, + private val notificationRepository: NotificationRepository, + private val userRepository: UserRepository, +) : ViewModel() { + private val _uiState: MutableLiveData = MutableLiveData(HomeUiState()) + val uiState: LiveData get() = _uiState - private fun updateHomeData(isLogin: Boolean) { - viewModelScope.launch { - if (isLogin) { - fetchUserHomeData() - checkIsNotificationPermissionFirstLaunched() - } else { - fetchGuestData() - } + private val _isNotificationPermissionFirstLaunched: MutableLiveData = MutableLiveData() + val isNotificationPermissionFirstLaunched: LiveData get() = _isNotificationPermissionFirstLaunched + + private val _termsAgreementState = MutableStateFlow(null) + val termsAgreementState: StateFlow = _termsAgreementState.asStateFlow() + + private val _showTermsAgreementDialog = MutableStateFlow(false) + val showTermsAgreementDialog: StateFlow = _showTermsAgreementDialog.asStateFlow() + + init { + updateHomeData(true) + updateNotificationUnread() + checkTermsAgreement() + } + + private fun updateHomeData(isLogin: Boolean) { + + viewModelScope.launch { + if (isLogin) { + fetchUserHomeData() + checkIsNotificationPermissionFirstLaunched() + } else { + fetchGuestData() } } + } + + private suspend fun fetchUserHomeData() { + viewModelScope.launch { + runCatching { + val results = listOf( + async { runCatching { novelRepository.fetchPopularNovels() } }, + async { runCatching { feedRepository.fetchPopularFeeds() } }, + async { runCatching { feedRepository.fetchUserInterestFeeds() } }, + async { runCatching { novelRepository.fetchRecommendedNovelsByUserTaste() } }, + ).awaitAll() - private suspend fun fetchUserHomeData() { - viewModelScope.launch { - runCatching { - val results = listOf( - async { runCatching { novelRepository.fetchPopularNovels() } }, - async { runCatching { feedRepository.fetchPopularFeeds() } }, - async { runCatching { feedRepository.fetchUserInterestFeeds() } }, - async { runCatching { novelRepository.fetchRecommendedNovelsByUserTaste() } }, - ).awaitAll() - - // 실패가 하나라도 있다면 상위 onFailure로 예외 전파 - val failures = results.filter { it.isFailure } - if (failures.isNotEmpty()) { - throw failures.first().exceptionOrNull() - ?: IllegalStateException("Unknown error") - } - - val popularNovels = results[0].getOrNull() as? PopularNovelsEntity - ?: PopularNovelsEntity(emptyList()) - val popularFeeds = results[1].getOrNull() as? PopularFeedsEntity - ?: PopularFeedsEntity(emptyList()) - val userInterestFeeds = results[2].getOrNull() as? UserInterestFeedsEntity - ?: UserInterestFeedsEntity(emptyList(), "") - val recommendedNovels = - results[3].getOrNull() as? RecommendedNovelsByUserTasteEntity - ?: RecommendedNovelsByUserTasteEntity(emptyList()) - - _uiState.value = uiState.value?.copy( - loading = false, - error = false, - popularNovels = popularNovels.popularNovels, - popularFeeds = popularFeeds.popularFeeds.chunked(3), - isInterestNovel = isUserInterestedInNovels(userInterestFeeds.message), - userInterestFeeds = userInterestFeeds.userInterestFeeds, - recommendedNovelsByUserTaste = recommendedNovels.tasteNovels, - ) - }.onFailure { - _uiState.value = uiState.value?.copy( - loading = false, - error = true, - ) + // 실패가 하나라도 있다면 상위 onFailure로 예외 전파 + val failures = results.filter { it.isFailure } + if (failures.isNotEmpty()) { + throw failures.first().exceptionOrNull() + ?: IllegalStateException("Unknown error") } + + val popularNovels = results[0].getOrNull() as? PopularNovelsEntity + ?: PopularNovelsEntity(emptyList()) + val popularFeeds = results[1].getOrNull() as? PopularFeedsEntity + ?: PopularFeedsEntity(emptyList()) + val userInterestFeeds = results[2].getOrNull() as? UserInterestFeedsEntity + ?: UserInterestFeedsEntity(emptyList(), "") + val recommendedNovels = + results[3].getOrNull() as? RecommendedNovelsByUserTasteEntity + ?: RecommendedNovelsByUserTasteEntity(emptyList()) + + _uiState.value = uiState.value?.copy( + loading = false, + error = false, + popularNovels = popularNovels.popularNovels, + popularFeeds = popularFeeds.popularFeeds.chunked(3), + isInterestNovel = isUserInterestedInNovels(userInterestFeeds.message), + userInterestFeeds = userInterestFeeds.userInterestFeeds, + recommendedNovelsByUserTaste = recommendedNovels.tasteNovels, + ) + }.onFailure { + _uiState.value = uiState.value?.copy( + loading = false, + error = true, + ) } } + } - private fun checkIsNotificationPermissionFirstLaunched() { - viewModelScope.launch { - runCatching { - pushMessageRepository.fetchNotificationPermissionFirstLaunched() - }.onSuccess { isFirstLaunched -> - _isNotificationPermissionFirstLaunched.value = isFirstLaunched - } + private fun checkIsNotificationPermissionFirstLaunched() { + viewModelScope.launch { + runCatching { + pushMessageRepository.fetchNotificationPermissionFirstLaunched() + }.onSuccess { isFirstLaunched -> + _isNotificationPermissionFirstLaunched.value = isFirstLaunched } } + } - fun updateIsNotificationPermissionFirstLaunched(isFirstLaunched: Boolean) { - viewModelScope.launch { - runCatching { - pushMessageRepository.saveNotificationPermissionFirstLaunched(isFirstLaunched) - }.onSuccess { - _isNotificationPermissionFirstLaunched.value = isFirstLaunched - } + fun updateIsNotificationPermissionFirstLaunched(isFirstLaunched: Boolean) { + viewModelScope.launch { + runCatching { + pushMessageRepository.saveNotificationPermissionFirstLaunched(isFirstLaunched) + }.onSuccess { + _isNotificationPermissionFirstLaunched.value = isFirstLaunched } } + } - private suspend fun fetchGuestData() { - viewModelScope.launch { - runCatching { - listOf( - async { novelRepository.fetchPopularNovels() }, - async { feedRepository.fetchPopularFeeds() }, - ).awaitAll() - }.onSuccess { responses -> - val popularNovels = responses[0] as PopularNovelsEntity - val popularFeeds = responses[1] as PopularFeedsEntity - - _uiState.value = uiState.value?.copy( - loading = false, - popularNovels = popularNovels.popularNovels, - popularFeeds = popularFeeds.popularFeeds.chunked(3), - ) - }.onFailure { - _uiState.value = uiState.value?.copy( - loading = false, - error = true, - ) - } + private suspend fun fetchGuestData() { + viewModelScope.launch { + runCatching { + listOf( + async { novelRepository.fetchPopularNovels() }, + async { feedRepository.fetchPopularFeeds() }, + ).awaitAll() + }.onSuccess { responses -> + val popularNovels = responses[0] as PopularNovelsEntity + val popularFeeds = responses[1] as PopularFeedsEntity + + _uiState.value = uiState.value?.copy( + loading = false, + popularNovels = popularNovels.popularNovels, + popularFeeds = popularFeeds.popularFeeds.chunked(3), + ) + }.onFailure { + _uiState.value = uiState.value?.copy( + loading = false, + error = true, + ) } } + } - fun updateFeed() { - viewModelScope.launch { - runCatching { - listOf( - async { feedRepository.fetchPopularFeeds() }, - async { feedRepository.fetchUserInterestFeeds() }, - ).awaitAll() - }.onSuccess { responses -> - val popularFeeds = responses[0] as PopularFeedsEntity - val userInterestFeeds = responses[1] as UserInterestFeedsEntity - - _uiState.value = uiState.value?.copy( - popularFeeds = popularFeeds.popularFeeds.chunked(3), - isInterestNovel = isUserInterestedInNovels(userInterestFeeds.message), - userInterestFeeds = userInterestFeeds.userInterestFeeds, - ) - }.onFailure { - _uiState.value = uiState.value?.copy( - error = true, - ) - } + fun updateFeed() { + viewModelScope.launch { + runCatching { + listOf( + async { feedRepository.fetchPopularFeeds() }, + async { feedRepository.fetchUserInterestFeeds() }, + ).awaitAll() + }.onSuccess { responses -> + val popularFeeds = responses[0] as PopularFeedsEntity + val userInterestFeeds = responses[1] as UserInterestFeedsEntity + + _uiState.value = uiState.value?.copy( + popularFeeds = popularFeeds.popularFeeds.chunked(3), + isInterestNovel = isUserInterestedInNovels(userInterestFeeds.message), + userInterestFeeds = userInterestFeeds.userInterestFeeds, + ) + }.onFailure { + _uiState.value = uiState.value?.copy( + error = true, + ) } } + } - fun updateNovel() { - viewModelScope.launch { - runCatching { - listOf( - async { novelRepository.fetchPopularNovels() }, - async { novelRepository.fetchRecommendedNovelsByUserTaste() }, - ).awaitAll() - }.onSuccess { responses -> - val popularNovels = responses[0] as PopularNovelsEntity - val recommendedNovels = responses[1] as RecommendedNovelsByUserTasteEntity - - _uiState.value = uiState.value?.copy( - popularNovels = popularNovels.popularNovels, - recommendedNovelsByUserTaste = recommendedNovels.tasteNovels, - ) - }.onFailure { - _uiState.value = uiState.value?.copy( - error = true, - ) - } + fun updateNovel() { + viewModelScope.launch { + runCatching { + listOf( + async { novelRepository.fetchPopularNovels() }, + async { novelRepository.fetchRecommendedNovelsByUserTaste() }, + ).awaitAll() + }.onSuccess { responses -> + val popularNovels = responses[0] as PopularNovelsEntity + val recommendedNovels = responses[1] as RecommendedNovelsByUserTasteEntity + + _uiState.value = uiState.value?.copy( + popularNovels = popularNovels.popularNovels, + recommendedNovelsByUserTaste = recommendedNovels.tasteNovels, + ) + }.onFailure { + _uiState.value = uiState.value?.copy( + error = true, + ) } } + } - private fun updateNotificationUnread() { - viewModelScope.launch { - runCatching { - notificationRepository.fetchNotificationUnread() - }.onSuccess { isNotificationUnread -> - _uiState.value = uiState.value?.copy( - isNotificationUnread = isNotificationUnread, - ) - }.onFailure { - _uiState.value = uiState.value?.copy( - error = true, - ) - } + private fun updateNotificationUnread() { + viewModelScope.launch { + runCatching { + notificationRepository.fetchNotificationUnread() + }.onSuccess { isNotificationUnread -> + _uiState.value = uiState.value?.copy( + isNotificationUnread = isNotificationUnread, + ) + }.onFailure { + _uiState.value = uiState.value?.copy( + error = true, + ) } } + } + + private fun isUserInterestedInNovels(userInterestFeedMessage: String): Boolean = + when (UserInterestFeedMessage.fromMessage(userInterestFeedMessage)) { + NO_INTEREST_NOVELS -> false + else -> true + } - private fun isUserInterestedInNovels(userInterestFeedMessage: String): Boolean = - when (UserInterestFeedMessage.fromMessage(userInterestFeedMessage)) { - NO_INTEREST_NOVELS -> false - else -> true + fun updateFCMToken(token: String) { + viewModelScope.launch { + runCatching { + pushMessageRepository.saveUserFCMToken(token) } + } + } - fun updateFCMToken(token: String) { - viewModelScope.launch { - runCatching { - pushMessageRepository.saveUserFCMToken(token) + private fun checkTermsAgreement() { + viewModelScope.launch { + userRepository.isTermsAgreementChecked.collect { checked -> + if (!checked) { + updateTermsAgreement() } } } } + + private fun updateTermsAgreement() { + viewModelScope.launch { + runCatching { userRepository.fetchTermsAgreements() } + .onSuccess { terms -> + + _termsAgreementState.value = terms + _showTermsAgreementDialog.value = !(terms.serviceAgreed && terms.privacyAgreed) + } + } + } +} From 4dd9d323d20556f6e36f1f21fb6246eb5e6301ae Mon Sep 17 00:00:00 2001 From: yeonjeen Date: Sun, 16 Feb 2025 10:05:03 +0900 Subject: [PATCH 10/11] =?UTF-8?q?feat:=20=EC=95=BD=EA=B4=80=EB=8F=99?= =?UTF-8?q?=EC=9D=98=20=EC=97=AC=EB=B6=80=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EB=8B=A4=EC=9D=B4=EC=96=BC=EB=A1=9C=EA=B7=B8=20=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/into/websoso/ui/main/home/HomeFragment.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/into/websoso/ui/main/home/HomeFragment.kt b/app/src/main/java/com/into/websoso/ui/main/home/HomeFragment.kt index 09f37a42a..d704fe6a5 100644 --- a/app/src/main/java/com/into/websoso/ui/main/home/HomeFragment.kt +++ b/app/src/main/java/com/into/websoso/ui/main/home/HomeFragment.kt @@ -17,6 +17,7 @@ import com.into.websoso.core.common.ui.model.ResultFrom.FeedDetailRemoved import com.into.websoso.core.common.ui.model.ResultFrom.NormalExploreBack import com.into.websoso.core.common.ui.model.ResultFrom.NovelDetailBack import com.into.websoso.core.common.ui.model.ResultFrom.ProfileEditSuccess +import com.into.websoso.core.common.util.collectWithLifecycle import com.into.websoso.core.common.util.tracker.Tracker import com.into.websoso.databinding.FragmentHomeBinding import com.into.websoso.ui.feedDetail.FeedDetailActivity @@ -91,7 +92,6 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) { onPostInterestNovelClick() onSettingPreferenceGenreClick() onNotificationButtonClick() - showTermsAgreementDialog() tracker.trackEvent("home") } @@ -156,6 +156,12 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) { showNotificationPermissionDialog() } } + + homeViewModel.showTermsAgreementDialog.collectWithLifecycle(viewLifecycleOwner) { shouldShow -> + if (shouldShow) { + showTermsAgreementDialog() + } + } } private fun updateUserInterestFeedsVisibility(isUserInterestEmpty: Boolean) { From 9ffa19313d00d247efbff09ee6453fdef65f3e80 Mon Sep 17 00:00:00 2001 From: yeonjeen Date: Sun, 16 Feb 2025 10:05:30 +0900 Subject: [PATCH 11/11] =?UTF-8?q?feat:=20=EC=95=BD=EA=B4=80=EB=8F=99?= =?UTF-8?q?=EC=9D=98=20=ED=99=95=EC=9D=B8=20=EC=8B=9C=20=EB=8F=99=EC=9D=98?= =?UTF-8?q?=20=EC=97=AC=EB=B6=80=20=EB=A0=88=ED=8F=AC=EC=A7=80=ED=84=B0?= =?UTF-8?q?=EB=A6=AC=EC=97=90=20=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../websoso/data/repository/UserRepository.kt | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/into/websoso/data/repository/UserRepository.kt b/app/src/main/java/com/into/websoso/data/repository/UserRepository.kt index b9fb99168..e9b730424 100644 --- a/app/src/main/java/com/into/websoso/data/repository/UserRepository.kt +++ b/app/src/main/java/com/into/websoso/data/repository/UserRepository.kt @@ -23,7 +23,9 @@ import com.into.websoso.data.remote.request.TermsAgreementRequestDto import com.into.websoso.data.remote.request.UserInfoRequestDto import com.into.websoso.data.remote.request.UserProfileEditRequestDto import com.into.websoso.data.remote.request.UserProfileStatusRequestDto +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map import javax.inject.Inject class UserRepository @@ -172,18 +174,35 @@ constructor( } } + val isTermsAgreementChecked: Flow = userStorage.data + .map { preferences -> preferences[TERMS_AGREEMENT_CHECKED_KEY] ?: false } + suspend fun saveTermsAgreements( serviceAgreed: Boolean, privacyAgreed: Boolean, marketingAgreed: Boolean, ) { - userApi.patchTermsAgreement(TermsAgreementRequestDto( serviceAgreed,privacyAgreed,marketingAgreed)) + userApi.patchTermsAgreement( + TermsAgreementRequestDto(serviceAgreed, privacyAgreed, marketingAgreed) + ) + saveTermsAgreementChecked(serviceAgreed, privacyAgreed) + } + + suspend fun fetchTermsAgreements(): TermsAgreementEntity { + val termsAgreement = userApi.getTermsAgreement().toData() + saveTermsAgreementChecked(termsAgreement.serviceAgreed, termsAgreement.privacyAgreed) + return termsAgreement } - suspend fun fetchTermsAgreements(): TermsAgreementEntity = userApi.getTermsAgreement().toData() + private suspend fun saveTermsAgreementChecked(serviceAgreed: Boolean, privacyAgreed: Boolean) { + userStorage.edit { preferences -> + preferences[TERMS_AGREEMENT_CHECKED_KEY] = serviceAgreed && privacyAgreed + } + } companion object { val NOVEL_DETAIL_FIRST_LAUNCHED_KEY = booleanPreferencesKey("NOVEL_DETAIL_FIRST_LAUNCHED") + val TERMS_AGREEMENT_CHECKED_KEY = booleanPreferencesKey("terms_agreement_checked") val USER_ID_KEY = stringPreferencesKey("USER_ID") val USER_NICKNAME_KEY = stringPreferencesKey("USER_NICKNAME") val USER_GENDER_KEY = stringPreferencesKey("USER_GENDER")