Docs: M10 complete, dual-pane no longer deferred, correct the 7z rationale

The last commit shipped the screenshots and the two-pane layout but left the roadmap and README saying otherwise. Also corrects the stated reason 7z is unsupported: RAR really does need native code, but SevenZFile is already inside the Commons Compress jar this app ships.
This commit is contained in:
2026-10-15 00:25:09 +02:00
parent 55dc2293b2
commit a461be2a66
2 changed files with 14 additions and 10 deletions
+8 -6
View File
@@ -12,10 +12,10 @@ no advertising or tracking SDKs.
## Status ## Status
**M10 — store assets: mostly done.** The app is named **Plain Files**, the icon and feature **M10 — store assets: done.** The app is named **Plain Files**, the icon and feature graphic
graphic are generated from the app's own vectors, the screenshot normaliser is written, and are generated from the app's own vectors, and [docs/STORE_LISTING.md](docs/STORE_LISTING.md)
[docs/STORE_LISTING.md](docs/STORE_LISTING.md) holds length-checked listing copy. The holds length-checked listing copy. The screenshots are captured: 5 phone (1080×2160), 4 on a
screenshots are still outstanding — the generator is ready but no captures exist yet. 7-inch tablet (1200×1920) and 4 on a 10-inch tablet (2560×1600).
## Tech stack ## Tech stack
@@ -141,8 +141,10 @@ UI.** Translated UI text has to be supplied in `values-<locale>/`.
- **"Open with" and Share only work in the all-files mode.** A SAF path is relative to the - **"Open with" and Share only work in the all-files mode.** A SAF path is relative to the
granted tree rather than a filesystem path, so it cannot be handed to `FileProvider`. granted tree rather than a filesystem path, so it cannot be handed to `FileProvider`.
- **RAR and 7z are refused**, not supported — they need native code, which this project - **RAR and 7z are refused**, not supported. The stated reason is only half right: RAR
deliberately does not ship. genuinely needs native code (the Commons Compress jar this app ships contains no RAR
classes at all), but **7z does not** — `SevenZFile`/`SevenZOutputFile` are already inside
that same jar, so 7z read, and AES-256-encrypted 7z write, is an unpack away.
- **Archive extraction does not restore original timestamps or permissions**, and there is - **Archive extraction does not restore original timestamps or permissions**, and there is
no archive encryption or password support. no archive encryption or password support.
- **Cancellation happens between entries**, so a single very large file finishes before a - **Cancellation happens between entries**, so a single very large file finishes before a
+6 -4
View File
@@ -19,7 +19,7 @@ Legend: ✅ done · 🚧 in progress · ⏳ not started · 💡 candidate (propo
| M7 | On-device validation & hardening | ✅ | Run on a real **Xiaomi M2101K7AG** (Android 12 / MIUI V140) — see [EDGE_CASE_TESTING](EDGE_CASE_TESTING.md). Verified on hardware: the first-run permission prompt, granting "All files access" while the app is alive (picked up on resume), browsing real storage, the text editor's read **and** write path (independently checked with `adb shell cat`), the storage-usage screen, landscape layout, and **graceful degradation when access is revoked mid-use**. Found and fixed two real defects: misleading first-run copy ("Full access was declined" on a device where nothing had been declined), and a usage screen that stayed blank for **~45–60 s** on a 55 GB volume — now one listing per directory instead of a `stat` per node, with rows streamed out as they are measured. **142 JVM tests** | | M7 | On-device validation & hardening | ✅ | Run on a real **Xiaomi M2101K7AG** (Android 12 / MIUI V140) — see [EDGE_CASE_TESTING](EDGE_CASE_TESTING.md). Verified on hardware: the first-run permission prompt, granting "All files access" while the app is alive (picked up on resume), browsing real storage, the text editor's read **and** write path (independently checked with `adb shell cat`), the storage-usage screen, landscape layout, and **graceful degradation when access is revoked mid-use**. Found and fixed two real defects: misleading first-run copy ("Full access was declined" on a device where nothing had been declined), and a usage screen that stayed blank for **~45–60 s** on a 55 GB volume — now one listing per directory instead of a `stat` per node, with rows streamed out as they are measured. **142 JVM tests** |
| M8 | Localisation groundwork | ✅ | Every user-visible string is in `res/values/strings.xml` with real `<plurals>`, and `text/TextRes.kt` maps **both** `OperationKind` and `FileKind` onto resources so the screen, the notification and the details sheet cannot drift. The audit found a genuine miss: the details sheet rendered `FileKind.name`, i.e. untranslatable English — now a resource. `isPseudoLocalesEnabled = true` on the debug build makes "did every string come from resources?" mechanically checkable; verified `en-rXA` is present in the debug APK and the flag is debug-only. Byte units and the timestamp pattern are deliberately unlocalised, and the README says why. **142 JVM tests** | | M8 | Localisation groundwork | ✅ | Every user-visible string is in `res/values/strings.xml` with real `<plurals>`, and `text/TextRes.kt` maps **both** `OperationKind` and `FileKind` onto resources so the screen, the notification and the details sheet cannot drift. The audit found a genuine miss: the details sheet rendered `FileKind.name`, i.e. untranslatable English — now a resource. `isPseudoLocalesEnabled = true` on the debug build makes "did every string come from resources?" mechanically checkable; verified `en-rXA` is present in the debug APK and the flag is debug-only. Byte units and the timestamp pattern are deliberately unlocalised, and the README says why. **142 JVM tests** |
| M9 | Monetisation | ✅ | **Decided: one-time paid — €4.49 base with a 14-day launch price of €2.29**, both set in the Play Console (*Products › App pricing*), so there is **no Billing client, no `com.android.vending.BILLING` permission and no purchase code**. Rationale, market anchors and Console steps: [MONETISATION](MONETISATION.md). Verified against the release APK: zero billing and zero `INTERNET` references. **The price must be set before the first upload** — Play allows paid → free but never free → paid | | M9 | Monetisation | ✅ | **Decided: one-time paid — €4.49 base with a 14-day launch price of €2.29**, both set in the Play Console (*Products › App pricing*), so there is **no Billing client, no `com.android.vending.BILLING` permission and no purchase code**. Rationale, market anchors and Console steps: [MONETISATION](MONETISATION.md). Verified against the release APK: zero billing and zero `INTERNET` references. **The price must be set before the first upload** — Play allows paid → free but never free → paid |
| M10 | Store assets | 🚧 | Name decided: **Plain Files** (one string; `applicationId` already locked). `tools/make-store-assets.sh` renders the 512×512 **RGBA** icon and the 1024×500 **RGB** feature graphic from the app's own vectors, so the store icon *is* the launcher icon; `tools/make-store-screenshots.sh` normalises `adb` captures to Play's 2:1 cap per form factor (phone crop default 93/130 px, tablets 0). [STORE_LISTING](STORE_LISTING.md) carries length-checked copy (name 11/30, short 67/80, full 1881/4000), the permissions paragraph the `MANAGE_EXTERNAL_STORAGE` declaration requires, and the graphics table. The feature graphic's copy was verified to survive Play's centre-square crop by cropping the rendered PNG. **Outstanding: screenshots** — the tooling and directories are in place but no captures exist yet | | M10 | Store assets | ✅ | Name decided: **Plain Files** (one string; `applicationId` already locked). `tools/make-store-assets.sh` renders the 512×512 **RGBA** icon and the 1024×500 **RGB** feature graphic from the app's own vectors, so the store icon *is* the launcher icon; `tools/make-store-screenshots.sh` normalises `adb` captures to Play's 2:1 cap per form factor (phone crop default 93/130 px, tablets 0). [STORE_LISTING](STORE_LISTING.md) carries length-checked copy (name 11/30, short 67/80, full 1881/4000), the permissions paragraph the `MANAGE_EXTERNAL_STORAGE` declaration requires, and the graphics table. The feature graphic's copy was verified to survive Play's centre-square crop by cropping the rendered PNG. **Screenshots captured:** 5 phone (1080×2160), 4 on a 7-inch tablet (1200×1920) and 4 on a 10-inch tablet (2560×1600), all 24-bit RGB, inside the 2:1 cap. The tablet sets came from AOSP AVDs. The normaliser refuses a capture whose app area is blank, which is how a pure-background capture was caught before it reached the listing |
## Key decisions ## Key decisions
@@ -32,7 +32,9 @@ Legend: ✅ done · 🚧 in progress · ⏳ not started · 💡 candidate (propo
## Deliberately deferred (post-1.0) ## Deliberately deferred (post-1.0)
- Dual-pane view; cloud storage (Drive/OneDrive/Dropbox/…); network clients - Cloud storage (Drive/OneDrive/Dropbox/…); network clients (SMB/FTP/SFTP/WebDAV); FTP/Web
(SMB/FTP/SFTP/WebDAV); FTP/Web server. server. All of these need `INTERNET`, which is the one permission the app deliberately
does not declare — see the connectivity decision above.
- App manager (`QUERY_ALL_PACKAGES`), APK installation (`REQUEST_INSTALL_PACKAGES`). - App manager (`QUERY_ALL_PACKAGES`), APK installation (`REQUEST_INSTALL_PACKAGES`).
- RAR/7z archives; root explorer; encryption vault; themes/icon packs. - RAR archives (the format needs native code) and 7z *creation*; root explorer; encryption
vault; themes/icon packs.