@@ -2,6 +2,7 @@ package net.mullvad.mullvadvpn.compose.screen
2
2
3
3
import androidx.compose.animation.animateContentSize
4
4
import androidx.compose.foundation.Image
5
+ import androidx.compose.foundation.layout.Arrangement
5
6
import androidx.compose.foundation.layout.Column
6
7
import androidx.compose.foundation.layout.ColumnScope
7
8
import androidx.compose.foundation.layout.fillMaxSize
@@ -34,6 +35,7 @@ import net.mullvad.mullvadvpn.R
34
35
import net.mullvad.mullvadvpn.compose.button.PrimaryButton
35
36
import net.mullvad.mullvadvpn.compose.button.VariantButton
36
37
import net.mullvad.mullvadvpn.compose.cell.BaseCell
38
+ import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorLarge
37
39
import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorMedium
38
40
import net.mullvad.mullvadvpn.compose.component.ScaffoldWithTopBar
39
41
import net.mullvad.mullvadvpn.compose.component.drawVerticalScrollbar
@@ -56,7 +58,73 @@ import org.koin.androidx.compose.koinViewModel
56
58
57
59
@Composable
58
60
@Preview
59
- private fun PreviewDeviceListScreen () {
61
+ private fun PreviewDeviceListScreenTooManyDevices () {
62
+ AppTheme {
63
+ DeviceListScreen (
64
+ state =
65
+ DeviceListUiState (
66
+ deviceUiItems =
67
+ listOf (
68
+ DeviceListItemUiState (
69
+ device =
70
+ Device (
71
+ id = " ID1" ,
72
+ name = " Name1" ,
73
+ pubkey = ByteArray (10 ),
74
+ created = " 2012-12-12 12:12:12 UTC"
75
+ ),
76
+ isLoading = false
77
+ ),
78
+ DeviceListItemUiState (
79
+ device =
80
+ Device (
81
+ id = " ID2" ,
82
+ name = " Name2" ,
83
+ pubkey = ByteArray (10 ),
84
+ created = " 2012-12-12 12:12:12 UTC"
85
+ ),
86
+ isLoading = false
87
+ ),
88
+ DeviceListItemUiState (
89
+ device =
90
+ Device (
91
+ id = " ID3" ,
92
+ name = " Name3" ,
93
+ pubkey = ByteArray (10 ),
94
+ created = " 2012-12-12 12:12:12 UTC"
95
+ ),
96
+ isLoading = false
97
+ ),
98
+ DeviceListItemUiState (
99
+ device =
100
+ Device (
101
+ id = " ID4" ,
102
+ name = " Name4" ,
103
+ pubkey = ByteArray (10 ),
104
+ created = " 2012-12-12 12:12:12 UTC"
105
+ ),
106
+ isLoading = false
107
+ ),
108
+ DeviceListItemUiState (
109
+ device =
110
+ Device (
111
+ id = " ID5" ,
112
+ name = " Name5" ,
113
+ pubkey = ByteArray (10 ),
114
+ created = " 2012-12-12 12:12:12 UTC"
115
+ ),
116
+ isLoading = true
117
+ )
118
+ ),
119
+ isLoading = false
120
+ )
121
+ )
122
+ }
123
+ }
124
+
125
+ @Composable
126
+ @Preview
127
+ private fun PreviewDeviceListScreenNotTooManyDevices () {
60
128
AppTheme {
61
129
DeviceListScreen (
62
130
state =
@@ -69,17 +137,33 @@ private fun PreviewDeviceListScreen() {
69
137
id = " ID" ,
70
138
name = " Name" ,
71
139
pubkey = ByteArray (10 ),
72
- created = " 2002 -12-12"
140
+ created = " 2012 -12-12 12:12:12 UTC "
73
141
),
74
142
isLoading = false
75
143
)
76
144
),
77
- isLoading = true
145
+ isLoading = false
78
146
)
79
147
)
80
148
}
81
149
}
82
150
151
+ @Composable
152
+ @Preview
153
+ private fun PreviewDeviceListScreenEmpty () {
154
+ AppTheme {
155
+ DeviceListScreen (state = DeviceListUiState (deviceUiItems = emptyList(), isLoading = false ))
156
+ }
157
+ }
158
+
159
+ @Composable
160
+ @Preview
161
+ private fun PreviewDeviceListLoading () {
162
+ AppTheme {
163
+ DeviceListScreen (state = DeviceListUiState (deviceUiItems = emptyList(), isLoading = true ))
164
+ }
165
+ }
166
+
83
167
@Destination
84
168
@Composable
85
169
fun DeviceList (
@@ -146,25 +230,55 @@ fun DeviceListScreen(
146
230
)
147
231
.verticalScroll(scrollState)
148
232
.weight(1f )
149
- ) {
150
- DeviceListHeader (state = state)
151
-
152
- state.deviceUiItems.forEachIndexed { index, deviceUiState ->
153
- DeviceListItem (
154
- deviceUiState = deviceUiState,
155
- ) {
156
- navigateToRemoveDeviceConfirmationDialog(deviceUiState.device)
157
- }
158
- if (state.deviceUiItems.lastIndex != index) {
159
- Divider ()
233
+ .fillMaxWidth(),
234
+ verticalArrangement =
235
+ if (state.isLoading) {
236
+ Arrangement .Center
237
+ } else {
238
+ Arrangement .Top
160
239
}
240
+ ) {
241
+ if (state.isLoading) {
242
+ DeviceListLoading ()
243
+ } else {
244
+ DeviceListContent (
245
+ state = state,
246
+ navigateToRemoveDeviceConfirmationDialog =
247
+ navigateToRemoveDeviceConfirmationDialog
248
+ )
161
249
}
162
250
}
163
251
DeviceListButtonPanel (state, onContinueWithLogin, onBackClick)
164
252
}
165
253
}
166
254
}
167
255
256
+ @Composable
257
+ private fun ColumnScope.DeviceListLoading () {
258
+ MullvadCircularProgressIndicatorLarge (
259
+ modifier = Modifier .padding(Dimens .smallPadding).align(Alignment .CenterHorizontally )
260
+ )
261
+ }
262
+
263
+ @Composable
264
+ private fun ColumnScope.DeviceListContent (
265
+ state : DeviceListUiState ,
266
+ navigateToRemoveDeviceConfirmationDialog : (Device ) -> Unit
267
+ ) {
268
+ DeviceListHeader (state = state)
269
+
270
+ state.deviceUiItems.forEachIndexed { index, deviceUiState ->
271
+ DeviceListItem (
272
+ deviceUiState = deviceUiState,
273
+ ) {
274
+ navigateToRemoveDeviceConfirmationDialog(deviceUiState.device)
275
+ }
276
+ if (state.deviceUiItems.lastIndex != index) {
277
+ Divider ()
278
+ }
279
+ }
280
+ }
281
+
168
282
@Composable
169
283
private fun ColumnScope.DeviceListHeader (state : DeviceListUiState ) {
170
284
Image (
@@ -267,6 +381,8 @@ private fun DeviceListItem(
267
381
Icon (
268
382
painter = painterResource(id = R .drawable.icon_close),
269
383
contentDescription = stringResource(id = R .string.remove_button),
384
+ tint = MaterialTheme .colorScheme.onPrimary,
385
+ modifier = Modifier .size(size = Dimens .deleteIconSize)
270
386
)
271
387
}
272
388
}
0 commit comments