Skip to content

Commit 87be29e

Browse files
committed
feat: move kado flow into app via webview modal
Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent 0c482dd commit 87be29e

19 files changed

Lines changed: 199 additions & 106 deletions

File tree

api/src/main/java/com/getcode/model/PrefBool.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ data class PrefBool(
1414
sealed interface InternalRouting
1515
sealed interface AppSetting
1616
sealed interface BetaFlag
17+
sealed interface DevSetting
1718

1819

1920
sealed class PrefsBool(val value: String) {
@@ -31,6 +32,9 @@ sealed class PrefsBool(val value: String) {
3132
data object CAMERA_START_BY_DEFAULT: PrefsBool("camera_start_default"), AppSetting
3233
data object REQUIRE_BIOMETRICS: PrefsBool("require_biometrics"), AppSetting
3334

35+
// dev settings
36+
data object ESTABLISH_CODE_RELATIONSHIP : PrefsBool("establish_code_relationship_enabled"), DevSetting
37+
3438
// beta flags
3539
data object BUCKET_DEBUGGER_ENABLED: PrefsBool("debug_buckets"), BetaFlag
3640
data object VIBRATE_ON_SCAN: PrefsBool("vibrate_on_scan"), BetaFlag
@@ -40,7 +44,7 @@ sealed class PrefsBool(val value: String) {
4044
data object GIVE_REQUESTS_ENABLED: PrefsBool("give_requests_enabled"), BetaFlag
4145
data object BUY_MODULE_ENABLED : PrefsBool("buy_kin_enabled"), BetaFlag
4246

43-
data object ESTABLISH_CODE_RELATIONSHIP : PrefsBool("establish_code_relationship_enabled"), BetaFlag
47+
4448
data object CHAT_UNSUB_ENABLED: PrefsBool("chat_unsub_enabled"), BetaFlag
4549
data object TIPS_ENABLED : PrefsBool("tips_enabled"), BetaFlag
4650
data object TIPS_CHAT_ENABLED: PrefsBool("tips_chat_enabled"), BetaFlag

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ data class BetaOptions(
1313
val displayErrors: Boolean,
1414
val giveRequestsEnabled: Boolean,
1515
val buyModuleEnabled: Boolean,
16-
val establishCodeRelationship: Boolean,
1716
val chatUnsubEnabled: Boolean,
1817
val tipsEnabled: Boolean,
1918
val tipsChatEnabled: Boolean,
@@ -30,7 +29,6 @@ data class BetaOptions(
3029
displayErrors = false,
3130
giveRequestsEnabled = false,
3231
buyModuleEnabled = true,
33-
establishCodeRelationship = false,
3432
chatUnsubEnabled = false,
3533
tipsEnabled = false,
3634
tipsChatEnabled = false,
@@ -43,6 +41,8 @@ data class BetaOptions(
4341
class BetaFlagsRepository @Inject constructor(
4442
private val prefRepository: PrefRepository,
4543
) {
44+
suspend fun isEnabled() = prefRepository.get(PrefsBool.IS_DEBUG_ALLOWED, false)
45+
4646
fun enableBeta(allowed: Boolean) {
4747
prefRepository.set(
4848
PrefsBool.IS_DEBUG_ALLOWED,
@@ -62,7 +62,6 @@ class BetaFlagsRepository @Inject constructor(
6262
observeBetaFlag(PrefsBool.LOG_SCAN_TIMES, default = defaults.debugScanTimesEnabled),
6363
observeBetaFlag(PrefsBool.GIVE_REQUESTS_ENABLED, default = defaults.giveRequestsEnabled),
6464
observeBetaFlag(PrefsBool.BUY_MODULE_ENABLED, default = defaults.buyModuleEnabled),
65-
observeBetaFlag(PrefsBool.ESTABLISH_CODE_RELATIONSHIP, default = defaults.establishCodeRelationship),
6665
observeBetaFlag(PrefsBool.CHAT_UNSUB_ENABLED, default = defaults.chatUnsubEnabled),
6766
observeBetaFlag(PrefsBool.TIPS_ENABLED, default = defaults.tipsEnabled),
6867
observeBetaFlag(PrefsBool.TIPS_CHAT_ENABLED, default = defaults.tipsChatEnabled),
@@ -77,13 +76,12 @@ class BetaFlagsRepository @Inject constructor(
7776
debugScanTimesEnabled = it[3],
7877
giveRequestsEnabled = it[4],
7978
buyModuleEnabled = it[5],
80-
establishCodeRelationship = it[6],
81-
chatUnsubEnabled = it[7],
82-
tipsEnabled = it[8],
83-
tipsChatEnabled = it[9],
84-
tipsChatCashEnabled = it[10],
85-
balanceCurrencySelectionEnabled = it[11],
86-
displayErrors = it[12],
79+
chatUnsubEnabled = it[6],
80+
tipsEnabled = it[7],
81+
tipsChatEnabled = it[8],
82+
tipsChatCashEnabled = it[9],
83+
balanceCurrencySelectionEnabled = it[10],
84+
displayErrors = it[11],
8785
)
8886
}
8987
}

app/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ dependencies {
131131

132132
//hilt dependency injection
133133
implementation(Libs.hilt)
134+
implementation("androidx.webkit:webkit:1.11.0")
134135
kapt(Libs.hilt_android_compiler)
135136
kapt(Libs.hilt_compiler)
136137
androidTestImplementation(Libs.hilt)
@@ -159,6 +160,7 @@ dependencies {
159160
implementation(Libs.compose_voyager_navigation_transitions)
160161
implementation(Libs.compose_voyager_navigation_bottomsheet)
161162
implementation(Libs.compose_voyager_navigation_hilt)
163+
implementation(Libs.compose_webview)
162164

163165
implementation(Libs.androidx_biometrics)
164166

app/src/main/java/com/getcode/CodeAppState.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ package com.getcode
33
import androidx.compose.material.ScaffoldState
44
import androidx.compose.material.rememberScaffoldState
55
import androidx.compose.runtime.Composable
6-
import androidx.compose.runtime.MutableState
76
import androidx.compose.runtime.Stable
87
import androidx.compose.runtime.remember
98
import androidx.compose.runtime.rememberCoroutineScope
10-
import androidx.lifecycle.MutableLiveData
119
import com.getcode.manager.BottomBarManager
1210
import com.getcode.manager.TopBarManager
1311
import com.getcode.navigation.core.CodeNavigator
@@ -87,7 +85,6 @@ class CodeAppState(
8785
val topBarMessage = MutableStateFlow<TopBarManager.TopBarMessage?>(null)
8886
val bottomBarMessage = MutableStateFlow<BottomBarManager.BottomBarMessage?>(null)
8987

90-
9188
fun upPress() {
9289
if (navigator.pop().not()) {
9390
navigator.hide()

app/src/main/java/com/getcode/mapper/AppSettingsMapper.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import javax.inject.Inject
1010

1111
class AppSettingsMapper @Inject constructor(
1212
private val biometricManager: BiometricManager,
13-
): Mapper<AppSettings, List<SettingItem>> {
14-
override fun map(from: AppSettings): List<SettingItem> {
13+
): SuspendMapper<AppSettings, List<SettingItem>> {
14+
override suspend fun map(from: AppSettings): List<SettingItem> {
1515

1616
return APP_SETTINGS.map { setting ->
1717
when (setting) {

app/src/main/java/com/getcode/navigation/screens/MainScreens.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package com.getcode.navigation.screens
22

33
import androidx.compose.runtime.Composable
4-
import androidx.compose.ui.platform.LocalLifecycleOwner
54
import androidx.compose.ui.res.stringResource
65
import androidx.lifecycle.Lifecycle
76
import cafe.adriel.voyager.core.screen.ScreenKey
87
import cafe.adriel.voyager.core.screen.uniqueScreenKey
98
import cafe.adriel.voyager.hilt.getViewModel
109
import com.getcode.R
11-
import com.getcode.analytics.AnalyticsManager
1210
import com.getcode.model.KinAmount
1311
import com.getcode.navigation.core.LocalCodeNavigator
1412
import com.getcode.ui.utils.RepeatOnLifecycle
@@ -186,6 +184,7 @@ data object ShareDownloadLinkModal : MainGraph, ModalRoot {
186184
}
187185
}
188186

187+
189188
@Composable
190189
fun <T> AppScreen.OnScreenResult(block: (T) -> Unit) {
191190
RepeatOnLifecycle(

app/src/main/java/com/getcode/navigation/screens/ModalScreens.kt

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
11
package com.getcode.navigation.screens
22

3+
import android.webkit.JavascriptInterface
4+
import androidx.compose.foundation.isSystemInDarkTheme
5+
import androidx.compose.foundation.layout.fillMaxSize
6+
import androidx.compose.foundation.layout.imePadding
37
import androidx.compose.runtime.Composable
48
import androidx.compose.runtime.LaunchedEffect
9+
import androidx.compose.ui.Alignment
10+
import androidx.compose.ui.Modifier
11+
import androidx.compose.ui.graphics.Color
512
import androidx.compose.ui.res.stringResource
613
import cafe.adriel.voyager.core.screen.ScreenKey
714
import cafe.adriel.voyager.core.screen.uniqueScreenKey
815
import cafe.adriel.voyager.hilt.getViewModel
916
import com.getcode.R
1017
import com.getcode.navigation.core.LocalCodeNavigator
18+
import com.getcode.theme.CodeTheme
19+
import com.getcode.ui.components.CodeCircularProgressIndicator
20+
import com.getcode.ui.components.SheetTitleDefaults
1121
import com.getcode.ui.utils.getActivityScopedViewModel
1222
import com.getcode.ui.utils.getStackScopedViewModel
23+
import com.getcode.ui.utils.toAGColor
1324
import com.getcode.view.login.PhoneConfirm
1425
import com.getcode.view.login.PhoneVerify
1526
import com.getcode.view.login.PhoneVerifyViewModel
@@ -29,10 +40,14 @@ import com.getcode.view.main.getKin.BuyAndSellKin
2940
import com.getcode.view.main.getKin.BuyKinScreen
3041
import com.getcode.view.main.getKin.GetKinSheet
3142
import com.getcode.view.main.getKin.GetKinSheetViewModel
43+
import com.getcode.view.main.tip.ConnectAccountScreen
3244
import com.getcode.view.main.tip.EnterTipScreen
3345
import com.getcode.view.main.tip.IdentityConnectionReason
34-
import com.getcode.view.main.tip.ConnectAccountScreen
3546
import com.getcode.view.main.tip.TipConnectViewModel
47+
import com.kevinnzou.web.LoadingState
48+
import com.kevinnzou.web.WebView
49+
import com.kevinnzou.web.rememberWebViewNavigator
50+
import com.kevinnzou.web.rememberWebViewState
3651
import kotlinx.parcelize.IgnoredOnParcel
3752
import kotlinx.parcelize.Parcelize
3853

@@ -261,7 +276,8 @@ data object DeleteConfirmationScreen : MainGraph, ModalContent {
261276
}
262277

263278
@Parcelize
264-
data class CurrencySelectionModal(val kind: CurrencySelectKind = CurrencySelectKind.Entry) : MainGraph, ModalContent {
279+
data class CurrencySelectionModal(val kind: CurrencySelectKind = CurrencySelectKind.Entry) :
280+
MainGraph, ModalContent {
265281
@IgnoredOnParcel
266282
override val key: ScreenKey = uniqueScreenKey
267283

@@ -309,11 +325,7 @@ data class BuyMoreKinModal(
309325
BuyKinScreen(
310326
viewModel = getViewModel(),
311327
onRedirected = {
312-
if (showClose) {
313-
navigator.hide()
314-
} else {
315-
navigator.popAll()
316-
}
328+
navigator.hide()
317329
}
318330
)
319331
}
@@ -346,6 +358,68 @@ data class BuyMoreKinModal(
346358
}
347359
}
348360

361+
@Parcelize
362+
data class KadoWebScreen(val url: String) : MainGraph, ModalContent {
363+
364+
@IgnoredOnParcel
365+
override val key: ScreenKey = uniqueScreenKey
366+
367+
override val name: String
368+
@Composable get() = stringResource(id = R.string.action_buyMoreKin)
369+
370+
@Composable
371+
override fun Content() {
372+
val state = rememberWebViewState(url = url)
373+
val navigator = LocalCodeNavigator.current
374+
val webNavigator = rememberWebViewNavigator()
375+
ModalContainer(
376+
modalColor = if (isSystemInDarkTheme()) {
377+
Color(0xFF0A121F)
378+
} else {
379+
CodeTheme.colors.background
380+
},
381+
backButtonEnabled = { true },
382+
backButton = { SheetTitleDefaults.CloseButton() },
383+
onBackClicked = { navigator.hide() },
384+
closeButtonEnabled = { true },
385+
closeButton = {
386+
SheetTitleDefaults.RefreshButton()
387+
},
388+
onCloseClicked = { webNavigator.reload() }
389+
) {
390+
val loadingState = state.loadingState
391+
if (loadingState is LoadingState.Loading) {
392+
CodeCircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
393+
}
394+
WebView(
395+
modifier = Modifier
396+
.fillMaxSize()
397+
.imePadding(),
398+
captureBackPresses = false,
399+
navigator = webNavigator,
400+
state = state,
401+
onCreated = { nativeWebView ->
402+
nativeWebView.addJavascriptInterface(BuyKinWebInterface(), "Android")
403+
nativeWebView.clipToOutline = true
404+
nativeWebView.setBackgroundColor(Color.Transparent.toAGColor())
405+
nativeWebView.settings.apply {
406+
javaScriptEnabled = true
407+
domStorageEnabled = true
408+
}
409+
}
410+
)
411+
}
412+
}
413+
414+
class BuyKinWebInterface {
415+
416+
@JavascriptInterface
417+
fun handleMessage(message: String) {
418+
println("KADO BUY KIN MESSAGE :: $message")
419+
}
420+
}
421+
}
422+
349423
@Parcelize
350424
data class EnterTipModal(val isInChat: Boolean = false) : MainGraph, ModalRoot {
351425

app/src/main/java/com/getcode/navigation/screens/Modals.kt

Lines changed: 9 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@ package com.getcode.navigation.screens
22

33
import androidx.compose.foundation.ExperimentalFoundationApi
44
import androidx.compose.foundation.LocalOverscrollConfiguration
5+
import androidx.compose.foundation.background
56
import androidx.compose.foundation.layout.Box
67
import androidx.compose.foundation.layout.BoxScope
78
import androidx.compose.foundation.layout.Column
9+
import androidx.compose.foundation.layout.ColumnScope
810
import androidx.compose.foundation.layout.WindowInsets
911
import androidx.compose.foundation.layout.fillMaxHeight
1012
import androidx.compose.foundation.layout.fillMaxWidth
1113
import androidx.compose.foundation.layout.navigationBars
1214
import androidx.compose.foundation.layout.padding
15+
import androidx.compose.foundation.layout.statusBarsPadding
1316
import androidx.compose.foundation.layout.windowInsetsPadding
1417
import androidx.compose.runtime.Composable
1518
import androidx.compose.runtime.CompositionLocalProvider
@@ -20,6 +23,7 @@ import androidx.compose.runtime.remember
2023
import androidx.compose.runtime.rememberCoroutineScope
2124
import androidx.compose.ui.Alignment
2225
import androidx.compose.ui.Modifier
26+
import androidx.compose.ui.graphics.Color
2327
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
2428
import cafe.adriel.voyager.core.screen.Screen
2529
import com.getcode.LocalBetaFlags
@@ -32,47 +36,16 @@ import com.getcode.ui.components.SheetTitle
3236
import com.getcode.ui.components.SheetTitleDefaults
3337
import com.getcode.ui.components.SheetTitleText
3438
import com.getcode.ui.components.keyboardAsState
39+
import com.getcode.ui.utils.addIf
3540
import com.getcode.ui.utils.getActivityScopedViewModel
3641
import kotlinx.coroutines.delay
3742
import kotlinx.coroutines.launch
3843

39-
40-
@Composable
41-
internal fun NamedScreen.ModalContainer(
42-
closeButton: (Screen?) -> Boolean = { false },
43-
screenContent: @Composable () -> Unit
44-
) {
45-
ModalContainer(
46-
navigator = LocalCodeNavigator.current,
47-
displayLogo = false,
48-
backButtonEnabled = { false },
49-
onLogoClicked = {},
50-
closeButtonEnabled = closeButton,
51-
screenContent = screenContent,
52-
)
53-
}
54-
55-
@Composable
56-
internal fun NamedScreen.ModalContainer(
57-
displayLogo: Boolean = false,
58-
onLogoClicked: () -> Unit = { },
59-
closeButton: (Screen?) -> Boolean = { false },
60-
screenContent: @Composable () -> Unit
61-
) {
62-
ModalContainer(
63-
navigator = LocalCodeNavigator.current,
64-
displayLogo = displayLogo,
65-
backButtonEnabled = { false },
66-
onLogoClicked = onLogoClicked,
67-
closeButtonEnabled = closeButton,
68-
screenContent = screenContent,
69-
)
70-
}
71-
7244
@OptIn(ExperimentalFoundationApi::class)
7345
@Composable
7446
internal fun NamedScreen.ModalContainer(
7547
navigator: CodeNavigator = LocalCodeNavigator.current,
48+
modalColor: Color = CodeTheme.colors.background,
7649
displayLogo: Boolean = false,
7750
titleString: @Composable (NamedScreen?) -> String? = { name },
7851
title: @Composable BoxScope.() -> Unit = { },
@@ -83,12 +56,13 @@ internal fun NamedScreen.ModalContainer(
8356
closeButtonEnabled: (Screen?) -> Boolean = { false },
8457
onCloseClicked: (() -> Unit)? = null,
8558
onLogoClicked: () -> Unit = { },
86-
screenContent: @Composable () -> Unit
59+
screenContent: @Composable BoxScope.() -> Unit
8760
) {
8861
Column(
8962
modifier = Modifier
9063
.fillMaxWidth()
9164
.fillMaxHeight(CodeTheme.dimens.modalHeightRatio)
65+
.background(modalColor)
9266
) {
9367
val lastItem by remember(navigator.lastModalItem) {
9468
derivedStateOf { navigator.lastModalItem }
@@ -117,6 +91,7 @@ internal fun NamedScreen.ModalContainer(
11791
}
11892
SheetTitle(
11993
modifier = Modifier,
94+
color = modalColor,
12095
title = {
12196
titleString(this@ModalContainer)?.let {
12297
SheetTitleText(text = it)

0 commit comments

Comments
 (0)