Skip to content

Unwrap FilesDesign#121

Merged
Goooler merged 1 commit intotrunkfrom
unwrap-files-design
Apr 26, 2026
Merged

Unwrap FilesDesign#121
Goooler merged 1 commit intotrunkfrom
unwrap-files-design

Conversation

@Goooler
Copy link
Copy Markdown
Owner

@Goooler Goooler commented Apr 23, 2026

Refs #119.

@Goooler Goooler force-pushed the unwrap-files-design branch 5 times, most recently from f866c4c to f74390a Compare April 26, 2026 11:38
@Goooler Goooler force-pushed the unwrap-files-design branch from f74390a to ca6205d Compare April 26, 2026 11:41
@Goooler Goooler merged commit 9faf7b4 into trunk Apr 26, 2026
2 checks passed
@Goooler Goooler deleted the unwrap-files-design branch April 26, 2026 11:42
Goooler added a commit that referenced this pull request Apr 26, 2026
@Goooler Goooler requested a review from Copilot April 27, 2026 00:33
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR follows issue #119’s goal of splitting the prior Design-based implementation into a @Composable screen + ViewModel, specifically for the Files feature.

Changes:

  • Introduces FilesViewModel to own file browsing state and one-off UI events.
  • Refactors the UI into FilesScreen/FilesContent composables and wires ActivityResult launchers/events.
  • Simplifies FilesActivity to a BaseActivity that only hosts Compose content.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
app/src/main/kotlin/com/github/kr328/clash/files/vm/FilesViewModel.kt New ViewModel for listing/navigating/importing/exporting/renaming/deleting files and emitting UI events.
app/src/main/kotlin/com/github/kr328/clash/files/ui/FilesScreen.kt Replaces FilesDesign with composables; connects UI interactions to the ViewModel and ActivityResult APIs.
app/src/main/kotlin/com/github/kr328/clash/files/FilesActivity.kt Replaces DesignActivity loop with Compose setContent hosting FilesScreen.
Comments suppressed due to low confidence (2)

app/src/main/kotlin/com/github/kr328/clash/files/ui/FilesScreen.kt:110

  • openFileLauncher.launch(...) can throw (e.g., ActivityNotFoundException if no app can handle ACTION_VIEW for the given URI/type). Previously this was wrapped in a try/catch and surfaced to the user. Consider catching launch failures and emitting ShowMessage/toast instead of crashing.
    app/src/main/kotlin/com/github/kr328/clash/files/ui/FilesScreen.kt:206
  • BackHandler is always enabled and is registered after the ModalBottomSheet/dialog UI. This can intercept the system back press and trigger navigation (onBack) instead of dismissing the bottom sheet (or the rename dialog) first. Consider enabling the handler only when no transient UI is showing, or handling back by first clearing menuFile/renameFile and only then calling onBack.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

eventState.value = EventState.Finish
return@launch
}
uiState.update { it.copy(configurationEditable = profile.type != Profile.Type.File) }
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

configurationEditable logic changed from the previous implementation (was based on Profile.Type.Url). This alters when imports into the base config.yaml are allowed; if the intent of this PR is only to unwrap the design, please keep the old condition or document/justify the behavior change.

Suggested change
uiState.update { it.copy(configurationEditable = profile.type != Profile.Type.File) }
uiState.update { it.copy(configurationEditable = profile.type == Profile.Type.Url) }

Copilot uses AI. Check for mistakes.
Comment on lines +135 to +140
private fun fetch() {
// Snapshot stack state on the main thread before switching to IO
val documentId = stack.lastOrNull() ?: root
val inBaseDir = stack.isEmpty()
viewModelScope.launch(Dispatchers.IO) {
if (root.isEmpty()) return@launch
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stack is a mutable ArrayDeque and fetch() reads it before launching IO work, but fetch() is invoked from IO coroutines (e.g., after delete/rename/import/export). That means stack can be accessed concurrently from main/UI callbacks (onOpen/onBack) and background threads, which is not thread-safe. Consider ensuring all stack access happens on the main thread (e.g., snapshot with withContext(Dispatchers.Main) and only then switch to IO) or guard it with a Mutex, and avoid calling fetch() directly from IO contexts.

Copilot uses AI. Check for mistakes.
Comment on lines +139 to +155
viewModelScope.launch(Dispatchers.IO) {
if (root.isEmpty()) return@launch
try {
val files =
if (inBaseDir) {
val list = client.list(documentId)
val config = list.firstOrNull { it.id.endsWith("config.yaml") }
if (config == null || config.size > 0) list else listOf(config)
} else {
client.list(documentId)
}

uiState.update { it.copy(files = files, currentInBaseDir = inBaseDir) }
} catch (e: Exception) {
eventState.value = EventState.ShowMessage(e.message ?: "Unknown error")
}
}
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fetch() launches a new coroutine every time without cancelling/serializing previous fetches. Quick navigation (open dir/back) can result in out-of-order responses updating uiState with a stale directory listing. Other ViewModels in this repo use a fetchJob?.cancel() pattern; consider doing the same here (or use flatMapLatest/channelFlow) so only the latest fetch updates state.

Copilot uses AI. Check for mistakes.
Comment thread app/src/main/kotlin/com/github/kr328/clash/files/FilesActivity.kt
Copilot AI added a commit that referenced this pull request Apr 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants