Skip to content

Commit fe487e6

Browse files
authored
Merge branch 'code/cash' into dependabot/gradle/code/cash/androidx-credentials-1.6.0
2 parents 3b1c79a + 27f7311 commit fe487e6

129 files changed

Lines changed: 3387 additions & 730 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,34 @@
11
package com.flipcash.app.internal.debug
22

33
import com.bugsnag.android.OnErrorCallback
4+
import com.getcode.utils.ErrorUtils
5+
import com.getcode.utils.TraceManager
6+
import io.grpc.StatusException
47

58
internal val FlipcashErrorCallback = OnErrorCallback onError@{ event ->
6-
// Only tag unhandled errors — handled errors go through ErrorUtils.handleError()
7-
if (!event.isUnhandled) return@onError true
89
val error = event.originalError ?: return@onError true
9-
1010
val cause = error.cause ?: error
11-
event.addMetadata("alert", "slack_notify", true)
12-
event.addMetadata("alert", "error_type", cause.javaClass.simpleName)
13-
event.addMetadata("alert", "error_family", cause.javaClass.enclosingClass?.simpleName ?: "Unknown")
11+
12+
// Discard gRPC client-error / validation status codes — these are not bugs
13+
if (cause is StatusException && cause.status.code in ErrorUtils.ignoredGrpcStatusCodes) {
14+
return@onError false
15+
}
16+
17+
// Discard handled gRPC INTERNAL — server-side errors, not actionable from the client
18+
if (!event.isUnhandled && cause is StatusException && cause.status.code == io.grpc.Status.Code.INTERNAL) {
19+
return@onError false
20+
}
21+
22+
if (!event.isUnhandled) return@onError true
23+
24+
// Attach recent logs
25+
val logFile = TraceManager.getLogFile(includeHeader = false)
26+
if (logFile != null && logFile.exists()) {
27+
// Bugsnag metadata has a size limit (~1MB per event).
28+
// Attach the last ~64KB of log content as a metadata tab.
29+
val tail = logFile.readText().takeLast(64_000)
30+
event.addMetadata("App Logs", "app_log", tail)
31+
}
32+
1433
true
1534
}

apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/startup/TraceInitializer.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ class TraceInitializer: Initializer<Unit> {
2222
Timber.plant(FlipcashDebugTree)
2323
} else {
2424
CoroutineScope(Dispatchers.IO).launch {
25-
val config = Configuration.load(context)
26-
config.addOnError(FlipcashErrorCallback)
25+
val config = Configuration.load(context).apply {
26+
addOnError(FlipcashErrorCallback)
27+
}
2728
Bugsnag.start(context, config)
2829

2930
ErrorUtils.addReporter(BugsnagErrorReporter())

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

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ import com.getcode.ui.components.OnLifecycleEvent
6363
import com.getcode.ui.components.bars.rememberBarManager
6464
import com.getcode.ui.core.RestrictionType
6565
import com.flipcash.app.core.extensions.navigateTo
66-
import com.getcode.navigation.animation.LocalSharedTransitionScope
66+
import com.getcode.animation.LocalSharedTransitionScope
6767
import com.getcode.navigation.scrim.LocalScrimController
6868
import com.getcode.navigation.scrim.ScrimController
6969
import com.getcode.navigation.scrim.ScrimOverlay
@@ -159,13 +159,16 @@ internal fun App(
159159
),
160160
rememberNavBlockingOverlayEntryDecorator(),
161161
),
162-
sceneStrategy = ModalBottomSheetSceneStrategy<NavKey>(
163-
codeNavigator.resultStore
164-
) {
165-
codeNavigator.backStack.getOrNull(
166-
codeNavigator.backStack.lastIndex - 1
167-
)
168-
} then SinglePaneSceneStrategy(),
162+
sceneStrategies = listOf(
163+
ModalBottomSheetSceneStrategy(
164+
codeNavigator.resultStore
165+
) {
166+
codeNavigator.backStack.getOrNull(
167+
codeNavigator.backStack.lastIndex - 1
168+
)
169+
},
170+
SinglePaneSceneStrategy(),
171+
),
169172
transitionSpec = {
170173
val shouldCrossfade =
171174
initialState.key == AppRoute.Loading.toString() ||

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ fun appEntryProvider(
102102

103103
// Tokens
104104
annotatedEntry<AppRoute.Token.Info> { key ->
105-
TokenInfoScreen(key.mint, key.isFundingShortfall, key.fromDeeplink)
105+
TokenInfoScreen(key.mint, key.shortfall, key.fromDeeplink)
106106
}
107107
annotatedEntry<AppRoute.Token.Transactions> { key -> TransactionHistoryScreen(key.mint) }
108108
annotatedEntry<AppRoute.Token.Swap> { key ->
@@ -195,9 +195,12 @@ private fun SheetContent(
195195
decorators = listOf(
196196
rememberNavMessagingEntryDecorator(navigator.backStack, barManager)
197197
),
198-
sceneStrategy = ModalBottomSheetSceneStrategy<NavKey>(navigator.resultStore) {
199-
navigator.backStack.getOrNull(navigator.backStack.lastIndex - 1)
200-
} then SinglePaneSceneStrategy(),
198+
sceneStrategies = listOf(
199+
ModalBottomSheetSceneStrategy(navigator.resultStore) {
200+
navigator.backStack.getOrNull(navigator.backStack.lastIndex - 1)
201+
},
202+
SinglePaneSceneStrategy(),
203+
),
201204
transitionSpec = {
202205
if (targetState is OverlayScene<*> || initialState is OverlayScene<*>) {
203206
EnterTransition.None togetherWith ExitTransition.None

apps/flipcash/app/src/screenshotTest/kotlin/com/flipcash/app/login/LoginContentScreenshotTest.kt

Lines changed: 0 additions & 15 deletions
This file was deleted.

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import com.getcode.navigation.NonDismissableRoute
1717
import com.getcode.navigation.NonDraggableRoute
1818
import com.getcode.navigation.flow.FlowRouteWithResult
1919
import com.getcode.opencode.internal.solana.model.SwapId
20+
import com.getcode.opencode.model.financial.Fiat
2021
import com.getcode.solana.keys.Mint
2122
import com.getcode.ui.core.RestrictionType
2223
import kotlinx.parcelize.Parcelize
@@ -119,7 +120,7 @@ sealed interface AppRoute : NavKey, Parcelable {
119120
@Serializable
120121
data class Info(
121122
val mint: Mint,
122-
val isFundingShortfall: Boolean = false,
123+
val shortfall: Fiat? = null,
123124
val fromDeeplink: Boolean = false
124125
) : Token
125126

@@ -128,7 +129,7 @@ sealed interface AppRoute : NavKey, Parcelable {
128129
@Serializable
129130
data class Swap(
130131
val purpose: SwapPurpose,
131-
val isFundingShortfall: Boolean = false,
132+
val shortfall: Fiat? = null,
132133
) : Token, FlowRouteWithResult<SwapResult> {
133134
override val initialStack: List<NavKey>
134135
get() = listOf(SwapStep.Entry(purpose))

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/onramp/deeplinks/WalletDeeplinkConnectionResult.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ sealed class OnRampDeeplinkOrigin: Parcelable {
5050
@Serializable @Parcelize
5151
data object Reserves: OnRampDeeplinkOrigin()
5252

53+
@Serializable @Parcelize
54+
data object CurrencyCreator: OnRampDeeplinkOrigin()
55+
5356

5457
fun forUri(): String {
5558
return when(this) {
@@ -58,6 +61,7 @@ sealed class OnRampDeeplinkOrigin: Parcelable {
5861
Wallet -> "wallet"
5962
is TokenInfo -> "token-${mint.base58().base64UrlSafe}"
6063
Reserves -> "reserves"
64+
CurrencyCreator -> "currency-creator"
6165
}.lowercase()
6266
}
6367

@@ -70,6 +74,7 @@ sealed class OnRampDeeplinkOrigin: Parcelable {
7074
is AppRoute.Token.Info -> {
7175
if (route.mint == Mint.usdf) Reserves else TokenInfo(route.mint)
7276
}
77+
is AppRoute.Token.CurrencyCreator -> CurrencyCreator
7378

7479
else -> null
7580
}
@@ -87,6 +92,7 @@ sealed class OnRampDeeplinkOrigin: Parcelable {
8792
}
8893
value == "wallet" -> Wallet
8994
value == "reserves" -> Reserves
95+
value == "currency-creator" -> CurrencyCreator
9096
value?.startsWith("token-") == true -> {
9197
val mintString = value.removePrefix("token-").decodeBase64().base58
9298
val mint = runCatching {

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/ui/CurrencyAppreciationLabel.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.flipcash.core.R
1515
import com.getcode.opencode.model.financial.Fiat
1616
import com.getcode.theme.CodeTheme
1717
import com.getcode.theme.extraSmall
18+
import com.getcode.ui.components.text.AnimatedNumberText
1819

1920
@Composable
2021
fun CurrencyAppreciationLabel(
@@ -34,7 +35,7 @@ fun CurrencyAppreciationLabel(
3435
verticalAlignment = Alignment.CenterVertically,
3536
horizontalArrangement = Arrangement.spacedBy(CodeTheme.dimens.grid.x1),
3637
) {
37-
Text(
38+
AnimatedNumberText(
3839
modifier = Modifier
3940
.background(
4041
color = changeColor.copy(0.20f),
@@ -44,7 +45,7 @@ fun CurrencyAppreciationLabel(
4445
vertical = 2.dp,
4546
horizontal = CodeTheme.dimens.grid.x1
4647
),
47-
text = appreciation.formatted(
48+
value = appreciation.formatted(
4849
extraPrefix = when {
4950
isZero -> null
5051
hasAppreciation -> "+"

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/ui/TokenBalanceRow.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import com.getcode.opencode.model.financial.Token
2929
import com.getcode.opencode.model.financial.TokenWithBalance
3030
import com.getcode.opencode.model.financial.TokenWithLocalizedBalance
3131
import com.getcode.theme.CodeTheme
32+
import com.getcode.ui.components.text.AnimatedNumberText
3233
import com.getcode.ui.core.addIf
3334

3435
data class TokenBalanceRowSizing(
@@ -187,8 +188,8 @@ fun TokenBalanceRow(
187188
}
188189
}
189190

190-
Text(
191-
text = formattedBalance(balance),
191+
AnimatedNumberText(
192+
value = formattedBalance(balance),
192193
style = sizing.balanceTextStyle,
193194
color = CodeTheme.colors.textMain,
194195
)

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/ui/transitions/SharedTransitions.kt

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,16 @@ import androidx.compose.animation.core.spring
1919
import androidx.compose.animation.fadeIn
2020
import androidx.compose.animation.fadeOut
2121
import androidx.compose.runtime.Composable
22-
import androidx.compose.runtime.compositionLocalOf
23-
import androidx.compose.runtime.staticCompositionLocalOf
2422
import androidx.compose.ui.Alignment.Companion.Center
2523
import androidx.compose.ui.Modifier
2624
import androidx.compose.ui.geometry.Rect
2725
import androidx.compose.ui.graphics.Path
2826
import androidx.compose.ui.layout.ContentScale
27+
import androidx.compose.ui.platform.LocalInspectionMode
2928
import androidx.compose.ui.unit.Density
3029
import androidx.compose.ui.unit.LayoutDirection
3130
import androidx.navigation3.ui.LocalNavAnimatedContentScope
32-
import com.getcode.navigation.animation.LocalSharedTransitionScope
31+
import com.getcode.animation.LocalSharedTransitionScope
3332

3433
sealed class SharedTransition(
3534
val key: String,
@@ -84,7 +83,7 @@ val CircleOverlayClip: OverlayClip =
8483
@Composable
8584
fun Modifier.sharedBoundsTransition(
8685
key: String,
87-
animatedVisibilityScope: AnimatedVisibilityScope = LocalNavAnimatedContentScope.current,
86+
animatedVisibilityScope: AnimatedVisibilityScope? = null,
8887
sharedTransitionScope: SharedTransitionScope = LocalSharedTransitionScope.current,
8988
enter: EnterTransition = fadeIn(),
9089
exit: ExitTransition = fadeOut(),
@@ -95,12 +94,18 @@ fun Modifier.sharedBoundsTransition(
9594
placeholderSize: PlaceholderSize = AnimatedSize,
9695
clipInOverlayDuringTransition: OverlayClip = ParentClip,
9796
): Modifier {
97+
if(LocalInspectionMode.current) {
98+
return this
99+
}
100+
101+
val animatedScope = animatedVisibilityScope ?: LocalNavAnimatedContentScope.current
102+
98103
return with(sharedTransitionScope) {
99104
this@sharedBoundsTransition.sharedBounds(
100105
sharedContentState = rememberSharedContentState(key = key),
101106
enter = enter,
102107
exit = exit,
103-
animatedVisibilityScope = animatedVisibilityScope,
108+
animatedVisibilityScope = animatedScope,
104109
boundsTransform = boundsTransform,
105110
renderInOverlayDuringTransition = renderInOverlayDuringTransition,
106111
resizeMode = resizeMode,
@@ -114,7 +119,7 @@ fun Modifier.sharedBoundsTransition(
114119
@Composable
115120
fun Modifier.sharedBoundsTransition(
116121
transition: SharedTransition,
117-
animatedVisibilityScope: AnimatedVisibilityScope = LocalNavAnimatedContentScope.current,
122+
animatedVisibilityScope: AnimatedVisibilityScope? = null,
118123
sharedTransitionScope: SharedTransitionScope = LocalSharedTransitionScope.current,
119124
zIndexInOverlay: Float = 0f,
120125
renderInOverlayDuringTransition: Boolean = true,
@@ -139,17 +144,23 @@ fun Modifier.sharedBoundsTransition(
139144
@Composable
140145
fun Modifier.sharedElementTransition(
141146
key: String,
142-
animatedVisibilityScope: AnimatedVisibilityScope = LocalNavAnimatedContentScope.current,
147+
animatedVisibilityScope: AnimatedVisibilityScope? = null,
143148
sharedTransitionScope: SharedTransitionScope = LocalSharedTransitionScope.current,
144149
boundsTransform: BoundsTransform = DefaultTransform,
145150
placeholderSize: PlaceholderSize = AnimatedSize,
146151
zIndexInOverlay: Float = 0f,
147152
renderInOverlayDuringTransition: Boolean = true,
148153
): Modifier {
154+
if(LocalInspectionMode.current) {
155+
return this
156+
}
157+
158+
val animatedScope = animatedVisibilityScope ?: LocalNavAnimatedContentScope.current
159+
149160
return with(sharedTransitionScope) {
150161
this@sharedElementTransition.sharedElement(
151162
sharedContentState = rememberSharedContentState(key = key),
152-
animatedVisibilityScope = animatedVisibilityScope,
163+
animatedVisibilityScope = animatedScope,
153164
boundsTransform = boundsTransform,
154165
placeholderSize = placeholderSize,
155166
zIndexInOverlay = zIndexInOverlay,
@@ -161,7 +172,7 @@ fun Modifier.sharedElementTransition(
161172
@Composable
162173
fun Modifier.sharedElementTransition(
163174
transition: SharedTransition,
164-
animatedVisibilityScope: AnimatedVisibilityScope = LocalNavAnimatedContentScope.current,
175+
animatedVisibilityScope: AnimatedVisibilityScope? = null,
165176
boundsTransform: BoundsTransform? = null,
166177
sharedTransitionScope: SharedTransitionScope = LocalSharedTransitionScope.current,
167178
placeholderSize: PlaceholderSize = AnimatedSize,
@@ -190,6 +201,10 @@ fun Modifier.sharedElementTransitionWithCallerManagedVisibility(
190201
renderInOverlayDuringTransition: Boolean = true,
191202
clipInOverlayDuringTransition: OverlayClip = ParentClip,
192203
): Modifier {
204+
if(LocalInspectionMode.current) {
205+
return this
206+
}
207+
193208
return with(sharedTransitionScope) {
194209
this@sharedElementTransitionWithCallerManagedVisibility.sharedElementWithCallerManagedVisibility(
195210
sharedContentState = rememberSharedContentState(key = key),

0 commit comments

Comments
 (0)