4970 Commits

Author SHA1 Message Date
DIYgod 28ab52296e fix(mobile): embed the real OTA runtime version in Android builds
EAS generates android/ with `expo prebuild`, which sets NODE_ENV to
"development" when it is unset. The app config picked the 0.0.0-dev
runtime from NODE_ENV, so every Android binary since the React Native
0.79 upgrade embedded expo_runtime_version 0.0.0-dev, and ota.folo.is
rejects its update checks. iOS kept the real runtime because eas-cli
syncs its committed Expo.plist outside of prebuild.

Decide the development runtime from the EAS build profile and fall back
to NODE_ENV only without one (expo start, local prebuild). The
eas-build-post-install hook now fails any build whose native runtime
differs from the expected one, and a test evaluates every eas.json
profile the way prebuild does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 16:21:11 +08:00
github-actions[bot] cffb8f0113 Merge pull request #5113 from RSSNext/mobile-main
chore(sync): merge mobile-main into dev
2026-10-16 07:01:00 +00:00
DIYgod 980019b65e release(mobile): release v0.6.0 2026-10-16 13:31:59 +08:00
DIYgod ec58ad2886 release(desktop): release v1.16.0 2026-10-16 13:31:28 +08:00
DIYgod 148b453af2 docs(mobile): prepare release metadata
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 13:31:15 +08:00
DIYgod 0174702aed docs(desktop): prepare release inputs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 13:31:13 +08:00
DIYgod 13e169760d fix(mobile): open the lightbox on the cached thumbnail and size thumbnails to the card
The lightbox placeholder was the original image URL instead of the
proxied thumbnail the card had loaded, so it never came from the cache,
and expo-image on Android decodes placeholders at full size. Every
lightbox page also got the tapped image as its placeholder, so the other
pages showed the wrong picture until their own loaded.

Hand the lightbox the card's proxied thumbnail for the tapped page only,
and let the carousel and the lightbox page through the same deduplicated
media list so an index means the same image in both. The Social Media
view had the same placeholder bug.

Cards in the Pictures view asked the proxy for 1200 px tall images. Ask
for one side sized from the measured card instead, rounded up to 50 dp
so the URL stays stable, and the card's height for images relatively
wider than the card so cover fit stays sharp. Asking for both sides
would make the proxy crop the image.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 12:00:43 +08:00
DIYgod a044040bad fix(mobile): stop loading every image of an entry at once
Entries in the Pictures view can carry dozens of images (cosplaytele
posts have 25 to 110), and MediaCarousel rendered every page of its
ScrollView, so each mounted row loaded all of them. Until onLayout the
carousel was 0 px tall, so FlashList measured rows at footer height,
mounted every row of the page and kept them in its recycle pool. The
lightbox likewise mounted the original of every page.

Load images only for the visible page and its neighbors in both, and
size the carousel by its aspect ratio before its width is measured.

On an Android emulator with 20 cosplaytele entries (1142 images),
opening the Pictures view took the native heap from 96 MB to 2.1 GB
before this change and to about 170 MB after it.

Refs #5108

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 11:19:29 +08:00
DIYgod 4e489f4e5e fix(mobile): keep marking entries read after the first one scrolls past
Marking entries read on scroll stopped after the first entry. Once the
scrolled-out entries were handed off, the list kept for them was stored
again as a new array, an empty one when all of them were handed off.
That ran the marking effect again, and since marking goes through the
transaction queue, marking nothing resolves at once, so the effect ran
every few milliseconds without end. It kept the JS thread busy: no
later entry was reported as scrolled out, and the queue's flush timer
never fired, so even the first entry only reached the server on the
next launch.

Store the same list when nothing changed, and none when nothing is
left.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:30:31 +08:00
DIYgod 306460b755 fix(mobile): give search results for unstored feeds distinct keys
Discover search results for feeds the server has not stored yet all have
an empty id, so their cards shared the key "" and React warned about
duplicate keys. Fall back to the feed URL when the id is empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:25:52 +08:00
DIYgod 7463bc3d4f fix(store): follow a feed the server has not stored by its URL
A new feed address was previewed under a random nonce id that mobile sent
as feedId, so following it failed with 422 "Invalid Snowflake ID". The
nonce is no longer sent and the feed is followed by its URL; the feed that
arrives for that URL then replaces the preview.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 03:35:35 +08:00
DIYgod 2291d66500 fix(mobile): stop keyboards capitalizing and correcting the handle
The Handle field kept the text defaults, so keyboards capitalized its first
letter and offered corrections that can rewrite it or add a space, which the
new check then refuses. It now turns both off, as the Website field does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:08:30 +08:00
DIYgod 850714d788 fix(mobile): name what the handle check refuses in its message
Edit Profile refuses only spaces and invisible characters in a new handle,
as the server does, yet said "Use only letters, numbers and underscores."
from desktop's stricter check, although dots, dashes and CJK handles save.
It now says what it refuses, in every locale.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 01:57:18 +08:00
DIYgod 51a32f11ec fix(mobile): lock Hide Special Badges on a free plan, as desktop does
The paid lock missed this Appearance switch, which desktop also marks paid,
so on a free or trial plan it flipped back off without a reason. It now
shows the paid badge and offers the upgrade, and a test checks that each
settings screen locks the paid settings it changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 01:55:30 +08:00
DIYgod 515bc47ae3 fix(mobile): check profile edits as the server does and explain refusals
Edit Profile sent blank names, values too long for their columns and handles
with spaces, then toasted the server's English text or a bare 500. Fields are
now checked as the server checks them, its update-user codes show translated
messages under their fields, and after a bare 500 a taken handle is looked up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 01:33:40 +08:00
DIYgod 8af5f0dee2 fix(mobile): lock the paid settings a free plan lacks, as desktop does
A free or trial account could turn on AI Translation, its mode, Hide private
or Hide Recent Readers, which then did nothing without saying why. These now
read as off, show the paid badge and offer an upgrade when pressed; a value
saved before applies again once the plan includes them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 01:23:58 +08:00
DIYgod d284517c12 fix(mobile): explain an invalid email once typing pauses
The Forgot Password and Edit Email hints waited for the field to lose focus.
Android keeps it focused when Back closes the keyboard, as does tapping the
Edit Email header, so Continue or Submit stayed disabled without a reason.
The hint now also shows a second after typing stops.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:51:23 +08:00
DIYgod f56d18558e fix(mobile): drop the old follow.db copy when exporting the database
Earlier exports left a full copy of the database named follow.db in the
app's documents. With exports now named folo.db nothing replaced that copy
any more, so it stayed next to the new one. Exporting now removes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod 8f7bafb342 fix(mobile): dim disabled switches on Android
Android kept the custom colors of a disabled switch, so a list's locked
Private Follow and Hide from Timeline switches looked usable to free users
and did nothing when tapped. A disabled switch is now dimmed on Android, as
iOS already does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod f6d29f06e3 fix(mobile): shrink long Discover category names on Android, not cut them
On a 411dp Android phone the Application Updates tile read only
"Application": Android fits the font to the text view's width with its
padding included, so it kept the size and hid the second word. The name is
now indented with a margin and shrinks to fit, as on iOS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod 0fea778106 fix(mobile): show untranslated Discover tags by name, not by key
In Discover's Popular list, sites with route tags outside the translated
categories, such as other or sport, showed chips reading
"discover.category.other". Those tags now show their own name, as on desktop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod 12a1b64e76 fix(mobile): share the exported database as folo.db
Export Database shared a file named follow.db. It now uses the Folo name; the
database the app reads stays follow.db, so existing data is kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod 6df30a472e fix(mobile): keep the category tags of long Discover site names on screen
A long site name in a Discover category, such as Association for Computing
Machinery (ACM), pushed its category tag past the right edge. The name is now
truncated to one line, and a site with many tags wraps them as desktop does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod 8eb6391972 fix(mobile): keep Discover category names clear of their emoji
Long category names such as Programming and Application Updates ran under or
over the emoji on their tiles. The emoji now sits above the name and shrinks
on small tiles, and a name too long for one line shrinks to fit it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod e2c732a6b3 fix(mobile): show feed descriptions in Discover as plain text
Feeds that publish their description as HTML showed tags such as <em> and
<br> as text in Discover search results and the follow form. The summary now
shows the description's text on one line, with character references decoded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod a58cf39b25 fix(mobile): explain an empty Trending list and name the filter buttons
With no trending feeds, Discover showed the Trending header over a blank
gap. It now says there are no trending feeds yet, as desktop does. The
filter buttons by Trending and Categories had no accessible name and are
now announced as Discover Filters buttons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod d7563d0119 fix(mobile): mark a list's private follow and timeline hiding as paid
Free users could turn on Private Follow and Hide from Timeline for a list,
which their plan does not include. Both switches now show the paid badge,
which offers an upgrade, and are disabled for them, as on desktop. A list
that already has one on can still turn it off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod a7a51a47a8 fix(mobile): name form fields and switches and report action bar toggles
Fields and switches of the follow and list forms had no accessible name,
so screen readers announced only "edit box" or "switch". They now take
their label or the label of their grouped cell. Action bar items are
buttons, and toggles such as Show Readability report when they are on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod b0dca1e528 fix(mobile): show both initials in a round header avatar
The 24 pt initials avatar padded its text into 8 pt, so "SW" wrapped and
showed only "S". On Android it also turned square after sign-in, as the
unfilled signed-out view was flattened and recreated without its corner
radius. Drop the padding, keep the initials on one line, never flatten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod a949cef043 fix(mobile): word the list title hint for lists and use an email keyboard
The follow-list form called its title "Custom title for this Feed". Edit
Email opened a text keyboard with autocorrect and kept Submit disabled for
an invalid address without a reason; it now checks the address like the
server does and explains it under the field.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod 32cfeb2fc0 fix(mobile): show the handle description under the Handle field
Edit Profile placed "Your unique identifier." under the Email row, which
had been inserted between the Handle field and its description.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod 557aeee10c fix(mobile): keep long values of aligned text fields from being cut off
On iOS an aligned field word-wrapped its value when not focused, so Edit
Email showed only "sweep-mobile-" and profile fields such as Website were
cut at a hyphen the same way. Single-line fields now end in an ellipsis
like other iOS text fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod cecf2f39e9 fix(mobile): say the passwords do not match when saving a new password
Save stayed disabled while the confirmation differed, so tapping it did
nothing and the mismatch message was only reachable from the keyboard.
Save is now enabled once every field is filled and reports the mismatch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod cf66870969 fix(mobile): explain an invalid email on the forgot password screen
Continue sent any text to the server, which answered with the raw
"[body.email] Invalid email address" toast in every language. Check the
address first, keep Continue disabled until it is valid and say why
under the field.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod fe5614b61c fix(mobile): offer an upgrade when a free plan asks for a translation
On a free plan "Show Translation" got checked but nothing was translated and
nothing said why, and the item was hidden whenever the AI Translation setting
was on. Free plans now always see the item, and it opens the upgrade dialog
that names the Basic plan, as desktop's paid badge does, instead of toggling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod bb8eb5a2ee fix(mobile): show the feed artwork in the podcast player
The player bars and the full player were blank for episodes without their
own image, or whose image failed to load, while the list showed the feed icon.
Playback now starts with the artwork the row shows, and the player loads it
through the image proxy and falls back to a letter avatar if it can't load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod 7ee3fbb025 fix(mobile): mark only the open feed as read from its header button
The header of a feed screen renders outside the screen, so its Mark all as
read button marked the whole view selected on Home as read instead of the
feed, list or category on screen. The header actions now get the screen's
entry list context again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod 141c8d146e fix(mobile): keep header titles centered when the header buttons change
The header measured its buttons once to center the title, so after signing
in or rebuilding the database, when the Home actions appeared later, the
title sat off center until the tab was switched. It now re-measures them on
every layout change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod cff92214c6 fix(mobile): switch the tab bar and relative times with the language
After a language switch the native iOS tab bar kept its old labels, since
only the first title reached the tab bar item, and times on screen mixed
languages ("2 years前"). Later titles now reach the item, the dayjs locale
switches before the language, and relative times re-format on the switch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod 755742b106 fix(mobile): keep the header on the follow screen while it loads or fails
While a feed or list loaded, failed or was missing, the follow screen showed
only a spinner or an error, with no header to close it, and the feed error
said the list failed to load. These states now keep a Follow header with its
close button, and the feed error names the feed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod 6e0b04b154 fix(mobile): show a close button on the profile banner
The profile's header with its close button stayed invisible until scrolled,
so on Android, where the profile opens full screen, the top showed only an
unlabeled share icon. The banner now shows a close and a labeled share
button, in the banner's colors, until the header fades in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod b2ed0a6611 fix(mobile): keep the keyboard from staying open after a form closes
When a screen or dialog with a focused field closed on Android, focus moved
to the hidden TTS WebView, which kept the keyboard up with nowhere to type.
The WebView now sits in a native view that blocks focus (needs a new Android
build; older binaries fall back to a plain view).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod 21292fbdaf fix(mobile): open a feed from a profile in its own view
The feed screen used the view selected on Home, so with Pictures selected
an articles feed opened from a profile showed no entries, and its mark as
read requests named the wrong view. It now uses the subscription's view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod 4d370c5b8c fix(mobile): explain Spotlight and let its empty list add a rule
With no rules, Spotlight showed "Add rule" as gray text that did nothing,
and the footer repeated "Add rule" even when rules existed. The empty list
now has an "Add rule" button, and the footer says what Spotlight
highlights and which rule wins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:48:32 +08:00
DIYgod 55690ce2d8 fix(mobile): keep Spotlight highlights readable in dark mode
Highlighted words kept the theme's white or gray text on the pale
highlight colors, about 2:1 contrast in dark mode, in the timeline, entry
titles and entry text. Highlights now set black text, or white on a dark
color.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:47:47 +08:00
DIYgod 7855d42eae fix(mobile): drop a Spotlight rule closed without a pattern
Tapping + saved an empty rule before the editor opened, so closing the
editor with X, a swipe or Back left a blank "Pattern" rule in the list
each time. Closing the editor now removes its rule while the pattern is
still empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:47:47 +08:00
DIYgod 52973d6ab9 fix(mobile): show the Edit Rule action icons in dark mode
The symbols of the Then Do actions, such as Star and Webhooks, were tinted
black and all but vanished on the dark grouped background. Tint them with the
label color, which stays black in light mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:47:47 +08:00
DIYgod 4fdc56972e fix(mobile): keep the lines between action rules and between lists
On Actions and Lists, the line between two rows vanished once another row was
added or grew. As the only flex-1 child of its list cell, the separator kept a
zero flex basis; it no longer flexes and keeps its hairline height.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:47:47 +08:00
DIYgod 1142fa2cc8 fix(mobile): show the Rewrite Rules and Webhooks rows at full width
On Edit Rule, a row wrapper shrank the Rewrite Rules and Webhooks actions to
their chevron, so their labels wrapped into a tall unreadable column. Drop
the wrapper, and let the list cell grow instead of flex-1 so a lone cell in
a swipeable row keeps its height.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:47:47 +08:00
DIYgod d2d017e4aa fix(mobile): show the swipe action color only while a row is swiped
Since gesture handler 3 the Delete color sat behind every swipeable row at
rest, so Edit Webhook rows and the Edit Rule Then Do rows showed solid red.
Hide it until the row moves, and give webhook rows the grouped cell background.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:47:47 +08:00