Skip to content

Commit 5f1bd8b

Browse files
authored
Merge pull request #109 from YAPP-Github/develop
[Release] v1.0.6
2 parents f13c849 + b9f5884 commit 5f1bd8b

File tree

114 files changed

+1723
-2051
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

114 files changed

+1723
-2051
lines changed

AiLoading

Whitespace-only changes.

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ android {
1212
namespace = "com.puzzle.piece"
1313

1414
defaultConfig {
15-
versionCode = 6
16-
versionName = "1.0.5"
15+
versionCode = 7
16+
versionName = "1.0.6"
1717
targetSdk = 35
1818

1919
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

core/analytics/src/main/java/com/puzzle/analytics/AnalyticsHelper.kt

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,63 @@ package com.puzzle.analytics
33
import androidx.compose.runtime.Composable
44
import androidx.compose.runtime.LaunchedEffect
55
import androidx.compose.runtime.staticCompositionLocalOf
6+
import com.puzzle.analytics.AnalyticsEvent.PropertiesKeys.ACTION_NAME
67
import com.puzzle.analytics.AnalyticsEvent.PropertiesKeys.BUTTON_NAME
78
import com.puzzle.analytics.AnalyticsEvent.PropertiesKeys.SCREEN_NAME
9+
import com.puzzle.analytics.AnalyticsEvent.Types.ACTION
810
import com.puzzle.analytics.AnalyticsEvent.Types.BUTTON_CLICK
911
import com.puzzle.analytics.AnalyticsEvent.Types.SCREEN_VIEW
1012

1113
abstract class AnalyticsHelper {
1214
abstract fun logEvent(event: AnalyticsEvent)
1315
abstract fun setUserId(userId: String?)
16+
17+
fun trackClickEvent(
18+
screenName: String,
19+
buttonName: String,
20+
properties: MutableMap<String, Any?>? = null,
21+
) {
22+
val eventProperties = mutableMapOf<String, Any?>(
23+
SCREEN_NAME to screenName,
24+
BUTTON_NAME to buttonName,
25+
)
26+
27+
properties?.let { eventProperties.putAll(it) }
28+
29+
logEvent(
30+
AnalyticsEvent(
31+
type = BUTTON_CLICK,
32+
properties = eventProperties
33+
)
34+
)
35+
}
36+
37+
fun trackActionEvent(
38+
screenName: String,
39+
actionName: String,
40+
properties: MutableMap<String, Any?>? = null,
41+
) {
42+
val eventProperties = mutableMapOf<String, Any?>(
43+
SCREEN_NAME to screenName,
44+
ACTION_NAME to actionName,
45+
)
46+
47+
properties?.let { eventProperties.putAll(it) }
48+
49+
logEvent(
50+
AnalyticsEvent(
51+
type = ACTION,
52+
properties = eventProperties
53+
)
54+
)
55+
}
56+
57+
fun clearUserId() = setUserId(null)
58+
}
59+
60+
class NoOpAnalyticsHelper : AnalyticsHelper() {
61+
override fun logEvent(event: AnalyticsEvent) = Unit
62+
override fun setUserId(userId: String?) = Unit
1463
}
1564

1665
val LocalAnalyticsHelper = staticCompositionLocalOf<AnalyticsHelper> {
@@ -19,7 +68,7 @@ val LocalAnalyticsHelper = staticCompositionLocalOf<AnalyticsHelper> {
1968

2069
@Composable
2170
fun TrackScreenViewEvent(
22-
key: Any?,
71+
key: Any? = Unit,
2372
screenName: String?,
2473
analyticsHelper: AnalyticsHelper = LocalAnalyticsHelper.current,
2574
) = LaunchedEffect(key) {
@@ -34,26 +83,3 @@ fun TrackScreenViewEvent(
3483
)
3584
}
3685
}
37-
38-
@Composable
39-
fun TrackClickEvent(
40-
key: Any?,
41-
screenName: String,
42-
buttonName: String,
43-
properties: MutableMap<String, Any?>? = null,
44-
analyticsHelper: AnalyticsHelper = LocalAnalyticsHelper.current,
45-
) = LaunchedEffect(key) {
46-
val eventProperties = mutableMapOf<String, Any?>(
47-
SCREEN_NAME to screenName,
48-
BUTTON_NAME to buttonName,
49-
)
50-
51-
properties?.let { eventProperties.putAll(it) }
52-
53-
analyticsHelper.logEvent(
54-
AnalyticsEvent(
55-
type = BUTTON_CLICK,
56-
properties = eventProperties
57-
)
58-
)
59-
}

core/analytics/src/main/java/com/puzzle/analytics/NoOpAnalyticsHelper.kt

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.puzzle.common.ui
2+
3+
import androidx.compose.animation.AnimatedContent
4+
import androidx.compose.animation.AnimatedContentScope
5+
import androidx.compose.animation.AnimatedVisibility
6+
import androidx.compose.animation.AnimatedVisibilityScope
7+
import androidx.compose.animation.animateColorAsState
8+
import androidx.compose.animation.core.tween
9+
import androidx.compose.animation.expandVertically
10+
import androidx.compose.animation.fadeIn
11+
import androidx.compose.animation.fadeOut
12+
import androidx.compose.animation.shrinkVertically
13+
import androidx.compose.animation.togetherWith
14+
import androidx.compose.runtime.Composable
15+
import androidx.compose.ui.Modifier
16+
import androidx.compose.ui.graphics.Color
17+
18+
private const val ANIMATION_DURATION = 700
19+
20+
fun pieceExitTransitionAnimation() = fadeOut(tween(ANIMATION_DURATION))
21+
fun pieceEnterTransitionAnimation() = fadeIn(tween(ANIMATION_DURATION))
22+
23+
@Composable
24+
fun PieceBottomBarAnimation(
25+
visible: Boolean,
26+
modifier: Modifier = Modifier,
27+
contents: @Composable () -> Unit,
28+
) = AnimatedVisibility(
29+
visible = visible,
30+
enter = fadeIn(tween(ANIMATION_DURATION)) + expandVertically(tween(ANIMATION_DURATION)),
31+
exit = fadeOut(tween(ANIMATION_DURATION)) + shrinkVertically(tween(ANIMATION_DURATION)),
32+
modifier = modifier,
33+
) {
34+
contents()
35+
}
36+
37+
@Composable
38+
fun <S> PiecePageTransitionAnimation(
39+
targetState: S,
40+
modifier: Modifier = Modifier,
41+
content: @Composable() AnimatedContentScope.(targetState: S) -> Unit
42+
) = AnimatedContent(
43+
targetState = targetState,
44+
transitionSpec = {
45+
fadeIn(tween(ANIMATION_DURATION)) togetherWith fadeOut(tween(ANIMATION_DURATION))
46+
},
47+
content = content,
48+
modifier = modifier,
49+
)
50+
51+
@Composable
52+
fun PieceVisibleAnimation(
53+
visible: Boolean,
54+
modifier: Modifier = Modifier,
55+
content: @Composable AnimatedVisibilityScope.() -> Unit,
56+
) = AnimatedVisibility(
57+
visible = visible,
58+
enter = fadeIn() + expandVertically(),
59+
exit = fadeOut() + shrinkVertically(),
60+
content = content,
61+
modifier = modifier,
62+
)
63+
64+
@Composable
65+
fun pieceColorTransitionAnimation(targetValue: Color) = animateColorAsState(
66+
targetValue = targetValue,
67+
animationSpec = tween(ANIMATION_DURATION),
68+
)

core/common-ui/src/main/java/com/puzzle/common/ui/Constant.kt

Lines changed: 0 additions & 3 deletions
This file was deleted.

core/data/src/main/java/com/puzzle/data/repository/MatchingRepositoryImpl.kt

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import com.puzzle.network.model.profile.ContactResponse
1818
import com.puzzle.network.source.matching.MatchingDataSource
1919
import kotlinx.coroutines.async
2020
import kotlinx.coroutines.coroutineScope
21-
import kotlinx.coroutines.flow.first
21+
import kotlinx.coroutines.flow.firstOrNull
2222
import javax.inject.Inject
2323

2424
class MatchingRepositoryImpl @Inject constructor(
@@ -46,16 +46,12 @@ class MatchingRepositoryImpl @Inject constructor(
4646
override suspend fun getMatchInfo(): Result<MatchInfo> =
4747
matchingDataSource.getMatchInfo().mapCatching(GetMatchInfoResponse::toDomain)
4848

49-
override suspend fun retrieveOpponentProfile(): Result<OpponentProfile> {
50-
val profile = localMatchingDataSource.opponentProfile.first()
51-
return if (profile != null) {
52-
Result.success(profile)
53-
} else {
54-
Result.failure(NullPointerException("OpponentProfile is null"))
55-
}
49+
override suspend fun getOpponentProfile(): Result<OpponentProfile> = suspendRunCatching {
50+
val localProfile = localMatchingDataSource.opponentProfile.firstOrNull()
51+
localProfile ?: loadOpponentProfile().getOrThrow()
5652
}
5753

58-
override suspend fun loadOpponentProfile(): Result<Unit> = suspendRunCatching {
54+
private suspend fun loadOpponentProfile(): Result<OpponentProfile> = suspendRunCatching {
5955
coroutineScope {
6056
val valueTalksDeferred = async { getOpponentValueTalks() }
6157
val valuePicksDeferred = async { getOpponentValuePicks() }
@@ -67,7 +63,7 @@ class MatchingRepositoryImpl @Inject constructor(
6763
val profileBasic = profileBasicDeferred.await().getOrThrow()
6864
val imageUrl = profileImageDeferred.await().getOrThrow()
6965

70-
val result = OpponentProfile(
66+
val opponentProfile = OpponentProfile(
7167
matchId = profileBasic.matchId,
7268
description = profileBasic.description,
7369
nickname = profileBasic.nickname,
@@ -82,7 +78,8 @@ class MatchingRepositoryImpl @Inject constructor(
8278
valueTalks = valueTalks,
8379
imageUrl = imageUrl,
8480
)
85-
localMatchingDataSource.setOpponentProfile(result)
81+
localMatchingDataSource.setOpponentProfile(opponentProfile)
82+
opponentProfile
8683
}
8784
}
8885

core/data/src/main/java/com/puzzle/data/repository/ProfileRepositoryImpl.kt

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -37,56 +37,74 @@ class ProfileRepositoryImpl @Inject constructor(
3737
override val aiSummary: Flow<AiSummary> =
3838
sseClient.aiSummaryResponse.map(SseAiSummaryResponse::toDomain)
3939

40-
override suspend fun loadValuePickQuestions(): Result<Unit> = suspendRunCatching {
41-
val valuePickQuestions = profileDataSource.loadValuePickQuestions()
42-
.getOrThrow()
43-
.toDomain()
44-
.filter { it.id != UNKNOWN_INT }
40+
override suspend fun getValuePickQuestions(): Result<List<ValuePickQuestion>> =
41+
suspendRunCatching {
42+
val localValuePickQuestions = localProfileDataSource.valuePickQuestions.firstOrNull()
43+
localValuePickQuestions ?: loadValuePickQuestions().getOrThrow()
44+
}
4545

46-
localProfileDataSource.setValuePickQuestions(valuePickQuestions)
46+
override suspend fun getValueTalkQuestions(): Result<List<ValueTalkQuestion>> =
47+
suspendRunCatching {
48+
val localValueTalkQuestions = localProfileDataSource.valueTalkQuestions.firstOrNull()
49+
localValueTalkQuestions ?: loadValueTalkQuestions().getOrThrow()
50+
}
51+
52+
override suspend fun getMyProfileBasic(): Result<MyProfileBasic> = suspendRunCatching {
53+
val localMyProfileBasic = localProfileDataSource.myProfileBasic.firstOrNull()
54+
localMyProfileBasic ?: loadMyProfileBasic().getOrThrow()
4755
}
4856

49-
override suspend fun loadValueTalkQuestions(): Result<Unit> = suspendRunCatching {
50-
val valueTalkQuestions = profileDataSource.loadValueTalkQuestions()
51-
.getOrThrow()
52-
.toDomain()
53-
.filter { it.id != UNKNOWN_INT }
57+
override suspend fun getMyValueTalks(): Result<List<MyValueTalk>> = suspendRunCatching {
58+
val localMyValueTalks = localProfileDataSource.myValueTalks.firstOrNull()
59+
localMyValueTalks ?: loadMyValueTalks().getOrThrow()
60+
}
5461

55-
localProfileDataSource.setValueTalkQuestions(valueTalkQuestions)
62+
override suspend fun getMyValuePicks(): Result<List<MyValuePick>> = suspendRunCatching {
63+
val localMyValuePicks = localProfileDataSource.myValuePicks.firstOrNull()
64+
localMyValuePicks ?: loadMyValuePicks().getOrThrow()
5665
}
5766

58-
override suspend fun retrieveValuePickQuestion(): List<ValuePickQuestion>? =
59-
localProfileDataSource.valuePickQuestions.firstOrNull()
67+
private suspend fun loadValuePickQuestions(): Result<List<ValuePickQuestion>> =
68+
suspendRunCatching {
69+
val valuePickQuestions = profileDataSource.loadValuePickQuestions()
70+
.getOrThrow()
71+
.toDomain()
72+
.filter { it.id != UNKNOWN_INT }
73+
74+
localProfileDataSource.setValuePickQuestions(valuePickQuestions)
75+
valuePickQuestions
76+
}
6077

61-
override suspend fun retrieveValueTalkQuestion(): List<ValueTalkQuestion>? =
62-
localProfileDataSource.valueTalkQuestions.firstOrNull()
78+
private suspend fun loadValueTalkQuestions(): Result<List<ValueTalkQuestion>> =
79+
suspendRunCatching {
80+
val valueTalkQuestions = profileDataSource.loadValueTalkQuestions()
81+
.getOrThrow()
82+
.toDomain()
83+
.filter { it.id != UNKNOWN_INT }
6384

64-
override suspend fun retrieveMyProfileBasic(): MyProfileBasic? =
65-
localProfileDataSource.myProfileBasic.firstOrNull()
85+
localProfileDataSource.setValueTalkQuestions(valueTalkQuestions)
86+
valueTalkQuestions
87+
}
6688

67-
override suspend fun loadMyValueTalks(): Result<Unit> = suspendRunCatching {
89+
private suspend fun loadMyValueTalks(): Result<List<MyValueTalk>> = suspendRunCatching {
6890
val valueTalks = profileDataSource.getMyValueTalks().getOrThrow().toDomain()
6991

7092
localProfileDataSource.setMyValueTalks(valueTalks)
93+
valueTalks
7194
}
7295

73-
override suspend fun retrieveMyValueTalks(): List<MyValueTalk>? =
74-
localProfileDataSource.myValueTalks.firstOrNull()
75-
76-
override suspend fun loadMyValuePicks(): Result<Unit> = suspendRunCatching {
96+
private suspend fun loadMyValuePicks(): Result<List<MyValuePick>> = suspendRunCatching {
7797
val valuePicks = profileDataSource.getMyValuePicks().getOrThrow().toDomain()
7898

7999
localProfileDataSource.setMyValuePicks(valuePicks)
100+
valuePicks
80101
}
81102

82-
override suspend fun retrieveMyValuePicks(): List<MyValuePick>? =
83-
localProfileDataSource.myValuePicks.firstOrNull()
84-
85-
86-
override suspend fun loadMyProfileBasic(): Result<Unit> = suspendRunCatching {
103+
private suspend fun loadMyProfileBasic(): Result<MyProfileBasic> = suspendRunCatching {
87104
val profileBasic = profileDataSource.getMyProfileBasic().getOrThrow().toDomain()
88105

89106
localProfileDataSource.setMyProfileBasic(profileBasic)
107+
profileBasic
90108
}
91109

92110
override suspend fun updateMyValueTalks(valueTalks: List<MyValueTalk>): Result<List<MyValueTalk>> =
@@ -144,7 +162,7 @@ class ProfileRepositoryImpl @Inject constructor(
144162
profileTalkId = profileTalkId,
145163
summary = summary,
146164
).onSuccess {
147-
val oldValueTalks = retrieveMyValueTalks() ?: emptyList()
165+
val oldValueTalks = localProfileDataSource.myValueTalks.firstOrNull() ?: emptyList()
148166
val newValueTalks = oldValueTalks.map { valueTalk ->
149167
if (valueTalk.id == profileTalkId) valueTalk.copy(summary = summary)
150168
else valueTalk

core/data/src/main/java/com/puzzle/data/repository/TermsRepositoryImpl.kt

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,27 @@ import com.puzzle.domain.model.terms.Term
66
import com.puzzle.domain.repository.TermsRepository
77
import com.puzzle.network.model.UNKNOWN_INT
88
import com.puzzle.network.source.term.TermDataSource
9-
import kotlinx.coroutines.flow.first
9+
import kotlinx.coroutines.flow.firstOrNull
1010
import javax.inject.Inject
1111

1212
class TermsRepositoryImpl @Inject constructor(
1313
private val termDataSource: TermDataSource,
1414
private val localTermDataSource: LocalTermDataSource,
1515
) : TermsRepository {
16-
override suspend fun loadTerms(): Result<Unit> = suspendRunCatching {
16+
override suspend fun getTerms(): Result<List<Term>> = suspendRunCatching {
17+
val localTerms = localTermDataSource.terms.firstOrNull()
18+
localTerms ?: loadTerms().getOrThrow()
19+
}
20+
21+
override suspend fun agreeTerms(ids: List<Int>): Result<Unit> = termDataSource.agreeTerms(ids)
22+
23+
private suspend fun loadTerms(): Result<List<Term>> = suspendRunCatching {
1724
val terms = termDataSource.loadTerms()
1825
.getOrThrow()
1926
.toDomain()
2027
.filter { it.id != UNKNOWN_INT }
2128

2229
localTermDataSource.setTerms(terms)
30+
terms
2331
}
24-
25-
override suspend fun retrieveTerms(): Result<List<Term>> = suspendRunCatching {
26-
localTermDataSource.terms.first()
27-
}
28-
29-
override suspend fun agreeTerms(ids: List<Int>): Result<Unit> = termDataSource.agreeTerms(ids)
3032
}

core/data/src/test/java/com/puzzle/data/fake/source/matching/FakeLocalMatchingDataSource.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ import kotlinx.coroutines.flow.flow
88
class FakeLocalMatchingDataSource : LocalMatchingDataSource {
99
private var storedOpponentProfile: OpponentProfile? = null
1010

11-
override val opponentProfile: Flow<OpponentProfile> = flow {
11+
override val opponentProfile: Flow<OpponentProfile?> = flow {
1212
storedOpponentProfile?.let { emit(it) }
13-
?: throw NoSuchElementException("No value present in DataStore")
1413
}
1514

1615
override suspend fun setOpponentProfile(opponentProfile: OpponentProfile) {

0 commit comments

Comments
 (0)