@@ -4,6 +4,8 @@ package `in`.hridayan.ashell.settings.presentation.page.backup.screens
44
55import androidx.activity.compose.rememberLauncherForActivityResult
66import androidx.activity.result.contract.ActivityResultContracts
7+ import androidx.compose.animation.animateContentSize
8+ import androidx.compose.animation.core.animateFloatAsState
79import androidx.compose.foundation.layout.Arrangement
810import androidx.compose.foundation.layout.Column
911import androidx.compose.foundation.layout.Row
@@ -25,14 +27,18 @@ import androidx.compose.runtime.LaunchedEffect
2527import androidx.compose.runtime.collectAsState
2628import androidx.compose.runtime.getValue
2729import androidx.compose.runtime.mutableStateOf
30+ import androidx.compose.runtime.remember
2831import androidx.compose.runtime.saveable.rememberSaveable
2932import androidx.compose.runtime.setValue
3033import androidx.compose.ui.Alignment
3134import androidx.compose.ui.Modifier
3235import androidx.compose.ui.draw.alpha
36+ import androidx.compose.ui.draw.rotate
3337import androidx.compose.ui.graphics.painter.Painter
3438import androidx.compose.ui.input.nestedscroll.nestedScroll
39+ import androidx.compose.ui.layout.onGloballyPositioned
3540import androidx.compose.ui.platform.LocalContext
41+ import androidx.compose.ui.platform.LocalDensity
3642import androidx.compose.ui.platform.LocalResources
3743import androidx.compose.ui.res.painterResource
3844import androidx.compose.ui.res.stringResource
@@ -46,6 +52,7 @@ import `in`.hridayan.ashell.core.common.LocalSettings
4652import `in`.hridayan.ashell.core.presentation.components.card.RoundedCornerCard
4753import `in`.hridayan.ashell.core.presentation.components.dialog.DialogKey
4854import `in`.hridayan.ashell.core.presentation.components.dialog.createDialog
55+ import `in`.hridayan.ashell.core.presentation.components.haptic.withHaptic
4956import `in`.hridayan.ashell.core.presentation.components.shape.CardCornerShape
5057import `in`.hridayan.ashell.core.presentation.components.shape.CardCornerShape.getRoundedShape
5158import `in`.hridayan.ashell.core.utils.getFileNameFromUri
@@ -78,6 +85,7 @@ fun BackupAndRestoreScreen(
7885 val lastLocalBackupTime = LocalSettings .current.lastLocalBackupTime
7986 val lastCloudBackupTime = LocalSettings .current.lastCloudBackupTime
8087 val isFetchingCloudBackupTime by backupAndRestoreViewModel.isFetchingCloudBackupTime.collectAsState()
88+ var isLastBackupDetailsCardExpanded by rememberSaveable { mutableStateOf(false ) }
8189
8290 val googleUserState by backupAndRestoreViewModel.googleUserState.collectAsState()
8391 val isSigningIn by backupAndRestoreViewModel.isSigningIn.collectAsState()
@@ -250,11 +258,16 @@ fun BackupAndRestoreScreen(
250258 LastBackupTimeCard (
251259 modifier = Modifier
252260 .fillMaxWidth()
253- .padding(top = 20 .dp),
261+ .padding(top = 10 .dp),
254262 lastLocalBackupTime = lastLocalBackupTime,
255263 lastCloudBackupTime = lastCloudBackupTime,
256264 userState = googleUserState,
257265 isFetching = isFetchingCloudBackupTime,
266+ isExpanded = isLastBackupDetailsCardExpanded,
267+ onClick = withHaptic {
268+ isLastBackupDetailsCardExpanded =
269+ ! isLastBackupDetailsCardExpanded
270+ }
258271 )
259272 }
260273 }
@@ -340,8 +353,15 @@ private fun LastBackupTimeCard(
340353 lastLocalBackupTime : String ,
341354 lastCloudBackupTime : String ,
342355 userState : GoogleUserState ,
343- isFetching : Boolean
356+ isFetching : Boolean ,
357+ isExpanded : Boolean = false,
358+ onClick : () -> Unit = {}
344359) {
360+ var cardHeight by remember { mutableStateOf(0 .dp) }
361+ val screenDensity = LocalDensity .current
362+ val roundedCornerShape =
363+ if (isExpanded) CardCornerShape .FIRST_CARD else RoundedCornerShape (cardHeight / 2 )
364+
345365 val perUserLastCloudBackupTime = when {
346366 ! userState.isSignedIn -> stringResource(R .string.not_signed_in)
347367
@@ -353,6 +373,7 @@ private fun LastBackupTimeCard(
353373 val time = parts.getOrNull(1 ).orEmpty()
354374 " $date | $time "
355375 }
376+
356377 else -> stringResource(R .string.none)
357378 }
358379
@@ -363,38 +384,64 @@ private fun LastBackupTimeCard(
363384 " $date | $time "
364385 }
365386
366- Column (modifier = modifier) {
387+ Column (modifier = modifier.animateContentSize() ) {
367388 RoundedCornerCard (
368- modifier = Modifier .fillMaxWidth(),
369- roundedCornerShape = CardCornerShape .FIRST_CARD
389+ modifier = Modifier
390+ .fillMaxWidth()
391+ .onGloballyPositioned { coordinates ->
392+ cardHeight = with (screenDensity) { coordinates.size.height.toDp() }
393+ },
394+ onClick = onClick,
395+ roundedCornerShape = roundedCornerShape
370396 ) {
371- Text (
372- modifier = Modifier .padding(horizontal = 25 .dp, vertical = 10 .dp),
373- text = stringResource(R .string.last_backup_details),
374- style = MaterialTheme .typography.labelLarge,
375- color = MaterialTheme .colorScheme.primary
376- )
397+ Row (
398+ modifier = Modifier
399+ .fillMaxWidth()
400+ .animateContentSize()
401+ .padding(horizontal = 25 .dp, vertical = 15 .dp),
402+ horizontalArrangement = Arrangement .spacedBy(25 .dp)
403+ ) {
404+ Text (
405+ text = stringResource(R .string.last_backup_details),
406+ style = MaterialTheme .typography.labelLarge,
407+ color = MaterialTheme .colorScheme.primary,
408+ modifier = Modifier
409+ .weight(1f )
410+ .fillMaxWidth()
411+ )
412+
413+ val rotateAngle by animateFloatAsState(if (isExpanded) 180f else 0f )
414+
415+ Icon (
416+ painter = painterResource(R .drawable.ic_expand),
417+ contentDescription = " Expand" ,
418+ modifier = Modifier
419+ .align(Alignment .CenterVertically )
420+ .rotate(rotateAngle)
421+ )
422+ }
377423 }
378424
379- TimeCard (
380- modifier = Modifier .fillMaxWidth(),
381- roundedCornerShape = CardCornerShape .MIDDLE_CARD ,
382- icon = painterResource(R .drawable.ic_mobile),
383- title = stringResource(R .string.device_backup_local),
384- timeDescription = formattedLastLocalBackupTime
385- )
425+ if (isExpanded) {
426+ TimeCard (
427+ modifier = Modifier .fillMaxWidth(),
428+ roundedCornerShape = CardCornerShape .MIDDLE_CARD ,
429+ icon = painterResource(R .drawable.ic_mobile),
430+ title = stringResource(R .string.device_backup_local),
431+ timeDescription = formattedLastLocalBackupTime
432+ )
386433
387- TimeCard (
388- modifier = Modifier .fillMaxWidth(),
389- roundedCornerShape = CardCornerShape .LAST_CARD ,
390- icon = painterResource(R .drawable.ic_cloud_done),
391- title = stringResource(R .string.cloud_backup_google_drive),
392- timeDescription = perUserLastCloudBackupTime
393- )
434+ TimeCard (
435+ modifier = Modifier .fillMaxWidth(),
436+ roundedCornerShape = CardCornerShape .LAST_CARD ,
437+ icon = painterResource(R .drawable.ic_cloud_done),
438+ title = stringResource(R .string.cloud_backup_google_drive),
439+ timeDescription = perUserLastCloudBackupTime
440+ )
441+ }
394442 }
395443}
396444
397-
398445@Composable
399446private fun TimeCard (
400447 modifier : Modifier = Modifier ,
@@ -405,7 +452,8 @@ private fun TimeCard(
405452) {
406453 RoundedCornerCard (
407454 modifier = modifier,
408- roundedCornerShape = roundedCornerShape
455+ roundedCornerShape = roundedCornerShape,
456+ onClick = withHaptic { }
409457 ) {
410458 Row (
411459 modifier = Modifier
0 commit comments