diff --git a/app/src/main/java/com/droiddeck/launcher/files/FileManagerItems.kt b/app/src/main/java/com/droiddeck/launcher/files/FileManagerItems.kt index caf3b5a71..8efe2c6cd 100644 --- a/app/src/main/java/com/droiddeck/launcher/files/FileManagerItems.kt +++ b/app/src/main/java/com/droiddeck/launcher/files/FileManagerItems.kt @@ -22,6 +22,7 @@ import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.ArrowUpward import androidx.compose.material.icons.filled.Checklist import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.FileCopy @@ -312,6 +313,47 @@ internal fun FileItemRow( } } +// The ".." row at the top of a folder: one level up, styled like a folder row so it reads as part +// of the list and takes controller focus the same way. +@Composable +internal fun ParentFolderRow(compact: Boolean = false, onTap: () -> Unit) { + Card( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp, vertical = 3.dp) + .clickable(onClick = onTap), + shape = RoundedCornerShape(10.dp), + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceContainer), + border = BorderStroke(1.dp, MaterialTheme.colorScheme.outline), + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(horizontal = 12.dp, vertical = if (compact) 3.dp else 8.dp), + ) { + Icon( + imageVector = Icons.Filled.ArrowUpward, + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(if (compact) 24.dp else 36.dp), + ) + Spacer(Modifier.width(10.dp)) + Column(modifier = Modifier.weight(1f)) { + Text( + text = "..", + color = MaterialTheme.colorScheme.onBackground, + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + ) + Text( + text = stringResource(R.string.fm_up_one_level), + color = MaterialTheme.colorScheme.onSurfaceVariant, + fontSize = 12.sp, + ) + } + } + } +} + // Dedicated Favorites list that replaces the file list while the star toggle is on. // Reads the store keyed on [favTick] so it recomposes after any pin/unpin. @Composable diff --git a/app/src/main/java/com/droiddeck/launcher/files/FileManagerScreen.kt b/app/src/main/java/com/droiddeck/launcher/files/FileManagerScreen.kt index be22e7d00..56556faba 100644 --- a/app/src/main/java/com/droiddeck/launcher/files/FileManagerScreen.kt +++ b/app/src/main/java/com/droiddeck/launcher/files/FileManagerScreen.kt @@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.GridItemSpan import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.rememberLazyListState @@ -143,7 +144,14 @@ fun FileManagerScreen( val name = abs.removePrefix("/storage/").substringBefore('/') if (name.isNotEmpty() && name != "emulated" && name != "self") File("/storage/$name") else rootDir } - else -> rootDir + // A game's own folder or Proton prefix lives in the app's private storage, which has no + // volume above it: floor at the app's files dir so up/back still reach the library roots. + else -> { + val appFiles = runCatching { context.filesDir.canonicalPath }.getOrNull() + generateSequence(rootDir) { it.parentFile } + .firstOrNull { appFiles != null && runCatching { it.canonicalPath }.getOrNull() == appFiles } + ?: rootDir + } } mutableStateOf(vol) } @@ -232,7 +240,9 @@ fun FileManagerScreen( loadDirectory(dir) } - LaunchedEffect(Unit) { openDrive(rootDir) } + // Open the start dir without openDrive(): that pins the floor to the start dir itself, which + // greyed out up/back whenever the manager was opened at a game's folder. + LaunchedEffect(Unit) { loadDirectory(rootDir) } // System/gesture Back: while the Favorites view is open it closes that first; otherwise // it goes up one directory. Only at the current drive's root with Favorites closed is it @@ -246,6 +256,14 @@ fun FileManagerScreen( if (parent != null && parent.exists()) loadDirectory(parent) } + // One level up, never above the current drive's root: shared by the toolbar arrow and the + // ".." row at the top of the list. + val canGoUp = currentDir != currentRoot && currentDir.parentFile?.exists() == true + fun goUp() { + val parent = currentDir.parentFile + if (currentDir != currentRoot && parent != null && parent.exists()) loadDirectory(parent) + } + // Resolve a non-colliding destination in [dir] for [name] (foo.txt -> "foo (1).txt"). fun uniqueDestination(dir: File, name: String): File { var candidate = File(dir, name) @@ -617,11 +635,7 @@ fun FileManagerScreen( .background(MaterialTheme.colorScheme.surfaceContainer) .padding(horizontal = 8.dp, vertical = 6.dp), ) { - IconButton(onClick = { - val parent = currentDir.parentFile - // Don't climb above the current drive's root. - if (currentDir != currentRoot && parent != null && parent.exists()) loadDirectory(parent) - }, enabled = currentDir != currentRoot) { + IconButton(onClick = { goUp() }, enabled = canGoUp) { Icon(Icons.Filled.ArrowBack, stringResource(R.string.fm_back), tint = MaterialTheme.colorScheme.primary) } @@ -1044,6 +1058,9 @@ fun FileManagerScreen( modifier = Modifier.fillMaxSize(), contentPadding = PaddingValues(8.dp), ) { + if (canGoUp) item(key = "..", span = { GridItemSpan(maxLineSpan) }) { + ParentFolderRow(compact = compactRows, onTap = { goUp() }) + } items(shownEntries, key = { it.absolutePath }) { file -> val isFav = remember(file.absolutePath, favTick) { FavoritesStore.isFavorite(context, file.absolutePath) @@ -1109,6 +1126,9 @@ fun FileManagerScreen( } } else LazyColumn(state = listState, modifier = Modifier.fillMaxSize()) { + if (canGoUp) item(key = "..") { + ParentFolderRow(compact = compactRows, onTap = { goUp() }) + } if (entries.isEmpty()) { item { Box( diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 6e3b9e004..a17a31e67 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1567,6 +1567,7 @@ Se quitó \"%1$s\" de Favoritos Carpeta vacía + Subir un nivel Elige una carpeta Elige un archivo diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 2255f73d4..0439c85ec 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -946,4 +946,5 @@ Choisir un dossier pour les fichiers du jeu frontal Fichiers du jeu enregistrés dans %1$s Fichiers frontaux + Remonter d\'un niveau \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 3102cb2ce..e22b96365 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -1531,6 +1531,7 @@ 「%1$s」をお気に入りから削除しました 空のフォルダ + 1つ上の階層へ フォルダを選択 ファイルを選択 diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index c6984ed04..04b781dac 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -1531,6 +1531,7 @@ \"%1$s\"을(를) 즐겨찾기에서 제거했습니다 빈 폴더 + 상위 폴더로 폴더 선택 파일 선택 diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 0013f3912..1504ef112 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -954,4 +954,5 @@ Выбрать папку для файлов игры фронтенда Файлы игры сохранены в %1$s Файлы фронтенда + На уровень вверх \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index b8b01c90e..cb7086432 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1531,6 +1531,7 @@ 已将“%1$s”从收藏夹移除 空文件夹 + 返回上一级 选择文件夹 选择文件 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index ac9b39950..2f14bbf6d 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -1531,6 +1531,7 @@ 已將「%1$s」從我的最愛移除 空白目錄 + 返回上一層 選擇資料夾 選擇檔案 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 0404e6c55..52bf7f3fe 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1531,6 +1531,7 @@ 已將「%1$s」從我的最愛移除 空的資料夾 + 返回上一層 選擇資料夾 選擇檔案 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 45a134090..add3b1128 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1481,6 +1481,7 @@ Removed \"%1$s\" from Favorites Empty directory + Up one level Choose a folder Choose a file