Skip to content

Release v1.94.0 (1940) — the stable that gathers three dev builds - #360

Merged
trinadhthatakula merged 13 commits into
masterfrom
dev
Aug 5, 2026
Merged

Release v1.94.0 (1940) — the stable that gathers three dev builds#360
trinadhthatakula merged 13 commits into
masterfrom
dev

Conversation

@trinadhthatakula

Copy link
Copy Markdown
Owner

Brings master up to dev for v1.94.0. Five PRs since master's tip: #355, #356, #357, #358, #359. versionCode 1933 → 1940.

⚠️ This merge does not publish v1.94.0

That changed in this very PR, in #359. dev-check.yml now declines to publish any versionCode ending in 0, because a stable belongs to production:

version code publisher track GitHub release
ends in 0 — 1940 production-deploy.yml (production) beta full release
anything else — 1933 dev-check.yml (master) alpha pre-release

So the run this merge triggers builds and verifies only: no Play upload, no Telegram broadcast, no GitHub pre-release. v1.94.0 publishes when 1940 reaches production — currently at 1930, dev is 388 ahead and 0 behind, and merge-tree says that merge is clean.

Play allows a version code to be uploaded exactly once app-wide, so before #359 both branches raced for 1940 and one of them had to fail. Routing on the last digit gives every code exactly one uploader. Full reasoning in docs/follow-ups/two-branches-one-play-version-code.md, now marked resolved.

What is in it

Release notes, verified

check result
playstore.txt 483 / 500 chars
assembled Telegram caption 998 / 1024 UTF-16 units, margin 26
playstore.txtfastlane/…/changelogs/1940.txt identical
check-shizu-manifest.sh all checks pass, changelog matches 1940
merge-tree master…dev clean

Expected side effect

Commit 59236b5e carries Closes #344 in its body. master is the default branch, so this merge will close #344 — which is correct: the setting it asked for shipped in #357. No other closing keyword appears anywhere in master..dev, checked.

Merging this

master also drives the landing page's Vercel Production deploy and hosts shizu_store.json, so the merge still matters even though it no longer publishes the APK. The APK release is a separate devproduction PR, not yet opened.

trinadhthatakula and others added 13 commits August 5, 2026 11:07
… stable

v1.93.0 is the last stable. Everything since then shipped as pre-release
(1931, 1932, 1933) and never reached the stable lane, so these notes roll all
three up: 65 merged PRs, from the freeze-profile and bulk-export features to
the privilege-readback and app-lock fixes.

Written to the three-file contract in release-notes/README.md:

- playstore.txt — 483 chars, inside the hard 500-char Play limit; copied
  byte-identical to fastlane/metadata/android/en-US/changelogs/1940.txt and
  synced into shizu_store.json by sync-shizu-changelog.sh.
- telegram.md — 804 UTF-16 units, 953 once CI wraps it. The caption cap is
  1024 and a caption over it posts *nothing* while the workflow still goes
  green, so this is measured assembled, not as a file.
- github.md — the audit trail: highlights, 13 themed sections, and all 65
  commits with their PR numbers.

check-shizu-manifest.sh passes, including the changelog-matches-playstore.txt
check for versionCode 1940 -> v1.94.0.

Nothing publishes from this branch: dev-check.yml triggers on push to master,
not dev, so the 1933 build already with testers is untouched. Merging dev into
master is what fires Play, Telegram and the GitHub release.
chore(release): 1.94.0 (1940) — the stable that gathers three dev builds
…ite already does

The website (web/src/lib/site.ts) and .github/FUNDING.yml have both advertised
five funding routes for a while. The in-app support sheet offered three —
GitHub Sponsors, Patreon, PayPal — so two of the routes a reader saw on the
site simply did not exist in the app. Both flavours now carry all five, in the
same order: Sponsors first (lowest fees, and it sits beside the source), then
recurring-capable, then one-off.

Icons are drawn rather than borrowed. SupportDeveloperBottomSheet renders every
action icon with Icon(tint = colorScheme.primary), so a real brand mark could
never keep its brand colour — which is why PayPal already uses the generic
shield_with_heart. brand_kofi is a mug with a heart; brand_buymeacoffee is a
lidded takeaway cup with steam. The silhouettes are deliberately unalike
because the two rows sit next to each other and two coffee cups differing only
in detail are two identical smudges at 24dp. Both were rendered and inspected
at 24 and 48 px before landing.

Two details worth knowing:

- brand_kofi needs fillType="evenOdd". Everything is drawn in a single tint, so
  the heart has to be a HOLE in the cup; as a second filled subpath it would be
  invisible.
- brand_buymeacoffee strokes its steam instead of filling it. Icon()'s tint is a
  ColorFilter over the whole drawable, so strokeColor is tinted along with
  fillColor and those paths need no fillColor at all.

Going from three rows to five needed no layout change: both
SupportDeveloperBottomSheet and SupportDeveloperTabbedBottomSheet already wrap
their content in verticalScroll.

Strings are in all five locales, so lint reports no MissingTranslation. Neither
new drawable trips VectorPath — the five hints in the report are the
pre-existing thor_mono, thor_drawn_foreground and dhizuku icons.

assembleFossDebug, assembleStoreDebug, lintFossDebug and lintStoreDebug all
pass.
1940 has not published yet — dev-check.yml fires on push to master, and the
dev->master merge is still to come — so #356 belongs to this release rather
than the next one, and the notes have to say so.

Three edits, all in github.md: a bullet under Support, the commit-log line, and
the intro's PR count, which is a number the commit log can be counted against
and so goes stale loudly. 65 -> 66; the two now agree.

playstore.txt and telegram.md are deliberately untouched. Both are size-capped
(483/500 chars and 804 units against a ~870 budget), and "two more ways to
donate" is not what a Play or Telegram reader needs from a release that fixed a
data-wiping freeze. github.md is the audit trail and takes it.

check-shizu-manifest.sh still passes, including the changelog-matches-
playstore.txt check for versionCode 1940.
… treat

`请喝一杯咖啡` reads as "please have a cup of coffee" — addressed at the reader.
The missing `我` inverts who is being treated; the idiom is `请我喝杯咖啡`.
The Buy Me a Coffee line was a bare noun phrase (`一次性咖啡或按月会员`) that
never named the action either.

Kept the two lines distinguishable, as the English pair and the two icons
already are: Ko-fi leads on frequency (`一次或每月`), Buy Me a Coffee on
membership (`按月成为会员`). Only zh-rCN was inverted — es `invita a un café`,
fr `offrir un café` and ar `اشترِ قهوة` all already put the user as the payer.

Also indexes #356 in the Support section heading of the v1.94.0 notes, which
listed the three older PRs but not the change the section's own bullet documents.
…long press

Closes #344.

The grid used fixed positional buckets — Reinstall+Install on row 1, Clear
cache+Extensions on row 2 — so the shape was decided by which slot a tile sat
in rather than by how many tiles there were. Install was unconditional in row 1,
which meant Reinstall and Clear cache could never go full-width no matter how
few tiles were showing.

homeActionRows now flows the visible actions into pairs with a single wide
leader when the count is odd: 4 -> 2x2, 3 -> wide then a pair, 2 -> one pair,
1 -> one wide tile. Reinstall moves to the end of the flow because it is the
only dismissible tile; dismissing it now re-packs the rows after it instead of
shifting every other tile up a slot.

Half-width tiles have never had room for a title and a description both. At
393 dp across five locales and three font scales, 156 titles and 224
descriptions clipped; en/es/fr already lost 4/9/9 of 13 descriptions at the
default font size. Paired tiles therefore drop the description and give the
title its second line, and a long press opens a bottom sheet with the full text
— measured at 218-266 dp, no scrolling in any locale. Wide tiles keep their
description inline and have no long press, since there would be nothing to add.
Nothing clips at the default font size in any locale now.

The wide-screen rail gets narrowContainer: at roughly a third of a 600 dp
window even a full-width tile cannot hold a one-line title plus a description,
so every tile there goes full-width and compact. That is the only combination
measured to clip nothing in that pane.

Two details the design turns on, both covered by instrumented tests:

- The dismiss X is a plain Box with combinedClickable, not an IconButton.
  IconButton inflates an 18 dp icon to a 48 dp target and its clickable
  consumes the pointer down, so the tile's long-press timer never started and
  holding that corner dismissed the card instead of explaining it.
- Dropping the subtitle Text also drops its string from the tile's merged
  semantics node, taking the scope of the action away from TalkBack. A
  zero-size semantics node after the title keeps the content and its order.

A long press fires onLongClick instead of onClick, so holding a tile no longer
performs its action; the sheet's confirm button hands that back and reuses the
tile's own title, costing no new translation.

Strings are net zero: show_details lands in all five locales, and
home_extensions_subtitle ("Manage & open") leaves them — the sheet needs an
explanation, not a label, so Extensions reuses manage_extensions_desc.

Verified: 9 unit tests, 10 instrumented tests on API 36, lintStoreRelease
clean, 472/472 string parity across en/ar/es/fr/zh-rCN.
…acoffee

feat(support): offer Ko-fi and Buy Me a Coffee in the app, like the site already does
The adaptive bento re-packs whatever tiles are visible, but nothing could
make either of these two invisible: INSTALL was unconditional and EXTENSIONS
was gated only on privilege. That is what #344 actually asked for — the grid
was the means, not the request.

Both are shortcuts to something still reachable elsewhere: hiding Installer
leaves APK intent handling untouched, hiding Extensions leaves the Settings
entry. So the preferences stack with the eligibility rules rather than
replacing them — Extensions still needs a privilege *and* the preference.

Hiding both with no privilege leaves nothing eligible, which is a legitimate
answer rather than a bug to guard against. homeActionRows returns an empty
list, HomeActionsBento emits no Column, and both HomeScreen layouts drop the
spacer that separates the grid from the summary row — a bare 36 dp gap reads
as a rendering fault.

Plumbed on the showReinstallAllCard path end to end: two DataStore keys
defaulting to true, two Settings switches in GENERAL, five locales.

HomeActionsTest now crosses the five reachable privilege states with all four
preference pairs and asserts each tile's visibility against its own rule, so
a tile cannot ride along on another's condition (16 tests, was 9).
feat(home): let users hide the Installer and Extensions tiles, and pack the bento adaptively
#357 merged after the notes were written and, like #356 before it, belongs
to this release rather than the next: 1940 has not published yet, since the
dev->master merge that fires dev-check.yml is still to come.

github.md takes it in full — a Highlights bullet, a "What's Changed" section
covering both halves (the adaptive packing and the two Settings switches for
GH#344), the commit-log line, and the PR count, 66 -> 67, which is the one
number in the file the commit log can be counted against.

telegram.md gets one line, which needed making room for. The caption the
channel actually receives is the file plus a 141-unit wrapper from
dev-check.yml, so the real budget is 1024 minus that, and the file was
already at 803 of it. Two lines were tightened losslessly ("check the
result, not the exit code"; "Recents hides your app list") to buy the space.
Measured assembled, not by hand: 998 of 1024, margin 26. A hand count of the
new line said 55 units; it is 68.

playstore.txt is deliberately untouched, as it was for #356. It sits at
483 of Play's 500, and the only way to fit a home-tile line is to shave
nuance off bullets that matter more to a Play reader than this does — a
freeze that stopped wiping data, and privileged actions that now report
what really happened. Left unchanged, so the fastlane changelog and
shizu_store.json still match it byte for byte.

check-shizu-manifest.sh passes, including the changelog-matches-playstore
check for versionCode 1940.
… racing for one Play code

Google Play allows a version code to be uploaded exactly once app-wide — the
limit is per app, not per track. Both master and production upload, and both
are fed from dev, so a single chore(release) commit reached both branches
carrying the same code and whichever workflow got there first made the other
die on "Version code NNNN has already been used". That is the open half of
docs/follow-ups/two-branches-one-play-version-code.md, and the version-code
guard in production-deploy.yml never could cover it: it compares production
against production's own previous tip and cannot see what master did.

Route on the last digit instead. versionName is derived as
code/1000 . code%1000/10 . code%10, so the last digit IS the patch number and
a code ending in 0 is an x.y.0 — 1940 is 1.94.0. dev-check.yml now sets
release=false for those, builds them for verification, and publishes nothing.
Every code therefore has exactly one uploader: stables from production on
`beta`, everything between them from master on `alpha`.

This is a fourth option the doc did not list, and it is the one that keeps
what the owner rejected option 2 to protect — master really does still publish
to a Play test track, it just never publishes a stable. It needs no Fastfile
change, so neither lane grows a promote-vs-upload branch. The trade against
option 1 is that `beta` no longer carries the bytes `alpha` tested, because a
stable never reaches `alpha` at all; the doc says so rather than implying
otherwise.

Two residuals, both deliberate and both written down. workflow_dispatch still
overrides the check, because a manual dispatch is an explicit request to
publish — the escape hatch for a stable is production-deploy.yml's own
dispatch, not master's. And nothing enforces the rule on the production side,
so merging a mid-cycle build into production would re-open the collision from
that direction; convention holds there, not a check.

`case` rather than $((NEW % 10)): arithmetic expansion errors out on a
non-numeric read, which would turn a step deliberately written to fail OPEN
into a red build. Behaviour checked against the extracted step: 1940 after
1933 -> false, 1933 after 1932 -> true, 1933 unchanged -> false (the existing
rule, intact), 1941 after 1940 -> true, a non-numeric read -> true, still
failing open.

Also corrects the comments that asserted the collision was unfixed —
production-deploy.yml claimed it in two places — and the workflow line numbers
this insertion shifted, in release-notes/README.md, pr-ci.yml and
telegram-caption-length-guard.md. Two of those were already stale by two lines
before this change.

First release to exercise it is v1.94.0 (1940), which is why it lands before
that merge rather than after it.
docs(release-notes): record #357 in the v1.94.0 notes
…m-production

ci(dev-check): leave stables to production, and stop the two branches racing for one Play code
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
thor Ignored Ignored Aug 5, 2026 12:17pm

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@trinadhthatakula, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 14 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 04c71625-5753-4116-9fda-4101026de340

📥 Commits

Reviewing files that changed from the base of the PR and between b1fd8bb and ee9a687.

📒 Files selected for processing (37)
  • .github/workflows/dev-check.yml
  • .github/workflows/pr-ci.yml
  • .github/workflows/production-deploy.yml
  • app/src/androidTest/java/com/valhalla/thor/presentation/home/BentoTileTest.kt
  • app/src/androidTest/java/com/valhalla/thor/presentation/home/HomeActionsBentoTest.kt
  • app/src/foss/java/com/valhalla/thor/presentation/settings/SupportDeveloperHelper.kt
  • app/src/main/java/com/valhalla/thor/data/repository/PreferenceRepositoryImpl.kt
  • app/src/main/java/com/valhalla/thor/domain/model/UserPreferences.kt
  • app/src/main/java/com/valhalla/thor/domain/repository/PreferenceRepository.kt
  • app/src/main/java/com/valhalla/thor/presentation/home/HomeScreen.kt
  • app/src/main/java/com/valhalla/thor/presentation/home/HomeViewModel.kt
  • app/src/main/java/com/valhalla/thor/presentation/home/components/BentoTile.kt
  • app/src/main/java/com/valhalla/thor/presentation/home/components/HomeActions.kt
  • app/src/main/java/com/valhalla/thor/presentation/home/components/HomeActionsBento.kt
  • app/src/main/java/com/valhalla/thor/presentation/settings/SettingsScreen.kt
  • app/src/main/java/com/valhalla/thor/presentation/settings/SettingsViewModel.kt
  • app/src/main/java/com/valhalla/thor/presentation/widgets/InfoBottomSheet.kt
  • app/src/main/res/drawable/brand_buymeacoffee.xml
  • app/src/main/res/drawable/brand_kofi.xml
  • app/src/main/res/values-ar/strings.xml
  • app/src/main/res/values-es/strings.xml
  • app/src/main/res/values-fr/strings.xml
  • app/src/main/res/values-zh-rCN/strings.xml
  • app/src/main/res/values/strings.xml
  • app/src/store/java/com/valhalla/thor/presentation/settings/SupportDeveloperHelper.kt
  • app/src/test/java/com/valhalla/thor/presentation/ViewModelTestDoubles.kt
  • app/src/test/java/com/valhalla/thor/presentation/home/HomeActionsTest.kt
  • docs/follow-ups/README.md
  • docs/follow-ups/telegram-caption-length-guard.md
  • docs/follow-ups/two-branches-one-play-version-code.md
  • fastlane/metadata/android/en-US/changelogs/1940.txt
  • gradle.properties
  • release-notes/README.md
  • release-notes/v1.94.0/github.md
  • release-notes/v1.94.0/playstore.txt
  • release-notes/v1.94.0/telegram.md
  • shizu_store.json

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added documentation Improvements or additions to documentation area: ui/ux UI, theming, navigation, layout area: localization Translations / i18n area: billing Support-the-developer / Play billing labels Aug 5, 2026
@trinadhthatakula
trinadhthatakula merged commit f9e823c into master Aug 5, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: billing Support-the-developer / Play billing area: localization Translations / i18n area: ui/ux UI, theming, navigation, layout documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant