Skip to content

Commit a58c58d

Browse files
authored
Merge pull request #254 from YAPP-Github/feat/#253-update-notice-bottom-sheet
[FEAT] 업데이트 공지 바텀시트
2 parents 0c0c8a9 + de737d4 commit a58c58d

File tree

22 files changed

+340
-70
lines changed

22 files changed

+340
-70
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
1212
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
1313
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
14+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
1415

1516
<application
1617
android:name=".OrbitApplication"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.yapp.orbit.di
2+
3+
import com.yapp.orbit.BuildConfig
4+
import dagger.Module
5+
import dagger.Provides
6+
import dagger.hilt.InstallIn
7+
import dagger.hilt.components.SingletonComponent
8+
import javax.inject.Named
9+
import javax.inject.Singleton
10+
11+
@Module
12+
@InstallIn(SingletonComponent::class)
13+
object AppVersionModule {
14+
@Provides
15+
@Singleton
16+
@Named("appVersion")
17+
fun provideAppVersion(): String = BuildConfig.VERSION_NAME
18+
}

core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import kotlinx.coroutines.flow.catch
1313
import kotlinx.coroutines.flow.distinctUntilChanged
1414
import kotlinx.coroutines.flow.map
1515
import java.time.LocalDate
16-
import java.time.format.DateTimeFormatter
1716
import javax.inject.Inject
1817
import javax.inject.Singleton
1918

@@ -27,7 +26,7 @@ class UserPreferences @Inject constructor(
2726
val ONBOARDING_COMPLETED = booleanPreferencesKey("onboarding_completed")
2827

2928
val FORTUNE_ID = longPreferencesKey("fortune_id")
30-
val FORTUNE_DATE = stringPreferencesKey("fortune_date")
29+
val FORTUNE_DATE_EPOCH = longPreferencesKey("fortune_date_epoch")
3130
val FORTUNE_IMAGE_ID = intPreferencesKey("fortune_image_id")
3231
val FORTUNE_SCORE = intPreferencesKey("fortune_score")
3332
val FORTUNE_SEEN = booleanPreferencesKey("fortune_seen")
@@ -36,10 +35,13 @@ class UserPreferences @Inject constructor(
3635
val FORTUNE_FAILED = booleanPreferencesKey("fortune_failed")
3736

3837
val FIRST_ALARM_DISMISSED_TODAY = booleanPreferencesKey("first_alarm_dismissed_today")
39-
val FIRST_ALARM_DISMISSED_DATE = stringPreferencesKey("first_alarm_dismissed_date")
38+
val FIRST_ALARM_DISMISSED_DATE_EPOCH = longPreferencesKey("first_alarm_dismissed_date_epoch")
39+
40+
val UPDATE_NOTICE_DONT_SHOW_VERSION = stringPreferencesKey("update_notice_dont_show_version")
41+
val UPDATE_NOTICE_LAST_SHOWN_DATE_EPOCH = longPreferencesKey("update_notice_last_shown_date_epoch")
4042
}
4143

42-
private fun today(): String = LocalDate.now().format(DateTimeFormatter.ISO_DATE)
44+
private fun todayEpoch(): Long = LocalDate.now().toEpochDay()
4345

4446
val userIdFlow: Flow<Long?> = dataStore.data
4547
.catch { emit(emptyPreferences()) }
@@ -61,9 +63,9 @@ class UserPreferences @Inject constructor(
6163
.map { it[Keys.FORTUNE_ID] }
6264
.distinctUntilChanged()
6365

64-
val fortuneDateFlow: Flow<String?> = dataStore.data
66+
val fortuneDateEpochFlow: Flow<Long?> = dataStore.data
6567
.catch { emit(emptyPreferences()) }
66-
.map { it[Keys.FORTUNE_DATE] }
68+
.map { it[Keys.FORTUNE_DATE_EPOCH] }
6769
.distinctUntilChanged()
6870

6971
val fortuneImageIdFlow: Flow<Int?> = dataStore.data
@@ -79,18 +81,17 @@ class UserPreferences @Inject constructor(
7981
val hasUnseenFortuneFlow: Flow<Boolean> = dataStore.data
8082
.catch { emit(emptyPreferences()) }
8183
.map { pref ->
82-
pref[Keys.FORTUNE_DATE] == today() &&
83-
pref[Keys.FORTUNE_ID] != null &&
84-
(pref[Keys.FORTUNE_SEEN] != true)
84+
val isToday = pref[Keys.FORTUNE_DATE_EPOCH] == todayEpoch()
85+
isToday && (pref[Keys.FORTUNE_ID] != null) && (pref[Keys.FORTUNE_SEEN] != true)
8586
}
8687
.distinctUntilChanged()
8788

8889
val shouldShowFortuneToolTipFlow: Flow<Boolean> = dataStore.data
8990
.catch { emit(emptyPreferences()) }
9091
.map { pref ->
91-
val hasTodayFortune = pref[Keys.FORTUNE_DATE] == today() && pref[Keys.FORTUNE_ID] != null
92-
val tooltipNotShown = pref[Keys.FORTUNE_TOOLTIP_SHOWN] ?: false
93-
hasTodayFortune && !tooltipNotShown
92+
val hasTodayFortune = (pref[Keys.FORTUNE_DATE_EPOCH] == todayEpoch()) && (pref[Keys.FORTUNE_ID] != null)
93+
val tooltipShown = pref[Keys.FORTUNE_TOOLTIP_SHOWN] ?: false
94+
hasTodayFortune && !tooltipShown
9495
}
9596
.distinctUntilChanged()
9697

@@ -108,27 +109,31 @@ class UserPreferences @Inject constructor(
108109
.catch { emit(emptyPreferences()) }
109110
.map { pref ->
110111
val flag = pref[Keys.FIRST_ALARM_DISMISSED_TODAY] ?: false
111-
val date = pref[Keys.FIRST_ALARM_DISMISSED_DATE]
112-
flag && date == today()
112+
val isToday = pref[Keys.FIRST_ALARM_DISMISSED_DATE_EPOCH] == todayEpoch()
113+
flag && isToday
113114
}
114115
.distinctUntilChanged()
115116

117+
val updateNoticeDontShowVersionFlow: Flow<String?> = dataStore.data
118+
.catch { emit(emptyPreferences()) }
119+
.map { it[Keys.UPDATE_NOTICE_DONT_SHOW_VERSION] }
120+
.distinctUntilChanged()
121+
122+
val updateNoticeLastShownDateEpochFlow: Flow<Long?> = dataStore.data
123+
.catch { emit(emptyPreferences()) }
124+
.map { it[Keys.UPDATE_NOTICE_LAST_SHOWN_DATE_EPOCH] }
125+
.distinctUntilChanged()
126+
116127
suspend fun saveUserId(userId: Long) {
117-
dataStore.edit { pref ->
118-
pref[Keys.USER_ID] = userId
119-
}
128+
dataStore.edit { it[Keys.USER_ID] = userId }
120129
}
121130

122131
suspend fun saveUserName(userName: String) {
123-
dataStore.edit { pref ->
124-
pref[Keys.USER_NAME] = userName
125-
}
132+
dataStore.edit { it[Keys.USER_NAME] = userName }
126133
}
127134

128135
suspend fun setOnboardingCompleted() {
129-
dataStore.edit { pref ->
130-
pref[Keys.ONBOARDING_COMPLETED] = true
131-
}
136+
dataStore.edit { it[Keys.ONBOARDING_COMPLETED] = true }
132137
}
133138

134139
suspend fun markFortuneCreating() {
@@ -140,10 +145,12 @@ class UserPreferences @Inject constructor(
140145

141146
suspend fun markFortuneCreated(fortuneId: Long) {
142147
dataStore.edit { pref ->
143-
val isNewForToday = pref[Keys.FORTUNE_ID] != fortuneId || pref[Keys.FORTUNE_DATE] != today()
148+
val today = todayEpoch()
149+
val prevDate = pref[Keys.FORTUNE_DATE_EPOCH]
150+
val isNewForToday = (pref[Keys.FORTUNE_ID] != fortuneId) || (prevDate != today)
144151

145152
pref[Keys.FORTUNE_ID] = fortuneId
146-
pref[Keys.FORTUNE_DATE] = today()
153+
pref[Keys.FORTUNE_DATE_EPOCH] = today
147154
pref[Keys.FORTUNE_CREATING] = false
148155
pref[Keys.FORTUNE_FAILED] = false
149156

@@ -162,44 +169,46 @@ class UserPreferences @Inject constructor(
162169
}
163170

164171
suspend fun markFortuneSeen() {
165-
dataStore.edit { pref ->
166-
pref[Keys.FORTUNE_SEEN] = true
167-
}
172+
dataStore.edit { it[Keys.FORTUNE_SEEN] = true }
168173
}
169174

170175
suspend fun markFortuneTooltipShown() {
171-
dataStore.edit { pref ->
172-
pref[Keys.FORTUNE_TOOLTIP_SHOWN] = true
173-
}
176+
dataStore.edit { it[Keys.FORTUNE_TOOLTIP_SHOWN] = true }
174177
}
175178

176179
suspend fun saveFortuneImageId(imageResId: Int) {
177-
dataStore.edit { pref ->
178-
pref[Keys.FORTUNE_IMAGE_ID] = imageResId
179-
}
180+
dataStore.edit { it[Keys.FORTUNE_IMAGE_ID] = imageResId }
180181
}
181182

182183
suspend fun saveFortuneScore(score: Int) {
183-
dataStore.edit { pref ->
184-
pref[Keys.FORTUNE_SCORE] = score
185-
}
184+
dataStore.edit { it[Keys.FORTUNE_SCORE] = score }
186185
}
187186

188187
suspend fun markFirstAlarmDismissedToday() {
189188
dataStore.edit { pref ->
190189
pref[Keys.FIRST_ALARM_DISMISSED_TODAY] = true
191-
pref[Keys.FIRST_ALARM_DISMISSED_DATE] = today()
190+
pref[Keys.FIRST_ALARM_DISMISSED_DATE_EPOCH] = todayEpoch()
191+
}
192+
}
193+
194+
suspend fun markUpdateNoticeDontShow(version: String) {
195+
dataStore.edit { it[Keys.UPDATE_NOTICE_DONT_SHOW_VERSION] = version }
196+
}
197+
198+
suspend fun markUpdateNoticeShownToday() {
199+
dataStore.edit { pref ->
200+
pref[Keys.UPDATE_NOTICE_LAST_SHOWN_DATE_EPOCH] = todayEpoch()
192201
}
193202
}
194203

195204
suspend fun clearUserData() {
196-
dataStore.edit { pref -> pref.clear() }
205+
dataStore.edit { it.clear() }
197206
}
198207

199208
suspend fun clearFortuneData() {
200209
dataStore.edit { pref ->
201210
pref.remove(Keys.FORTUNE_ID)
202-
pref.remove(Keys.FORTUNE_DATE)
211+
pref.remove(Keys.FORTUNE_DATE_EPOCH)
203212
pref.remove(Keys.FORTUNE_IMAGE_ID)
204213
pref.remove(Keys.FORTUNE_SCORE)
205214
pref.remove(Keys.FORTUNE_SEEN)

data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSource.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import kotlinx.coroutines.flow.Flow
55

66
interface FortuneLocalDataSource {
77
val fortuneIdFlow: Flow<Long?>
8-
val fortuneDateFlow: Flow<String?>
8+
val fortuneDateEpochFlow: Flow<Long?>
99
val fortuneImageIdFlow: Flow<Int?>
1010
val fortuneScoreFlow: Flow<Int?>
1111
val hasUnseenFortuneFlow: Flow<Boolean>

data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@ import com.yapp.domain.model.FortuneCreateStatus
55
import kotlinx.coroutines.flow.combine
66
import kotlinx.coroutines.flow.distinctUntilChanged
77
import java.time.LocalDate
8-
import java.time.format.DateTimeFormatter
98
import javax.inject.Inject
109

1110
class FortuneLocalDataSourceImpl @Inject constructor(
1211
private val userPreferences: UserPreferences,
1312
) : FortuneLocalDataSource {
1413

1514
override val fortuneIdFlow = userPreferences.fortuneIdFlow
16-
override val fortuneDateFlow = userPreferences.fortuneDateFlow
15+
override val fortuneDateEpochFlow = userPreferences.fortuneDateEpochFlow
1716
override val fortuneImageIdFlow = userPreferences.fortuneImageIdFlow
1817
override val fortuneScoreFlow = userPreferences.fortuneScoreFlow
1918
override val hasUnseenFortuneFlow = userPreferences.hasUnseenFortuneFlow
@@ -22,19 +21,19 @@ class FortuneLocalDataSourceImpl @Inject constructor(
2221

2322
override val fortuneCreateStatusFlow = combine(
2423
userPreferences.fortuneIdFlow,
25-
userPreferences.fortuneDateFlow,
24+
userPreferences.fortuneDateEpochFlow,
2625
userPreferences.isFortuneCreatingFlow,
2726
userPreferences.isFortuneFailedFlow,
2827
) { fortuneId, fortuneDate, isCreating, isFailed ->
2928
when {
3029
isFailed -> FortuneCreateStatus.Failure
3130
isCreating -> FortuneCreateStatus.Creating
32-
fortuneId != null && fortuneDate == today() -> FortuneCreateStatus.Success(fortuneId)
31+
fortuneId != null && fortuneDate == todayEpoch() -> FortuneCreateStatus.Success(fortuneId)
3332
else -> FortuneCreateStatus.Idle
3433
}
3534
}.distinctUntilChanged()
3635

37-
private fun today(): String = LocalDate.now().format(DateTimeFormatter.ISO_DATE)
36+
private fun todayEpoch(): Long = LocalDate.now().toEpochDay()
3837

3938
override suspend fun markFortuneCreating() {
4039
userPreferences.markFortuneCreating()

data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSource.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@ interface UserLocalDataSource {
66
val userIdFlow: Flow<Long?>
77
val userNameFlow: Flow<String?>
88
val onboardingCompletedFlow: Flow<Boolean>
9+
val updateNoticeDontShowVersionFlow: Flow<String?>
10+
val updateNoticeLastShownDateEpochFlow: Flow<Long?>
911

1012
suspend fun saveUserId(userId: Long)
1113
suspend fun saveUserName(userName: String)
1214
suspend fun setOnboardingCompleted()
15+
suspend fun markUpdateNoticeDontShow(version: String)
16+
suspend fun markUpdateNoticeShownToday()
1317
suspend fun clearUserData()
1418
}

data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSourceImpl.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ class UserLocalDataSourceImpl @Inject constructor(
1111
override val userIdFlow: Flow<Long?> = userPreferences.userIdFlow
1212
override val userNameFlow: Flow<String?> = userPreferences.userNameFlow
1313
override val onboardingCompletedFlow: Flow<Boolean> = userPreferences.onboardingCompletedFlow
14+
override val updateNoticeDontShowVersionFlow: Flow<String?> = userPreferences.updateNoticeDontShowVersionFlow
15+
override val updateNoticeLastShownDateEpochFlow: Flow<Long?> = userPreferences.updateNoticeLastShownDateEpochFlow
1416

1517
override suspend fun saveUserId(userId: Long) {
1618
userPreferences.saveUserId(userId)
@@ -24,6 +26,14 @@ class UserLocalDataSourceImpl @Inject constructor(
2426
userPreferences.setOnboardingCompleted()
2527
}
2628

29+
override suspend fun markUpdateNoticeDontShow(version: String) {
30+
userPreferences.markUpdateNoticeDontShow(version)
31+
}
32+
33+
override suspend fun markUpdateNoticeShownToday() {
34+
userPreferences.markUpdateNoticeShownToday()
35+
}
36+
2737
override suspend fun clearUserData() {
2838
userPreferences.clearUserData()
2939
}

data/src/main/java/com/yapp/data/repositoryimpl/FortuneRepositoryImpl.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class FortuneRepositoryImpl @Inject constructor(
1515
) : FortuneRepository {
1616

1717
override val fortuneIdFlow: Flow<Long?> = fortuneLocalDataSource.fortuneIdFlow
18-
override val fortuneDateFlow: Flow<String?> = fortuneLocalDataSource.fortuneDateFlow
18+
override val fortuneDateEpochFlow: Flow<Long?> = fortuneLocalDataSource.fortuneDateEpochFlow
1919
override val fortuneImageIdFlow: Flow<Int?> = fortuneLocalDataSource.fortuneImageIdFlow
2020
override val fortuneScoreFlow: Flow<Int?> = fortuneLocalDataSource.fortuneScoreFlow
2121
override val hasUnseenFortuneFlow: Flow<Boolean> = fortuneLocalDataSource.hasUnseenFortuneFlow

data/src/main/java/com/yapp/data/repositoryimpl/UserInfoRepositoryImpl.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,14 @@ class UserInfoRepositoryImpl @Inject constructor(
1717
override val userIdFlow: Flow<Long?> = userLocalDataSource.userIdFlow
1818
override val userNameFlow: Flow<String?> = userLocalDataSource.userNameFlow
1919
override val onboardingCompletedFlow: Flow<Boolean> = userLocalDataSource.onboardingCompletedFlow
20+
override val updateNoticeDontShowVersionFlow: Flow<String?> = userLocalDataSource.updateNoticeDontShowVersionFlow
21+
override val updateNoticeLastShownDateEpochFlow: Flow<Long?> = userLocalDataSource.updateNoticeLastShownDateEpochFlow
2022

2123
override suspend fun saveUserId(userId: Long) = userLocalDataSource.saveUserId(userId)
2224
override suspend fun saveUserName(userName: String) = userLocalDataSource.saveUserName(userName)
2325
override suspend fun setOnboardingCompleted() = userLocalDataSource.setOnboardingCompleted()
26+
override suspend fun markUpdateNoticeDontShow(version: String) = userLocalDataSource.markUpdateNoticeDontShow(version)
27+
override suspend fun markUpdateNoticeShownToday() = userLocalDataSource.markUpdateNoticeShownToday()
2428
override suspend fun clearUserData() = userLocalDataSource.clearUserData()
2529

2630
override suspend fun getUserInfo(userId: Long): Result<User> {

domain/src/main/java/com/yapp/domain/repository/FortuneRepository.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import kotlinx.coroutines.flow.Flow
66

77
interface FortuneRepository {
88
val fortuneIdFlow: Flow<Long?>
9-
val fortuneDateFlow: Flow<String?>
9+
val fortuneDateEpochFlow: Flow<Long?>
1010
val fortuneImageIdFlow: Flow<Int?>
1111
val fortuneScoreFlow: Flow<Int?>
1212
val hasUnseenFortuneFlow: Flow<Boolean>

0 commit comments

Comments
 (0)