Skip to content

Commit 0a2920b

Browse files
authored
Merge branch 'code/cash' into dependabot/gradle/code/cash/androidx.compose.ui-ui-tooling-android-1.10.5
2 parents 5179dc5 + 6f3cb6b commit 0a2920b

30 files changed

Lines changed: 749 additions & 101 deletions

File tree

apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/ui/navigation/AppScreenContent.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ internal fun AppScreenContent(content: @Composable () -> Unit) {
9494
}
9595

9696
register<AppRoute.Token.TxProcessing> {
97-
TokenTxProcessingScreen(it.swapId)
97+
TokenTxProcessingScreen(it.swapId, it.awaitExternalWallet)
9898
}
9999

100100
register<AppRoute.Token.SellReceipt> {

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/AppRoute.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ sealed interface AppRoute : ScreenProvider, Parcelable {
6868
data class Info(val mint: Mint, val forNeededFunds: Boolean = false, val fromDeeplink: Boolean = false): Token
6969
data class Transactions(val mint: Mint): Token
7070
data class SwapTransact(val purpose: TokenSwapPurpose, val forNeededFunds: Boolean = false): Token
71-
data class TxProcessing(val swapId: SwapId): Token
71+
data class TxProcessing(val swapId: SwapId, val awaitExternalWallet: Boolean = false): Token
7272
data object SellReceipt: Token
7373
}
7474

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="18dp"
3+
android:height="18dp"
4+
android:viewportWidth="18"
5+
android:viewportHeight="18">
6+
<group>
7+
<clip-path
8+
android:pathData="M0,0h17.244v17.632h-17.244z"/>
9+
<path
10+
android:pathData="M14.648,3.818C13.535,3.297 12.357,2.927 11.146,2.718C10.995,2.99 10.819,3.357 10.697,3.649C9.391,3.453 8.097,3.453 6.815,3.649C6.694,3.357 6.514,2.99 6.361,2.718C5.149,2.927 3.97,3.298 2.856,3.821C0.64,7.17 0.039,10.437 0.339,13.657C1.809,14.755 3.234,15.422 4.635,15.858C4.983,15.379 5.291,14.873 5.555,14.343C5.052,14.151 4.567,13.915 4.106,13.638C4.227,13.548 4.346,13.454 4.461,13.357C7.255,14.663 10.29,14.663 13.05,13.357C13.166,13.453 13.284,13.547 13.405,13.638C12.943,13.916 12.458,14.153 11.954,14.344C12.219,14.876 12.526,15.383 12.874,15.859C14.276,15.423 15.702,14.756 17.172,13.657C17.524,9.924 16.57,6.688 14.648,3.818ZM5.935,11.677C5.097,11.677 4.409,10.894 4.409,9.94C4.409,8.987 5.082,8.203 5.935,8.203C6.789,8.203 7.476,8.986 7.462,9.94C7.463,10.894 6.789,11.677 5.935,11.677ZM11.576,11.677C10.737,11.677 10.05,10.894 10.05,9.94C10.05,8.987 10.722,8.203 11.576,8.203C12.429,8.203 13.117,8.986 13.102,9.94C13.102,10.894 12.429,11.677 11.576,11.677Z"
11+
android:strokeAlpha="0.4"
12+
android:fillColor="#ffffff"
13+
android:fillAlpha="0.4"/>
14+
</group>
15+
</vector>

apps/flipcash/core/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,8 @@
417417

418418
<string name="label_social_website">Website</string>
419419
<string name="label_social_x">\@%1$s</string>
420+
<string name="label_social_tg">Telegram</string>
421+
<string name="label_social_discord">Discord</string>
420422

421423
<string name="action_retry">Retry</string>
422424
<string name="error_unableToLoadChartData">Unable To Load</string>

apps/flipcash/features/tokens/src/main/kotlin/com/flipcash/app/tokens/TokenTxProcessingScreen.kt

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,15 @@ import android.os.Parcelable
44
import androidx.activity.compose.BackHandler
55
import androidx.compose.runtime.Composable
66
import androidx.compose.runtime.LaunchedEffect
7+
import androidx.compose.runtime.getValue
8+
import androidx.compose.runtime.mutableStateOf
9+
import androidx.compose.runtime.remember
10+
import androidx.compose.runtime.setValue
11+
import androidx.compose.runtime.snapshotFlow
712
import cafe.adriel.voyager.core.screen.ScreenKey
813
import cafe.adriel.voyager.core.screen.uniqueScreenKey
14+
import com.flipcash.app.onramp.LocalExternalWalletState
15+
import com.flipcash.app.onramp.internal.ExternalWalletState
916
import com.flipcash.app.tokens.internal.TokenTxProcessingScreen
1017
import com.flipcash.app.tokens.ui.BuySellSwapTokenViewModel
1118
import com.flipcash.app.tokens.ui.BuySellSwapTokenViewModel.Event
@@ -14,14 +21,19 @@ import com.getcode.navigation.extensions.getStackScopedViewModel
1421
import com.getcode.navigation.screens.ModalScreen
1522
import com.getcode.opencode.internal.solana.model.SwapId
1623
import com.getcode.ui.utils.DisableSheetGestures
24+
import com.getcode.view.LoadingSuccessState
1725
import kotlinx.coroutines.flow.filterIsInstance
26+
import kotlinx.coroutines.flow.first
1827
import kotlinx.coroutines.flow.launchIn
1928
import kotlinx.coroutines.flow.onEach
2029
import kotlinx.parcelize.IgnoredOnParcel
2130
import kotlinx.parcelize.Parcelize
2231

2332
@Parcelize
24-
class TokenTxProcessingScreen(val swapId: SwapId) : ModalScreen, Parcelable {
33+
class TokenTxProcessingScreen(
34+
val swapId: SwapId,
35+
val awaitExternalWallet: Boolean = false,
36+
) : ModalScreen, Parcelable {
2537

2638
@IgnoredOnParcel
2739
override val key: ScreenKey = uniqueScreenKey
@@ -33,10 +45,40 @@ class TokenTxProcessingScreen(val swapId: SwapId) : ModalScreen, Parcelable {
3345
override fun ModalContent() {
3446
val navigator = LocalCodeNavigator.current
3547
val viewModel = getStackScopedViewModel<BuySellSwapTokenViewModel>(BuySellFlow.key)
36-
TokenTxProcessingScreen(viewModel)
3748

38-
LaunchedEffect(viewModel, swapId) {
39-
viewModel.dispatchEvent(Event.OnSwapIdChanged(swapId))
49+
// When awaiting external wallet, show a local loading indicator that doesn't
50+
// affect the ViewModel's processingProgress timer. Once OnSwapIdChanged is
51+
// dispatched the ViewModel takes over with its own loading state and fresh timer.
52+
var awaitingWallet by remember { mutableStateOf(awaitExternalWallet) }
53+
54+
TokenTxProcessingScreen(
55+
viewModel = viewModel,
56+
processingProgressOverride = if (awaitingWallet) LoadingSuccessState(loading = true) else null,
57+
)
58+
59+
if (awaitExternalWallet) {
60+
val externalWalletState = LocalExternalWalletState.current
61+
LaunchedEffect(viewModel, swapId) {
62+
// Wait for the transaction to be submitted before starting swap polling
63+
snapshotFlow { externalWalletState.deeplinkState }
64+
.first { it == ExternalWalletState.TRANSACTED }
65+
66+
externalWalletState.reset()
67+
viewModel.dispatchEvent(Event.OnSwapIdChanged(swapId))
68+
69+
// Wait for the ViewModel's own loading state before dropping override.
70+
// Both are LoadingSuccessState(loading=true) — data class equality means
71+
// the indicator's remember(processingState) won't reset, so the timer
72+
// and progress continue seamlessly with no jump.
73+
snapshotFlow { viewModel.stateFlow.value.processingProgress }
74+
.first { it.loading }
75+
76+
awaitingWallet = false
77+
}
78+
} else {
79+
LaunchedEffect(viewModel, swapId) {
80+
viewModel.dispatchEvent(Event.OnSwapIdChanged(swapId))
81+
}
4082
}
4183

4284
LaunchedEffect(viewModel) {
@@ -62,4 +104,4 @@ class TokenTxProcessingScreen(val swapId: SwapId) : ModalScreen, Parcelable {
62104
BackHandler { /* intercept */ }
63105
DisableSheetGestures()
64106
}
65-
}
107+
}

apps/flipcash/features/tokens/src/main/kotlin/com/flipcash/app/tokens/internal/TokenTxProcessingScreen.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,16 @@ import com.getcode.view.LoadingSuccessState
4545

4646
@Composable
4747
internal fun TokenTxProcessingScreen(
48-
viewModel: BuySellSwapTokenViewModel
48+
viewModel: BuySellSwapTokenViewModel,
49+
processingProgressOverride: LoadingSuccessState? = null,
4950
) {
5051
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
51-
TokenTxProcessingScreen(state = state, dispatch = viewModel::dispatchEvent)
52+
val effectiveState = if (processingProgressOverride != null) {
53+
state.copy(processingProgress = processingProgressOverride)
54+
} else {
55+
state
56+
}
57+
TokenTxProcessingScreen(state = effectiveState, dispatch = viewModel::dispatchEvent)
5258
}
5359

5460
@Composable

apps/flipcash/features/tokens/src/main/kotlin/com/flipcash/app/tokens/internal/components/info/SocialChip.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ internal fun SocialChip(
4747
when (socialLink) {
4848
is SocialLink.Website -> R.drawable.ic_social_web
4949
is SocialLink.X -> R.drawable.ic_social_x
50+
is SocialLink.Discord -> R.drawable.ic_social_discord
51+
is SocialLink.Telegram -> R.drawable.ic_social_tg
5052
}
5153
),
5254
contentDescription = null,
@@ -57,6 +59,8 @@ internal fun SocialChip(
5759
text = when (socialLink) {
5860
is SocialLink.Website -> stringResource(R.string.label_social_website)
5961
is SocialLink.X -> stringResource(R.string.label_social_x, socialLink.username)
62+
is SocialLink.Discord -> stringResource(R.string.label_social_discord)
63+
is SocialLink.Telegram -> stringResource(R.string.label_social_tg)
6064
},
6165
color = CodeTheme.colors.textMain,
6266
style = CodeTheme.typography.textMedium

apps/flipcash/features/tokens/src/main/kotlin/com/flipcash/app/tokens/internal/components/marketcap/MarketCapChart.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,23 @@ internal fun MarketCapChart(
8282
mutableStateOf<List<MarketCapPoint>>(emptyList())
8383
}
8484

85-
LaunchedEffect(data) {
85+
// Track the period that corresponds to the current historicalData so we
86+
// don't collapse stale data with a new period (which produces an
87+
// intermediate curve that causes Vico to animate from the bottom).
88+
var dataPeriod by remember { mutableStateOf(selectedPeriod) }
89+
90+
LaunchedEffect(data, selectedPeriod) {
8691
if (data.isNotEmpty()) {
8792
historicalData = data
93+
dataPeriod = selectedPeriod
8894
}
8995
}
9096

9197
val modelProducer = remember { CartesianChartModelProducer() }
9298

93-
val windowedData by remember(historicalData, selectedPeriod) {
99+
val windowedData by remember(historicalData, dataPeriod) {
94100
derivedStateOf {
95-
historicalData.collapse(selectedPeriod, currentValue = currentValue)
101+
historicalData.collapse(dataPeriod, currentValue = currentValue)
96102
}
97103
}
98104

apps/flipcash/shared/onramp/deeplinks/src/main/kotlin/com/flipcash/app/onramp/ExternalWalletOnRampHandler.kt

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import android.annotation.SuppressLint
55
import android.content.Context
66
import androidx.compose.runtime.Composable
77
import androidx.compose.runtime.LaunchedEffect
8+
import androidx.compose.runtime.getValue
9+
import androidx.compose.runtime.mutableStateOf
10+
import androidx.compose.runtime.remember
811
import androidx.compose.runtime.rememberCoroutineScope
12+
import androidx.compose.runtime.setValue
913
import androidx.compose.ui.platform.LocalContext
1014
import androidx.compose.ui.platform.LocalUriHandler
1115
import androidx.lifecycle.Lifecycle
@@ -75,6 +79,9 @@ fun ExternalWalletOnRampHandler(
7579
}
7680
} ?: run { navigator.popAll() }
7781
}
82+
var preNavigatedToEntry by remember { mutableStateOf(false) }
83+
var preNavigatedToProcessing by remember { mutableStateOf(false) }
84+
7885
val uriHandler = LocalUriHandler.current
7986
val context = LocalContext.current
8087

@@ -167,6 +174,19 @@ fun ExternalWalletOnRampHandler(
167174
type = TraceType.Process
168175
)
169176
if (uri?.canNativelyHandle(context) == true) {
177+
val origin = state.origin
178+
if (origin is AppRoute.Token.Info) {
179+
preNavigatedToEntry = true
180+
navigator.push(
181+
ScreenRegistry.get(
182+
AppRoute.Token.SwapTransact(
183+
TokenSwapPurpose.FundWithWallet(origin.mint),
184+
forNeededFunds = origin.forNeededFunds
185+
)
186+
)
187+
)
188+
}
189+
170190
analytics.connectWallet(state.provider!!)
171191
uriHandler.openUri(uri.toString())
172192
state.deeplinkState = ExternalWalletState.CONNECTING
@@ -196,19 +216,24 @@ fun ExternalWalletOnRampHandler(
196216
message = "wallet connected",
197217
type = TraceType.Process
198218
)
199-
when (val origin = state.origin) {
200-
is AppRoute.Token.Info -> {
201-
navigator.push(
202-
ScreenRegistry.get(
203-
AppRoute.Token.SwapTransact(
204-
TokenSwapPurpose.FundWithWallet(origin.mint),
205-
forNeededFunds = origin.forNeededFunds
219+
if (preNavigatedToEntry) {
220+
// Already pushed SwapTransact at STARTED
221+
preNavigatedToEntry = false
222+
} else {
223+
when (val origin = state.origin) {
224+
is AppRoute.Token.Info -> {
225+
navigator.push(
226+
ScreenRegistry.get(
227+
AppRoute.Token.SwapTransact(
228+
TokenSwapPurpose.FundWithWallet(origin.mint),
229+
forNeededFunds = origin.forNeededFunds
230+
)
206231
)
207232
)
208-
)
209-
}
210-
else -> {
211-
navigator.push(ScreenRegistry.get(AppRoute.OnRamp.AmountEntry))
233+
}
234+
else -> {
235+
navigator.push(ScreenRegistry.get(AppRoute.OnRamp.AmountEntry))
236+
}
212237
}
213238
}
214239
}
@@ -226,6 +251,17 @@ fun ExternalWalletOnRampHandler(
226251
message = "wallet transact uri: $uri",
227252
type = TraceType.Process
228253
)
254+
255+
val swapId = state.swapId
256+
if (state.origin is AppRoute.Token.Info && swapId != null) {
257+
preNavigatedToProcessing = true
258+
navigator.push(
259+
ScreenRegistry.get(
260+
AppRoute.Token.TxProcessing(swapId, awaitExternalWallet = true)
261+
)
262+
)
263+
}
264+
229265
analytics.amountSelectedForWalletTransfer(state.provider!!, state.amount!!.underlyingTokenAmount)
230266
uriHandler.openUri(uri.toString())
231267
}
@@ -255,6 +291,12 @@ fun ExternalWalletOnRampHandler(
255291
)
256292
analytics.transactionSubmittedToWallet(state.provider!!)
257293

294+
if (preNavigatedToProcessing) {
295+
// TxProcessingScreen observes TRANSACTED, calls reset() and dispatches OnSwapIdChanged
296+
preNavigatedToProcessing = false
297+
return@LaunchedEffect
298+
}
299+
258300
val swapId = state.swapId
259301
state.reset()
260302

apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/converters/TokenTypeConverters.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ sealed interface SocialLinkSerialized {
5151
@Serializable
5252
@SerialName("x")
5353
data class X(val username: String) : SocialLinkSerialized
54+
55+
@Serializable
56+
@SerialName("tg")
57+
data class Telegram(val username: String) : SocialLinkSerialized
58+
59+
@Serializable
60+
@SerialName("discord")
61+
data class Discord(val inviteCode: String) : SocialLinkSerialized
5462
}
5563

5664
@Serializable

0 commit comments

Comments
 (0)