Skip to content

Ask for a review at two earned moments instead of on every load - #560

Merged
andiwand merged 2 commits into
mainfrom
feat/in-app-review-gating
Aug 2, 2026
Merged

Ask for a review at two earned moments instead of on every load#560
andiwand merged 2 commits into
mainfrom
feat/in-app-review-gating

Conversation

@andiwand

@andiwand andiwand commented Aug 2, 2026

Copy link
Copy Markdown
Member

Follow-up to #559. That PR restored the review request in lite; this one fixes when it fires.

The problem

onLoadSuccess is reached by more than "the user opened a document":

trigger user state
fresh open — MainActivity.loadUri (intent, picker, recent list) just opened ✅
onStart() replay — result arrived while stopped returning ✅
entering edit mode — EditActionModeCallback:35reloadUri(true) mid-task ❌
leaving edit mode — EditActionModeCallback:59reloadUri(false) mid-task ❌
after a save — onSaveSuccessloadUri(...) success, worth asking ✅
webview hands back a file — PageView.sendFileloadUri(...) mid-read ❌

Toggling edit mode twice asked twice, while the user was working.

The change

loadUri takes a freshOpen flag, reloadUri clears it, and onLoadSuccess only asks when the load was one the user asked for. PageView.sendFile passes freshOpen = false.

Saving still counts, because onSaveSuccess reloads through loadUri — that's a success the user just caused. So "keep it on save, drop it on enter/exit" falls out of one condition rather than three special cases.

The landing screen becomes the second moment, for people who open the app and browse rather than arriving with a document from another app.

The threshold

Both moments are counted in the new UsageCounters, and neither asks until the third open. A fresh install has nothing to say yet, and asking anyway costs stars — one of the 1★ reviews in the console is literally "not used it but asking for a review".

A counter rather than the length of the recently opened list: that list is capped, pruned and user-deletable, so it undercounts exactly the returning users this is meant to find, and it counts distinct documents rather than visits. MINIMUM_OPENS is one constant if 3 turns out to be the wrong number.

requestInAppRating moves out of DocumentFragment into nonfree/InAppReview so both call sites share it — also where the Play dependency belongs.

Notes

  • The two counters are independent, so someone who only ever opens documents from other apps still earns the ask on the document side.
  • No behaviour change for pro beyond the timing: it was already asking.
  • in_app_review_eligible / _error / _start / _done now report from lite too, which is the visibility that would have caught the v4.2 regression.

Verification

spotlessCheck, assembleLiteDebug, assembleProDebug, lintProDebug and testProDebugUnitTest pass locally. The flow itself can't be exercised off a Play install — requestReviewFlow() fails into the existing in_app_review_error branch — so this is reviewed by reading, not by running.

🤖 Generated with Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b20dfa764c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread app/src/main/java/app/opendocument/droid/ui/activity/MainActivity.kt Outdated
andiwand and others added 2 commits August 2, 2026 21:15
The review request sat in onLoadSuccess, which is reached by more than a user
opening a document: reloadUri drives it when edit mode is entered and when it is
left, and PageView hands a file back through loadUri while the user is reading.
So toggling edit mode twice asked twice, mid-task.

Gate it on a fresh open. loadUri takes a freshOpen flag, reloadUri clears it, and
onLoadSuccess only asks when the load was one the user asked for. Saving still
counts, because onSaveSuccess reloads through loadUri - that one is a success the
user just caused, and worth asking after.

Add the landing screen as the second moment, for people who open the app and
browse rather than arriving with a document from another app.

Both are counted in UsageCounters and neither asks until the third open. A fresh
install has nothing to say about the app yet, and asking anyway costs stars - one
of the one-star reviews in the play console is literally "not used it but asking
for a review". A counter rather than the length of the recently opened list: that
list is capped, pruned and deletable, so it undercounts returning users, and it
counts distinct documents rather than visits.

requestInAppRating moves out of DocumentFragment into nonfree/InAppReview so both
call sites share it, which is also where the play dependency belongs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E1ANEeai87KtnX5pBzgDEJ
Tapping the launcher while the task is still alive resumes MainActivity instead of
creating it, so a flag set in onCreate missed exactly the users who keep the app in
recents - the ones most likely to have something to say. Count in onStart instead,
when the landing screen is what is on show.

Coming back from the document picker also lands there, so the picker marks itself
before it starts and that return is not counted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E1ANEeai87KtnX5pBzgDEJ
@andiwand
andiwand force-pushed the feat/in-app-review-gating branch from b20dfa7 to 34a5cda Compare August 2, 2026 19:17
@andiwand
andiwand enabled auto-merge (squash) August 2, 2026 19:22
@andiwand
andiwand merged commit 244f867 into main Aug 2, 2026
7 checks passed
@andiwand
andiwand deleted the feat/in-app-review-gating branch August 2, 2026 19:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant