Commit graph

236 commits

Author SHA1 Message Date
Adam Brown
5c3d90ac7f Fix PDF export crash on desktop (#789)
ProGuard stripped org.apache.commons.logging.impl.LogFactoryImpl, which
LogFactory resolves by name, so PDDocument's static init threw
ExceptionInInitializerError on every PDF export from a packaged build.
Only pdfkmp-jvm pulls in PDFBox, so Android is unaffected.

Export failures also went uncaught in ExportDirectoryPicker on all three
platforms, killing the app instead of showing the existing failure toast.
2026-08-17 21:28:46 -07:00
Wavesonics
540392a7a7 Move the sandbox first-run flow onto native AppKit
The Mac App Store build's first-run folder picker ran through AWT, which
claims NSApp before Tao installs its event loop — the app then runs on
with no window and no crash. Move the picker and its alerts into the
Objective-C helper so nothing touches AWT before nucleusApplication().

Localized dialog text now comes from SandboxStrings, which reads the
packaged Compose Resources .cvr value files directly; getString() can't
be called pre-Compose because resolving a ResourceEnvironment
initializes AWT for the density qualifier. Value files layer English
under each locale so a key Crowdin hasn't round-tripped falls back to
real text rather than its own name. SandboxStringsTest guards the format
coupling, since a Compose upgrade would otherwise only surface as raw key
names on an App Store first launch.

Also declare the clang flags as an input on compileMacosBookmarksLib so a
flags-only edit can't leave a stale dylib for signMacAppResources to sign
into the bundle, and document the sandboxed config and data paths in
SUPPORT.md.
2026-08-17 20:42:00 -07:00
Adam Brown
9cde66bef6
Fix AltGr shortcuts closing the desktop app (#859) (#907)
Windows reports AltGr as Ctrl+Alt, so typing @ on a Turkish-Q or German
QWERTZ layout matched the loose Ctrl+Q quit test and closed the app.

Window shortcut matching moves into WindowShortcuts.kt, built on the
exact-modifier matchesShortcut helper, which also tightens Ctrl+W and
Ctrl+Shift+F.

* Move save-all off Ctrl+Alt+S to Ctrl+Shift+S

Ctrl+Alt+S is itself an AltGr chord on Windows, so it fired and ate the
character on layouts that map AltGr+S, such as Polish (s with acute).
Rebound on desktop, Android, and iOS, and Android's global search now
matches its modifiers exactly like the rest.

No shortcut uses Alt now, which is what keeps AltGr keystrokes reaching
the editor.

* Keep Koin hint classes out of test detection
2026-08-16 00:00:10 -07:00
Adam Brown
2f59a614f5 Bump Nucleus, lots of nice improvements 2026-08-15 22:55:51 -07:00
Wavesonics
d9598e225f Fix MacOS crash 2026-08-10 21:00:05 -07:00
Adam Brown
e33e4bf24e
About: promote Dark Rock Studios attribution, hoist Cairn overlay above nav (#877)
* Move Dark Rock Studios attribution above the community section on About

Replaces the "Manuscript" section with a "Studio" section carrying the
made-by attribution and the button that opens the Cairn overlay, giving
it top billing above Community.

Hoists the Cairn overlay from AboutAppUi up to the nav shell
(ProjectSelectScaffold on Android/iOS, ProjectSelectionWindow's Content
on desktop) so its full-screen ceremony covers the nav rail/bottom bar
too, not just the About content pane.

* Force x11 until Nucleus fixes it's bug
2026-08-10 20:48:31 -07:00
Adam Brown
5eebd1b4e6
Drop the JetBrains Runtime requirement (#873)
Nothing in the desktop app needs the JBR anymore, so go back to OpenJDK
(Temurin 21) everywhere:

- Remove the JETBRAINS vendor pin from the desktop toolchain and from the
  launcher that jpackage bundles as the app runtime
- Replace the setup-jbr composite action with actions/setup-java; the
  retry logic only existed to survive rate limits on the jetbrains
  distribution's release listing
- Swap the JBR SDK tarball for Temurin 21 in the snap and flatpak builds,
  and verify the snap download's checksum
- Standardize the remaining 'adopt' setup-java steps on 'temurin'
2026-08-09 23:18:56 -07:00
Adam Brown
1c856dc32b
Fix the F3 sync and Ctrl+Alt+S shortcuts, and give them to Android and iOS (#865)
Some checks are pending
Build CI / build (push) Waiting to run
Build CI / static-analysis (push) Waiting to run
Build CI / android-instrumented-tests (push) Waiting to run
Build CI / iOS compile & test (push) Waiting to run
Build CI / iOS UI tests (push) Waiting to run
PublishInternal / publish-google-play (push) Waiting to run
* Handle F3 and Ctrl+Alt+S on the project window

Both shortcuts hung off a Modifier.onPreviewKeyEvent in ProjectRootUi, so
they only fired when focus sat inside the project subtree and did nothing
from the home screen. Move them to the window onKeyEvent that already owns
Esc, Ctrl+W, Ctrl+Q and Ctrl+Shift+F.

F3 now goes through ProjectRoot.startProjectSync(), which opens the sync
modal only for server-linked projects, restoring the gate the old sync menu
item had.

* Match shortcut modifiers exactly and run them pre-focus

F3 and Ctrl+Alt+S were hand-rolled in the window's when-chain, which
dropped the exact-modifier matching onKeyShortcut enforced: Ctrl+F3 and
Ctrl+Alt+Shift+S both fired. Extract that predicate as
KeyEvent.matchesShortcut and use it for both.

Move the two to onPreviewKeyEvent as well. onKeyEvent only runs when
nothing on the focus path consumed the key, so a focused editor could
swallow them; the docs claimed otherwise. The other window shortcuts stay
on onKeyEvent so a focused component can still handle Esc first.

* Give Android and iOS the project shortcuts back

Moving F3 and Ctrl+Alt+S to the desktop window left the other platforms
with nothing. Add ProjectShortcutHost, which ProjectRootScaffold binds
while the project UI is composed, and drive it from each platform's own
key hook: Activity.dispatchKeyEvent on Android and UIKit key commands on
iOS. Both are focus independent, which the Compose modifiers were not.

The iOS container lives in Swift because keyCommands is an Objective-C
category member and Kotlin cannot override those.

* Bind the project shortcuts in one place

Desktop kept its own copy of the save-all action while Android and iOS went
through ProjectShortcutHost. Move the binding down to ProjectRootUi, the one
composable all three platforms render, so each host only detects keys and
calls the host object.

That also lets the window drop the snackbar state and coroutine scope it had
hoisted purely to run the action.
2026-08-07 00:45:59 -07:00
Adam Brown
b92b0c3eb5
Migrate desktop window decoration to Nucleus 2.1.9 TAO backend (#854)
Some checks are pending
Build CI / build (push) Waiting to run
Build CI / static-analysis (push) Waiting to run
Build CI / android-instrumented-tests (push) Waiting to run
Build CI / iOS compile & test (push) Waiting to run
Build CI / iOS UI tests (push) Waiting to run
PublishInternal / publish-google-play (push) Waiting to run
Holy crap this is so much better!
2026-08-05 23:22:38 -07:00
Adam Brown
6314756c62 Clean up unused and mislabeled string resources
Remove 98 string resources that have no reference anywhere in the source.

Fix five strings that were wrong or misleading:
- notes_delete_toast_success printed the note's numeric id ("Note 4 Deleted").
  Notes have no title, so the toast no longer names the note at all.
- encyclopedia_create_entry_toast_tag_too_short is shown for an empty entry
  name, not a tag. There is no TAG_TOO_SHORT error. Renamed and reworded.
- backup_manager_delete_content_description is a visible button label, not a
  content description. Renamed.
- splash_subtitle duplicated about_description. All six locales already
  translated them identically, so the splash screen now uses about_description.
- "Time Line" is now "Timeline", matching the glossary and every other screen.
2026-07-26 20:54:14 -07:00
Adam Brown
7ab8d656a7
Bump material-kolor to 5.0.0 (#764)
* update testcontainers

* Update material-kolor to 5.0.0

* Regenerate desktop aboutlibraries metadata
2026-07-21 09:04:04 -07:00
Wavesonics
7bd395e2d4 Add Ctrl+Q quit shortcut to the project selection window 2026-07-14 23:10:11 -07:00
Adam Brown
7838b3242d Fix Encyclopedia image selection
Also fix Drag-and-Drop support on Desktop and Android
2026-07-10 23:48:54 -07:00
Wavesonics
7730d9e3fe
Log and exit on uncaught exceptions (desktop)
Install a default uncaught-exception handler in main() that logs the
crash and terminates. The file logger is async and won't reliably flush
before exit (and packaged builds have no visible stderr), so also write
a synchronous crash dump to the logs directory so the stack trace
survives the process dying.
2026-07-01 22:04:11 -07:00
Wavesonics
8bcd696761
Add startup logging: build/environment banner and startup breadcrumbs
Log a single identifying line as the first line on every platform:
version plus OS/runtime, and on desktop the display server (Wayland/X11
+ DE) and Skia renderApi. Makes user-submitted logs self-describing.

Banner is expect/actual in :common, wired into the desktop, Android, and
iOS startup entry points. Also adds INFO breadcrumbs across desktop
startup so a stall localizes to a stage.
2026-07-01 22:04:11 -07:00
Wavesonics
cf35dd3739
Disable linux quick list
I suspect this is crashing for some users
2026-07-01 13:22:47 -07:00
Adam Brown
a4fa14c6c3 Add two new shortcuts for closing the project window
Ctrl + W - Closes the project, returns to project selection
Ctrl + Q - Close the application

Resolves #614
2026-06-22 10:15:11 -07:00
Adam Brown
bf5277a056 Warn before discarding in-progress timeline edits on project close (#588)
Exiting a project with auto-sync on runs requestClose(), which queued
CloseConfirm.Sync and tore down open editors before the sync ran. Scenes,
notes, and encyclopedia entries flagged unsaved edits via shouldConfirmClose(),
but TimeLineComponent returned emptySet(), so an in-progress timeline event
edit was silently discarded with no warning.

Wire TimeLineComponent.shouldConfirmClose() to the existing isEditingAndDirty()
check and add a CloseConfirm.Timeline confirmation dialog on Android/common and
desktop, mirroring the notes/encyclopedia pattern.

Closes #588
2026-06-22 10:09:23 -07:00
renovate[bot]
233d0cf094
Update jna monorepo to v5.19.1 (#598)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-20 00:05:44 -07:00
Wavesonics
83785c9f89
Fix SL4J being stripped out of desktop builds 2026-06-19 17:23:11 -07:00
Adam Brown
491da055ef Replaced kotlinx.cli with Clikt 2026-06-18 00:35:55 -07:00
renovate[bot]
342ae4c1d5
Update jna monorepo to v5.19.0 (#546)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-07 19:21:33 -07:00
Wavesonics
52dbde1daf Suppress generic-exception catches at must-not-crash boundaries
Sync, background jobs, API/email send, and UI boundaries legitimately
catch broadly; annotate each with @Suppress and a reason, and log the
exception where it was previously swallowed.
2026-06-06 15:42:35 -07:00
Adam Brown
d1e265a44c
Add Foundation primitives tier; rename Id/Sync/Settings repos (#558)
* Rename IdRepository to IdAllocator
It is a special foundational primative

* Rename SyncDataRepository to SyncJournal
It is a special foundational primative

* Rename GlobalSettingsRepository to GlobalSettingsStore
It is a special foundational primitive

* docs: add Foundation primitives tier to the architecture doc

Document IdAllocator, SyncJournal, and GlobalSettingsStore as a fixed set of
stateful, cross-cutting primitives that the whole data layer may depend on —
acyclic leaves (GlobalSettingsStore <- SyncJournal <- IdAllocator) that named
the dependency reality instead of treating it as a no-sibling violation.
2026-06-06 01:17:13 -07:00
Wavesonics
d4502dc227 MacOS sandboxing 2026-06-02 20:54:18 -07:00
Wavesonics
fd8f857001 Merge branch 'macos-sandboxing' into develop
# Conflicts:
#	common/src/commonMain/composeResources/values/strings_desktop.xml
2026-06-02 20:52:18 -07:00
Wavesonics
fcf25c8caf Merge branch 'macos-sandboxing' into develop
# Conflicts:
#	common/src/commonMain/composeResources/values/strings_desktop.xml
2026-06-02 20:50:21 -07:00
Wavesonics
f392b06ba2 MacOS publish fixes 2026-06-02 20:49:08 -07:00
Wavesonics
569c9faaa5 Add a desktop splash screen 2026-05-31 01:46:30 -07:00
Adam Brown
ea17b263d5
Fix IllegalStateException: closed race in FileLogger (#524)
The log-consumer coroutine could write to appendBuffer after another
thread (the logging framework / shutdown) had already closed it, e.g.
during CoroutineScope cancellation, throwing IllegalStateException: closed.

Make the single consumer coroutine the sole owner of the sink: it writes,
flushes, and closes appendBuffer (the latter in a finally block so it runs
on normal channel close and on cancellation alike). close() now just closes
the message channel, which ends the consumer; flush()/close() no longer
touch the sink from foreign threads. As a bonus, queued messages are
drained before the sink closes. Applies to both desktop and android.
2026-05-28 23:06:21 -07:00
Adam Brown
2365b33c87
Fix IllegalStateException: closed race in FileLogger (#519)
The log-consumer coroutine could write to appendBuffer after close()
closed it from another thread (e.g. during scope cancellation on
shutdown), throwing IllegalStateException: closed.

Guard all sink access with a lock and a closed flag, and close the
message channel on close() so the consumer terminates cleanly. Applies
to both the desktop and android FileLogger.
2026-05-28 23:00:23 -07:00
Wavesonics
310cd423fb Add localized first-run intro dialog for sandboxed macOS builds
Show an explanatory welcome dialog before the projects-directory picker so
first-time users understand why macOS is asking them to choose a folder.
Route all user-facing strings in the sandbox first-run flow through StrRes
so they're translatable via Crowdin.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 21:52:17 -07:00
Wavesonics
e5400b5cc5 Fix split preprocessor directives in HammerBookmarks.m
The #import/#include directives were split across two lines, which clang
rejects, breaking the compileMacosBookmarksLib task for App Store builds.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 21:25:43 -07:00
Wavesonics
62e137df59 Implement sandbox bookmark handling for MacOS 2026-05-27 00:29:26 -07:00
Adam Brown
803fadd72c
Fix non-mac app store desktop runs 2026-05-22 23:49:53 -07:00
Adam Brown
7f2dea41a5
Remove flatpakGradleGenerator
We only needed this for flathub which we gave up on
2026-05-22 23:30:04 -07:00
Wavesonics
2517bb80c6 Add manifest-driven asset generation pipeline
Replace ad-hoc icon scripts with a single source-of-truth manifest
  (scripts/assets.yaml) and a Python generator that renders every app icon,
  store-listing graphic, MSIX tile, favicon, and the Play feature graphic from
  two SVG sources. Compositions (icon + "Hammer" wordmark in Kingthings
  Trypewriter) are defined once as percentages of canvas and reused across the
  Play feature graphic, MSIX wide/splash tiles, and the Snap featured banner.

  Adds the missing snap store icon, fixes the snap desktop icon to the correct
  256x256 hicolor size, and routes uploads-only assets to build/store-assets/
  (gitignored).

  See docs/ASSET-GENERATION.md for the manifest schema.
2026-05-22 19:26:49 -07:00
Wavesonics
5c4da8909c Add Mac App Store packaging for the desktop module
Pass -PmacOsAppStoreRelease=true -PbuildNumber=N to produce a sandboxed,
signed .pkg ready for TestFlight upload via Transporter / iTMSTransporter.
Apple Silicon only for v1; JBR runtime stays.

- Sandbox-friendly entitlements (network.client + user-selected files
  for the app; JIT/unsigned-mem/disable-library-validation for the JVM).
- JNA libjnidispatch.jnilib is pre-extracted into desktop/resources/macos/
  and located via -Djna.boot.library.path so JNA never tries to extract
  to a temp dir at runtime (which would hang silently in the sandbox).
- com.apple.application-identifier / team-identifier baked into the app
  signature so it matches the embedded provisioning profile.
- UrlLauncher drops the Runtime.exec("open") fallback in favor of the
  Desktop API only.
- Projects-directory picker is hidden in App Store builds; the sandbox
  container's ~/Documents is the only writable location for v1.
- unquarantineMacApp Gradle task strips com.apple.quarantine xattrs
  before pkg packaging to avoid App Store validation errors.
- New helper: desktop/scripts/build-appstore.sh — pre-flight checks,
  one-shot build, codesign + pkgutil signature verification.

Signing assets and API key live in desktop/{embedded,runtime}.provisionprofile
and desktop/secrets/ (both gitignored).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 17:46:07 -07:00
Wavesonics
327b5322cb Remove macos AppImage target format 2026-05-18 21:24:06 -07:00
Wavesonics
7664c1fe8d Upgrade to Gradle and AGP 9 2026-05-18 18:48:39 -07:00
Adam Brown
60b654c002
Upgrade gradle to version 9.5.1 2026-05-17 19:35:37 -07:00
Adam Brown
90ed8e0fd5
Switch desktop window chrome to Material3-themed DecoratedWindow and MaterialTitleBar 2026-05-17 14:54:46 -07:00
Adam Brown
3f9c497657
Add recent-projects launcher menus for Linux (D-Bus quicklist) and macOS (Dock menu), reaching parity with the Windows jump list. All three platforms are now unified behind a QuickShortcuts interface so callers don't care which OS they're on. Pulled the shared "top N projects by lastAccessed" pipeline up onto ProjectsRepository.getRecentProjects() (used by the desktop and Android shortcut managers), and replaced scattered os.name string-matching with a typed HostOs enum. 2026-05-17 14:40:56 -07:00
Adam Brown
6762eb61e6
Add deep linking to Desktop!
You can now deep link to any project and even entity inside that project.
Added jumplist support for windows to deep link directly to a project
2026-05-17 13:35:40 -07:00
Adam Brown
aaaaa6f79f
Update libraries metadata 2026-05-14 21:47:43 -07:00
Adam Brown
fdd4350bd1
Update gradle wrapper URL to 9.5.1 2026-05-14 21:22:05 -07:00
Adam Brown
0e8a6c1a4f
Make MSIX build more robust by prioritizing x64 2026-05-14 18:53:15 -07:00
Adam Brown
aeeacc3d29
We have to use the JBR! 2026-05-14 01:44:30 -07:00
Adam Brown
4b19951655
Remove Nucleus from build pipeline (keep runtime libs)
Reverts the Nucleus packaging port and its follow-ups:
  - 93c7973c Trying nucleus for packaging Snap stays bespoke
  - 7c14bcd5 Broaden artifact staging to handle Nucleus sandboxed pipeline paths
  - d24f6183 Add homepage and debMaintainer for electron-builder
  - 8831e9c5 Update release workflows for Nucleus packaging
  - 4af31163 Port :desktop packaging to Nucleus framework

Compose Desktop is back as the packaging backend (jpackage targets,
custom packageMsix task, bespoke buildDistSnap/AppImage/Flatpak via
registerLinuxDistributionTasks). The Nucleus runtime libraries —
nucleus.darkmode-detector and nucleus.decorated-window-jbr — are
kept for window decoration and dark-mode detection in code, along
with the JBR jvmToolchain vendor pin and the libs.versions.toml
'nucleus' version entry that they depend on.

The Nucleus-pipeline state is preserved on branch
'nucleus-build-pipeline' for future reference.
2026-05-14 00:49:10 -07:00
Adam Brown
93c7973cf8
Trying nucleus for packaging
Snap stays bespoke
2026-05-13 23:00:55 -07:00