Skip to content

Commit 77f76af

Browse files
committed
Fix FilesPage last selected path
1 parent d537f83 commit 77f76af

File tree

3 files changed

+92
-14
lines changed

3 files changed

+92
-14
lines changed

app/src/main/java/com/ismartcoding/plain/ui/models/FilesViewModel.kt

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ import com.ismartcoding.lib.extensions.getParentPath
1212
import com.ismartcoding.lib.extensions.scanFileByConnection
1313
import com.ismartcoding.lib.helpers.CoroutinesHelper.withIO
1414
import com.ismartcoding.plain.MainApp
15+
import com.ismartcoding.plain.R
1516
import com.ismartcoding.plain.enums.FilesType
1617
import com.ismartcoding.plain.features.file.DFile
1718
import com.ismartcoding.plain.features.file.FileSortBy
1819
import com.ismartcoding.plain.features.file.FileSystemHelper
20+
import com.ismartcoding.plain.features.locale.LocaleHelper
1921
import com.ismartcoding.plain.features.media.FileMediaStoreHelper
2022
import com.ismartcoding.plain.preference.FilePathData
2123
import com.ismartcoding.plain.preference.LastFilePathPreference
@@ -60,7 +62,7 @@ class FilesViewModel : ISearchableViewModel<DFile>, ISelectableViewModel<DFile>,
6062
}
6163
}
6264

63-
val breadcrumbs = mutableStateListOf(BreadcrumbItem(FileSystemHelper.getInternalStorageName(), root))
65+
val breadcrumbs = mutableStateListOf<BreadcrumbItem>()
6466
val selectedBreadcrumbIndex = mutableIntStateOf(0)
6567
var cutFiles = mutableListOf<DFile>()
6668
var copyFiles = mutableListOf<DFile>()
@@ -71,6 +73,11 @@ class FilesViewModel : ISearchableViewModel<DFile>, ISelectableViewModel<DFile>,
7173

7274
private val navigationHistory = Stack<String>()
7375

76+
init {
77+
// Initialize with default breadcrumb - will be updated when loadLastPathAsync is called
78+
breadcrumbs.add(BreadcrumbItem(getRootDisplayName(), root))
79+
}
80+
7481
val selectedFile = mutableStateOf<DFile?>(null)
7582
val showRenameDialog = mutableStateOf(false)
7683

@@ -125,6 +132,8 @@ class FilesViewModel : ISearchableViewModel<DFile>, ISelectableViewModel<DFile>,
125132
val data = LastFilePathPreference.getValueAsync(context)
126133
if (data.selectedPath.isNotEmpty() && File(data.selectedPath).exists()) {
127134
root = data.rootPath
135+
// Infer the file system type from the root path
136+
type = inferFileTypeFromRoot(context, data.rootPath)
128137
// Restore complete breadcrumbs from fullPath
129138
rebuildBreadcrumbs(data.fullPath)
130139
_path = data.selectedPath
@@ -134,12 +143,31 @@ class FilesViewModel : ISearchableViewModel<DFile>, ISelectableViewModel<DFile>,
134143
selectedBreadcrumbIndex.value = breadcrumbs.size - 1
135144
}
136145
navigationHistory.clear()
146+
} else {
147+
// No saved path, but still infer the type based on current root
148+
type = inferFileTypeFromRoot(context, root)
149+
updateRootBreadcrumb()
150+
}
151+
}
152+
153+
private fun inferFileTypeFromRoot(context: Context, rootPath: String): FilesType {
154+
val internalStoragePath = FileSystemHelper.getInternalStoragePath()
155+
val appDataPath = FileSystemHelper.getExternalFilesDirPath(context)
156+
val sdCardPath = FileSystemHelper.getSDCardPath(context)
157+
val usbPaths = FileSystemHelper.getUsbDiskPaths()
158+
159+
return when {
160+
rootPath == appDataPath -> FilesType.APP
161+
rootPath == sdCardPath -> FilesType.SDCARD
162+
usbPaths.contains(rootPath) -> FilesType.USB_STORAGE
163+
rootPath == internalStoragePath -> FilesType.INTERNAL_STORAGE
164+
else -> FilesType.INTERNAL_STORAGE // default fallback
137165
}
138166
}
139167

140168
private fun rebuildBreadcrumbs(targetPath: String) {
141169
breadcrumbs.clear()
142-
breadcrumbs.add(BreadcrumbItem(FileSystemHelper.getInternalStorageName(), root))
170+
breadcrumbs.add(BreadcrumbItem(getRootDisplayName(), root))
143171

144172
if (targetPath != root) {
145173
val relativePath = targetPath.removePrefix(root).trim('/')
@@ -155,6 +183,22 @@ class FilesViewModel : ISearchableViewModel<DFile>, ISelectableViewModel<DFile>,
155183
selectedBreadcrumbIndex.value = breadcrumbs.size - 1
156184
}
157185

186+
fun getRootDisplayName(): String {
187+
return when (type) {
188+
FilesType.INTERNAL_STORAGE -> FileSystemHelper.getInternalStorageName()
189+
FilesType.APP -> LocaleHelper.getString(R.string.app_data)
190+
FilesType.SDCARD -> LocaleHelper.getString(R.string.sdcard)
191+
FilesType.USB_STORAGE -> LocaleHelper.getString(R.string.usb_storage)
192+
FilesType.RECENTS -> LocaleHelper.getString(R.string.recents)
193+
}
194+
}
195+
196+
fun updateRootBreadcrumb() {
197+
if (breadcrumbs.isNotEmpty()) {
198+
breadcrumbs[0] = BreadcrumbItem(getRootDisplayName(), root)
199+
}
200+
}
201+
158202
// Check if we can navigate back
159203
fun canNavigateBack(): Boolean {
160204
return navigationHistory.isNotEmpty()

app/src/main/java/com/ismartcoding/plain/ui/page/TextFilePage.kt

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
package com.ismartcoding.plain.ui.page
22

33
import androidx.activity.compose.BackHandler
4+
import androidx.compose.animation.core.animateFloatAsState
5+
import androidx.compose.animation.core.tween
46
import androidx.compose.foundation.layout.Column
57
import androidx.compose.foundation.layout.padding
68
import androidx.compose.material3.ExperimentalMaterial3Api
79
import androidx.compose.material3.MaterialTheme
810
import androidx.compose.runtime.Composable
911
import androidx.compose.runtime.LaunchedEffect
12+
import androidx.compose.runtime.getValue
13+
import androidx.compose.runtime.mutableStateOf
14+
import androidx.compose.runtime.remember
1015
import androidx.compose.runtime.rememberCoroutineScope
16+
import androidx.compose.runtime.setValue
1117
import androidx.compose.ui.Modifier
18+
import androidx.compose.ui.draw.rotate
1219
import androidx.compose.ui.platform.LocalContext
20+
import androidx.compose.ui.platform.LocalFocusManager
21+
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
1322
import androidx.compose.ui.res.stringResource
1423
import androidx.lifecycle.viewmodel.compose.viewModel
1524
import androidx.navigation.NavHostController
@@ -35,6 +44,7 @@ import com.ismartcoding.plain.ui.components.EditorData
3544
import com.ismartcoding.plain.ui.helpers.DialogHelper
3645
import com.ismartcoding.plain.ui.models.TextFileViewModel
3746
import kotlinx.coroutines.Dispatchers
47+
import kotlinx.coroutines.delay
3848
import kotlinx.coroutines.launch
3949
import java.io.File
4050

@@ -52,6 +62,15 @@ fun TextFilePage(
5262
val scope = rememberCoroutineScope()
5363
val darkTheme = LocalDarkTheme.current
5464
val isDarkTheme = DarkTheme.isDarkTheme(darkTheme)
65+
val keyboardController = LocalSoftwareKeyboardController.current
66+
val focusManager = LocalFocusManager.current
67+
68+
var isSaving by remember { mutableStateOf(false) }
69+
val rotation by animateFloatAsState(
70+
targetValue = if (isSaving) 360f else 0f,
71+
animationSpec = tween(durationMillis = 600),
72+
label = "save_rotation"
73+
)
5574

5675
LaunchedEffect(Unit) {
5776
scope.launch(Dispatchers.IO) {
@@ -107,7 +126,8 @@ fun TextFilePage(
107126
PIconButton(
108127
icon = R.drawable.save,
109128
contentDescription = stringResource(R.string.save),
110-
tint = MaterialTheme.colorScheme.onSurface,
129+
tint = if (isSaving) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface,
130+
modifier = Modifier.rotate(rotation),
111131
) {
112132
scope.launch {
113133
// Prevent saving external files (content URIs)
@@ -116,12 +136,22 @@ fun TextFilePage(
116136
return@launch
117137
}
118138

139+
// Close keyboard and clear focus
140+
keyboardController?.hide()
141+
focusManager.clearFocus()
142+
143+
// Start saving animation
144+
isSaving = true
145+
119146
DialogHelper.showLoading()
120147
withIO { File(path).writeText(textFileVM.content.value) }
121148
textFileVM.oldContent.value = textFileVM.content.value
122149
context.scanFileByConnection(path)
123150
DialogHelper.hideLoading()
124-
DialogHelper.showMessage(R.string.saved)
151+
152+
// Wait for animation to complete
153+
delay(600)
154+
isSaving = false
125155
}
126156
}
127157
}

app/src/main/java/com/ismartcoding/plain/ui/page/files/FilesPage.kt

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ import kotlinx.coroutines.withContext
8585
@Composable
8686
fun FilesPage(
8787
navController: NavHostController,
88-
fileType: FilesType = FilesType.INTERNAL_STORAGE,
88+
fileType: FilesType? = null,
8989
audioPlaylistVM: AudioPlaylistViewModel,
9090
filesVM: FilesViewModel = viewModel(),
9191
) {
@@ -145,12 +145,16 @@ fun FilesPage(
145145
LaunchedEffect(fileType) {
146146
scope.launch(Dispatchers.IO) {
147147
filesVM.loadLastPathAsync(context)
148-
if (fileType == FilesType.APP) {
149-
filesVM.root = FileSystemHelper.getExternalFilesDirPath(context)
150-
filesVM.breadcrumbs.clear()
151-
filesVM.breadcrumbs.add(BreadcrumbItem(LocaleHelper.getString(R.string.app_data), filesVM.root))
152-
filesVM.initPath(filesVM.root)
153-
filesVM.type = FilesType.APP
148+
// Only override the inferred type if explicitly passed
149+
fileType?.let { type ->
150+
if (type == FilesType.APP) {
151+
filesVM.root = FileSystemHelper.getExternalFilesDirPath(context)
152+
filesVM.type = FilesType.APP
153+
filesVM.breadcrumbs.clear()
154+
filesVM.breadcrumbs.add(BreadcrumbItem(filesVM.getRootDisplayName(), filesVM.root))
155+
filesVM.initPath(filesVM.root)
156+
}
157+
// Add other specific file type handling here if needed
154158
}
155159
filesVM.loadAsync(context)
156160
audioPlaylistVM.loadAsync(context)
@@ -170,16 +174,16 @@ fun FilesPage(
170174
val m = event.model
171175
filesVM.offset = 0
172176
filesVM.root = m.data as String
173-
filesVM.breadcrumbs.clear()
174-
filesVM.breadcrumbs.add(BreadcrumbItem(m.title, filesVM.root))
175-
filesVM.initPath(filesVM.root)
176177
filesVM.type = when (m.iconId) {
177178
R.drawable.sd_card -> FilesType.SDCARD
178179
R.drawable.usb -> FilesType.USB_STORAGE
179180
R.drawable.app_icon -> FilesType.APP
180181
R.drawable.history -> FilesType.RECENTS
181182
else -> FilesType.INTERNAL_STORAGE
182183
}
184+
filesVM.breadcrumbs.clear()
185+
filesVM.breadcrumbs.add(BreadcrumbItem(filesVM.getRootDisplayName(), filesVM.root))
186+
filesVM.initPath(filesVM.root)
183187

184188
scope.launch(Dispatchers.IO) {
185189
filesVM.loadAsync(context)

0 commit comments

Comments
 (0)