Skip to content

Commit a52ebb1

Browse files
authored
[PROPOSAL] chore: setup new BaseViewModel for UDF state management (#7)
* chore: setup new BaseViewModel for UDF state management Signed-off-by: Brandon McAnsh <[email protected]> * chore(account/sheet): convert to new BaseVM Signed-off-by: Brandon McAnsh <[email protected]> --------- Signed-off-by: Brandon McAnsh <[email protected]>
1 parent 07a6512 commit a52ebb1

25 files changed

+510
-163
lines changed

api/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ dependencies {
5353
implementation(Libs.grpc_okhttp)
5454
implementation(Libs.grpc_kotlin)
5555
implementation(Libs.androidx_room_runtime)
56+
implementation(Libs.androidx_room_ktx)
5657
implementation(Libs.androidx_room_rxjava3)
5758
implementation(Libs.okhttp)
5859
implementation(Libs.mixpanel)

api/src/main/java/com/getcode/db/PrefBoolDao.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ import androidx.room.Query
77
import com.getcode.model.PrefBool
88
import io.reactivex.rxjava3.core.Flowable
99
import io.reactivex.rxjava3.core.Maybe
10+
import kotlinx.coroutines.flow.Flow
1011

1112
@Dao
1213
interface PrefBoolDao {
1314
@Query("SELECT * FROM PrefBool WHERE key = :key")
1415
fun get(key: String): Flowable<PrefBool>
16+
@Query("SELECT * FROM PrefBool WHERE key = :key")
17+
fun observe(key: String): Flow<PrefBool?>
1518

1619
@Query("SELECT * FROM PrefBool WHERE key = :key")
1720
fun getMaybe(key: String): Maybe<PrefBool>

api/src/main/java/com/getcode/db/PrefDoubleDao.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ import androidx.room.Dao
44
import androidx.room.Insert
55
import androidx.room.OnConflictStrategy
66
import androidx.room.Query
7+
import com.getcode.model.PrefBool
78
import com.getcode.model.PrefDouble
89
import io.reactivex.rxjava3.core.Flowable
910
import io.reactivex.rxjava3.core.Maybe
11+
import kotlinx.coroutines.flow.Flow
1012

1113
@Dao
1214
interface PrefDoubleDao {
1315
@Query("SELECT * FROM PrefDouble WHERE `key` = :key")
1416
fun get(key: String): Flowable<PrefDouble>
1517

18+
@Query("SELECT * FROM PrefDouble WHERE key = :key")
19+
fun observe(key: String): Flow<PrefDouble?>
20+
1621
@Query("SELECT * FROM PrefDouble WHERE `key` = :key")
1722
fun getMaybe(key: String): Maybe<PrefDouble>
1823

api/src/main/java/com/getcode/db/PrefIntDao.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ import androidx.room.Dao
44
import androidx.room.Insert
55
import androidx.room.OnConflictStrategy
66
import androidx.room.Query
7+
import com.getcode.model.PrefBool
78
import com.getcode.model.PrefInt
89
import io.reactivex.rxjava3.core.Flowable
910
import io.reactivex.rxjava3.core.Maybe
11+
import kotlinx.coroutines.flow.Flow
1012

1113
@Dao
1214
interface PrefIntDao {
1315
@Query("SELECT * FROM PrefInt WHERE key = :key")
1416
fun get(key: String): Flowable<PrefInt>
1517

18+
@Query("SELECT * FROM PrefInt WHERE key = :key")
19+
fun observe(key: String): Flow<PrefInt?>
20+
1621
@Query("SELECT * FROM PrefInt WHERE key = :key")
1722
fun getMaybe(key: String): Maybe<PrefInt>
1823

api/src/main/java/com/getcode/db/PrefStringDao.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ import androidx.room.Dao
44
import androidx.room.Insert
55
import androidx.room.OnConflictStrategy
66
import androidx.room.Query
7+
import com.getcode.model.PrefBool
78
import com.getcode.model.PrefString
89
import io.reactivex.rxjava3.core.Flowable
910
import io.reactivex.rxjava3.core.Maybe
11+
import kotlinx.coroutines.flow.Flow
1012

1113
@Dao
1214
interface PrefStringDao {
1315
@Query("SELECT * FROM PrefString WHERE key = :key")
1416
fun get(key: String): Flowable<PrefString>
1517

18+
@Query("SELECT * FROM PrefString WHERE key = :key")
19+
fun observe(key: String): Flow<PrefString?>
20+
1621
@Query("SELECT * FROM PrefString WHERE key = :key")
1722
fun getMaybe(key: String): Maybe<PrefString>
1823

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.getcode.network.repository
2+
3+
import com.getcode.model.PrefsBool
4+
import kotlinx.coroutines.flow.Flow
5+
import kotlinx.coroutines.flow.combine
6+
import javax.inject.Inject
7+
8+
data class AccountDebugSettings(
9+
val isDebugBuckets: Boolean = false,
10+
val isVibrateOnScan: Boolean = false,
11+
val isDisplayErrors: Boolean = false,
12+
val isRemoteSendEnabled: Boolean = false,
13+
val isIncentivesEnabled: Boolean = false,
14+
)
15+
16+
class AccountDebugRepository @Inject constructor(
17+
private val prefRepository: PrefRepository,
18+
) {
19+
20+
fun observe(): Flow<AccountDebugSettings> = combine(
21+
prefRepository.observeOrDefault(PrefsBool.IS_DEBUG_BUCKETS, false),
22+
prefRepository.observeOrDefault(PrefsBool.IS_DEBUG_VIBRATE_ON_SCAN, false),
23+
prefRepository.observeOrDefault(PrefsBool.IS_DEBUG_DISPLAY_ERRORS, false),
24+
) { buckets, vibez, errors ->
25+
AccountDebugSettings(
26+
isDebugBuckets = buckets,
27+
isVibrateOnScan = vibez,
28+
isDisplayErrors = errors
29+
)
30+
}
31+
}

api/src/main/java/com/getcode/network/repository/IdentityRepository.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class IdentityRepository @Inject constructor(
7373
PrefsString.KEY_DATA_CONTAINER_ID,
7474
user.dataContainerId.toByteArray().encodeBase64()
7575
)
76-
phoneRepository.phoneLinked = true
76+
phoneRepository.phoneLinked.value = true
7777
prefRepository.set(
7878
PrefsBool.IS_DEBUG_ALLOWED,
7979
user.enableDebugOptions
@@ -111,7 +111,7 @@ class IdentityRepository @Inject constructor(
111111
dataContainerId = dataContainerId.decodeBase64().toList(),
112112
enableDebugOptions = isDebugAllowed,
113113
eligibleAirdrops = eligibleAirdrops,
114-
isPhoneNumberLinked = isPhoneNumberLinked
114+
isPhoneNumberLinked = isPhoneNumberLinked.value
115115
)
116116
}
117117
.filter { it.userId.isNotEmpty() && it.dataContainerId.isNotEmpty() }
@@ -176,7 +176,7 @@ class IdentityRepository @Inject constructor(
176176
.let { networkOracle.managedRequest(it) }
177177
.doOnComplete {
178178
phoneRepository.phoneNumber = ""
179-
phoneRepository.phoneLinked = false
179+
phoneRepository.phoneLinked.value = false
180180
}
181181
.firstOrError()
182182
}

api/src/main/java/com/getcode/network/repository/PhoneRepository.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import com.getcode.network.core.NetworkOracle
1010
import com.getcode.network.api.PhoneApi
1111
import io.reactivex.rxjava3.core.Flowable
1212
import io.reactivex.rxjava3.core.Single
13+
import kotlinx.coroutines.flow.MutableStateFlow
1314
import java.io.ByteArrayOutputStream
1415
import javax.inject.Inject
1516
import javax.inject.Singleton
@@ -21,7 +22,7 @@ class PhoneRepository @Inject constructor(
2122
) {
2223

2324
var phoneNumber: String = ""
24-
var phoneLinked: Boolean = false
25+
var phoneLinked: MutableStateFlow<Boolean> = MutableStateFlow(false)
2526

2627
data class GetAssociatedPhoneNumberResponse(
2728
val isSuccess: Boolean,
@@ -99,7 +100,7 @@ class PhoneRepository @Inject constructor(
99100
.flatMap { response -> Database.isInit.map { response } }
100101
.doOnNext { phone ->
101102
phoneNumber = phone.phoneNumber
102-
phoneLinked = phone.isLinked
103+
phoneLinked.value = phone.isLinked
103104
}
104105
//.onErrorResumeNext { getAssociatedPhoneNumberLocal().map { Pair(true, it) } }
105106
}
@@ -109,7 +110,7 @@ class PhoneRepository @Inject constructor(
109110
Flowable.just(phoneLinked),
110111
Flowable.just(phoneNumber)
111112
) { v1, v2 ->
112-
GetAssociatedPhoneNumberResponse(true, v1, false, v2)
113+
GetAssociatedPhoneNumberResponse(true, v1.value, false, v2)
113114
}
114115
}
115116
}

api/src/main/java/com/getcode/network/repository/PrefRepository.kt

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,21 @@ import io.reactivex.rxjava3.core.Single
77
import io.reactivex.rxjava3.schedulers.Schedulers
88
import kotlinx.coroutines.CoroutineScope
99
import kotlinx.coroutines.Dispatchers
10+
import kotlinx.coroutines.flow.Flow
11+
import kotlinx.coroutines.flow.MutableStateFlow
12+
import kotlinx.coroutines.flow.distinctUntilChanged
13+
import kotlinx.coroutines.flow.flowOf
14+
import kotlinx.coroutines.flow.flowOn
15+
import kotlinx.coroutines.flow.map
16+
import kotlinx.coroutines.flow.onEach
1017
import kotlinx.coroutines.launch
18+
import timber.log.Timber
1119
import javax.inject.Inject
1220

13-
class PrefRepository @Inject constructor() {
21+
22+
23+
class PrefRepository @Inject constructor(): CoroutineScope by CoroutineScope(Dispatchers.IO) {
24+
1425
fun get(key: PrefsString): Flowable<String> {
1526
val db = Database.getInstance() ?: return Flowable.empty()
1627
return db.prefStringDao().get(key.value)
@@ -27,6 +38,38 @@ class PrefRepository @Inject constructor() {
2738
.distinctUntilChanged()
2839
}
2940

41+
fun observeOrDefault(key: PrefsBool, default: Boolean): Flow<Boolean> {
42+
val db = Database.getInstance() ?: return flowOf(default)
43+
return db.prefBoolDao().observe(key.value)
44+
.flowOn(Dispatchers.IO)
45+
.map { it?.value ?: default }
46+
.distinctUntilChanged()
47+
}
48+
49+
fun observeOrDefault(key: PrefsString, default: String): Flow<String> {
50+
val db = Database.getInstance() ?: return flowOf(default)
51+
return db.prefStringDao().observe(key.value)
52+
.flowOn(Dispatchers.IO)
53+
.map { it?.value ?: default }
54+
.distinctUntilChanged()
55+
}
56+
57+
fun observeOrDefault(key: PrefDouble, default: Double): Flow<Double> {
58+
val db = Database.getInstance() ?: return flowOf(default)
59+
return db.prefDoubleDao().observe(key.key)
60+
.flowOn(Dispatchers.IO)
61+
.map { it?.value ?: default }
62+
.distinctUntilChanged()
63+
}
64+
65+
fun observeOrDefault(key: PrefInt, default: Long): Flow<Long> {
66+
val db = Database.getInstance() ?: return flowOf(default)
67+
return db.prefIntDao().observe(key.key)
68+
.flowOn(Dispatchers.IO)
69+
.map { it?.value ?: default }
70+
.distinctUntilChanged()
71+
}
72+
3073
fun get(key: String): Flowable<Long> {
3174
val db = Database.getInstance() ?: return Flowable.empty()
3275
return db.prefIntDao().get(key)
@@ -60,7 +103,7 @@ class PrefRepository @Inject constructor() {
60103
}
61104

62105
fun set(vararg list: Pair<PrefsString, String>) {
63-
CoroutineScope(Dispatchers.IO).launch {
106+
launch {
64107
list.forEach { pair ->
65108
Database.getInstance()?.prefStringDao()?.insert(PrefString(pair.first.value, pair.second))
66109
}
@@ -74,13 +117,13 @@ class PrefRepository @Inject constructor() {
74117
fun set(key: String, value: Int) = set(key, value.toLong())
75118

76119
fun set(key: String, value: Long) {
77-
CoroutineScope(Dispatchers.IO).launch {
120+
launch {
78121
Database.getInstance()?.prefIntDao()?.insert(PrefInt(key, value))
79122
}
80123
}
81124

82125
fun set(key: PrefsBool, value: Boolean) {
83-
CoroutineScope(Dispatchers.IO).launch {
126+
launch {
84127
Database.getInstance()?.prefBoolDao()?.insert(PrefBool(key.value, value))
85128
}
86129
}

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ dependencies {
165165
}
166166
androidTestImplementation(Libs.espresso_intents)
167167
implementation(Libs.androidx_room_runtime)
168+
implementation(Libs.androidx_room_ktx)
168169
implementation(Libs.androidx_room_rxjava3)
169170
kapt(Libs.androidx_room_compiler)
170171

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.getcode.inject
2+
3+
import android.content.Context
4+
import com.getcode.util.AndroidResources
5+
import com.getcode.util.resources.ResourceHelper
6+
import dagger.Module
7+
import dagger.Provides
8+
import dagger.hilt.InstallIn
9+
import dagger.hilt.android.qualifiers.ApplicationContext
10+
import dagger.hilt.components.SingletonComponent
11+
12+
@Module
13+
@InstallIn(SingletonComponent::class)
14+
object AppModule {
15+
@Provides
16+
fun providesResourceHelper(
17+
@ApplicationContext context: Context,
18+
): ResourceHelper = AndroidResources(context)
19+
}

app/src/main/java/com/getcode/manager/AuthManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ class AuthManager @Inject constructor(
223223
user.dataContainerId.toByteArray().encodeBase64()
224224
)
225225
)
226-
phoneRepository.phoneLinked = phone.isLinked
226+
phoneRepository.phoneLinked.value = phone.isLinked
227227

228228
prefRepository.set(
229229
PrefsBool.IS_DEBUG_ALLOWED,
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.getcode.util
2+
3+
import android.content.Context
4+
import androidx.annotation.RawRes
5+
import androidx.annotation.StringRes
6+
import com.getcode.util.resources.ResourceHelper
7+
import dagger.hilt.android.qualifiers.ApplicationContext
8+
import timber.log.Timber
9+
import java.io.File
10+
import javax.inject.Inject
11+
12+
class AndroidResources @Inject constructor(
13+
@ApplicationContext private val context: Context,
14+
) : ResourceHelper {
15+
16+
override fun getString(@StringRes resourceId: Int): String {
17+
return context.getString(resourceId)
18+
}
19+
20+
override fun getString(@StringRes resourceId: Int, vararg formatArgs: Any): String {
21+
return context.getString(resourceId, *formatArgs)
22+
}
23+
24+
override fun getRawResource(@RawRes resourceId: Int): String {
25+
return try {
26+
context.resources.openRawResource(resourceId).bufferedReader().use { it.readText() }
27+
} catch (e: Exception) {
28+
Timber.e(t = e, "Failed to get raw res for resource id:$resourceId")
29+
""
30+
}
31+
}
32+
33+
override fun getQuantityString(
34+
id: Int,
35+
quantity: Int,
36+
vararg formatArgs: Any,
37+
default: String,
38+
): String {
39+
return try {
40+
context.resources.getQuantityString(id, quantity, *formatArgs)
41+
} catch (e: Exception) {
42+
Timber.e(t = e, "Failed to get quantity string for resource id:$id")
43+
default
44+
}
45+
}
46+
47+
override fun getDimension(dimenId: Int, default: Float): Float {
48+
return try {
49+
context.resources.getDimension(dimenId)
50+
} catch (e: Exception) {
51+
Timber.e(t = e, "Failed to get dimension for resource id:$dimenId")
52+
default
53+
}
54+
}
55+
56+
override fun getDimensionPixelSize(dimenId: Int, default: Int): Int {
57+
return try {
58+
context.resources.getDimensionPixelSize(dimenId)
59+
} catch (e: Exception) {
60+
Timber.e(t = e, message = "Failed to get dimension for resource id:$dimenId")
61+
default
62+
}
63+
}
64+
65+
override fun getDir(name: String, mode: Int): File? {
66+
return context.getDir(name, mode)
67+
}
68+
}

0 commit comments

Comments
 (0)