diff --git a/app/src/main/java/de/softwareapp_hb/filemanager/ui/browser/BrowserViewModel.kt b/app/src/main/java/de/softwareapp_hb/filemanager/ui/browser/BrowserViewModel.kt index fec9abc..05f7efc 100644 --- a/app/src/main/java/de/softwareapp_hb/filemanager/ui/browser/BrowserViewModel.kt +++ b/app/src/main/java/de/softwareapp_hb/filemanager/ui/browser/BrowserViewModel.kt @@ -622,7 +622,10 @@ class BrowserViewModel( } else { runCatching { source.list(path) }.getOrDefault(emptyList()) } - entries.filter { it.isDirectory } + // Folders only, and hidden ones only when the listing shows hidden files: the picker is a + // listing, and a `.plainfiles-trash` or a `.thumbnails` folder in a copy dialog is an + // invitation to put a file somewhere it will never be seen again. + entries.filter { it.isDirectory && (_state.value.showHidden || !it.isHidden) } .sortedWith(SortSpec().comparator) .map { PickerFolder(path = it.path) } } diff --git a/app/src/test/java/de/softwareapp_hb/filemanager/ui/browser/BrowserViewModelTest.kt b/app/src/test/java/de/softwareapp_hb/filemanager/ui/browser/BrowserViewModelTest.kt index a390fde..d02c783 100644 --- a/app/src/test/java/de/softwareapp_hb/filemanager/ui/browser/BrowserViewModelTest.kt +++ b/app/src/test/java/de/softwareapp_hb/filemanager/ui/browser/BrowserViewModelTest.kt @@ -311,6 +311,26 @@ class BrowserViewModelTest { assertEquals(R.string.browser_internal_storage, crumb.labelRes) } + @Test + fun `the picker leaves hidden folders out until they are asked for`() { + storage.addDirectory(root.child(".hidden-backup")) + val model = viewModel() + model.openDirectory(downloads) + model.toggleSelection(downloads.child("a.txt")) + + model.startTransferTo(cut = false) + model.pickerOpen(root) + + // A copy dialog is a listing: the trash folder and a `.thumbnails` folder are not destinations. + val offered = model.state.value.transferPicker!!.folders.map { it.path.name } + assertFalse(".hidden-backup" in offered) + + // Showing hidden files is a statement about what the user wants to see, so the picker follows it. + model.toggleShowHidden() + model.pickerOpen(root) + assertTrue(".hidden-backup" in model.state.value.transferPicker!!.folders.map { it.path.name }) + } + @Test fun `the picker walks up to the volumes and back down`() { val model = viewModel() diff --git a/docs/CODE_MAP.md b/docs/CODE_MAP.md index fca584c..2eff0b4 100644 --- a/docs/CODE_MAP.md +++ b/docs/CODE_MAP.md @@ -2,7 +2,7 @@ Generated from the source by `tools/make-code-map.py` - do not edit by hand. Regenerate it after a change (`python3 tools/make-code-map.py`); `--check` exits non-zero when this file is stale. -80 source files, 13899 lines - 37 test files, 430 tests. The behaviour index at the end lists every test name, and in this project a test name is a sentence about what the app does, so it doubles as the specification. +80 source files, 13902 lines - 37 test files, 431 tests. The behaviour index at the end lists every test name, and in this project a test name is a sentence about what the app does, so it doubles as the specification. Start at `AGENTS.md`. What is done, and why: `docs/ROADMAP.md` and `CHANGELOG.md`. What was verified by hand rather than by a test: `docs/EDGE_CASE_TESTING.md`. @@ -104,7 +104,7 @@ The browser screen: view model, state, list and grid, dialogs, selection bar | `BrowserScreen.kt` | 661 | The browser, and everything that can be on top of it. BrowserScreen(), messageText() | - | | `BrowserTopBar.kt` | 238 | The browser's app bar: title, up, the favourite star, and the search / sort / overflow actions. BrowserTopBar(), SEARCH_FIELD_WIDTH | `BrowserTopBarTest` (4) | | `BrowserUiState.kt` | 391 | One immutable description of everything the browser shows. ViewMode, SearchScope, Clipboard, CompressRequest, PickerFolder, TransferPicker, MessageAction, UiMessage, ConflictPrompt, RootItem, Bookmark, DetailFocus, Undo, UndoMove, Overlay, BrowserUiState | - | -| `BrowserViewModel.kt` | 2598 | Drives the browser screen. BrowserViewModel, ArchivePreview | `BrowserViewModelTest` (116) | +| `BrowserViewModel.kt` | 2601 | Drives the browser screen. BrowserViewModel, ArchivePreview | `BrowserViewModelTest` (117) | | `DetailsSheet.kt` | 109 | Name, location, size, type and modified date for one entry. DetailsSheet(), DetailLines(), DetailLine() | - | | `EntryIntents.kt` | 58 | Wraps an entry's path in a content:// URI another app may read. contentUriFor(), viewIntent(), shareIntent() | - | | `IncomingBar.kt` | 60 | The bar shown while another app is waiting on this one. IncomingBar() | - | @@ -595,7 +595,7 @@ Every test name in the suite, by file: the fastest way to see whether something - a library or the root list has nothing to star - the star gives way to the search field -### `ui/browser/BrowserViewModelTest.kt` (116) +### `ui/browser/BrowserViewModelTest.kt` (117) - starts on the root list - opening a folder lists it with directories first and natural order @@ -607,6 +607,7 @@ Every test name in the suite, by file: the fastest way to see whether something - move to a chosen folder takes the rows with it - the picker offers folders and nothing else - the picker names a volume the way the browser does +- the picker leaves hidden folders out until they are asked for - the picker walks up to the volumes and back down - a conflicting destination asks before overwriting, naming that folder - cancelling the picker copies nothing diff --git a/docs/PLAY_RELEASE_CHECKLIST.md b/docs/PLAY_RELEASE_CHECKLIST.md index a9124c6..6740b9c 100644 --- a/docs/PLAY_RELEASE_CHECKLIST.md +++ b/docs/PLAY_RELEASE_CHECKLIST.md @@ -197,7 +197,7 @@ Full copy and the generated graphics land in **M10** (`docs/STORE_LISTING.md`). fields needed: app name, short description, full description, app icon 512×512, feature graphic 1024×500, and the screenshots. -- [ ] Upload the screenshots from `store-assets/screenshots/`: **phone** 1080×2160 (5), +- [ ] Upload the screenshots from `store-assets/screenshots/`: **phone** 1080×2160 (8), **7-inch tablet** 1200×1920 (4), **10-inch tablet** 2560×1600 (4). Play wants 4+ per large-screen form factor. All three sets clear its rules — 24-bit PNG with no alpha, shorter side ≥ 320, longer side ≤ 3840, and longer side ≤ 2× the shorter side. @@ -205,11 +205,16 @@ graphic 1024×500, and the screenshots. whose app area is blank. - [ ] Expect the 7-inch set to be single-pane and the 10-inch set two-pane. That is the adaptive layout working, not an inconsistency — see the CHANGELOG. -- [ ] The committed sets show browsing, a folder list, an image preview and storage usage. - **None of them show search, undo, the trash or receiving a share** — four features the - app now has. The existing shots stay accurate (no layout changed), so this is an - opportunity rather than a defect: two or three more captures would let the listing - advertise them. See `tools/make-store-screenshots.sh`. +- [x] The phone set was re-shot on 2026-10-18 and now shows **browsing, a folder list, the photo +grid, storage usage, the sort sheet, the Copy to… picker, the trash (with its 24-hour window and +Empty trash) and the compress dialog** — the last three are what M16-M20 added. **Still not +shown**: search, undo, and receiving a share. The picker shot is taken at the volume list on +purpose: one level down it would publish the real phone's folder names, which the demo-library +rule above forbids. +- [ ] The tablet sets were **not** re-shot: the TV/tablet AVDs cannot boot on this machine (no KVM), + and the phone-resized path needs more navigation work. They stay accurate for the screens they + show (roots, folder list, image preview, storage usage) and should be regenerated on a machine + with KVM before the listing goes live. ## 8. Release tracks and pricing diff --git a/docs/STORE_LISTING.md b/docs/STORE_LISTING.md index 0c1d659..b9fc6cf 100644 --- a/docs/STORE_LISTING.md +++ b/docs/STORE_LISTING.md @@ -34,6 +34,11 @@ Play's slots, and what each needs: | 7-inch tablet | 4+ recommended | `screenshots/tablet-7in/` — 1200×1920 | A tablet frame is already inside the 2:1 cap, so 0 px of crop | | 10-inch tablet | 4+ recommended | `screenshots/tablet-10in/` — 2560×1600 | Landscape profile (matches the `tablet10` AVD); Play accepts either orientation | +**What the phone set shows** (eight slots, the maximum): the home screen, a folder listing, the photo +grid, storage usage, the sort sheet, the **Copy to… picker**, the **trash** with its 24-hour window, +and the **compress dialog**. The last three are M16-M20's work; the picker is shot at the volume list +so it names no folder that exists on the real device. + ### The library the shots are taken over **Never shoot over a real device's storage.** Published screenshots are public, and a file diff --git a/store-assets/screenshots/phone/02-folder-list.png b/store-assets/screenshots/phone/02-folder-list.png index a386df0..8ca4e26 100644 Binary files a/store-assets/screenshots/phone/02-folder-list.png and b/store-assets/screenshots/phone/02-folder-list.png differ diff --git a/store-assets/screenshots/phone/03-photos-thumbnails.png b/store-assets/screenshots/phone/03-photos-thumbnails.png index 864d8ca..2d7d9c3 100644 Binary files a/store-assets/screenshots/phone/03-photos-thumbnails.png and b/store-assets/screenshots/phone/03-photos-thumbnails.png differ diff --git a/store-assets/screenshots/phone/05-sort-sheet.png b/store-assets/screenshots/phone/05-sort-sheet.png index a74af75..06c1814 100644 Binary files a/store-assets/screenshots/phone/05-sort-sheet.png and b/store-assets/screenshots/phone/05-sort-sheet.png differ diff --git a/store-assets/screenshots/phone/06-copy-to.png b/store-assets/screenshots/phone/06-copy-to.png new file mode 100644 index 0000000..cacb0c6 Binary files /dev/null and b/store-assets/screenshots/phone/06-copy-to.png differ diff --git a/store-assets/screenshots/phone/07-trash.png b/store-assets/screenshots/phone/07-trash.png new file mode 100644 index 0000000..7479f79 Binary files /dev/null and b/store-assets/screenshots/phone/07-trash.png differ diff --git a/store-assets/screenshots/phone/08-compress.png b/store-assets/screenshots/phone/08-compress.png new file mode 100644 index 0000000..cb74de2 Binary files /dev/null and b/store-assets/screenshots/phone/08-compress.png differ