Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
3e8c071
feat: 약관동의 토글 아이콘 추가
yeonjeen Feb 15, 2025
b0b2f1a
feat: 약관동의 바텀시트 xml 구현
yeonjeen Feb 15, 2025
df3d8ac
feat: 약관동의 다이얼로그 xml 구현
yeonjeen Feb 15, 2025
a45cbde
feat: 약관동의 타입 enum
yeonjeen Feb 15, 2025
5eea022
feat: 스트링 추출
yeonjeen Feb 15, 2025
a070c9d
feat: 약관동의 바텀시트 버튼 스트링 추가
yeonjeen Feb 15, 2025
f7a3b06
feat: 약관동의 바텀시트 구현
yeonjeen Feb 15, 2025
e06c169
feat: 약관동의 바텀시트 뷰모델 구현
yeonjeen Feb 15, 2025
3109354
feat: 약관동의 기존유저 팝업 구현
yeonjeen Feb 15, 2025
2820bf7
feat: 온보딩에 약관동의 바텀시트 연결
yeonjeen Feb 15, 2025
f50c604
feat: 홈에 약관동의 기존유저 팝업 연결
yeonjeen Feb 15, 2025
34c7fba
Merge remote-tracking branch 'origin/develop' into feat/554
yeonjeen Feb 15, 2025
a546646
refactor: 코드리뷰 반영
yeonjeen Feb 15, 2025
af0b82e
refactor: 코드리뷰 반영
yeonjeen Feb 15, 2025
8ae9463
feat: 약관동의 Entity 구현
yeonjeen Feb 15, 2025
61b0564
refactor: 코드리뷰 반영
yeonjeen Feb 15, 2025
f1bb411
feat: flow 수집을 위한 collectWithLifecycle 확장 함수 구현
yeonjeen Feb 15, 2025
ecc8417
refactor: 확장함수 적용
yeonjeen Feb 15, 2025
57396ea
Merge pull request #577 from Team-WSS/feat/554
yeonjeen Feb 15, 2025
81bd25e
Merge remote-tracking branch 'origin/feat/571' into feat/578
yeonjeen Feb 15, 2025
a80cafe
feat: 약관동의 응답 dto
yeonjeen Feb 16, 2025
3691971
feat: 약관동의 요청 dto
yeonjeen Feb 16, 2025
bf92ef0
feat: 약관동의 patch/get api 설정
yeonjeen Feb 16, 2025
450b0a3
feat: 약관동의 dto와 entity 매핑
yeonjeen Feb 16, 2025
7366446
feat: 레포지터리 api 연결 함수 구현
yeonjeen Feb 16, 2025
5083b8b
feat: 약관동의 보내기 api 연결
yeonjeen Feb 16, 2025
595cedd
feat: 약관동의 성공 후 바텀시트 닫기 구현
yeonjeen Feb 16, 2025
52f77c1
feat: 약관동의 확인 api 연결
yeonjeen Feb 16, 2025
4dd9d32
feat: 약관동의 여부에 따른 다이얼로그 호출 구현
yeonjeen Feb 16, 2025
9ffa193
feat: 약관동의 확인 시 동의 여부 레포지터리에 저장
yeonjeen Feb 16, 2025
3e2a457
Merge pull request #580 from Team-WSS/feat/578
yeonjeen Feb 16, 2025
8e45cd3
Merge remote-tracking branch 'origin/develop' into feat/571
yeonjeen Feb 16, 2025
0fa67c3
refactor: 린트해결
yeonjeen Feb 16, 2025
a62fa8a
refactor: 린트해결
yeonjeen Feb 16, 2025
ad8ed4d
refactor: 린트해결
yeonjeen Feb 16, 2025
5735bf6
refactor: 린트해결
yeonjeen Feb 16, 2025
9630997
refactor: 린트해결
yeonjeen Feb 16, 2025
61b7267
refactor: 린트해결
yeonjeen Feb 16, 2025
6abf589
refactor: 린트해결
yeonjeen Feb 16, 2025
3c8e413
refactor: 린트해결
yeonjeen Feb 16, 2025
3c56c05
refactor: 린트해결
yeonjeen Feb 16, 2025
65c1754
refactor: 린트해결
yeonjeen Feb 16, 2025
d033038
refactor: 린트해결
yeonjeen Feb 16, 2025
164ca26
build: 린트 해결
m6z1 Feb 16, 2025
7f2d2a6
Merge branch 'feat/571' of https://github.com/Team-WSS/WSS-Android in…
m6z1 Feb 16, 2025
be0782b
build: 린트 해결
m6z1 Feb 16, 2025
f0a4722
Merge branch 'develop' into feat/571
m6z1 Feb 16, 2025
6f53008
build: 린트 해결
m6z1 Feb 16, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,15 @@ import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.emptyPreferences
import androidx.datastore.preferences.preferencesDataStoreFile
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.into.websoso.BuildConfig
import com.into.websoso.core.common.ui.custom.WebsosoCustomSnackBar
import com.into.websoso.core.common.ui.custom.WebsosoCustomToast
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import java.io.Serializable

fun Float.toFloatPxFromDp(): Float = this * Resources.getSystem().displayMetrics.density
Expand Down Expand Up @@ -96,23 +102,26 @@ inline fun <reified T : Serializable> Intent.getAdaptedSerializableExtra(key: St
getSerializableExtra(key, T::class.java)
} else {
@Suppress("DEPRECATION")
getSerializableExtra(key) as? T
getSerializableExtra(key)
as? T
}

inline fun <reified T : Parcelable> Intent.getAdaptedParcelableExtra(key: String): T? =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getParcelableExtra(key, T::class.java)
} else {
@Suppress("DEPRECATION")
getParcelableExtra(key) as? T
getParcelableExtra(key)
as? T
}

inline fun <reified T : Parcelable> Bundle.getAdaptedParcelable(key: String): T? =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getParcelable(key, T::class.java)
} else {
@Suppress("DEPRECATION")
getParcelable(key) as? T
getParcelable(key)
as? T
}

fun Context.createDataStore(preferencesName: String): DataStore<Preferences> =
Expand All @@ -137,3 +146,15 @@ fun Modifier.clickableWithoutRipple(
onClick = onClick,
)
}

fun <T> Flow<T>.collectWithLifecycle(
lifecycleOwner: LifecycleOwner,
state: Lifecycle.State = Lifecycle.State.STARTED,
collector: suspend (T) -> Unit,
) {
lifecycleOwner.lifecycleScope.launch {
lifecycleOwner.repeatOnLifecycle(state) {
collect { collector(it) }
}
}
}
90 changes: 44 additions & 46 deletions app/src/main/java/com/into/websoso/data/mapper/UserMapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -29,56 +31,52 @@ import com.into.websoso.data.remote.response.UserStorageResponseDto
import com.into.websoso.data.remote.response.UserStorageResponseDto.StorageNovelDto
import com.into.websoso.ui.main.myPage.myActivity.model.Genres

fun UserInfoResponseDto.toData(): UserInfoEntity {
return UserInfoEntity(
fun UserInfoResponseDto.toData(): UserInfoEntity =
UserInfoEntity(
userId = this.userId,
nickname = this.nickname,
gender = this.gender,
)
}

fun UserInfoDetailResponseDto.toData(): UserInfoDetailEntity {
return UserInfoDetailEntity(
fun UserInfoDetailResponseDto.toData(): UserInfoDetailEntity =
UserInfoDetailEntity(
email = email,
gender = gender,
birthYear = birth,
)
}

fun BlockedUsersResponseDto.toData(): BlockedUsersEntity {
return BlockedUsersEntity(blockedUsers = blocks.map { blockedUser ->
BlockedUserEntity(
blockId = blockedUser.blockId,
userId = blockedUser.userId,
nickName = blockedUser.nickName,
avatarImage = blockedUser.avatarImage,
)
})
}
fun BlockedUsersResponseDto.toData(): BlockedUsersEntity =
BlockedUsersEntity(
blockedUsers = blocks.map { blockedUser ->
BlockedUserEntity(
blockId = blockedUser.blockId,
userId = blockedUser.userId,
nickName = blockedUser.nickName,
avatarImage = blockedUser.avatarImage,
)
},
)

fun UserNovelStatsResponseDto.toData(): UserNovelStatsEntity {
return UserNovelStatsEntity(
fun UserNovelStatsResponseDto.toData(): UserNovelStatsEntity =
UserNovelStatsEntity(
interestNovelCount = interestNovelCount,
watchingNovelCount = watchingNovelCount,
watchedNovelCount = watchedNovelCount,
quitNovelCount = quitNovelCount,
)
}

fun UserProfileStatusResponseDto.toData(): UserProfileStatusEntity {
return UserProfileStatusEntity(
fun UserProfileStatusResponseDto.toData(): UserProfileStatusEntity =
UserProfileStatusEntity(
isProfilePublic = isProfilePublic,
)
}

fun MyProfileResponseDto.toData(): MyProfileEntity {
return MyProfileEntity(
fun MyProfileResponseDto.toData(): MyProfileEntity =
MyProfileEntity(
nickname = this.nickname,
intro = this.intro,
avatarImage = this.avatarImage,
genrePreferences = this.genrePreferences,
)
}

fun GenrePreferenceResponseDto.GenrePreferenceDto.toData(): GenrePreferenceEntity {
val koreanGenreName = Genres.from(this.genreName)?.korean ?: this.genreName
Expand All @@ -89,59 +87,53 @@ fun GenrePreferenceResponseDto.GenrePreferenceDto.toData(): GenrePreferenceEntit
)
}

fun NovelPreferenceResponseDto.toData(): NovelPreferenceEntity {
return NovelPreferenceEntity(
fun NovelPreferenceResponseDto.toData(): NovelPreferenceEntity =
NovelPreferenceEntity(
attractivePoints = this.attractivePoints,
keywords = this.keywords.map { it.toData() },
)
}

fun NovelPreferenceResponseDto.AttractivePointKeywordDto.toData(): NovelPreferenceEntity.KeywordEntity {
return NovelPreferenceEntity.KeywordEntity(
fun NovelPreferenceResponseDto.AttractivePointKeywordDto.toData(): NovelPreferenceEntity.KeywordEntity =
NovelPreferenceEntity.KeywordEntity(
keywordName = this.keywordName,
keywordCount = this.keywordCount,
)
}

fun OtherUserProfileResponseDto.toData(): OtherUserProfileEntity {
return OtherUserProfileEntity(
fun OtherUserProfileResponseDto.toData(): OtherUserProfileEntity =
OtherUserProfileEntity(
nickname = this.nickname,
intro = this.intro,
avatarImage = this.avatarImage,
isProfilePublic = this.isProfilePublic,
genrePreferences = this.genrePreferences,
)
}

fun UserStorageResponseDto.toData(): UserStorageEntity {
return UserStorageEntity(
fun UserStorageResponseDto.toData(): UserStorageEntity =
UserStorageEntity(
isLoadable = this.isLoadable,
userNovelRating = this.userNovelRating,
userNovelCount = this.userNovelCount,
userNovels = this.userNovels.map { it.toData() },
)
}

fun StorageNovelDto.toData(): StorageNovelEntity {
return StorageNovelEntity(
fun StorageNovelDto.toData(): StorageNovelEntity =
StorageNovelEntity(
author = this.author,
userNovelId = this.userNovelId,
novelId = this.novelId,
novelRating = this.novelRating,
novelImage = this.novelImage,
title = this.title,
)
}

fun UserFeedsResponseDto.toData(): UserFeedsEntity {
return UserFeedsEntity(
fun UserFeedsResponseDto.toData(): UserFeedsEntity =
UserFeedsEntity(
isLoadable = this.isLoadable,
feeds = this.feeds.map { it.toData() },
)
}

fun UserFeedResponseDto.toData(): UserFeedEntity {
return UserFeedEntity(
fun UserFeedResponseDto.toData(): UserFeedEntity =
UserFeedEntity(
feedId = this.feedId,
isSpoiler = this.isSpoiler,
feedContent = this.feedContent,
Expand All @@ -156,4 +148,10 @@ fun UserFeedResponseDto.toData(): UserFeedEntity {
novelRating = this.novelRating,
relevantCategories = this.relevantCategories,
)
}

fun TermsAgreementResponseDto.toData(): TermsAgreementEntity =
TermsAgreementEntity(
serviceAgreed = this.serviceAgreed,
privacyAgreed = this.privacyAgreed,
marketingAgreed = this.marketingAgreed,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.into.websoso.data.model

data class TermsAgreementEntity(
val serviceAgreed: Boolean,
val privacyAgreed: Boolean,
val marketingAgreed: Boolean,
)
11 changes: 10 additions & 1 deletion app/src/main/java/com/into/websoso/data/remote/api/UserApi.kt
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -25,7 +27,6 @@ import retrofit2.http.Path
import retrofit2.http.Query

interface UserApi {

@GET("users/me")
suspend fun getUserInfo(): UserInfoResponseDto

Expand Down Expand Up @@ -106,4 +107,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
}
Original file line number Diff line number Diff line change
@@ -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,
)
Original file line number Diff line number Diff line change
@@ -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,
)
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,21 @@ 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
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
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import javax.inject.Inject

class UserRepository
Expand All @@ -30,6 +34,9 @@ class UserRepository
private val userApi: UserApi,
private val userStorage: DataStore<Preferences>,
) {
val isTermsAgreementChecked: Flow<Boolean> = userStorage.data
.map { preferences -> preferences[TERMS_AGREEMENT_CHECKED_KEY] ?: false }

suspend fun fetchUserInfo(): UserInfoEntity {
val userInfo = userApi.getUserInfo().toData()
saveUserInfo(userInfo.userId, userInfo.nickname, userInfo.gender)
Expand Down Expand Up @@ -164,8 +171,35 @@ class UserRepository
}
}

suspend fun saveTermsAgreements(
serviceAgreed: Boolean,
privacyAgreed: Boolean,
marketingAgreed: Boolean,
) {
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
}

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")
Expand Down
Loading