Skip to content

Commit c7645ef

Browse files
committed
chore(flipcash/scanner): remove visibility tracking from airdrop requests; drive via state
Signed-off-by: Brandon McAnsh <[email protected]>
1 parent cf56853 commit c7645ef

File tree

4 files changed

+39
-47
lines changed

4 files changed

+39
-47
lines changed

apps/flipcash/features/scanner/src/main/kotlin/com/flipcash/app/scanner/internal/Scanner.kt

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ internal fun Scanner(deepLink: DeeplinkType?) {
4646
var isPaused by remember { mutableStateOf(false) }
4747

4848
var previewing by remember {
49-
mutableStateOf(false)
49+
mutableStateOf<Boolean?>(null)
5050
}
5151

5252
var deepLinkSaved by remember {
@@ -60,33 +60,19 @@ internal fun Scanner(deepLink: DeeplinkType?) {
6060
val focusManager = LocalFocusManager.current
6161
val biometricsState = LocalBiometricsState.current
6262

63-
var visibilityInfo by remember { mutableStateOf<VisibilityInfo?>(null) }
64-
65-
LaunchedEffect(
66-
biometricsState,
67-
visibilityInfo,
68-
) {
69-
if (!biometricsState.passed) return@LaunchedEffect
70-
val viz = visibilityInfo ?: return@LaunchedEffect
71-
if (viz.isVisible) {
72-
session.onCameraVisible()
73-
}
74-
}
75-
76-
LaunchedEffect(previewing) {
77-
session.onCameraScanning(previewing)
78-
}
79-
8063
LaunchedEffect(
8164
biometricsState,
8265
previewing,
8366
deepLinkSaved
8467
) {
85-
if (previewing) {
68+
if (previewing == true) {
8669
focusManager.clearFocus()
8770
}
8871

8972
if (!biometricsState.passed) return@LaunchedEffect
73+
if (previewing != null) {
74+
session.onCameraScanning(previewing == true)
75+
}
9076
val deeplink = deepLinkSaved ?: return@LaunchedEffect
9177

9278
when (deeplink) {
@@ -101,20 +87,16 @@ internal fun Scanner(deepLink: DeeplinkType?) {
10187
}
10288

10389
BillContainer(
104-
modifier = Modifier.fillMaxSize().trackVisibility(
105-
thresholdPercentage = 1f,
106-
onVisibilityChanged = { visibilityInfo = it }
107-
),
10890
isPaused = isPaused,
109-
isCameraReady = previewing,
91+
isCameraReady = previewing == true,
11092
isCameraStarted = cameraStarted,
11193
onStartCamera = { cameraStarted = true },
11294
onAction = {
11395
navigator.show(ScreenRegistry.get(it.screen))
11496
},
11597
scannerView = {
11698
CodeScanner(
117-
scanningEnabled = previewing,
99+
scanningEnabled = previewing == true,
118100
cameraGesturesEnabled = true,
119101
invertedDragZoomEnabled = true,
120102
onPreviewStateChanged = { previewing = it },

apps/flipcash/shared/session/src/main/kotlin/com/flipcash/app/session/SessionController.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ interface SessionController {
2323
val billState: StateFlow<BillState>
2424
fun onAppInForeground()
2525
fun onAppInBackground()
26-
fun onCameraVisible()
2726
fun onCameraScanning(scanning: Boolean)
2827
fun onCameraPermissionResult(result: PermissionResult)
2928
fun showBill(bill: Bill, vibrate: Boolean = false)
@@ -39,7 +38,7 @@ data class SessionState(
3938
val logScanTimes: Boolean = false,
4039
val showNetworkOffline: Boolean = false,
4140
val autoStartCamera: Boolean? = true,
42-
val isCameraScanEnabled: Boolean = true,
41+
val isCameraUp: Boolean? = null,
4342
val billResult: BillDeterminationResult = BillDeterminationResult.None,
4443
val restrictionType: RestrictionType? = null,
4544
val isRemoteSendLoading: Boolean = false,

apps/flipcash/shared/session/src/main/kotlin/com/flipcash/app/session/internal/RealSessionController.kt

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import com.flipcash.services.analytics.AnalyticsEvent
2929
import com.flipcash.services.analytics.FlipcashAnalyticsService
3030
import com.flipcash.services.billing.BillingClient
3131
import com.flipcash.services.controllers.AccountController
32+
import com.flipcash.services.user.AuthState
3233
import com.flipcash.services.user.UserManager
3334
import com.getcode.manager.BottomBarAction
3435
import com.getcode.manager.BottomBarManager
@@ -57,16 +58,21 @@ import com.kik.kikx.models.ScannableKikCode
5758
import kotlinx.coroutines.CoroutineScope
5859
import kotlinx.coroutines.Dispatchers
5960
import kotlinx.coroutines.SupervisorJob
61+
import kotlinx.coroutines.channels.BufferOverflow
6062
import kotlinx.coroutines.delay
6163
import kotlinx.coroutines.flow.MutableStateFlow
6264
import kotlinx.coroutines.flow.StateFlow
6365
import kotlinx.coroutines.flow.asStateFlow
66+
import kotlinx.coroutines.flow.buffer
6467
import kotlinx.coroutines.flow.distinctUntilChanged
6568
import kotlinx.coroutines.flow.filter
69+
import kotlinx.coroutines.flow.filterIsInstance
6670
import kotlinx.coroutines.flow.launchIn
6771
import kotlinx.coroutines.flow.map
6872
import kotlinx.coroutines.flow.mapNotNull
6973
import kotlinx.coroutines.flow.onEach
74+
import kotlinx.coroutines.flow.scan
75+
import kotlinx.coroutines.flow.take
7076
import kotlinx.coroutines.flow.update
7177
import kotlinx.coroutines.launch
7278
import kotlinx.coroutines.suspendCancellableCoroutine
@@ -108,9 +114,15 @@ class RealSessionController @Inject constructor(
108114

109115
private val scannedRendezvous = mutableListOf<String>()
110116

111-
private var welcomeBonus: LocalFiat? = null
112-
113117
init {
118+
// reset state on logouts
119+
userManager.state
120+
.map { it.authState }
121+
.filterIsInstance<AuthState.LoggedOut>()
122+
.onEach {
123+
_state.update { SessionState() }
124+
}.launchIn(scope)
125+
114126
userManager.state
115127
.map { it.isTimelockUnlocked }
116128
.onEach { _state.update { it.copy(restrictionType = RestrictionType.TIMELOCK_UNLOCKED) } }
@@ -138,6 +150,18 @@ class RealSessionController @Inject constructor(
138150
featureFlagController.observe(FeatureFlag.VibrateOnScan)
139151
.onEach { enabled -> _state.update { it.copy(vibrateOnScan = enabled) } }
140152
.launchIn(scope)
153+
154+
state
155+
.map { it.isCameraUp }
156+
.distinctUntilChanged() // Emit only when value changes
157+
.scan(Pair(null as Boolean?, null as Boolean?)) { previousPair, current ->
158+
Pair(previousPair.second, current)
159+
}
160+
.mapNotNull { (previous, current) ->
161+
if (previous == null && current != null) current else null
162+
}
163+
.onEach { checkForAirdrops() }
164+
.launchIn(scope)
141165
}
142166

143167
/**
@@ -146,7 +170,6 @@ class RealSessionController @Inject constructor(
146170
* This function performs several actions to ensure the app is up-to-date and ready for user interaction:
147171
* 1. Starts polling for updates (e.g., balance, exchange rates, activity feed).
148172
* 2. Updates user flags.
149-
* 3. Requests an airdrop if applicable.
150173
* 4. Checks for pending items in the activity feed.
151174
* 5. Brings the activity feed to the current state.
152175
* 6. Checks for any pending share actions via the share sheet.
@@ -160,7 +183,6 @@ class RealSessionController @Inject constructor(
160183
)
161184
startPolling()
162185
updateUserFlags()
163-
checkForAirdrops()
164186
checkPendingItemsInFeed()
165187
bringActivityFeedCurrent()
166188
shareSheetController.checkForShare()
@@ -215,16 +237,15 @@ class RealSessionController @Inject constructor(
215237
}
216238
}
217239

218-
private fun checkForAirdrops(onAirdropReceived: (LocalFiat) -> Unit = {}) {
240+
private fun checkForAirdrops() {
219241
if (userManager.authState.canAccessAuthenticatedApis) {
220242
scope.launch {
221243
userManager.accountCluster?.let {
222244
transactionController.airdrop(
223245
type = AirdropType.WelcomeBonus,
224246
destination = it.authority.keyPair
225247
).onSuccess { amount ->
226-
welcomeBonus = amount
227-
onAirdropReceived(amount)
248+
presentWelcomeBonus(amount)
228249
}
229250
}
230251
}
@@ -280,19 +301,8 @@ class RealSessionController @Inject constructor(
280301
}
281302
}
282303

283-
override fun onCameraVisible() {
284-
if (welcomeBonus != null) {
285-
presentWelcomeBonus(welcomeBonus!!)
286-
welcomeBonus = null
287-
} else {
288-
checkForAirdrops {
289-
presentWelcomeBonus(it)
290-
}
291-
}
292-
}
293-
294304
override fun onCameraScanning(scanning: Boolean) {
295-
_state.update { it.copy(isCameraScanEnabled = scanning) }
305+
_state.update { it.copy(isCameraUp = scanning) }
296306
}
297307

298308
override fun onCameraPermissionResult(result: PermissionResult) {

ui/scanner/src/main/kotlin/com/getcode/ui/scanner/CodeScanner.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ fun CodeScanner(
5656
scanningEnabled: Boolean,
5757
cameraGesturesEnabled: Boolean,
5858
invertedDragZoomEnabled: Boolean,
59+
modifier: Modifier = Modifier,
5960
onPreviewStateChanged: (Boolean) -> Unit,
6061
onCodeScanned: (ScannableKikCode) -> Unit,
6162
onError: (Throwable) -> Unit = { },
@@ -195,7 +196,7 @@ fun CodeScanner(
195196
}.launchIn(this)
196197
}
197198

198-
AndroidView(factory = { previewView }, modifier = Modifier.fillMaxSize())
199+
AndroidView(factory = { previewView }, modifier = modifier.fillMaxSize())
199200

200201
FocusIndicator(autoFocusPoint) {
201202
autoFocusPoint = Offset.Unspecified

0 commit comments

Comments
 (0)