Skip to content

Pro: correct the link destinations and read the home CTA windows from network time - #2167

Merged
mpretty-cyro merged 3 commits into
session-foundation:devfrom
mpretty-cyro:fix/pro-urls-and-clock
Aug 18, 2026
Merged

Pro: correct the link destinations and read the home CTA windows from network time#2167
mpretty-cyro merged 3 commits into
session-foundation:devfrom
mpretty-cyro:fix/pro-urls-and-clock

Conversation

@mpretty-cyro

Copy link
Copy Markdown
Collaborator

The Android half of two fixes iOS has just had (#746). Three commits, each independent.

The Pro link destinations

Five Pro URLs had drifted from the libSession registry they mirror (session_protocol.cpp, the
url_pro_* fields): /pro/terms, /pro/privacy, /pro-roadmap, /faq#pro and /pro-form are now
/pro-terms, /pro-privacy, /pro#roadmap, /pro#faq and /pro-support.

They were literals at six use sites — /pro-roadmap had two copies — which is how they diverged one at a
time. They now come from a single ProUrls object, with the existing ProStatusManager.URL_PRO_SUPPORT
moved into it so there is one convention rather than two. Constant names mirror the registry's field
suffixes so comparing the two is a line-up rather than a translation.

The registry is a C struct of const char* with no accessor exposed to Kotlin, so these stay copies:
reading it directly would mean new JNI surface for five constants.

The home CTAs and the device clock

HomeViewModel took Instant.now() — the device clock — and compared it against two backend-supplied
instants: renewingAt for the expiring CTA and coverageEndedAt for the expired one, plus the rendered
"expires in N days" label. Every entitlement comparison already used network time; this was the CTA
layer only.

Skew does not fail in one direction here: a fast clock fires the expiring warning early and stops
warning of expiration early, so one over-warns while the other under-warns. It now reads SnodeClock,
matching ProSettingsViewModel, and passes that one instant into the label so the window and the text
cannot disagree.

DateUtils.getExpiryString defaulted its now parameter to Instant.now(), which is what let the wrong
clock in without anything looking wrong at the call site. The parameter is now required. All three callers
already pass it, so this changes no behaviour — it removes the way back in.

Testing

:app:compilePlayDebugKotlin green, and the generated HomeViewModel_Factory confirmed to carry the
SnodeClock provider. No device run yet: the clock change alters when two CTAs fire, and the
session-appium spec that covers that will be re-run against this branch before merge.

…nition

The five Pro URLs had drifted from the values libsession's URL registry holds, and
each was a string literal at the use site that needed it — so they diverged one at
a time, and correcting them in place would have left that intact.

They now live together in ProUrls, which is what makes comparing them against the
registry a single check. Copies rather than reads: the registry is a C struct of
const char* with no accessor exposed to Kotlin, so consuming it directly would
mean adding JNI surface for five constants.

URL_PRO_SUPPORT moves in with them. It was already a named constant, so leaving it
in place would have meant two conventions for one kind of value.

The roadmap link is reached from two surfaces — a Pro settings row and the
no-billing choose-plan screen — and they now name one constant rather than
repeating a destination.
Both home CTAs gated backend-supplied instants against the device clock: the
expiring window against the renewal date, the expired window against coverage
end. Clock skew moved the boundary rather than the subscription, and the rendered
label took the same reading via a defaulted parameter.

The two skew in opposite directions — a fast clock warns of expiry early and
stops warning of expiration early — so a wrong device clock does not produce a
uniform bias that would be easy to notice.

The Pro settings screen already reads network time for the same values; this makes
the home surface match it, and passes the instant into the label so both share one
reading.
The parameter defaulted to the device clock, so a caller that omitted it silently
compared a backend-supplied expiry against the wrong clock while looking correct
at the call site.

Every caller already passes it, so this changes no behaviour. It removes the way
back: the next caller cannot reintroduce the device clock by leaving an argument
off.
@mpretty-cyro
mpretty-cyro merged commit 38f6b01 into session-foundation:dev Aug 18, 2026
5 checks passed
@mpretty-cyro
mpretty-cyro deleted the fix/pro-urls-and-clock branch August 18, 2026 23:51
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.

2 participants