Skip to content

Commit 06c504b

Browse files
authored
Merge pull request #200 from YAPP-Github/feat/#195-tap-mission
2 parents ff7d977 + 8d41b4b commit 06c504b

File tree

25 files changed

+310
-21
lines changed

25 files changed

+310
-21
lines changed
Loading
Loading
Loading

core/designsystem/src/main/res/raw/mission_letter_open.json

+1
Large diffs are not rendered by default.

core/designsystem/src/main/res/raw/mission_letter_tap.json

+1
Large diffs are not rendered by default.

core/remoteconfig/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

core/remoteconfig/build.gradle.kts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import com.yapp.convention.setNamespace
2+
3+
plugins {
4+
id("orbit.android.library")
5+
id("orbit.android.hilt")
6+
}
7+
8+
android {
9+
setNamespace("core.remoteconfig")
10+
}
11+
12+
dependencies {
13+
implementation(platform(libs.firebase.bom))
14+
implementation(libs.firebase.config)
15+
}

core/remoteconfig/consumer-rules.pro

Whitespace-only changes.

core/remoteconfig/proguard-rules.pro

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
3+
4+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.yapp.remoteconfig
2+
3+
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
4+
import kotlinx.coroutines.tasks.await
5+
import javax.inject.Inject
6+
7+
class FirebaseRemoteConfigManager @Inject constructor(
8+
private val remoteConfig: FirebaseRemoteConfig,
9+
) {
10+
suspend fun fetchAndActivate(): Boolean {
11+
return try {
12+
remoteConfig.fetchAndActivate().await()
13+
} catch (e: Exception) {
14+
false
15+
}
16+
}
17+
18+
fun getRawMissionType(): String {
19+
val rawValue = remoteConfig.getString(KEY_MISSION_TYPE)
20+
return rawValue
21+
}
22+
23+
companion object {
24+
private const val KEY_MISSION_TYPE = "alarm_mission_type"
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.yapp.remoteconfig.di
2+
3+
import com.google.firebase.ktx.Firebase
4+
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
5+
import com.google.firebase.remoteconfig.ktx.remoteConfig
6+
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
7+
import com.yapp.remoteconfig.FirebaseRemoteConfigManager
8+
import dagger.Module
9+
import dagger.Provides
10+
import dagger.hilt.InstallIn
11+
import dagger.hilt.components.SingletonComponent
12+
import javax.inject.Singleton
13+
14+
@Module
15+
@InstallIn(SingletonComponent::class)
16+
object RemoteConfigModule {
17+
18+
@Provides
19+
@Singleton
20+
fun provideFirebaseRemoteConfig(): FirebaseRemoteConfig {
21+
return Firebase.remoteConfig.apply {
22+
setConfigSettingsAsync(
23+
remoteConfigSettings {
24+
minimumFetchIntervalInSeconds = 3600L
25+
},
26+
)
27+
}
28+
}
29+
30+
@Provides
31+
@Singleton
32+
fun provideRemoteConfigManager(
33+
remoteConfig: FirebaseRemoteConfig,
34+
): FirebaseRemoteConfigManager = FirebaseRemoteConfigManager(remoteConfig)
35+
}

core/ui/src/main/java/com/yapp/ui/component/lottie/LottieAnimation.kt

+19-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
99
import androidx.compose.runtime.Composable
1010
import androidx.compose.runtime.LaunchedEffect
1111
import androidx.compose.runtime.getValue
12+
import androidx.compose.runtime.mutableStateOf
1213
import androidx.compose.runtime.remember
1314
import androidx.compose.ui.Modifier
1415
import androidx.compose.ui.graphics.graphicsLayer
@@ -26,12 +27,17 @@ fun LottieAnimation(
2627
contentScale: ContentScale = ContentScale.FillWidth,
2728
scaleXAdjustment: Float = 1f,
2829
scaleYAdjustment: Float = 1f,
30+
play: Boolean = iterations == 1,
31+
restartOnPlay: Boolean = false,
2932
onAnimationEnd: (() -> Unit)? = null,
3033
) {
3134
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(resId))
32-
val progress by animateLottieCompositionAsState(
35+
val isPlaying = remember { mutableStateOf(iterations == LottieConstants.IterateForever || play) }
36+
val animationState = animateLottieCompositionAsState(
3337
composition = composition,
3438
iterations = iterations,
39+
isPlaying = isPlaying.value,
40+
restartOnPlay = restartOnPlay,
3541
)
3642
val alpha = remember { Animatable(0f) }
3743

@@ -44,9 +50,18 @@ fun LottieAnimation(
4450
}
4551
}
4652

47-
LaunchedEffect(progress) {
48-
if (progress == 1f) {
53+
LaunchedEffect(play) {
54+
if (play) {
55+
isPlaying.value = true
56+
}
57+
}
58+
59+
LaunchedEffect(animationState.progress) {
60+
if (animationState.progress == 1f) {
4961
onAnimationEnd?.invoke()
62+
if (iterations == 1) {
63+
isPlaying.value = false
64+
}
5065
}
5166
}
5267

@@ -62,7 +77,7 @@ fun LottieAnimation(
6277
if (composition != null) {
6378
com.airbnb.lottie.compose.LottieAnimation(
6479
composition = composition,
65-
progress = { progress },
80+
progress = { animationState.progress },
6681
modifier = Modifier.fillMaxSize(),
6782
)
6883
}

data/build.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ dependencies {
1414
implementation(projects.core.network)
1515
implementation(projects.core.datastore)
1616
implementation(projects.core.media)
17+
implementation(projects.core.remoteconfig)
1718

1819
ksp(libs.androidx.room.compiler)
1920
implementation(libs.androidx.room.ktx)

data/src/main/java/com/yapp/data/remote/di/RepositoryModule.kt

+8
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package com.yapp.data.remote.di
22

33
import com.yapp.data.remote.repositoryimpl.DummyRepositoryImpl
44
import com.yapp.data.remote.repositoryimpl.FortuneRepositoryImpl
5+
import com.yapp.data.remote.repositoryimpl.RemoteConfigRepositoryImpl
56
import com.yapp.data.remote.repositoryimpl.SignUpRepositoryImpl
67
import com.yapp.data.remote.repositoryimpl.UserInfoRepositoryImpl
78
import com.yapp.domain.repository.DummyRepository
89
import com.yapp.domain.repository.FortuneRepository
10+
import com.yapp.domain.repository.RemoteConfigRepository
911
import com.yapp.domain.repository.SignUpRepository
1012
import com.yapp.domain.repository.UserInfoRepository
1113
import dagger.Binds
@@ -40,4 +42,10 @@ abstract class RepositoryModule {
4042
abstract fun bindsFortuneRepository(
4143
fortuneRepository: FortuneRepositoryImpl,
4244
): FortuneRepository
45+
46+
@Binds
47+
@Singleton
48+
abstract fun bindsRemoteConfigRepository(
49+
remoteConfigRepository: RemoteConfigRepositoryImpl,
50+
): RemoteConfigRepository
4351
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.yapp.data.remote.repositoryimpl
2+
3+
import com.yapp.domain.model.MissionType
4+
import com.yapp.domain.repository.RemoteConfigRepository
5+
import com.yapp.remoteconfig.FirebaseRemoteConfigManager
6+
import javax.inject.Inject
7+
8+
class RemoteConfigRepositoryImpl @Inject constructor(
9+
private val manager: FirebaseRemoteConfigManager,
10+
) : RemoteConfigRepository {
11+
12+
override suspend fun fetchAndActivate(): Boolean = manager.fetchAndActivate()
13+
14+
override fun getMissionType(): MissionType {
15+
return MissionType.fromRemoteValue(manager.getRawMissionType())
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.yapp.domain.model
2+
3+
sealed class MissionType {
4+
data object Shake : MissionType()
5+
data object Click : MissionType()
6+
7+
companion object {
8+
fun fromRemoteValue(value: String): MissionType {
9+
return when (value) {
10+
"tap_mission" -> Click
11+
"shake_mission" -> Shake
12+
else -> {
13+
Click
14+
}
15+
}
16+
}
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.yapp.domain.repository
2+
3+
import com.yapp.domain.model.MissionType
4+
5+
interface RemoteConfigRepository {
6+
suspend fun fetchAndActivate(): Boolean
7+
fun getMissionType(): MissionType
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.yapp.domain.usecase
2+
3+
import com.yapp.domain.model.MissionType
4+
import com.yapp.domain.repository.RemoteConfigRepository
5+
import javax.inject.Inject
6+
7+
class GetMissionTypeUseCase @Inject constructor(
8+
private val repository: RemoteConfigRepository,
9+
) {
10+
suspend fun execute(): MissionType {
11+
repository.fetchAndActivate()
12+
return repository.getMissionType()
13+
}
14+
}

feature/mission/src/main/java/com/yapp/mission/MissionContract.kt

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
package com.yapp.mission
22

3+
import com.yapp.domain.model.MissionType
4+
35
sealed class MissionContract {
46

57
data class State(
8+
val missionType: MissionType = MissionType.Click,
69
val showOverlayText: Boolean = false,
710
val showOverlay: Boolean = true,
811
val missionProgress: Int = 0,
912
val isMissionCompleted: Boolean = false,
10-
val isFlipped: Boolean = false,
1113
val shakeCount: Int = 0,
14+
val clickCount: Int = 0,
15+
val playWhenClick: Boolean = false,
16+
val showFinalAnimation: Boolean = false,
17+
val isFlipped: Boolean = false,
1218
val rotationY: Float = 0f,
1319
val rotationZ: Float = 0f,
1420
val showExitDialog: Boolean = false,

0 commit comments

Comments
 (0)