Fix file result alignment
This commit is contained in:
parent
dd081a362b
commit
a399f3e744
@ -1,10 +1,10 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.search.files
|
package de.mm20.launcher2.ui.launcher.search.files
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedContent
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.SharedTransitionLayout
|
||||||
import androidx.compose.animation.core.MutableTransitionState
|
import androidx.compose.animation.core.MutableTransitionState
|
||||||
import androidx.compose.animation.core.animateDp
|
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.animation.core.updateTransition
|
|
||||||
import androidx.compose.animation.expandIn
|
import androidx.compose.animation.expandIn
|
||||||
import androidx.compose.animation.shrinkOut
|
import androidx.compose.animation.shrinkOut
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@ -40,17 +40,16 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.geometry.Rect
|
import androidx.compose.ui.geometry.Rect
|
||||||
import androidx.compose.ui.graphics.TransformOrigin
|
import androidx.compose.ui.graphics.TransformOrigin
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.roundToIntRect
|
import androidx.compose.ui.unit.roundToIntRect
|
||||||
|
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import de.mm20.launcher2.search.File
|
import de.mm20.launcher2.search.File
|
||||||
import de.mm20.launcher2.search.FileMetaType
|
import de.mm20.launcher2.search.FileMetaType
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.animation.animateTextStyleAsState
|
|
||||||
import de.mm20.launcher2.ui.component.DefaultToolbarAction
|
import de.mm20.launcher2.ui.component.DefaultToolbarAction
|
||||||
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
|
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
|
||||||
import de.mm20.launcher2.ui.component.Toolbar
|
import de.mm20.launcher2.ui.component.Toolbar
|
||||||
@ -85,237 +84,272 @@ fun FileItem(
|
|||||||
val lifecycleOwner = LocalLifecycleOwner.current
|
val lifecycleOwner = LocalLifecycleOwner.current
|
||||||
val snackbarHostState = LocalSnackbarHostState.current
|
val snackbarHostState = LocalSnackbarHostState.current
|
||||||
|
|
||||||
val transition = updateTransition(showDetails, label = "ContactItem")
|
val icon by viewModel.icon.collectAsStateWithLifecycle()
|
||||||
|
val badge by viewModel.badge.collectAsState(null)
|
||||||
|
|
||||||
Column(
|
SharedTransitionLayout(
|
||||||
modifier = modifier
|
modifier = modifier,
|
||||||
) {
|
) {
|
||||||
Row(
|
AnimatedContent(showDetails) { showDetails ->
|
||||||
verticalAlignment = Alignment.Top
|
if (showDetails) {
|
||||||
) {
|
Column(
|
||||||
Column(
|
) {
|
||||||
modifier = Modifier
|
Row(
|
||||||
.weight(1f)
|
modifier = Modifier
|
||||||
.padding(16.dp)
|
.padding(
|
||||||
) {
|
top = 16.dp,
|
||||||
val textStyle by animateTextStyleAsState(
|
start = 16.dp,
|
||||||
if (showDetails) MaterialTheme.typography.titleMedium
|
end = 16.dp,
|
||||||
else MaterialTheme.typography.titleSmall
|
bottom = 8.dp
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = file.labelOverride ?: file.label,
|
|
||||||
style = textStyle,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
AnimatedVisibility(!showDetails) {
|
|
||||||
Text(
|
|
||||||
file.getFileType(context),
|
|
||||||
style = MaterialTheme.typography.bodySmall,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
modifier = Modifier.padding(top = 2.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
AnimatedVisibility(showDetails) {
|
|
||||||
Column {
|
|
||||||
val tags by viewModel.tags.collectAsState(emptyList())
|
|
||||||
if (tags.isNotEmpty()) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(top = 1.dp, bottom = 4.dp),
|
|
||||||
text = tags.joinToString(separator = " #", prefix = "#"),
|
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
|
||||||
style = MaterialTheme.typography.labelSmall
|
|
||||||
)
|
)
|
||||||
}
|
) {
|
||||||
Text(
|
Column(
|
||||||
text = stringResource(
|
modifier = Modifier.weight(1f)
|
||||||
R.string.file_meta_type,
|
) {
|
||||||
file.mimeType
|
|
||||||
),
|
|
||||||
style = MaterialTheme.typography.bodySmall,
|
|
||||||
)
|
|
||||||
for ((k, v) in file.metaData) {
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(k.labelRes, v),
|
modifier = Modifier.sharedBounds(
|
||||||
style = MaterialTheme.typography.bodySmall
|
rememberSharedContentState("label"),
|
||||||
|
this@AnimatedContent,
|
||||||
|
),
|
||||||
|
text = file.labelOverride ?: file.label,
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
}
|
val tags by viewModel.tags.collectAsState(emptyList())
|
||||||
Text(
|
if (tags.isNotEmpty()) {
|
||||||
text = stringResource(
|
Text(
|
||||||
R.string.file_meta_path,
|
modifier = Modifier.padding(top = 1.dp),
|
||||||
file.path
|
text = tags.joinToString(separator = " #", prefix = "#"),
|
||||||
),
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.labelSmall
|
||||||
)
|
)
|
||||||
if (!file.isDirectory) {
|
}
|
||||||
Text(
|
Text(
|
||||||
|
modifier = Modifier.padding(top = 8.dp),
|
||||||
text = stringResource(
|
text = stringResource(
|
||||||
R.string.file_meta_size,
|
R.string.file_meta_type,
|
||||||
formatFileSize(file.size)
|
file.mimeType
|
||||||
),
|
),
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
)
|
)
|
||||||
|
for ((k, v) in file.metaData) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(k.labelRes, v),
|
||||||
|
style = MaterialTheme.typography.bodySmall
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
R.string.file_meta_path,
|
||||||
|
file.path
|
||||||
|
),
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
)
|
||||||
|
if (!file.isDirectory) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
R.string.file_meta_size,
|
||||||
|
formatFileSize(file.size)
|
||||||
|
),
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ShapedLauncherIcon(
|
||||||
|
modifier = Modifier
|
||||||
|
.sharedElement(
|
||||||
|
rememberSharedContentState("icon"),
|
||||||
|
this@AnimatedContent,
|
||||||
|
),
|
||||||
|
size = 48.dp,
|
||||||
|
icon = { icon },
|
||||||
|
badge = { badge }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val toolbarActions = mutableListOf<ToolbarAction>()
|
||||||
|
|
||||||
|
if (LocalFavoritesEnabled.current) {
|
||||||
|
val isPinned by viewModel.isPinned.collectAsState(false)
|
||||||
|
val favAction = if (isPinned) {
|
||||||
|
DefaultToolbarAction(
|
||||||
|
label = stringResource(R.string.menu_favorites_unpin),
|
||||||
|
icon = Icons.Rounded.Star,
|
||||||
|
action = {
|
||||||
|
viewModel.unpin()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
DefaultToolbarAction(
|
||||||
|
label = stringResource(R.string.menu_favorites_pin),
|
||||||
|
icon = Icons.Rounded.StarOutline,
|
||||||
|
action = {
|
||||||
|
viewModel.pin()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
toolbarActions.add(favAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
toolbarActions.add(
|
||||||
|
DefaultToolbarAction(
|
||||||
|
label = stringResource(R.string.menu_open_file),
|
||||||
|
icon = Icons.Rounded.OpenInNew,
|
||||||
|
action = {
|
||||||
|
viewModel.launch(context)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (file.canShare) {
|
||||||
|
toolbarActions.add(DefaultToolbarAction(
|
||||||
|
label = stringResource(R.string.menu_share),
|
||||||
|
icon = Icons.Rounded.Share,
|
||||||
|
action = {
|
||||||
|
file.share(context)
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.isDeletable) {
|
||||||
|
var showConfirmDialog by remember { mutableStateOf(false) }
|
||||||
|
toolbarActions.add(DefaultToolbarAction(
|
||||||
|
label = stringResource(R.string.menu_delete),
|
||||||
|
icon = Icons.Rounded.Delete,
|
||||||
|
action = {
|
||||||
|
showConfirmDialog = true
|
||||||
|
}
|
||||||
|
))
|
||||||
|
if (showConfirmDialog) {
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = { showConfirmDialog = false },
|
||||||
|
confirmButton = {
|
||||||
|
TextButton(onClick = {
|
||||||
|
viewModel.delete(context)
|
||||||
|
showConfirmDialog = false
|
||||||
|
}) {
|
||||||
|
Text(stringResource(android.R.string.ok))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
TextButton(onClick = {
|
||||||
|
showConfirmDialog = false
|
||||||
|
}) {
|
||||||
|
Text(stringResource(android.R.string.cancel))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
if (file.isDirectory) stringResource(
|
||||||
|
R.string.alert_delete_directory,
|
||||||
|
file.label
|
||||||
|
)
|
||||||
|
else stringResource(R.string.alert_delete_file, file.label)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
val sheetManager = LocalBottomSheetManager.current
|
||||||
}
|
toolbarActions.add(DefaultToolbarAction(
|
||||||
|
label = stringResource(R.string.menu_customize),
|
||||||
|
icon = Icons.Rounded.Edit,
|
||||||
|
action = { sheetManager.showCustomizeSearchableModal(file) }
|
||||||
|
))
|
||||||
|
|
||||||
val icon by viewModel.icon.collectAsStateWithLifecycle()
|
val isHidden by viewModel.isHidden.collectAsState(false)
|
||||||
val badge by viewModel.badge.collectAsState(null)
|
val hideAction = if (isHidden) {
|
||||||
val padding by transition.animateDp(label = "iconPadding") {
|
|
||||||
if (it) 16.dp else 8.dp
|
|
||||||
}
|
|
||||||
ShapedLauncherIcon(
|
|
||||||
size = 48.dp,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(end = padding, top = padding, bottom = padding),
|
|
||||||
icon = { icon },
|
|
||||||
badge = { badge }
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedVisibility(showDetails) {
|
|
||||||
Column {
|
|
||||||
|
|
||||||
val toolbarActions = mutableListOf<ToolbarAction>()
|
|
||||||
|
|
||||||
if (LocalFavoritesEnabled.current) {
|
|
||||||
val isPinned by viewModel.isPinned.collectAsState(false)
|
|
||||||
val favAction = if (isPinned) {
|
|
||||||
DefaultToolbarAction(
|
DefaultToolbarAction(
|
||||||
label = stringResource(R.string.menu_favorites_unpin),
|
label = stringResource(R.string.menu_unhide),
|
||||||
icon = Icons.Rounded.Star,
|
icon = Icons.Rounded.Visibility,
|
||||||
action = {
|
action = {
|
||||||
viewModel.unpin()
|
viewModel.unhide()
|
||||||
|
onBack()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
DefaultToolbarAction(
|
DefaultToolbarAction(
|
||||||
label = stringResource(R.string.menu_favorites_pin),
|
label = stringResource(R.string.menu_hide),
|
||||||
icon = Icons.Rounded.StarOutline,
|
icon = Icons.Rounded.VisibilityOff,
|
||||||
action = {
|
action = {
|
||||||
viewModel.pin()
|
viewModel.hide()
|
||||||
|
onBack()
|
||||||
|
lifecycleOwner.lifecycleScope.launch {
|
||||||
|
val result = snackbarHostState.showSnackbar(
|
||||||
|
message = context.getString(
|
||||||
|
R.string.msg_item_hidden,
|
||||||
|
file.label
|
||||||
|
),
|
||||||
|
actionLabel = context.getString(R.string.action_undo),
|
||||||
|
duration = SnackbarDuration.Short,
|
||||||
|
)
|
||||||
|
if (result == SnackbarResult.ActionPerformed) {
|
||||||
|
viewModel.unhide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
toolbarActions.add(favAction)
|
toolbarActions.add(hideAction)
|
||||||
}
|
|
||||||
|
|
||||||
toolbarActions.add(
|
Toolbar(
|
||||||
DefaultToolbarAction(
|
leftActions = listOf(
|
||||||
label = stringResource(R.string.menu_open_file),
|
DefaultToolbarAction(
|
||||||
icon = Icons.Rounded.OpenInNew,
|
label = stringResource(id = R.string.menu_back),
|
||||||
action = {
|
icon = Icons.Rounded.ArrowBack
|
||||||
viewModel.launch(context)
|
) {
|
||||||
}
|
onBack()
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (file.canShare) {
|
|
||||||
toolbarActions.add(DefaultToolbarAction(
|
|
||||||
label = stringResource(R.string.menu_share),
|
|
||||||
icon = Icons.Rounded.Share,
|
|
||||||
action = {
|
|
||||||
file.share(context)
|
|
||||||
}
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file.isDeletable) {
|
|
||||||
var showConfirmDialog by remember { mutableStateOf(false) }
|
|
||||||
toolbarActions.add(DefaultToolbarAction(
|
|
||||||
label = stringResource(R.string.menu_delete),
|
|
||||||
icon = Icons.Rounded.Delete,
|
|
||||||
action = {
|
|
||||||
showConfirmDialog = true
|
|
||||||
}
|
|
||||||
))
|
|
||||||
if (showConfirmDialog) {
|
|
||||||
AlertDialog(
|
|
||||||
onDismissRequest = { showConfirmDialog = false },
|
|
||||||
confirmButton = {
|
|
||||||
TextButton(onClick = {
|
|
||||||
viewModel.delete(context)
|
|
||||||
showConfirmDialog = false
|
|
||||||
}) {
|
|
||||||
Text(stringResource(android.R.string.ok))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dismissButton = {
|
|
||||||
TextButton(onClick = {
|
|
||||||
showConfirmDialog = false
|
|
||||||
}) {
|
|
||||||
Text(stringResource(android.R.string.cancel))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Text(
|
|
||||||
if (file.isDirectory) stringResource(
|
|
||||||
R.string.alert_delete_directory,
|
|
||||||
file.label
|
|
||||||
)
|
|
||||||
else stringResource(R.string.alert_delete_file, file.label)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
),
|
||||||
|
rightActions = toolbarActions
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(
|
||||||
|
start = 16.dp,
|
||||||
|
top = 8.dp,
|
||||||
|
bottom = 8.dp,
|
||||||
|
end = 8.dp
|
||||||
|
),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.sharedBounds(
|
||||||
|
rememberSharedContentState("label"),
|
||||||
|
this@AnimatedContent,
|
||||||
|
),
|
||||||
|
text = file.labelOverride ?: file.label,
|
||||||
|
style = MaterialTheme.typography.titleSmall,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
file.getFileType(context),
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
modifier = Modifier.padding(top = 2.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val sheetManager = LocalBottomSheetManager.current
|
ShapedLauncherIcon(
|
||||||
toolbarActions.add(DefaultToolbarAction(
|
size = 48.dp,
|
||||||
label = stringResource(R.string.menu_customize),
|
modifier = Modifier
|
||||||
icon = Icons.Rounded.Edit,
|
.padding(8.dp)
|
||||||
action = { sheetManager.showCustomizeSearchableModal(file) }
|
.sharedElement(
|
||||||
))
|
rememberSharedContentState("icon"),
|
||||||
|
this@AnimatedContent,
|
||||||
val isHidden by viewModel.isHidden.collectAsState(false)
|
),
|
||||||
val hideAction = if (isHidden) {
|
icon = { icon },
|
||||||
DefaultToolbarAction(
|
badge = { badge }
|
||||||
label = stringResource(R.string.menu_unhide),
|
|
||||||
icon = Icons.Rounded.Visibility,
|
|
||||||
action = {
|
|
||||||
viewModel.unhide()
|
|
||||||
onBack()
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
DefaultToolbarAction(
|
|
||||||
label = stringResource(R.string.menu_hide),
|
|
||||||
icon = Icons.Rounded.VisibilityOff,
|
|
||||||
action = {
|
|
||||||
viewModel.hide()
|
|
||||||
onBack()
|
|
||||||
lifecycleOwner.lifecycleScope.launch {
|
|
||||||
val result = snackbarHostState.showSnackbar(
|
|
||||||
message = context.getString(
|
|
||||||
R.string.msg_item_hidden,
|
|
||||||
file.label
|
|
||||||
),
|
|
||||||
actionLabel = context.getString(R.string.action_undo),
|
|
||||||
duration = SnackbarDuration.Short,
|
|
||||||
)
|
|
||||||
if (result == SnackbarResult.ActionPerformed) {
|
|
||||||
viewModel.unhide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
toolbarActions.add(hideAction)
|
|
||||||
|
|
||||||
Toolbar(
|
|
||||||
leftActions = listOf(
|
|
||||||
DefaultToolbarAction(
|
|
||||||
label = stringResource(id = R.string.menu_back),
|
|
||||||
icon = Icons.Rounded.ArrowBack
|
|
||||||
) {
|
|
||||||
onBack()
|
|
||||||
}
|
|
||||||
),
|
|
||||||
rightActions = toolbarActions
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user