feat: add Files tab backed by the managed-files endpoint (#727)
* feat: add Files tab backed by the managed-files endpoint Add a Hermes Mobile tab that browses the gateway's managed-files root via the existing /api/files* backend routes: list/navigate folders, breadcrumb path, create folder, upload (streaming multipart), delete, and open files via the authenticated GatewayFileClient download URL. - data/model/ManagedFile: entry + list/read/upload/mkdir/delete models - HermesApiService: list/read/upload(+stream)/mkdir/delete endpoints - FilesViewModel: state, navigation, per-row busy, transient-state cleanup - FilesScreen: folder list, breadcrumb, FAB new folder, upload picker, delete confirm, open via system viewer - NavigationKeys + ScreenRegistry + strings: register in Inspect drawer section * fix(files): open files in-app via FileProvider instead of browser URL The previous file-open path handed a ?token=-authenticated URL to the system browser, but /api/files/download only accepts the ephemeral in-process session token as ?token=, not the mobile's Bearer token — so the request failed and the browser rendered the JSON error body instead of the file. Fix: download the file in-app through the authenticated client (Bearer/ session-cookie, same path as the rest of the app), decode the base64 data_url, write it to cacheDir, and open it via FileProvider.getUriForFile + ACTION_VIEW (mirrors the existing ChatScreen/SystemViewModel open-from-cache pattern). Works on a remote phone since the file is materialized locally first. --------- Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
439ae9fcba
commit
6aee02c4da
8 files changed
+1024
No files matched your search
@@ -14,6 +14,7 @@ import androidx.compose.material.icons.filled.Code
|
||||
import androidx.compose.material.icons.filled.Dashboard
|
||||
import androidx.compose.material.icons.filled.EmojiEvents
|
||||
import androidx.compose.material.icons.filled.Extension
|
||||
import androidx.compose.material.icons.filled.Folder
|
||||
import androidx.compose.material.icons.filled.History
|
||||
import androidx.compose.material.icons.filled.HistoryEdu
|
||||
import androidx.compose.material.icons.filled.Info
|
||||
@@ -33,6 +34,7 @@ import com.m57.hermescontrol.ui.channels.ChannelsScreen as ChannelsScreenContent
|
||||
import com.m57.hermescontrol.ui.chat.ChatScreen as ChatScreenContent
|
||||
import com.m57.hermescontrol.ui.config.ConfigScreen as ConfigScreenContent
|
||||
import com.m57.hermescontrol.ui.cron.CronJobsScreen as CronJobsScreenContent
|
||||
import com.m57.hermescontrol.ui.files.FilesScreen as FilesScreenContent
|
||||
import com.m57.hermescontrol.ui.gateway.GatewayScreen as GatewayScreenContent
|
||||
import com.m57.hermescontrol.ui.kanban.KanbanScreen as KanbanScreenContent
|
||||
import com.m57.hermescontrol.ui.keys.KeysScreen as KeysScreenContent
|
||||
@@ -196,6 +198,12 @@ object ScreenRegistry {
|
||||
Icons.Filled.AccountBalanceWallet,
|
||||
DrawerSection.INSPECT,
|
||||
) { sessionId, openDrawer -> BillingScreenContent(onOpenDrawer = openDrawer) },
|
||||
ScreenDefinition(
|
||||
FilesScreen,
|
||||
R.string.screen_files,
|
||||
Icons.Filled.Folder,
|
||||
DrawerSection.INSPECT,
|
||||
) { sessionId, openDrawer -> FilesScreenContent(onOpenDrawer = openDrawer) },
|
||||
ScreenDefinition(
|
||||
AchievementsScreen,
|
||||
R.string.screen_achievements,
|
||||
|
||||
Reference in new issue
Block a user