Master moved code in files the iOS and Kotlin specs link to by line (Kotlin ChatListView.kt by 29 lines and others); two references from this run's slices also had a stale line column or link text.
Review R1-3, run 008-dirsearch-known-chats
It drew by hand what ChatInfoImage draws for a group (its image, or the group's icon), which the Kotlin row uses too.
Review R1-2, run 008-dirsearch-known-chats
Master changed ProfileImage's iconName: String to icon: Image (#7767's merge brought it in). The Directory and Names rows and New chat's group row still passed iconName, which no longer compiles; they pass Image(systemName:) as master's own callers do.
As on iOS: a directory result whose link resolves to a chat the screen doesn't list is drawn with that screen's chat row, which opens it, instead of "Join group" / "Join channel": ChatListNavLinkView in the chat list, ContactListNavLinkView (now with a group branch) in New chat. When every result of the last page is a chat already shown, the Directory part says "All results on this page are already in your chats" above "Show more".
Run: 008-dirsearch-known-chats, slice 3
A directory result whose link resolves to a chat the screen doesn't list is drawn with that screen's chat row, which opens it, instead of "Join group" / "Join channel": the chat list's row there, a contact-style row in New chat (ContactListNavLink gets a group case). When every result of the last page is a chat already shown, the Directory part says "All results on this page are already in your chats" above "Show more", instead of showing the header and "Show more" alone.
Run: 008-dirsearch-known-chats, slice 2
The Directory part will draw known chats with the chat list's own row, so its two modifier chains (iOS 16+, iOS 15) move unchanged into chatListNavLink(_:), and the list's two ForEach branches become one. The iOS 16 offset moves from the ForEach to each row, which SwiftUI applies the same way.
Run: 008-dirsearch-known-chats, slice 1
The same change as on iOS: the rows without a local chat look it up again when a connection started from one ends, so a group or channel opened from its row is no longer listed twice until the next search.
A result's local chat was looked up only when the search ran, so a group or channel opened from its row stayed listed twice, as the chat and as the row, until the next search (a test run joined cinews_digest from the Directory part and saw both). The rows without a chat look it up again when a connection started from one ends.
While a "Search in Directory" or Search key search runs or shows results, the chat list leaves out its banner slot, the reachable toolbar card and the connect cards. Typing alone, which only filters the chats, keeps them, and they come back when the results go.
The count used typography.caption, which is 18 sp in this theme, larger than the description above it. It now uses body2, as the other subscriber counts do.
The one-hand chat list is reversed, so a header emitted before its rows was drawn below them. searchPart puts the header after the rows in that layout, as the iOS fix does; the rows keep their order, nearest the search field. The onboarding results list, whose first item is now a keyed row, scrolls to its start when name results arrive, since the list would otherwise hold a directory row in place and leave the names below it. Spec links into ChatListView.kt refreshed.
After "Search in Directory" or the keyboard's Search key, the results are shown without the Wefunder or badge banner, the one-hand UI card and the "New 1-time link" / "Paste link / Scan" cards. Typing still keeps them, as it only filters the chats, and they come back when the search text is cleared.
The one-hand chat list is flipped, so a header emitted before its rows was drawn below them. searchPart puts the header after the rows in that layout; the rows keep their order, nearest the search field. Spec links into ChatListView.swift refreshed.
* desktop: fix crash in SimpleX address screen when there is no profile
* desktop: close SimpleX address screen when there is no profile
* desktop: rerun address screen self-close when its modal is reused or the stack changes
* desktop: close SimpleX address screen only when it is the top modal
* plans: correct address no-profile crash triggers and fix description
* plans: correct address no-profile crash fix description and verification
* plans: tighten address no-profile crash wording
* plans: add self-destruct trigger to address no-profile crash
* plans: qualify self-destruct trigger on desktop
* plans: drop desktop-only title from address no-profile crash
* plans: no connected mobile, not no mobile
* spec, product: document isLastModal and address screen without profile
* plans, spec, product: plan sections, address row spec, GAP-08 and GAP-09
* spec, product, plans: fix GAP-08/09 wording, table placement, ModalManager line
* spec, product: GAP-08/09 accuracy, gap count, clickable ModalManager location
* product, plans: GAP-09 at the level the code supports; qualify picker auto-open
* spec, product, plans: fix GAP-09 locations, stale line links, wording
* spec, product, plans: update plain-text line numbers; GAP-09 read wording
* plans: name the picker auto-open condition
* spec, plans: wording; security note
* plans: self-destruct did not crash on Android master; not a trigger
* plans: self-destruct path possible but unconfirmed; Android recovers silently
* spec, product, plans: drop GAP-09 and unrelated line refreshes
* plan: Android self-destruct path confirmed in logcat
* desktop: close Chat preferences screen when there is no profile, as the address screen does
R1-1: state OnlineSearchModel's main-thread premise, which iOS's
@MainActor carries and Kotlin otherwise leaves implicit.
R1-2: state the @Transient mechanism that keeps the directory link
check from being bypassed or deferred.
Spec line references into the two files shift by one accordingly.
Run: 003-kotlin-directory-search, review round 1
CODE.md asks for every line reference in an affected spec document to be
updated. Most of these were already stale on master. Numbers only: no
wording changes. Kept apart from the feature documentation so it can be
reviewed or dropped on its own.
Run: 003-kotlin-directory-search, slice 7
apps/multiplatform/CODE.md requires spec and product updates with every
code change. Mirror the iOS online search docs in the Kotlin docs' own
formats and numbering, stating where Android and desktop differ, and
fix the ConnectProgressManager signatures the branch's owner parameter
had made stale.
Run: 003-kotlin-directory-search, slice 6
Port the iOS New chat online search: the Search key and the "Search in
Directory" row work as on the chat list, and the Names and Directory
sections follow the contacts, de-duplicated against them. "No filtered
contacts" shows only when the online search found nothing. Archived
contacts are unchanged.
Run: 003-kotlin-directory-search, slice 5
Port the iOS chat list online search: the Search key resolves a typed
SimpleX name online and searches the directory, the "Search in
Directory" row searches the directory only, and the Names and Directory
parts follow the local chats, de-duplicated against them. The onboarding
state now shows the search bar too, with its results in place of the
onboarding pages (on desktop the pages stay in the centre pane). The
empty-state overlays no longer cover online results.
Run: 003-kotlin-directory-search, slice 4
Port OnlineSearchModel and its rows from the iOS DirectorySearchView:
directory pages and SimpleX name resolution share one lifecycle, run on
the main thread like the iOS @MainActor model, and drop late replies by
generation. Add the "Search in Directory" row, the directory and name
rows, the first-search alert, and an onSearch handler on SearchTextField
(Android IME Search action, desktop Enter). Nothing calls them yet.
Run: 003-kotlin-directory-search, slice 3
Port the iOS online-search model: a directory entry now carries a
non-optional link that decoding accepts only for group and channel links
(the core fetches an invitation link even in a store-only plan), plus
planLocalChatId, NameSearchResult, DirectoryResult and OnlineSearchRows.
apiConnectPlan gains onFailure so lookups can log instead of alerting,
and the first-search alert gets its hint preference.
Run: 003-kotlin-directory-search, slice 2
The onboarding state will render the same search bar as the chat list,
as iOS renders ChatListSearchBar in both. Move the three search states
to ChatListView, next to searchText, where iOS keeps them, and extract
the sticky header's search bar and tags into ChatListSearchBarWithTags.
No behaviour change.
Run: 003-kotlin-directory-search, slice 1
* badge-service: accept a list of Apple roots
* badge-service: document root_certificates
---------
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
* ci: drop dlltool from nodejs libs release
* nodejs: download libsimplex into the user cache
* nodejs: load libsimplex at runtime per backend
* support bot: select db backend with --db
* python: match backend switch error text
* nodejs: download prebuilt add-on at runtime
* ci: build nodejs add-on for libs release
* calculator bot: load libs and add-on in image
* support bot: document add-on override
* nodejs: keep worker test output free of colors
* nodejs: verify sha-256 of downloaded assets
* python: pin core libs release with sha-256
* ci: add packages release script
* ci: release nodejs add-on and open release PR
* ci: publish packages after release PR
* nodejs: keep npm from building the add-on
* calculator bot: build the add-on in the image
* ci: merge package release workflows
* ci: open release PR when publishing fails
* ci: build the add-on with node-addon-api only
* ci: skip publishing in a called packages workflow
* ci: update package release actions to Node 24
* nodejs: fix receive test timeout
* ci: test packages on pull requests
* nodejs: reuse the database in the close stress test
* ci: keep failed package tests from hanging
* ci: skip preset server tests
* ci: plan package builds from the changes
* ci: test packages with a given libsimplex
* ci: test packages with libsimplex of core changes
apps/ios/CODE.md asks that every #Lxx-Lyy reference in an affected
spec document point at the right lines. Most of these were already
stale on master; this corrects them in the documents the online search
change touched. Numbers only: no wording changes. Kept apart from the
feature documentation so it can be reviewed or dropped on its own.
Run: 002-ios-directory-search-ui, review round 1 (R1-7)
apps/ios/CODE.md asks every iOS change to keep spec/ and product/ in
step with the code. The online search (SimpleX Directory and names, on
the chat list and in New chat) had no documentation, including the
parts added on this branch before: the spec gains a chat-list section
and a New chat section, the API entries for the service request and
the connection plan's failure mode, the impact and index rows and the
Document Map rows for the new source files; the product docs gain the
views, a concept row, rules for what the search may and may not do,
and the known gaps. Only line references moved by this branch's own
code are updated here.
Run: 002-ios-directory-search-ui, review round 1 (R1-7)
R1-1 New chat clears its online results on a profile switch, as the chat list does
R1-3 the search spinner follows its two flags through property observers
R1-4 the join verb keeps one line, so the name truncates instead
Run: 002-ios-directory-search-ui, review round 1
The New chat sheet gets the chat list's online search: a "Search in
Directory" row, the keyboard Search key for names and the directory,
and Names and Directory sections after the contacts. Tapping a result
connects and closes the sheet, as other New chat actions do. A contact
the list already shows is not repeated as a name result, and the
contacts list's empty state stays hidden while a search runs or shows
results. Archived contacts, which share the search bar and the list,
are unchanged.
Run: 002-ios-directory-search-ui, slice 4
The keyboard Search key on the chat list now also resolves a typed
SimpleX name online, alongside the directory search, and shows what it
finds as a Names part between the local chats and the directory
results. Resolution never raises an alert: apiConnectPlan gains an
onFailure mode, and existing callers keep alerting by default.
Each directory entry is looked up in the store (store-only, as entries
are now group or channel links only) so a chat the user already sees
locally, or found by name, is not shown again; names already in the
local list are hidden the same way. A directory row is matched to a
name only by the link the core resolved, never by a profile field the
name's owner writes, so a name cannot hide a genuine directory row.
The "Search in Directory" row, retry and "Show more" keep the names
already shown. One helper drives the spinner from whether anything is
in flight, and every publish checks the search generation, so a late
reply after a text change or cancel writes nothing. The first-search
alert now also names the server that resolves names.
Run: 002-ios-directory-search-ui, slice 3
A directory result is untrusted input: an entry is kept only when its
link is a group or channel link, because the core fetches a one-time
invitation link even when asked for a store-only plan, and the next
slice looks every entry up in the store. The entry's link is no longer
optional, so the tap needs no unwrap and the id no fallback.
The Directory part now renders only when it has a row: no header while
loading, no "No results" row; the empty-state overlay shows when the
search finished with nothing. Its header is a row rather than a sticky
section header, which in the flipped one-hand list would pin at an
unverified position. Rows say "Join channel" or "Join group". A pasted
link in one-hand mode leaves the tags in place.
Run: 002-ios-directory-search-ui, slice 2
The search model is about to hold name results beside directory
results, so it becomes OnlineSearchModel. The "Show more" and retry
rows, the first-search consent check and the contacts list's shown-chat
derivation move to where the New chat sheet can reuse them. No
behaviour change.
Run: 002-ios-directory-search-ui, slice 1