1
1
package com.x8bit.bitwarden.ui.platform.feature.settings.flightrecorder
2
2
3
+ import androidx.compose.foundation.layout.Column
4
+ import androidx.compose.foundation.layout.Spacer
5
+ import androidx.compose.foundation.layout.fillMaxWidth
6
+ import androidx.compose.foundation.layout.height
7
+ import androidx.compose.foundation.layout.navigationBarsPadding
8
+ import androidx.compose.foundation.rememberScrollState
9
+ import androidx.compose.foundation.verticalScroll
3
10
import androidx.compose.material3.ExperimentalMaterial3Api
11
+ import androidx.compose.material3.Text
4
12
import androidx.compose.material3.TopAppBarDefaults
5
13
import androidx.compose.material3.rememberTopAppBarState
6
14
import androidx.compose.runtime.Composable
15
+ import androidx.compose.runtime.getValue
7
16
import androidx.compose.runtime.remember
8
17
import androidx.compose.ui.Modifier
9
18
import androidx.compose.ui.input.nestedscroll.nestedScroll
19
+ import androidx.compose.ui.platform.LocalContext
20
+ import androidx.compose.ui.platform.testTag
10
21
import androidx.compose.ui.res.stringResource
22
+ import androidx.compose.ui.text.style.TextAlign
23
+ import androidx.compose.ui.unit.dp
24
+ import androidx.core.net.toUri
11
25
import androidx.hilt.navigation.compose.hiltViewModel
26
+ import androidx.lifecycle.compose.collectAsStateWithLifecycle
12
27
import com.x8bit.bitwarden.R
28
+ import com.x8bit.bitwarden.data.platform.repository.model.FlightRecorderDuration
13
29
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
30
+ import com.x8bit.bitwarden.ui.platform.base.util.standardHorizontalMargin
14
31
import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
32
+ import com.x8bit.bitwarden.ui.platform.components.button.BitwardenTextButton
33
+ import com.x8bit.bitwarden.ui.platform.components.dropdown.BitwardenMultiSelectButton
34
+ import com.x8bit.bitwarden.ui.platform.components.model.CardStyle
15
35
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
36
+ import com.x8bit.bitwarden.ui.platform.components.text.BitwardenHyperTextLink
16
37
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
38
+ import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
39
+ import com.x8bit.bitwarden.ui.platform.feature.settings.flightrecorder.util.displayText
40
+ import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
41
+ import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
42
+ import kotlinx.collections.immutable.toImmutableList
17
43
18
44
/* *
19
45
* Displays the flight recorder configuration screen.
@@ -23,10 +49,15 @@ import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
23
49
fun FlightRecorderScreen (
24
50
onNavigateBack : () -> Unit ,
25
51
viewModel : FlightRecorderViewModel = hiltViewModel(),
52
+ intentManager : IntentManager = LocalIntentManager .current,
26
53
) {
54
+ val state by viewModel.stateFlow.collectAsStateWithLifecycle()
27
55
EventsEffect (viewModel) { event ->
28
56
when (event) {
29
57
FlightRecorderEvent .NavigateBack -> onNavigateBack()
58
+ FlightRecorderEvent .NavigateToHelpCenter -> {
59
+ intentManager.launchUri(uri = " https://bitwarden.com/help" .toUri())
60
+ }
30
61
}
31
62
}
32
63
val scrollBehavior = TopAppBarDefaults .pinnedScrollBehavior(rememberTopAppBarState())
@@ -40,10 +71,130 @@ fun FlightRecorderScreen(
40
71
{ viewModel.trySendAction(FlightRecorderAction .BackClick ) }
41
72
},
42
73
scrollBehavior = scrollBehavior,
74
+ actions = {
75
+ BitwardenTextButton (
76
+ label = stringResource(id = R .string.save),
77
+ onClick = remember(viewModel) {
78
+ { viewModel.trySendAction(FlightRecorderAction .SaveClick ) }
79
+ },
80
+ modifier = Modifier .testTag(" SaveButton" ),
81
+ )
82
+ },
43
83
)
44
84
},
45
85
modifier = Modifier .nestedScroll(scrollBehavior.nestedScrollConnection),
46
86
) {
47
- // TODO: PM-19592 Create the flight recorder UI.
87
+ FlightRecorderContent (
88
+ state = state,
89
+ onDurationSelected = remember(viewModel) {
90
+ { viewModel.trySendAction(FlightRecorderAction .DurationSelect (it)) }
91
+ },
92
+ onHelpCenterClick = remember(viewModel) {
93
+ { viewModel.trySendAction(FlightRecorderAction .HelpCenterClick ) }
94
+ },
95
+ )
96
+ }
97
+ }
98
+
99
+ @Suppress(" LongMethod" )
100
+ @Composable
101
+ private fun FlightRecorderContent (
102
+ state : FlightRecorderState ,
103
+ onDurationSelected : (FlightRecorderDuration ) -> Unit ,
104
+ onHelpCenterClick : () -> Unit ,
105
+ modifier : Modifier = Modifier ,
106
+ ) {
107
+ Column (
108
+ modifier = modifier
109
+ .verticalScroll(state = rememberScrollState()),
110
+ ) {
111
+ Spacer (modifier = Modifier .height(height = 24 .dp))
112
+ Text (
113
+ text = stringResource(id = R .string.experiencing_an_issue),
114
+ color = BitwardenTheme .colorScheme.text.primary,
115
+ style = BitwardenTheme .typography.titleMedium,
116
+ textAlign = TextAlign .Center ,
117
+ modifier = Modifier
118
+ .fillMaxWidth()
119
+ .standardHorizontalMargin(),
120
+ )
121
+ Spacer (modifier = Modifier .height(height = 12 .dp))
122
+ Text (
123
+ text = stringResource(
124
+ id = R .string.enable_temporary_logging_to_collect_and_inspect_logs_locally,
125
+ ),
126
+ color = BitwardenTheme .colorScheme.text.primary,
127
+ style = BitwardenTheme .typography.bodyMedium,
128
+ textAlign = TextAlign .Center ,
129
+ modifier = Modifier
130
+ .fillMaxWidth()
131
+ .standardHorizontalMargin(),
132
+ )
133
+ Spacer (modifier = Modifier .height(height = 12 .dp))
134
+ Text (
135
+ text = stringResource(id = R .string.to_get_started_set_a_logging_duration),
136
+ color = BitwardenTheme .colorScheme.text.primary,
137
+ style = BitwardenTheme .typography.bodyMedium,
138
+ textAlign = TextAlign .Center ,
139
+ modifier = Modifier
140
+ .fillMaxWidth()
141
+ .standardHorizontalMargin(),
142
+ )
143
+ Spacer (modifier = Modifier .height(height = 24 .dp))
144
+ DurationSelectButton (
145
+ selectedOption = state.selectedDuration,
146
+ onOptionSelected = onDurationSelected,
147
+ modifier = Modifier
148
+ .fillMaxWidth()
149
+ .standardHorizontalMargin(),
150
+ )
151
+ Spacer (modifier = Modifier .height(height = 24 .dp))
152
+ Text (
153
+ text = stringResource(id = R .string.logs_will_be_automatically_deleted_after_30_days),
154
+ color = BitwardenTheme .colorScheme.text.secondary,
155
+ style = BitwardenTheme .typography.bodySmall,
156
+ textAlign = TextAlign .Center ,
157
+ modifier = Modifier
158
+ .fillMaxWidth()
159
+ .standardHorizontalMargin(),
160
+ )
161
+ Spacer (modifier = Modifier .height(height = 8 .dp))
162
+ BitwardenHyperTextLink (
163
+ annotatedResId = R .string.for_details_on_what_is_and_isnt_logged,
164
+ annotationKey = " helpCenter" ,
165
+ accessibilityString = stringResource(id = R .string.bitwarden_help_center),
166
+ onClick = onHelpCenterClick,
167
+ color = BitwardenTheme .colorScheme.text.secondary,
168
+ style = BitwardenTheme .typography.bodySmall,
169
+ modifier = Modifier
170
+ .fillMaxWidth()
171
+ .standardHorizontalMargin(),
172
+ )
173
+ Spacer (modifier = Modifier .height(height = 16 .dp))
174
+ Spacer (modifier = Modifier .navigationBarsPadding())
48
175
}
49
176
}
177
+
178
+ @Composable
179
+ private fun DurationSelectButton (
180
+ selectedOption : FlightRecorderDuration ,
181
+ onOptionSelected : (FlightRecorderDuration ) -> Unit ,
182
+ modifier : Modifier = Modifier ,
183
+ ) {
184
+ val resources = LocalContext .current.resources
185
+ val options = FlightRecorderDuration .entries.map { it.displayText() }.toImmutableList()
186
+ BitwardenMultiSelectButton (
187
+ label = stringResource(id = R .string.logging_duration),
188
+ options = options,
189
+ selectedOption = selectedOption.displayText(),
190
+ onOptionSelected = { selectedOption ->
191
+ onOptionSelected(
192
+ FlightRecorderDuration
193
+ .entries
194
+ .first { selectedOption == it.displayText.toString(resources) },
195
+ )
196
+ },
197
+ cardStyle = CardStyle .Full ,
198
+ modifier = modifier,
199
+ )
200
+ }
0 commit comments