diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d6bf85ae4..c856f2f0a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [FIX] Fix empty response in faphub category - [FIX] New file manager uploading progress - [FIX] Fix build when no metrics enabled +- [Feature] Add count subfolders for new file manager # 1.8.0 Attention: don't forget to add the flag for F-Droid before release diff --git a/components/core/ui/ktx/src/commonMain/kotlin/com/flipperdevices/core/ui/ktx/PlaceholderKtx.kt b/components/core/ui/ktx/src/commonMain/kotlin/com/flipperdevices/core/ui/ktx/PlaceholderKtx.kt index d4e85c52e0..46c66c95a2 100644 --- a/components/core/ui/ktx/src/commonMain/kotlin/com/flipperdevices/core/ui/ktx/PlaceholderKtx.kt +++ b/components/core/ui/ktx/src/commonMain/kotlin/com/flipperdevices/core/ui/ktx/PlaceholderKtx.kt @@ -14,10 +14,13 @@ import io.github.fornewid.placeholder.foundation.placeholder import io.github.fornewid.placeholder.foundation.shimmer @Suppress("ModifierComposed") // MOB-1039 -fun Modifier.placeholderConnecting(shape: Int = 4) = composed { +fun Modifier.placeholderConnecting( + shape: Int = 4, + visible: Boolean = true +) = composed { this.then( placeholder( - visible = true, + visible = visible, shape = RoundedCornerShape(shape.dp), color = LocalPallet.current.placeholder.copy(alpha = 0.2f), highlight = PlaceholderHighlight.shimmer( diff --git a/components/filemngr/listing/impl/src/commonMain/composeResources/values/strings.xml b/components/filemngr/listing/impl/src/commonMain/composeResources/values/strings.xml index 352e96d6e9..4463a08004 100644 --- a/components/filemngr/listing/impl/src/commonMain/composeResources/values/strings.xml +++ b/components/filemngr/listing/impl/src/commonMain/composeResources/values/strings.xml @@ -23,6 +23,7 @@ File Manager + %1$s items No Files Yet Upload Files Select All diff --git a/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/composable/LoadedFilesComposable.kt b/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/composable/LoadedFilesComposable.kt index 2a196f0c18..fb10cf83ef 100644 --- a/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/composable/LoadedFilesComposable.kt +++ b/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/composable/LoadedFilesComposable.kt @@ -10,6 +10,7 @@ import androidx.compose.ui.Modifier import com.flipperdevices.bridge.connection.feature.storage.api.model.FileType import com.flipperdevices.core.ktx.jre.toFormattedSize import com.flipperdevices.core.preference.pb.FileManagerOrientation +import com.flipperdevices.filemanager.listing.impl.model.ExtendedListingItem import com.flipperdevices.filemanager.listing.impl.model.PathWithType import com.flipperdevices.filemanager.listing.impl.viewmodel.DeleteFilesViewModel import com.flipperdevices.filemanager.listing.impl.viewmodel.FilesViewModel @@ -19,9 +20,12 @@ import com.flipperdevices.filemanager.ui.components.itemcard.FolderCardPlacehold import com.flipperdevices.filemanager.ui.components.itemcard.components.asPainter import com.flipperdevices.filemanager.ui.components.itemcard.components.asTint import com.flipperdevices.filemanager.ui.components.itemcard.model.ItemUiSelectionState +import flipperapp.components.filemngr.listing.impl.generated.resources.fml_items_in_folder import okio.Path +import org.jetbrains.compose.resources.stringResource +import flipperapp.components.filemngr.listing.impl.generated.resources.Res as FML -@Suppress("FunctionNaming", "LongParameterList") +@Suppress("FunctionNaming", "LongParameterList", "LongMethod") fun LazyGridScope.LoadedFilesComposable( path: Path, deleteFileState: DeleteFilesViewModel.State, @@ -37,7 +41,7 @@ fun LazyGridScope.LoadedFilesComposable( ) { items(filesState.files) { file -> val isFileLoading = remember(deleteFileState.fileNamesOrNull) { - deleteFileState.fileNamesOrNull.orEmpty().contains(file.fileName) + deleteFileState.fileNamesOrNull.orEmpty().contains(file.itemName) } Crossfade(isFileLoading) { animatedIsFileLoading -> if (animatedIsFileLoading) { @@ -49,27 +53,37 @@ fun LazyGridScope.LoadedFilesComposable( orientation = orientation, ) } else { - val filePathWithType = remember(path, file.fileName) { - val fullPath = path.resolve(file.fileName) - PathWithType(file.fileType ?: FileType.FILE, fullPath) + val filePathWithType = remember(path, file.itemName) { + val fullPath = path.resolve(file.itemName) + PathWithType(file.itemType, fullPath) } FolderCardComposable( modifier = Modifier .fillMaxWidth() .animateItem() .animateContentSize(), - painter = file.asPainter(), - iconTint = file.asTint(), - title = file.fileName, + painter = file.asListingItem().asPainter(), + iconTint = file.asListingItem().asTint(), + title = file.itemName, canDeleteFiles = canDeleteFiles, - subtitle = file.size.toFormattedSize(), + subtitle = when (file) { + is ExtendedListingItem.File -> file.size.toFormattedSize() + is ExtendedListingItem.Folder -> stringResource( + resource = FML.string.fml_items_in_folder, + file.itemsCount ?: 0 + ) + }, + isSubtitleLoading = when (file) { + is ExtendedListingItem.File -> false + is ExtendedListingItem.Folder -> file.itemsCount == null + }, selectionState = when { selectionState.selected.contains(filePathWithType) -> ItemUiSelectionState.SELECTED selectionState.isEnabled -> ItemUiSelectionState.UNSELECTED else -> ItemUiSelectionState.NONE }, onClick = { - when (file.fileType) { + when (file.itemType) { FileType.DIR -> { onPathChanged.invoke(filePathWithType.fullPath) } @@ -77,13 +91,11 @@ fun LazyGridScope.LoadedFilesComposable( FileType.FILE -> { onEditFileClick(filePathWithType.fullPath) } - - null -> Unit } }, onCheckChange = { onCheckToggle.invoke(filePathWithType) }, onMoreClick = { onFileMoreClick.invoke(filePathWithType) }, - onDelete = { onDelete.invoke(path.resolve(file.fileName)) }, + onDelete = { onDelete.invoke(path.resolve(file.itemName)) }, orientation = orientation ) } diff --git a/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/composable/appbar/FileListAppBar.kt b/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/composable/appbar/FileListAppBar.kt index 2bb94bd6a4..854467e28a 100644 --- a/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/composable/appbar/FileListAppBar.kt +++ b/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/composable/appbar/FileListAppBar.kt @@ -70,8 +70,8 @@ fun FileListAppBar( .orEmpty() .map { PathWithType( - fileType = it.fileType ?: FileType.FILE, - fullPath = path.resolve(it.fileName) + fileType = it.itemType, + fullPath = path.resolve(it.itemName) ) } selectionViewModel.select(paths) diff --git a/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/model/ExtendedListingItem.kt b/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/model/ExtendedListingItem.kt new file mode 100644 index 0000000000..c9a92778cb --- /dev/null +++ b/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/model/ExtendedListingItem.kt @@ -0,0 +1,46 @@ +package com.flipperdevices.filemanager.listing.impl.model + +import com.flipperdevices.bridge.connection.feature.storage.api.model.FileType +import com.flipperdevices.bridge.connection.feature.storage.api.model.ListingItem +import okio.Path + +sealed interface ExtendedListingItem { + /** + * Local file-only path + * example: file.txt, item.svg + */ + val path: Path + + val itemType: FileType + + val itemName: String + get() = path.name + + fun asListingItem() = ListingItem( + fileName = itemName, + fileType = itemType, + size = (this as? File)?.size ?: 0 + ) + + /** + * @param path file name path. Not full path + * @param size file size in bytes + */ + data class File( + override val path: Path, + val size: Long + ) : ExtendedListingItem { + override val itemType: FileType = FileType.FILE + } + + /** + * @param path file name path. Not full path + * @param itemsCount amount of items inside + */ + data class Folder( + override val path: Path, + val itemsCount: Int? = null, + ) : ExtendedListingItem { + override val itemType: FileType = FileType.DIR + } +} diff --git a/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/viewmodel/FilesViewModel.kt b/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/viewmodel/FilesViewModel.kt index 6e908971a1..d1e3179262 100644 --- a/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/viewmodel/FilesViewModel.kt +++ b/components/filemngr/listing/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/listing/impl/viewmodel/FilesViewModel.kt @@ -7,14 +7,17 @@ import com.flipperdevices.bridge.connection.feature.provider.api.get import com.flipperdevices.bridge.connection.feature.provider.api.getSync import com.flipperdevices.bridge.connection.feature.storage.api.FStorageFeatureApi import com.flipperdevices.bridge.connection.feature.storage.api.fm.FListingStorageApi +import com.flipperdevices.bridge.connection.feature.storage.api.model.FileType import com.flipperdevices.bridge.connection.feature.storage.api.model.ListingItem import com.flipperdevices.core.ktx.jre.launchWithLock import com.flipperdevices.core.ktx.jre.toThrowableFlow import com.flipperdevices.core.ktx.jre.withLock import com.flipperdevices.core.log.LogTagProvider +import com.flipperdevices.core.log.error import com.flipperdevices.core.preference.pb.FileManagerSort import com.flipperdevices.core.preference.pb.Settings import com.flipperdevices.core.ui.lifecycle.DecomposeViewModel +import com.flipperdevices.filemanager.listing.impl.model.ExtendedListingItem import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -24,12 +27,17 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChangedBy +import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update +import kotlinx.coroutines.flow.updateAndGet import kotlinx.coroutines.sync.Mutex import okio.Path +import okio.Path.Companion.toPath class FilesViewModel @AssistedInject constructor( private val featureProvider: FFeatureProvider, @@ -56,7 +64,7 @@ class FilesViewModel @AssistedInject constructor( if (settings.show_hidden_files_on_flipper) { true } else { - !it.fileName.startsWith(".") + !it.path.name.startsWith(".") } } .sortedByDescending { @@ -64,7 +72,14 @@ class FilesViewModel @AssistedInject constructor( is FileManagerSort.Unrecognized, FileManagerSort.DEFAULT -> null - FileManagerSort.SIZE -> it.size + FileManagerSort.SIZE -> { + when (it) { + is ExtendedListingItem.File -> it.size + // The default size for folder is 0 + // Here's placed 0 so sort works as on flipper + is ExtendedListingItem.Folder -> 0 + } + } } } .toImmutableList() @@ -74,12 +89,62 @@ class FilesViewModel @AssistedInject constructor( } ).stateIn(viewModelScope, SharingStarted.Eagerly, State.Loading) + private suspend fun updateFiles( + items: List, + listingApi: FListingStorageApi + ) { + items + .filterIsInstance() + .filter { directory -> directory.itemsCount == null } + .onEach { directory -> + _state.update { state -> + val loadedState = (state as? State.Loaded) + if (loadedState == null) { + error { "#updateFiles state changed during update" } + return@update state + } + val newList = loadedState.files.toMutableList() + val i = newList.indexOfFirst { item -> item == directory } + if (i == -1) { + error { "#updateFiles could not find item in list" } + return@update loadedState + } + val itemsCount = listingApi.ls(path.resolve(directory.path).toString()) + .getOrNull() + .orEmpty() + .size + val updatedDirectory = directory.copy(itemsCount = itemsCount) + newList[i] = updatedDirectory + loadedState.copy(files = newList.toImmutableList()) + } + } + } + + private fun ListingItem.toExtended(): ExtendedListingItem { + return when (fileType) { + FileType.DIR -> { + ExtendedListingItem.Folder( + path = fileName.toPath(), + itemsCount = null + ) + } + + null, FileType.FILE -> { + ExtendedListingItem.File( + path = fileName.toPath(), + size = size + ) + } + } + } + private suspend fun listFiles(listingApi: FListingStorageApi) { listingApi.lsFlow(path.toString()) .toThrowableFlow() .catch { _state.emit(State.CouldNotListPath) } + .map { items -> items.map { item -> item.toExtended() } } .onEach { files -> - _state.update { state -> + _state.updateAndGet { state -> when (state) { is State.Loaded -> { state.copy(state.files.plus(files).toImmutableList()) @@ -97,7 +162,7 @@ class FilesViewModel @AssistedInject constructor( val loadedState = _state.value as? State.Loaded ?: return _state.update { val newFileList = loadedState.files - .filter { it.fileName != path.name } + .filter { it.path.name != path.name } .toImmutableList() loadedState.copy(files = newFileList) } @@ -120,8 +185,8 @@ class FilesViewModel @AssistedInject constructor( (state as? State.Loaded)?.let { loadedState -> val newItemsNames = items.map(ListingItem::fileName) val newFiles = loadedState.files - .filter { item -> !newItemsNames.contains(item.fileName) } - .plus(items) + .filter { item -> !newItemsNames.contains(item.itemName) } + .plus(items.map { item -> item.toExtended() }) .toImmutableList() loadedState.copy(files = newFiles) } ?: state @@ -152,6 +217,20 @@ class FilesViewModel @AssistedInject constructor( .get() .onEach { featureStatus -> invalidate(featureStatus) } .launchIn(viewModelScope) + combine( + flow = featureProvider + .get() + .filterIsInstance>(), + flow2 = state + .filterIsInstance() + .distinctUntilChangedBy { it.files.size }, + transform = { feature, state -> + updateFiles( + items = state.files, + listingApi = feature.featureApi.listingApi() + ) + } + ).launchIn(viewModelScope) } sealed interface State { @@ -159,7 +238,7 @@ class FilesViewModel @AssistedInject constructor( data object Unsupported : State data object CouldNotListPath : State data class Loaded( - val files: ImmutableList, + val files: ImmutableList, ) : State } diff --git a/components/filemngr/search/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/search/impl/composable/FolderCardListLazyComposable.kt b/components/filemngr/search/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/search/impl/composable/FolderCardListLazyComposable.kt index c84b770d28..116ce9ba74 100644 --- a/components/filemngr/search/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/search/impl/composable/FolderCardListLazyComposable.kt +++ b/components/filemngr/search/impl/src/commonMain/kotlin/com/flipperdevices/filemanager/search/impl/composable/FolderCardListLazyComposable.kt @@ -29,6 +29,7 @@ fun LazyListScope.FolderCardListLazyComposable( subtitle = file.fullPath.parent ?.toString() ?: file.instance.size.toFormattedSize(), + isSubtitleLoading = false, selectionState = ItemUiSelectionState.NONE, onClick = { when (file.instance.fileType) { diff --git a/components/filemngr/ui-components/src/androidMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardGridComposablePreview.kt b/components/filemngr/ui-components/src/androidMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardGridComposablePreview.kt index a1478b4dcb..7f575e7a80 100644 --- a/components/filemngr/ui-components/src/androidMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardGridComposablePreview.kt +++ b/components/filemngr/ui-components/src/androidMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardGridComposablePreview.kt @@ -24,7 +24,8 @@ private fun FolderCardGridComposablePreview() { selectionState = selectionState, onClick = {}, onCheckChange = {}, - onMoreClick = {} + onMoreClick = {}, + isSubtitleLoading = false ) } ItemUiSelectionState.entries.forEach { selectionState -> @@ -35,7 +36,20 @@ private fun FolderCardGridComposablePreview() { selectionState = selectionState, onClick = {}, onCheckChange = {}, - onMoreClick = {} + onMoreClick = {}, + isSubtitleLoading = false + ) + } + ItemUiSelectionState.entries.forEach { selectionState -> + FolderCardGridComposable( + painter = painterResource(FR.drawable.ic_folder_black), + title = "A very very ultra mega super duper log title with some message at the end", + subtitle = "A very very ultra mega super duper log title with some message at the end", + selectionState = selectionState, + onClick = {}, + onCheckChange = {}, + onMoreClick = {}, + isSubtitleLoading = true ) } } diff --git a/components/filemngr/ui-components/src/androidMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardListComposablePreview.kt b/components/filemngr/ui-components/src/androidMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardListComposablePreview.kt index cbb5d4c555..09ec1ba252 100644 --- a/components/filemngr/ui-components/src/androidMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardListComposablePreview.kt +++ b/components/filemngr/ui-components/src/androidMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardListComposablePreview.kt @@ -24,6 +24,7 @@ private fun FolderCardListComposablePreview() { painter = painterResource(FR.drawable.ic_folder_black), title = "Short title", subtitle = "Short SubTitle", + isSubtitleLoading = false, selectionState = selectionState, canDeleteFiles = true, onClick = {}, @@ -39,6 +40,21 @@ private fun FolderCardListComposablePreview() { subtitle = "A very very ultra mega super duper log title with some message at the end", selectionState = selectionState, canDeleteFiles = true, + isSubtitleLoading = false, + onClick = {}, + onCheckChange = {}, + onMoreClick = {}, + onDelete = {} + ) + } + ItemUiSelectionState.entries.forEach { selectionState -> + SwipeToDismissFolderCardListComposable( + painter = rememberVectorPainter(Icons.Filled.Folder), + title = "A very very ultra mega super duper log title with some message at the end", + subtitle = "A very very ultra mega super duper log title with some message at the end", + selectionState = selectionState, + canDeleteFiles = true, + isSubtitleLoading = true, onClick = {}, onCheckChange = {}, onMoreClick = {}, diff --git a/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardComposable.kt b/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardComposable.kt index c56096726d..236ee52f5b 100644 --- a/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardComposable.kt +++ b/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardComposable.kt @@ -12,6 +12,7 @@ fun FolderCardComposable( painter: Painter, title: String, subtitle: String, + isSubtitleLoading: Boolean, selectionState: ItemUiSelectionState, canDeleteFiles: Boolean, onClick: () -> Unit, @@ -28,6 +29,7 @@ fun FolderCardComposable( painter = painter, title = title, subtitle = subtitle, + isSubtitleLoading = isSubtitleLoading, selectionState = selectionState, onClick = onClick, onCheckChange = onCheckChange, @@ -43,6 +45,7 @@ fun FolderCardComposable( painter = painter, title = title, subtitle = subtitle, + isSubtitleLoading = isSubtitleLoading, selectionState = selectionState, onClick = onClick, onCheckChange = onCheckChange, diff --git a/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardGridComposable.kt b/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardGridComposable.kt index 8f068dc2b6..34a3c010f0 100644 --- a/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardGridComposable.kt +++ b/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardGridComposable.kt @@ -29,6 +29,7 @@ fun FolderCardGridComposable( painter: Painter, title: String, subtitle: String, + isSubtitleLoading: Boolean, selectionState: ItemUiSelectionState, onClick: () -> Unit, onCheckChange: (Boolean) -> Unit, @@ -62,7 +63,10 @@ fun FolderCardGridComposable( horizontalAlignment = Alignment.Start ) { ItemCardTitle(title) - ItemCardSubtitle(subtitle) + ItemCardSubtitle( + text = subtitle, + isLoading = isSubtitleLoading + ) } } diff --git a/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardListComposable.kt b/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardListComposable.kt index 79e47eb3f9..fda29be805 100644 --- a/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardListComposable.kt +++ b/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/FolderCardListComposable.kt @@ -37,6 +37,7 @@ fun SwipeToDismissFolderCardListComposable( painter: Painter, title: String, subtitle: String, + isSubtitleLoading: Boolean, selectionState: ItemUiSelectionState, canDeleteFiles: Boolean, onClick: () -> Unit, @@ -63,6 +64,7 @@ fun SwipeToDismissFolderCardListComposable( onMoreClick = onMoreClick, onClick = onClick, iconTint = iconTint, + isSubtitleLoading = isSubtitleLoading ) }, actions = { @@ -104,6 +106,7 @@ fun FolderCardListComposable( painter: Painter, title: String, subtitle: String, + isSubtitleLoading: Boolean, selectionState: ItemUiSelectionState, onClick: () -> Unit, onCheckChange: (Boolean) -> Unit, @@ -138,7 +141,10 @@ fun FolderCardListComposable( horizontalAlignment = Alignment.Start ) { ItemCardTitle(title) - ItemCardSubtitle(subtitle) + ItemCardSubtitle( + text = subtitle, + isLoading = isSubtitleLoading + ) } } diff --git a/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/components/ItemCardSubtitle.kt b/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/components/ItemCardSubtitle.kt index 5853e0c7c9..386d5d3ae1 100644 --- a/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/components/ItemCardSubtitle.kt +++ b/components/filemngr/ui-components/src/commonMain/kotlin/com/flipperdevices/filemanager/ui/components/itemcard/components/ItemCardSubtitle.kt @@ -2,12 +2,20 @@ package com.flipperdevices.filemanager.ui.components.itemcard.components import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.flipperdevices.core.ui.ktx.placeholderConnecting import com.flipperdevices.core.ui.theme.LocalPalletV2 import com.flipperdevices.core.ui.theme.LocalTypography @Composable -internal fun ItemCardSubtitle(text: String) { +internal fun ItemCardSubtitle( + text: String, + isLoading: Boolean, + modifier: Modifier = Modifier +) { Text( + modifier = modifier + .placeholderConnecting(visible = isLoading), text = text, style = LocalTypography.current.subtitleM10, color = LocalPalletV2.current.text.label.secondary