1
1
package com.getcode
2
2
3
- import androidx.compose.animation.AnimatedContent
4
- import androidx.compose.animation.AnimatedVisibility
5
3
import androidx.compose.animation.fadeIn
6
4
import androidx.compose.animation.fadeOut
7
5
import androidx.compose.animation.togetherWith
8
- import androidx.compose.foundation.Image
9
6
import androidx.compose.foundation.background
10
- import androidx.compose.foundation.layout.Arrangement
11
7
import androidx.compose.foundation.layout.Box
12
- import androidx.compose.foundation.layout.Column
13
8
import androidx.compose.foundation.layout.PaddingValues
14
- import androidx.compose.foundation.layout.fillMaxHeight
15
9
import androidx.compose.foundation.layout.fillMaxSize
16
- import androidx.compose.foundation.layout.fillMaxWidth
17
10
import androidx.compose.foundation.layout.padding
18
11
import androidx.compose.material.ExperimentalMaterialApi
19
12
import androidx.compose.runtime.Composable
20
13
import androidx.compose.runtime.CompositionLocalProvider
21
14
import androidx.compose.runtime.LaunchedEffect
15
+ import androidx.compose.runtime.collectAsState
22
16
import androidx.compose.runtime.getValue
23
17
import androidx.compose.runtime.mutableStateOf
24
18
import androidx.compose.runtime.remember
25
19
import androidx.compose.runtime.setValue
26
- import androidx.compose.ui.Alignment
27
20
import androidx.compose.ui.Modifier
28
21
import androidx.compose.ui.platform.LocalContext
29
- import androidx.compose.ui.res.painterResource
30
22
import androidx.compose.ui.unit.dp
23
+ import androidx.lifecycle.Lifecycle
31
24
import cafe.adriel.voyager.core.screen.Screen
32
25
import cafe.adriel.voyager.core.screen.ScreenKey
33
26
import cafe.adriel.voyager.core.screen.uniqueScreenKey
@@ -46,102 +39,115 @@ import com.getcode.theme.CodeTheme
46
39
import com.getcode.theme.LocalCodeColors
47
40
import com.getcode.ui.components.AuthCheck
48
41
import com.getcode.ui.components.BottomBarContainer
49
- import com.getcode.ui.components.CodeCircularProgressIndicator
50
42
import com.getcode.ui.components.CodeScaffold
43
+ import com.getcode.ui.components.OnLifecycleEvent
51
44
import com.getcode.ui.components.TitleBar
52
45
import com.getcode.ui.components.TopBarContainer
53
46
import com.getcode.ui.utils.getActivity
54
47
import com.getcode.ui.utils.getActivityScopedViewModel
55
48
import com.getcode.ui.utils.measured
49
+ import com.getcode.view.main.home.components.BiometricsBlockingView
50
+ import com.getcode.view.main.home.components.rememberBiometricsState
56
51
import dev.bmcreations.tipkit.TipScaffold
57
52
import dev.bmcreations.tipkit.engines.TipsEngine
58
- import kotlinx.coroutines.delay
59
53
60
54
@Composable
61
55
fun CodeApp (tipsEngine : TipsEngine ) {
62
56
val tlvm = MainRoot .getActivityScopedViewModel<TopLevelViewModel >()
57
+ val state by tlvm.state.collectAsState()
63
58
val activity = LocalContext .current.getActivity()
59
+ val biometricsState = rememberBiometricsState(
60
+ requireBiometrics = state.requireBiometrics,
61
+ onBiometricsNotEnrolled = { tlvm.onMissingBiometrics() }
62
+ )
63
+
64
+ OnLifecycleEvent { _, event ->
65
+ if (event == Lifecycle .Event .ON_RESUME ) {
66
+ tlvm.onResume()
67
+ }
68
+ }
64
69
65
70
CodeTheme {
66
71
val appState = rememberCodeAppState()
67
- AppNavHost {
68
- val codeNavigator = LocalCodeNavigator .current
69
-
70
- TipScaffold (tipsEngine = tipsEngine) {
71
- CodeScaffold (
72
- scaffoldState = appState.scaffoldState
73
- ) { innerPaddingModifier ->
74
- Navigator (
75
- screen = MainRoot ,
76
- ) { navigator ->
77
- appState.navigator = codeNavigator
78
-
79
- LaunchedEffect (navigator.lastItem) {
80
- // update global navigator for platform access to support push/pop from a single
81
- // navigator current
82
- codeNavigator.screensNavigator = navigator
83
- }
72
+ CompositionLocalProvider ( LocalBiometricsState provides biometricsState) {
73
+ AppNavHost {
74
+ val codeNavigator = LocalCodeNavigator .current
75
+ TipScaffold (tipsEngine = tipsEngine) {
76
+ CodeScaffold (
77
+ scaffoldState = appState.scaffoldState
78
+ ) { innerPaddingModifier ->
79
+ Navigator (
80
+ screen = MainRoot ,
81
+ ) { navigator ->
82
+ appState.navigator = codeNavigator
83
+
84
+ LaunchedEffect (navigator.lastItem) {
85
+ // update global navigator for platform access to support push/pop from a single
86
+ // navigator current
87
+ codeNavigator.screensNavigator = navigator
88
+ }
84
89
85
- var topBarHeight by remember {
86
- mutableStateOf(0 .dp)
87
- }
90
+ var topBarHeight by remember {
91
+ mutableStateOf(0 .dp)
92
+ }
88
93
89
- val (isVisibleTopBar, isVisibleBackButton) = appState.isVisibleTopBar
90
- if (isVisibleTopBar && appState.currentTitle.isNotBlank()) {
91
- TitleBar (
92
- modifier = Modifier .measured { topBarHeight = it.height },
93
- title = appState.currentTitle,
94
- backButton = isVisibleBackButton,
95
- onBackIconClicked = appState::upPress
96
- )
97
- } else {
98
- topBarHeight = 0 .dp
99
- }
94
+ val (isVisibleTopBar, isVisibleBackButton) = appState.isVisibleTopBar
95
+ if (isVisibleTopBar && appState.currentTitle.isNotBlank()) {
96
+ TitleBar (
97
+ modifier = Modifier .measured { topBarHeight = it.height },
98
+ title = appState.currentTitle,
99
+ backButton = isVisibleBackButton,
100
+ onBackIconClicked = appState::upPress
101
+ )
102
+ } else {
103
+ topBarHeight = 0 .dp
104
+ }
100
105
101
- CompositionLocalProvider (
102
- LocalTopBarPadding provides PaddingValues (top = topBarHeight),
103
- ) {
104
- Box (
105
- modifier = Modifier
106
- .padding(innerPaddingModifier)
106
+ CompositionLocalProvider (
107
+ LocalTopBarPadding provides PaddingValues (top = topBarHeight),
107
108
) {
108
- when (navigator.lastEvent) {
109
- StackEvent .Push ,
110
- StackEvent .Pop -> {
111
- when (navigator.lastItem) {
112
- is LoginScreen , is MainRoot -> CrossfadeTransition (
113
- navigator = navigator
114
- )
115
-
116
- else -> SlideTransition (navigator = navigator)
109
+ Box (
110
+ modifier = Modifier
111
+ .padding(innerPaddingModifier)
112
+ ) {
113
+ when (navigator.lastEvent) {
114
+ StackEvent .Push ,
115
+ StackEvent .Pop -> {
116
+ when (navigator.lastItem) {
117
+ is LoginScreen , is MainRoot -> CrossfadeTransition (
118
+ navigator = navigator
119
+ )
120
+
121
+ else -> SlideTransition (navigator = navigator)
122
+ }
117
123
}
118
- }
119
124
120
- StackEvent .Idle ,
121
- StackEvent .Replace -> CurrentScreen ()
125
+ StackEvent .Idle ,
126
+ StackEvent .Replace -> CurrentScreen ()
127
+ }
122
128
}
123
129
}
124
- }
125
130
126
- // Listen for authentication changes here
127
- AuthCheck (
128
- navigator = codeNavigator,
129
- onNavigate = { screens ->
130
- codeNavigator.replaceAll(screens, inSheet = false )
131
- },
132
- onSwitchAccounts = { seed ->
133
- activity?.let {
134
- tlvm.logout(it) {
135
- appState.navigator.replaceAll(LoginScreen (seed))
131
+ // Listen for authentication changes here
132
+ AuthCheck (
133
+ navigator = codeNavigator,
134
+ onNavigate = { screens ->
135
+ codeNavigator.replaceAll(screens, inSheet = false )
136
+ },
137
+ onSwitchAccounts = { seed ->
138
+ activity?.let {
139
+ tlvm.logout(it) {
140
+ appState.navigator.replaceAll(LoginScreen (seed))
141
+ }
136
142
}
137
143
}
138
- }
139
- )
144
+ )
145
+ }
140
146
}
141
147
}
142
148
}
143
149
}
144
-
150
+ BiometricsBlockingView (modifier = Modifier .fillMaxSize(), biometricsState)
145
151
TopBarContainer (appState)
146
152
BottomBarContainer (appState)
147
153
}
0 commit comments