@@ -8,8 +8,13 @@ package `in`.hridayan.ashell.qstiles.presentation.screen
88
99import android.content.pm.PackageManager
1010import androidx.compose.animation.AnimatedContent
11+ import androidx.compose.animation.AnimatedVisibility
1112import androidx.compose.animation.Crossfade
1213import androidx.compose.animation.animateContentSize
14+ import androidx.compose.animation.expandVertically
15+ import androidx.compose.animation.fadeIn
16+ import androidx.compose.animation.fadeOut
17+ import androidx.compose.animation.shrinkVertically
1318import androidx.compose.animation.togetherWith
1419import androidx.compose.foundation.background
1520import androidx.compose.foundation.basicMarquee
@@ -33,11 +38,12 @@ import androidx.compose.foundation.lazy.items
3338import androidx.compose.foundation.lazy.rememberLazyListState
3439import androidx.compose.foundation.shape.CircleShape
3540import androidx.compose.foundation.shape.RoundedCornerShape
36- import androidx.compose.foundation.text.BasicTextField
3741import androidx.compose.material3.Button
3842import androidx.compose.material3.ButtonDefaults
3943import androidx.compose.material3.Card
4044import androidx.compose.material3.CardDefaults
45+ import androidx.compose.material3.DropdownMenu
46+ import androidx.compose.material3.DropdownMenuItem
4147import androidx.compose.material3.ExperimentalMaterial3Api
4248import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
4349import androidx.compose.material3.Icon
@@ -59,7 +65,6 @@ import androidx.compose.ui.Alignment
5965import androidx.compose.ui.Modifier
6066import androidx.compose.ui.draw.clip
6167import androidx.compose.ui.graphics.Color
62- import androidx.compose.ui.graphics.SolidColor
6368import androidx.compose.ui.graphics.painter.Painter
6469import androidx.compose.ui.hapticfeedback.HapticFeedbackType
6570import androidx.compose.ui.input.nestedscroll.nestedScroll
@@ -77,13 +82,14 @@ import androidx.lifecycle.LifecycleEventObserver
7782import androidx.lifecycle.compose.LocalLifecycleOwner
7883import androidx.navigation.NavController
7984import `in`.hridayan.ashell.R
85+ import `in`.hridayan.ashell.commandexamples.presentation.component.chip.LabelChip
8086import `in`.hridayan.ashell.core.common.LocalDarkMode
8187import `in`.hridayan.ashell.core.common.LocalWeakHaptic
8288import `in`.hridayan.ashell.core.common.constants.SHIZUKU_PACKAGE_NAME
8389import `in`.hridayan.ashell.core.common.constants.UrlConst
8490import `in`.hridayan.ashell.core.presentation.components.card.IconWithTextCard
85- import `in`.hridayan.ashell.core.presentation.components.modifier.dashedBorder
8691import `in`.hridayan.ashell.core.presentation.components.haptic.withHaptic
92+ import `in`.hridayan.ashell.core.presentation.components.modifier.dashedBorder
8793import `in`.hridayan.ashell.core.presentation.components.navigation.FloatingNavPill
8894import `in`.hridayan.ashell.core.presentation.components.navigation.FloatingNavPillDefaults
8995import `in`.hridayan.ashell.core.presentation.components.navigation.FloatingNavPillItem
@@ -101,6 +107,7 @@ import `in`.hridayan.ashell.navigation.slideFadeInFromRight
101107import `in`.hridayan.ashell.navigation.slideFadeOutToLeft
102108import `in`.hridayan.ashell.navigation.slideFadeOutToRight
103109import `in`.hridayan.ashell.qstiles.data.provider.TileIconProvider
110+ import `in`.hridayan.ashell.qstiles.domain.model.TileConfig
104111import `in`.hridayan.ashell.qstiles.domain.model.TileExecutionMode
105112import `in`.hridayan.ashell.qstiles.domain.model.TileLog
106113import `in`.hridayan.ashell.qstiles.presentation.model.TileDashBoardScreenUiState
@@ -277,11 +284,14 @@ private fun TilesContent(
277284 state = listState,
278285 contentPadding = innerPadding
279286 ) {
280-
281287 item { Spacer (Modifier .height(25 .dp)) }
282288
283- if (! hasNotificationAccess) {
284- item {
289+ item {
290+ AnimatedVisibility (
291+ visible = ! hasNotificationAccess,
292+ enter = fadeIn() + expandVertically(),
293+ exit = fadeOut() + shrinkVertically(),
294+ ) {
285295 NotificationAccessRequestCard (
286296 modifier = Modifier
287297 .fillMaxWidth()
@@ -291,8 +301,12 @@ private fun TilesContent(
291301 }
292302 }
293303
294- if (showShizukuUnavailableCard) {
295- item {
304+ item {
305+ AnimatedVisibility (
306+ visible = showShizukuUnavailableCard,
307+ enter = fadeIn() + expandVertically(),
308+ exit = fadeOut() + shrinkVertically(),
309+ ) {
296310 ShizukuUnavailableCard (
297311 modifier = Modifier
298312 .fillMaxWidth()
@@ -308,9 +322,13 @@ private fun TilesContent(
308322 }
309323 }
310324
311- if (Shizuku .pingBinder()) {
312- if (! shizukuPermissionGranted.value) {
313- item {
325+ item {
326+ if (Shizuku .pingBinder()) {
327+ AnimatedVisibility (
328+ visible = ! shizukuPermissionGranted.value,
329+ enter = fadeIn() + expandVertically(),
330+ exit = fadeOut() + shrinkVertically(),
331+ ) {
314332 ShizukuPermissionRequestCard (
315333 modifier = Modifier
316334 .fillMaxWidth()
@@ -413,8 +431,9 @@ private fun LogsContent(
413431 item {
414432 RecentActivityHeader (
415433 modifier = Modifier .padding(20 .dp),
416- searchQuery = uiState.logsSearchQuery,
417- onSearchQueryChange = viewModel::onLogsSearchQueryChange
434+ selectedTileId = uiState.selectedTileIdFilter,
435+ tilesWithLogs = uiState.tilesWithLogs,
436+ onFilterChange = viewModel::onFilterChange
418437 )
419438 }
420439
@@ -620,11 +639,15 @@ private fun StatCard(
620639@Composable
621640private fun RecentActivityHeader (
622641 modifier : Modifier = Modifier ,
623- searchQuery : String ,
624- onSearchQueryChange : (String ) -> Unit
642+ selectedTileId : Int? ,
643+ tilesWithLogs : List <TileConfig >,
644+ onFilterChange : (Int? ) -> Unit
625645) {
626- var isSearchExpanded by remember { mutableStateOf(false ) }
646+ var isMenuExpanded by remember { mutableStateOf(false ) }
627647 val weakHaptic = LocalWeakHaptic .current
648+ val selectedTile = remember(selectedTileId, tilesWithLogs) {
649+ tilesWithLogs.find { it.id == selectedTileId }
650+ }
628651
629652 Row (
630653 modifier = modifier
@@ -633,26 +656,13 @@ private fun RecentActivityHeader(
633656 verticalAlignment = Alignment .CenterVertically ,
634657 horizontalArrangement = Arrangement .SpaceBetween
635658 ) {
636- Crossfade (targetState = isSearchExpanded) { expanded ->
637- if (expanded) {
638- BasicTextField (
639- modifier = Modifier
640- .weight(1f )
641- .padding(end = 10 .dp)
642- .background(MaterialTheme .colorScheme.surfaceContainer, CircleShape )
643- .padding(horizontal = 16 .dp, vertical = 8 .dp),
644- value = searchQuery,
645- onValueChange = onSearchQueryChange,
646- textStyle = MaterialTheme .typography.bodyMedium.copy(color = MaterialTheme .colorScheme.onSurface),
647- cursorBrush = SolidColor (MaterialTheme .colorScheme.primary),
648- decorationBox = { innerTextField ->
649- if (searchQuery.isEmpty()) {
650- AutoResizeableText (
651- text = stringResource(R .string.search_tile),
652- color = MaterialTheme .colorScheme.onSurface.copy(alpha = 0.5f )
653- )
654- }
655- innerTextField()
659+ Crossfade (targetState = selectedTile) { tile ->
660+ if (tile != null ) {
661+ LabelChip (
662+ label = tile.name,
663+ showCrossIcon = true ,
664+ crossIconOnClick = {
665+ onFilterChange(null )
656666 }
657667 )
658668 } else {
@@ -664,30 +674,71 @@ private fun RecentActivityHeader(
664674 }
665675 }
666676
667- Row (
668- modifier = Modifier
669- .clip( CircleShape )
670- .clickable {
671- isSearchExpanded = ! isSearchExpanded
672- weakHaptic()
673- }
674- .padding(horizontal = 12 .dp, vertical = 6 .dp),
675- verticalAlignment = Alignment . CenterVertically ,
676- horizontalArrangement = Arrangement .spacedBy( 6 .dp)
677- ) {
678- Icon (
679- modifier = Modifier .size( 18 .dp),
680- painter = painterResource( if (isSearchExpanded) R .drawable.ts_close else R .drawable.ic_filter_alt ),
681- contentDescription = null ,
682- tint = MaterialTheme .colorScheme.primary
683- )
684- if ( ! isSearchExpanded) {
677+ Box {
678+ Row (
679+ modifier = Modifier
680+ .clip( CircleShape )
681+ .clickable {
682+ isMenuExpanded = ! isMenuExpanded
683+ weakHaptic()
684+ }
685+ .padding(horizontal = 12 .dp, vertical = 6 .dp) ,
686+ verticalAlignment = Alignment . CenterVertically ,
687+ horizontalArrangement = Arrangement .spacedBy( 6 .dp)
688+ ) {
689+ Icon (
690+ modifier = Modifier .size( 18 .dp ),
691+ painter = painterResource( R .drawable.ic_filter_alt) ,
692+ contentDescription = null ,
693+ tint = MaterialTheme .colorScheme.primary
694+ )
685695 Text (
686696 text = stringResource(R .string.filter),
687697 style = MaterialTheme .typography.labelLarge,
688698 color = MaterialTheme .colorScheme.primary
689699 )
690700 }
701+
702+ DropdownMenu (
703+ expanded = isMenuExpanded,
704+ onDismissRequest = { isMenuExpanded = false },
705+ modifier = Modifier .background(MaterialTheme .colorScheme.surfaceContainerHigh)
706+ ) {
707+ DropdownMenuItem (
708+ text = { Text (stringResource(R .string.all)) },
709+ onClick = {
710+ onFilterChange(null )
711+ isMenuExpanded = false
712+ weakHaptic()
713+ }
714+ )
715+ tilesWithLogs.forEach { tile ->
716+ DropdownMenuItem (
717+ text = {
718+ Row (
719+ verticalAlignment = Alignment .CenterVertically ,
720+ horizontalArrangement = Arrangement .spacedBy(8 .dp)
721+ ) {
722+ val tileIcon = TileIconProvider .iconById[tile.iconId]
723+ Icon (
724+ modifier = Modifier .size(18 .dp),
725+ painter = painterResource(
726+ tileIcon?.resId ? : R .drawable.ic_adb
727+ ),
728+ contentDescription = null ,
729+ tint = MaterialTheme .colorScheme.primary
730+ )
731+ Text (tile.name)
732+ }
733+ },
734+ onClick = {
735+ onFilterChange(tile.id)
736+ isMenuExpanded = false
737+ weakHaptic()
738+ }
739+ )
740+ }
741+ }
691742 }
692743 }
693744}
0 commit comments