Commit Graph

87 Commits

Author SHA1 Message Date
Maurice 35e0613986 test(native): read the listener names as strings, so the appLinks case typechecks 2026-11-13 08:34:05 +01:00
Maurice fdb2095ced fix(native): a widget tap opens its page every time, also after iOS ended the page
A widget or Live Activity tap reached the UI as Capacitor's appUrlOpen, or
as the launch URL. When iOS had ended the web view's process in the
background, the event went to the old page's listeners and was lost, and
the reloaded page found the same link in getLaunchUrl that it had already
followed once and skipped it: the second tap on the packing widget opened
the start page.

The binary now takes com.liketrek.trek://navigate links itself and hands
them over like a quick action, held until the UI takes it and kept for a
page that is still loading. It reports the feature appLinks, and the UI
only follows the link through Capacitor for binaries without it.
2026-11-13 08:27:23 +01:00
Maurice b6e3c9bf39 feat(native): the app needs TREK 5.1.4 on the server
nativeApi goes to 3 with 5.1.4, whose UI follows a widget or Live Activity
tap that starts the app. The apps refuse an older server with the hint to
update, and check a server they remember once more.
2026-11-12 20:21:16 +01:00
Maurice 74d243d8e0 fix(airtrail): a new host does not inherit the stored API key
Saving the AirTrail settings with a different URL and the key field left
masked or blank kept the stored key, so the next sync sent the old
instance's key to the new host. The key now goes with the host, as it
already did for the connection test and for Dawarich: a new origin without
a new key clears it, a path edit on the same origin keeps it. The key is
cleared before the new address is written.
2026-11-12 16:58:24 +01:00
Maurice 56b9bac031 fix(native): a widget tap that starts the app opens what it points at
A tap on a widget or a Live Activity hands the app
com.liketrek.trek://navigate/<path>. A running app gets it as appUrlOpen;
an app started by the tap gets it as its launch URL, which nothing read, so
the path was lost and the app opened its start page (the packing widget
landed on the trip's plan instead of its lists). The launch link is now
followed once per launch.
2026-11-12 16:53:04 +01:00
Maurice 11472c05ff fix(native): a failed SSO round trip from the app still hands back on the retry
A sign-in the app starts runs through the server's handoff page in the
system browser. When the SSO callback failed (an expired or overwritten
state), the login page dropped the way back to that page, so the retry from
there was a plain web login and ended in the web app inside the app's
browser sheet instead of signing in the app. The login page now keeps a way
back that points at the handoff page, and only that, and renews its
fallback copy for a slow retry. State, nonce, PKCE and the handoff verifier
are unchanged; the handoff page still asks for a tap before it passes
anything on.
2026-11-12 16:10:14 +01:00
Maurice fc648bc7e4 fix: green checks after the first-screen redesign and the safe-area floor
- native-shell/amount.ts: the no-break spaces in the price pattern were
  written out as characters; \s already matches them.
- widgets.ts: the Live Activity's lead time stays inside the module.
- i18n: the count strings of the new plan tiles replace the removed ones
  on NOT_PLURAL, and the address placeholders of the non-Latin locales
  are their own instead of English copies.
- mobile.css: the side safe-area margins of the floating bars use
  margin-inline, swapped for right to left, instead of physical sides.
2026-11-12 14:36:13 +01:00
Maurice b8ec428ad1 fix(native): show the travel day's Live Activity from three hours before its first stop
The Live Activity started with the first sync of a travel day and stayed on
the lock screen all day, so a day whose first stop is an evening flight held
it from the early morning on. It now appears three hours before the day's
first timed stop and stays until the day is done; liveDayDue() decides.
2026-11-12 14:00:47 +01:00
Maurice a1d3ffc2ce feat(native): the 'server not reachable' screen names the cause, small, for a report
A load that failed sent the app to the address screen with a general message only, and a tester's screenshot told nothing. The web view's own error (net::ERR_..., an HTTP status, NSURLErrorDomain and its code, a client certificate the proxy asked for) is kept natively and shown under the message once.
2026-11-12 10:11:01 +01:00
Maurice 46b9df54bf feat(native): the TREK Cloud screens show the app and make the choice of a plan easy
The cloud screen shows real screens of the app. The plans are a choice now: one tap marks a plan, the recommended one is marked, what every plan has is said once above them, storage says how many photos it holds, and the yearly switch shows what a year saves; one button at the foot carries the chosen plan on. The claim screen names the plan with a way to change it, shows the address as it will be once it is free, ticks off the password rules while typing, says in three words where the servers are, that it can be cancelled and that there are no ads, and puts the photo behind the form away.
2026-11-12 10:04:31 +01:00
Maurice 3c0c3b3f6e fix(native): a store account with a running TREK Cloud subscription buys no second one
One subscription per Apple ID or Google account. Choosing another plan in the app changed the running subscription on the App Store, and the redeem then failed with 'We could not set up your TREK'. The app now asks the store first and shows a screen of its own: the account already has TREK Cloud, a new one can be taken out once it has ended, with Open my TREK and the store's page to manage it. The native purchase refuses as well; a paid one that was never set up is still redeemed. On the address screens the link 'What is a TREK server?' is gone, and the small print under a purchase is set in the system text face at regular weight.
2026-11-12 09:28:56 +01:00
Maurice ec08032e98 fix(native): SSO in the Android app survives Android ending the app while the browser is open
A Samsung phone may end the app while the sign-in runs in the browser. The browser's return then started the app anew without the call that waited for it, the first page load failed while the network was still held back, and the user came back to 'server not reachable' and then to the sign-in page, in a loop. The return is now kept natively and redeemed by the sign-in page with the verifier kept until then, and a page that failed on the network is loaded once more before the app gives up.
2026-11-12 08:42:17 +01:00
Maurice cc5eca5553 feat(native): a client certificate can be added on the address screen before connecting
The import was only offered once the check saw the proxy ask for a certificate during the handshake. A proxy that refuses without asking left no way in. The wiki also points to the certificate's new place in Settings and explains why a certificate from an iOS configuration profile cannot be used by the app.
2026-11-12 08:42:16 +01:00
Maurice c515f95d17 fix(ci): the drag hook lists its dependencies, closeOnDone stays module-private, and the weight test waits for its save 2026-11-12 07:10:18 +00:00
Maurice 742edc4a79 fix(ci): today's changes pass the release gates
- iOS: the navigation proxy reports an error page through a callback the controller sets; it called the controller's method on itself and did not build.
- keyboard: the done key reads the field's text in the capture phase, before the field's own handler, so a list that adds an item on Enter and clears itself keeps the keyboard; the tests wire it as the app does.
- Ireland migration: the queued writes use addSql instead of awaiting inside loops; only table constants and integer ids reach the SQL.
- tests: the Dawarich GL test types its two layer specs once (strict baseline lowered), the collab test reads the id off the listed message, the reasoning test runs its four servers in parallel, and a wasm copy covers the precompressed branch without a charset.
- en wording: the deviations agreement no longer calls TREK self-hosted.
2026-11-11 22:06:50 +00:00
Maurice 7db5ec0721 fix(native): the keyboard's done key closes the keyboard
A field outside a form gets enterkeyhint="done", but a web view only sends Enter and nothing listened, so the key did nothing. When no handler took the Enter (same text, still focused a moment later) the field lets go of the focus; a field that acts on Enter and clears itself keeps it. TestFlight feedback, 5.1.3.
2026-11-11 20:41:24 +00:00
Maurice e0022c12c4 fix(native): an error page in place of the server's keeps a way back to the address screen
A proxy's block page or a refused client certificate (Cloudflare's "Sorry, you have been blocked") left the app on a page without TREK's UI and no way to change the server. Any 4xx main-frame page that the client-certificate path does not handle now shows the sign-in bar with its own hint and "Change server", on iOS and Android. TestFlight feedback, 5.1.2.
2026-11-11 20:41:24 +00:00
Maurice 0ac06555cb test(native): reset the file preview mock between the file opening tests
The second test asserted the preview was not called while the first one's call
was still counted, so it failed whenever both ran in order.
2026-11-10 09:55:36 +01:00
Maurice 1b87c62847 chore: keep the API client within its size and the native API minimum module-private 2026-11-10 09:55:36 +01:00
Maurice 19956f2742 fix(native): a leg without an arrival day lands on the day it leaves in the Live Activity 2026-11-10 09:50:30 +01:00
Maurice 57c9c9d5f2 style: format the Japanese and Korean app strings and two tests as Prettier wants them 2026-11-10 09:43:01 +01:00
Maurice 0b3d2873c2 feat(native): a proxy's sign-in page in the app has a way out and says what cannot work there
Behind Pangolin or authentik the app shows the proxy's sign-in page itself, and
nothing on it led back to the address screen: a failed passkey left users stuck
on every launch. A bar over that page now offers to change the server and says
that passkeys and security keys do not work there, as a web view cannot use them
for a domain the app is not tied to. It steps aside while the keyboard is up.
On iOS the page also gets the room the keyboard takes, so a button under it can
be scrolled into view. The address screen hands the bar its words in the user's
language when it connects.
2026-11-10 09:36:50 +01:00
Maurice 2ab4459bc3 fix(native): the Live Activity keeps a day with flights ahead open instead of calling it done
A booking with stopovers was one stop at its first departure, and a stop
counted as done the moment it began. With a car at one and a connecting flight
at two, the Live Activity said all done for today mid-afternoon. Each leg is
now a stop of its own, as the planner shows it, and a flight or anything else
with an end time counts as under way until it lands or ends.
2026-11-10 09:29:40 +01:00
Maurice 5cbe4e2fa3 feat(native): the app needs TREK 5.1.3 on the server and checks a remembered one once after the update
The fixes that keep the app's sign-in in the app live in the server's UI,
so an updated app on a 5.1.2 server still ended in the browser. The server now
reports nativeApi 2 and the app refuses anything below it, naming 5.1.3.

A server the app remembers from before is not loaded unchecked: the first
launch after the update shows the address screen filled in with it, says why
and checks it right away. A server that is new enough loads again with its
session; an older one gets the update hint.
2026-11-10 09:17:26 +01:00
Maurice 2f03554a60 feat(native): files open in the system viewer instead of the share sheet
A PDF, image or document opened in the app went straight to the share sheet.
It now opens in Quick Look on iOS, to page through and zoom with its own share
button, and in the app that views its type on Android. An app without the
viewer (feature filePreview), or a type nothing on the device shows, gets the
share sheet as before.
2026-11-10 00:21:28 +01:00
Maurice 56b13541bd chore(native): keep the handoff start path inside browserSignIn, nothing else reads it 2026-11-09 23:29:38 +01:00
Maurice 8dd2e9716d test(native): fix the sign-in handoff tests' quoting and formatting 2026-11-09 23:15:09 +01:00
Maurice 1cdde6e9a4 fix(native): a field on a page as tall as the screen comes up above the keyboard on iOS
The login on an iPhone scrolls in no pane of its own, and the keyboard plugin
holds the body's height, so the page had nothing to scroll by and the password
field stayed under the keyboard, most of all with an error shown above it. Such
a page now gets room as tall as the keyboard at its end and scrolls the field
above it; the room goes with the keyboard.
2026-11-09 23:12:27 +01:00
Maurice 034cfb539a fix(native): the app's browser sign-in no longer lands on the dashboard when the browser still holds an older TREK
A browser that ran TREK before 5.1.1 keeps that version's app in its service
worker. When the app opened /native-handoff, the worker answered it from its
cache with an app that has no such page, which sent the user to /, and the
sign-in ended on the dashboard in the browser instead of in the app.

The app now opens /api/auth/native/start, which every TREK service worker
passes to the server. That page takes the workers off the browser and
forwards to the handoff page. Until the sign-in is handed back, the web app
registers no service worker and does not reload for a new version: a tab
still open on the older TREK keeps its worker alive, and a registration or a
reload in the middle of the sign-in brought it back to answer the next page.
2026-11-09 23:02:33 +01:00
Maurice 07448e662c feat(native): client certificates for servers behind mutual TLS
A proxy in front of TREK (Cloudflare, nginx, Caddy, Traefik, HAProxy) can
let in only devices that show a client certificate. The apps could not, so
such a server was unusable from them.

- Address screen: the server check runs natively and notices when the
  server asks for a certificate. Instead of "no server answered" it says so
  and offers to add a .p12/.pfx file; a wrong password asks again, an
  expired, not yet valid or keyless file is named as such.
- The certificate is shown only to the host and port it was added for.
  iOS keeps it in the keychain (this device only), Android seals the key
  with an Android Keystore key. The file's password is never stored.
- The web view answers the server's certificate request on both platforms;
  WebSocket, service worker and API requests go through with it. The
  offline copy, watch requests and the check use it too.
- When the server stops letting the app in (certificate removed, expired
  or no longer trusted) while the page still comes from the service worker
  or the offline copy, a native check sends the app to the address screen,
  which offers to add another. A server that only asks and lets everyone
  in is left alone.
- Cloudflare-style 403 and nginx-style 400 refusals without a certificate
  lead to the same screen instead of staying up as an error page.
- Settings, Account: a Client certificate card (only with one stored)
  shows subject, issuer, server and expiry, with Replace and Remove.
- Wiki: Native-Apps "Client certificates (mTLS)" with Cloudflare, nginx,
  Caddy and Traefik setup and how to make a certificate for the app.
- The app icon on the unreachable screen is black on the light surface.
2026-11-09 12:03:31 +01:00
Maurice 80c04df4fc feat(native): swipe rows, long-press menus, placeholders while loading, fading pictures, iOS bounce and app icon quick actions
Packing items, tasks and expenses swipe sideways to their actions, as in
Mail or Reminders: done or open one way, delete and edit the other, the
first one run by a full swipe. They are second ways to what each row
already offers; an expense still asks before it goes.

A long press on a trip card lifts it and opens its menu with the card's own
actions. Plain confirmations in MConfirmSheet now also ask through the
system where the app can.

Lists, the atlas and a journey show grey placeholders in their shape while
loading instead of a spinner in an empty screen (MSkeleton); buttons keep
theirs. A picture still loading fades in once it is there; one from the
cache shows at once. In the iOS app the page bounces at its ends again,
except on screens with pull-to-refresh, whose pull it would race; Android
keeps its stretch off.

On iOS a long press on the app icon offers "New trip" and the trip coming
up by its name, set by the UI in its language (TrekShell.setQuickActions,
feature quickActions), and a tap opens it, also from a cold start.

The app's own CSS moves out of index.css into native/nativeApp.css, which
had outgrown its size budget.
2026-11-09 09:37:36 +01:00
Maurice c9a91bbdad fix(native): the native question reads no ref while rendering, and its tests type and lint clean 2026-11-09 09:16:58 +01:00
Maurice d06168d94a feat(native): the app answers a finger like a native app, not like a web page
After a tap, WebKit and Chrome keep :hover on what was tapped and send a
made-up mouseover, so buttons and rows stayed tinted until the next tap.
While a finger drives the app <html> carries data-touch-input: a PostCSS
step guards every :hover rule with it (no specificity change), and the
made-up mouseover and mouseout stop before any handler. A trackpad or mouse
clears the mark and gets hover back; a browser never sets it.

A control without a press of its own dims the moment a finger lands on it,
after a 60 ms wait so a scroll does not flash rows, and only the innermost
pressed control. A focus: ring no longer stays round a tapped button.

Fields get a fitting return key ("done", "go" in a form, "search" on the
search fields), and addresses, codes and numbers are no longer capitalised
or corrected. Ticking off packing items and tasks, a picker chip, a select
option, a picked date and dragging a plan row now give the haptics a native
list gives.

Confirmations ask through the system where the binary has the new
@capacitor/action-sheet and @capacitor/dialog plugins: a sheet with the
action in red when it destroys something, an alert otherwise, also for
"discard changes" in a sheet. An older app, a browser and a question with a
list under it keep the HTML dialog, as does a system that could not ask.

iOS no longer lifts a page preview on a long press on a link.
2026-11-09 08:54:51 +01:00
Maurice d9baaa8957 fix(native): a long press in the app selects no text and opens no callout
In the iOS and Android app a long press on a label, card or image started a text
selection, the magnifier or a "save image" menu, the clearest sign of a web page
in a frame. startNativeApp marks <html> with data-native-app, and index.css then
turns selection and the callout off for the UI. Inputs, textareas, selects and
editors stay selectable so typing, pasting and the caret work; text worth copying
opts in with .trek-selectable. A browser keeps its default.
2026-11-09 08:32:24 +01:00
Maurice b3113e66b9 feat(native): buying TREK Cloud in the app asks for the password of the new TREK and opens it signed in
The claim screen takes the password (TREK's policy, checked before anything is
bought) and sends it with the purchase; the control plane answers with a
one-time welcome code, which the app hands to setServer. iOS and Android open
the instance's welcome page with it once after the first page, which signs the
buyer in. Without the code (a restore, an older control plane) the app opens
the instance as before.
2026-11-08 23:43:15 +00:00
Maurice 3be87343b8 fix: the gate texts formatted as the locales are, gate detection as a table of rules, and no non-null assertions in its tests 2026-11-08 20:58:49 +01:00
Maurice 517efabbca feat(native): the address screen recognises a sign-in proxy in front of TREK and signs in to it inside the app, so its session works as in a browser 2026-11-08 20:44:26 +01:00
Maurice afb6eae4c8 fix(native): the handoff's passkey sign-in lives in native/browserSignIn, so the page hook reaches no API on its own 2026-11-08 18:33:00 +01:00
Maurice 36c8c5bc48 fix(native): a passkey sign-in from the app asks for the passkey straight away in the browser and returns to the app, instead of showing the whole login a second time 2026-11-08 17:50:50 +01:00
Maurice 4ba7db90e6 fix(native): SSO in the system browser hands back to the app even when the provider finishes in another tab, and the handoff button's label shows 2026-11-08 17:43:28 +01:00
Maurice ed6724035e fix(offline): a Cache Storage open that never settles is given up on, so preparing for offline and the offline map no longer wait on it forever 2026-11-08 12:26:07 +01:00
Maurice eea83bb1c9 fix: GL maps read the stored copy again while offline, and a switch that is on keeps a visible knob in the dark scheme 2026-11-08 12:21:52 +01:00
Maurice 06c03cbded fix(mobile): the 3D grade legend goes compact on the side, and a field under the keyboard gets room to scroll above it 2026-11-08 12:15:34 +01:00
Maurice 53c18b861a fix(native): GL maps load straight from their servers in the app, past the schemes they drew nothing through on iPadOS 26 2026-11-08 12:11:23 +01:00
Maurice 9b1bf89382 fix(native): a field low on a screen scrolls above the keyboard when it comes up 2026-11-08 12:07:57 +01:00
Maurice c7f144d3ff fix: the map falls back to raster where the vector style cannot load, the tour layer pill fits narrow maps and stands on the side in 3D, the dashboard's widget column scrolls on its own, and the CI checks the watch sync and journey write-up broke 2026-11-08 12:05:59 +01:00
Maurice 3458238db0 feat(native): a link shared to TREK can go to the trip's links
A page or a link shared from another app now carries its address. The app asks whether to keep it among the trip's links (Collab, Links) or to read a booking from it. A link whose page the phone cannot read is no longer refused: it is handed over as the link alone, which can be kept. With Collab off a page is read as a booking, as before.
2026-11-08 10:15:26 +01:00
Maurice afaacec61a fix(native): a tick on the watch, the phone or another member's device reaches every watch at once
The watch's snapshot was rebuilt every fifteen minutes, so a tick in the app or one arriving over the WebSocket did not reach the watch until then. It is now rebuilt as soon as the packing lists or the to-dos change in the offline tables. A tick on the watch goes as a message while the phone is in reach, which wakes the phone app, and a phone app in the background writes it to the server itself, so the trip's other devices hear of it at once instead of when the phone app is next opened.
2026-11-08 10:15:20 +01:00
Maurice dedbf16f03 fix(native): Android offers TREK Cloud while orders are closed and says a refused purchase is refunded
The licence testers of the internal test buy from a release build, so the
plan screen no longer hides the purchase on Android before the opening.
Their purchases are Play test purchases, which the cloud serves. A real
purchase made before the opening is refused with ordering-closed and never
acknowledged, so Google Play refunds it after three days; the claim and the
restore now say that instead of a general error. The app still acknowledges
a purchase only after a redeem that returned an instance. iOS is unchanged.
2026-11-08 02:31:13 +00:00
Maurice 6906f80ff8 feat(native): Android tablets get the shortcuts, two panes meet at a foldable's fold
The Android shell now reports keyCommands and windowLayout, so the large
screen layout no longer assumes an iPad:

- The keyboard host hands the shortcuts to the app whenever the shell has
  the keyCommands feature, whatever the platform. Before it also required
  iOS, so an Android tablet with a keyboard answered the keys in the page
  and never listed them in the system's shortcuts.
- useWindowFold follows the layout the Android shell reports (feature
  windowLayout). When a vertical fold separates the window, a foldable half
  open like a book, MobileShell marks it with data-fold and its place, and
  the leading pane (the trip's plan, a tab's summary, a list beside its
  detail) ends at the fold while the trailing one starts there, on either
  reading direction. A flat fold that does not separate stays one screen.
- The split size class starts at 840pt, Android's expanded width, instead
  of 900pt, so a foldable unfolded on its side (about 841dp) gets two panes
  like an iPad does. An 11" iPad upright (834pt) stays a single pane. The
  address screen of the native shell follows the same width.
- TrekShell exports NativeWindowLayout for it.

Also: the sheet's width and anchor types and the collab board type stay
private to their modules, which nothing else imports (knip).
2026-11-07 23:25:13 +01:00