Write the release notes, the permission answers, and the video
Play asks three separate things before a file manager may keep All files access: the What's new copy, a justification for why SAF and MediaStore cannot carry it, and a short video of the permission in use. Writing them exposed two stale claims and one privacy problem, so those are fixed here rather than repeated. - docs/RELEASE_NOTES.md holds the Console field at 450/500 characters, measured, and the longer announcement. The first release's copy leads with the claim no competitor makes (no ads, no INTERNET permission) and then proves the app is still a file manager. - docs/PLAY_RELEASE_CHECKLIST.md section 5 holds the declaration answer at 490/500 characters. It argues from what the Storage Access Framework and MediaStore cannot do - one picked tree, no volume enumeration or whole-device hierarchy, no arbitrary non-media files - and never from performance, which Google's wording rejects. Both APIs are named as already used where they can be, so the argument is not that they are useless. - docs/PERMISSION_VIDEO.md and store-assets/video hold a 19.7 s captioned video recorded on the release build. The home-screen segment is cut because its library counts are the owner's real totals; the published copy resumes on the internal-storage listing. Also recorded: the emulator captures one frame in three seconds, and only appops set --uid ... deny brings the prompt back after Settings has granted the app-op. - README and ROADMAP caught up with the build: the status stopped at M15, and the trash limitation still said there was no Empty trash and that expiry waited for the next delete, both changed in M19. Verified: ./tools/verify.sh green, the code map current, the Play field measured at 450 characters and the form answer at 490, and the video decoded as H.264 1080x2400, 19.666 s, no audio, with frames checked at the cut and the end state.
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
# Release notes
|
||||
|
||||
The copy a buyer reads *before* installing, as opposed to [CHANGELOG](../CHANGELOG.md), which is the
|
||||
reasoning for whoever maintains the app. Two lengths live here:
|
||||
|
||||
- **Play Console → What's new** — plain text, **500 characters per language**, no Markdown and no
|
||||
bullets (Play renders neither), measured rather than estimated.
|
||||
- **The longer announcement** — for a website, a forum post or a GitHub release, where the limit is
|
||||
the reader's patience rather than a Console field.
|
||||
|
||||
The source of truth for *what* changed is the changelog, and the source of truth for *what the app
|
||||
claims* is the [README](../README.md) and [STORE_LISTING](STORE_LISTING.md). This file only chooses
|
||||
which of those facts a new user should hear first.
|
||||
|
||||
## Writing the next one
|
||||
|
||||
1. **Version.** `versionName` and `versionCode` are in `app/build.gradle.kts`; the latter must be
|
||||
higher than every previous upload. The first release is `1.0.0` / `1`.
|
||||
2. **Changelog first.** Move the entries out of `## [Unreleased]` into a
|
||||
`## [1.0.0] - YYYY-MM-DD` heading, so this file and the changelog cannot describe different
|
||||
builds.
|
||||
3. **Then the Play field.** Say what a user can now do that they could not before — never what the
|
||||
code did. A first release describes the app instead of a diff.
|
||||
4. **Measure it.** Play counts characters, line breaks included:
|
||||
|
||||
```bash
|
||||
python3 -c "print(len(open('/tmp/whats-new.txt').read().strip()))"
|
||||
```
|
||||
|
||||
5. **Quote nothing that a device has not shown.** A limitation belongs in the announcement only if
|
||||
it is already in the README's *Known limitations*; if it is not, the README is what needs fixing.
|
||||
|
||||
---
|
||||
|
||||
## 1.0.0 — first release
|
||||
|
||||
### Play Console → What's new (500 characters max)
|
||||
|
||||
```
|
||||
Plain Files is here: a file manager with no ads, no account and no internet permission, so nothing leaves your device.
|
||||
|
||||
Browse internal storage, SD cards and USB drives. Copy, move, rename and delete files; undo a delete, rename or move; search everywhere; find duplicates; unpack ZIP, TAR, GZ, BZ2, XZ and 7z; star the folders you use; and read images, video, PDFs and text inside the app.
|
||||
|
||||
One purchase, every feature. No tracking, no subscription.
|
||||
```
|
||||
|
||||
**Measured: 450 characters** (including the two blank lines between paragraphs). The remaining
|
||||
headroom is deliberate: it leaves room for a sentence about a fix without rewriting the whole field.
|
||||
|
||||
Why this shape: the first two sentences are the claim no competitor in the survey makes — no ads and
|
||||
**no `INTERNET` permission** — and the middle one is the proof that it is still a file manager. The
|
||||
verbs are the ones people use ("copy, move, rename, delete"), not the app's internal names. Nothing
|
||||
here is a superlative, an emoji, or the word *free*: the app is paid, and a headline implying
|
||||
otherwise is both misleading and against Play's editorial policy.
|
||||
|
||||
### The longer announcement
|
||||
|
||||
> Plain Files 1.0.0 is available for Android 8.0 and later. One purchase, no subscription, no ads,
|
||||
> and no way for the app to send anything off the device — because it does not hold the network
|
||||
> permission at all.
|
||||
|
||||
#### What it does
|
||||
|
||||
**Browsing.** Internal storage, SD cards and USB drives side by side. List or grid, sorted by
|
||||
name — `file2` before `file10` — size, date or type; hidden files on request; breadcrumbs; and a
|
||||
search that either stays in the folder you are in or looks everywhere through an on-device index
|
||||
which says how current its answer is.
|
||||
|
||||
**Moving files around.** Copy, move, rename and delete one item or many. **Copy to…** and **Move
|
||||
to…** open a folder picker — volumes first, then one level at a time — and start the transfer into
|
||||
that folder without taking you out of the one you are standing in. A finished copy says
|
||||
*Copied to folder* and offers **Show**. A name that already exists asks what Paste asks instead of
|
||||
overwriting, and a batch that cannot succeed is refused as a whole rather than performed until it
|
||||
hits the problem. The rows an operation produced carry a dot until you next open that folder, so
|
||||
"what did that 4 GB copy do?" has an answer even when the destination was elsewhere.
|
||||
|
||||
**Undo, and a trash that explains itself.** A delete is a move into a hidden `.plainfiles-trash`
|
||||
folder on the same volume, kept for **24 hours**; the Trash screen states that window, offers
|
||||
**Empty trash** behind one question, and sweeps expired batches when you open it. Rename and move
|
||||
offer undo as well.
|
||||
|
||||
**Renaming a batch.** Select several files and Rename opens a pattern rather than the single-file
|
||||
dialog: one name, the number to start at, and a live preview of the names it will produce. The
|
||||
numbering **continues the folder's own series** — `Holiday (1)` and `Holiday (2)` already there make
|
||||
the next batch start at 3 — because a batch rename that always starts at 1 is useless the second
|
||||
time it is used. A name in the way blocks the batch and is named as it is typed.
|
||||
|
||||
**Finding things.** The duplicate finder compares size, then the head of every candidate, then the
|
||||
survivors in full — never a name or a date. The storage-usage view measures every folder and ranks
|
||||
it largest first, so the folder eating the card is the one at the top.
|
||||
|
||||
**Looking at files.** Image, text, PDF, media and archive viewers, and an APK's own details read
|
||||
without installing it. Thumbnails show the picture, and a **video shows a frame of itself** rather
|
||||
than a film icon. An archive can be read without extracting it first, with entry names checked
|
||||
against zip-slip.
|
||||
|
||||
**Archives.** Create ZIP; extract ZIP, TAR, TAR.GZ, TAR.BZ2, TAR.XZ, GZ, BZ2, XZ and 7z. When
|
||||
compressing, you choose the name and whether to compress at all: for copying a collection to a
|
||||
computer, storing the files as they are takes one pass and is still an ordinary archive.
|
||||
|
||||
**Working with other apps.** Plain Files can receive a share from anywhere and appear in another
|
||||
app's file chooser. Neither costs a permission.
|
||||
|
||||
**Tablets and large windows.** At expanded width the screen splits into two panes: the folder list
|
||||
on the left, and the contents — or a preview and the details — of the folder or file you pick on the
|
||||
right.
|
||||
|
||||
**Shortcuts.** Long-press the app icon for **Images**, **Recent** and **Trash**.
|
||||
|
||||
#### What it deliberately does not do
|
||||
|
||||
- **No cloud storage, network shares, FTP/SFTP/WebDAV or web server.** Every one of those needs
|
||||
`INTERNET`, which is the single permission this app refuses to hold. That is the product, not a
|
||||
gap in the schedule.
|
||||
- **RAR is not supported**, because it needs native code this app does not ship — and it says so
|
||||
rather than failing with a strange error. 7z can be read but not created.
|
||||
- **Extraction does not restore timestamps or permissions**, and archive passwords are not
|
||||
supported.
|
||||
- **Cancelling happens between entries**, so one very large file finishes before a stop is honoured.
|
||||
- **English is the only language so far.** Every string is in `strings.xml`, so a translation is a
|
||||
file rather than a refactor.
|
||||
- **Android TV is specified but not shipped.** Its acceptance needs a TV device pass this machine
|
||||
cannot provide, and a half-tested TV build reviews worse than none.
|
||||
- **A library is not restored across process death.** Images or Recent returns to the root screen
|
||||
after Android kills the process, because a library has no path to persist.
|
||||
|
||||
#### Privacy, in one paragraph
|
||||
|
||||
The app declares no `INTERNET` permission, contains no advertising or analytics SDK, and has no
|
||||
account or sign-in. It keeps three things on the device — an index of files for search, an index of
|
||||
staged deletes for the trash, and the list of starred folders — and none of them leaves it. The
|
||||
permission set and why "All files access" is the one sensitive declaration are in the
|
||||
[store listing](STORE_LISTING.md); the policy text is [PRIVACY.md](../PRIVACY.md).
|
||||
|
||||
#### Price
|
||||
|
||||
**€4.49**, with a **€2.29 launch price for the first 14 days**. One purchase, every feature; no
|
||||
subscription and nothing to buy inside the app. There is no Billing client in the build — the price
|
||||
lives on the listing — which is part of how "nothing leaves the device" stays true of the shipped
|
||||
artefact rather than only of the source.
|
||||
|
||||
#### What comes next
|
||||
|
||||
Android TV is specified and waits for a device; the post-1.0 queue and the deliberate deferrals are
|
||||
in [ROADMAP](ROADMAP.md). What will not change is the permission set: features arrive without a new
|
||||
permission, or they do not arrive.
|
||||
Reference in New Issue
Block a user