Delete the in-tree de.jonasbroeckmann.kzip ZIP format implementation
(~700 lines across commonMain/jvmMain/iosMain) and the kompress.core
dependency, in favor of the published no.synth:kmp-zip 0.11.3 library
plus its okio adapter.
ZipUtils now wraps zipTo/unzipFrom for directory operations and uses
the synchronous ZipInputStream(ByteArray) constructor for the in-memory
extract path, removing the previous write-temp-file workaround. The
skipHiddenFiles parameter is dropped (production callers already passed
false) and the corresponding tests are removed.
Co-authored-by: Claude <noreply@anthropic.com>
A-Z mode used a plain lexicographic compare, so "Chapter 10" sorted
before "Chapter 2". Switched to a natural-order comparator that
compares digit runs by numeric value, and added a TitleDesc mode so
title sort has the same asc/desc parity as sequence sort.
The static getString() call in loadSceneMetadata reaches
Toolkit.getScreenResolution() on Compose Desktop, which throws
HeadlessException on Linux CI and broke 8/9 integration tests.
RoundTripTestBase already stubbed StrRes for this exact reason;
this call was the one that bypassed it.
We've run into many problems where everything publishes fine, except 1 store. This provides a way to unblock that one store without pushing to the rest.
iOS sandbox container UUIDs can change between installs, dangling the
absolute projectsDirectory persisted by a prior install. Decorate the
iOS GlobalSettingsDatasource to re-anchor the post-/Documents/ suffix
under the live Documents dir on load and persist the correction.
iOS now runs the same shared Compose UI as Android and Desktop. The
existing Decompose component graph (IosRoot, ProjectSelection,
ProjectRoot) is reused; the Swift app shrinks to an AppDelegate, a
Koin bootstrap, and a UIViewControllerRepresentable that hands off to
a Kotlin ComposeUIViewController. The SwiftUI starter under
/ios/ios/ui and /ios/ios/DecomposeHelpers is deleted.
Hammer.framework moves from :common to :composeUi so the framework
ships the Compose entry point; Xcode's Run Script invokes
:composeUi:embedAndSignAppleFrameworkForXcode. iosArm64 and
iosSimulatorArm64 targets are declared with libbacktrace source-info
so K/N crashes report file:line. 17 expects across composeUi get iOS
actuals (file pickers via filekit, image loading via Coil3,
LanguageUtil via NSLocale.preferredLanguages, etc).
The adaptive nav scaffolds — bottom bar at compact width, side nav
rail otherwise — are extracted from the Android activities into
shared ProjectSelectScaffold and ProjectRootScaffold in
composeUi/commonMain, along with their Modifier helpers and the
close-confirm dialogs. Android activities are now thin shells that
delegate to these; iOS calls the same scaffolds, so phone/tablet
layout is unified across all three platforms.
App icon and CFBundleDisplayName set so the home screen reads
"Hammer" with the brand logo instead of the blueprint placeholder.
Lifts version check into VersionCheckRepository + GithubVersionCheckDataSource.
On launch, shows an update dialog when a newer release is available and the
tag hasn't been dismissed (tracked in GlobalSettings). Falls back to the
annotated tag message when the release body is empty. AboutApp's VersionCard
gains a button to open the same dialog on demand.
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>
countWordsInScene counted whitespace separators instead of words, undercounting every non-empty scene by 1. wordsByChapter was keyed by chapter name, so chapters with duplicate names collapsed into a single entry, under-reporting the total chapter count.
Schema bumped to v6 to invalidate stale caches.
Adds `created` and `lastEdited` timestamps to SceneMetadata, stamped
on every autosave tick in SceneEditorRepository.recordSceneActivity.
StatisticsService rolls them up into a new "Last Edited" tile on the
project home dashboard, and the Android widget reads the same field
from the stats cache.
The timestamps ride the sync wire on ApiProjectEntity.SceneEntity and
participate in EntityHasher.hashScene. On download, local values are
preserved when the server didn't ship them. No conflict resolution —
last write wins.
EntityHasher hash functions had their defaults removed so call sites
can't silently miss a newly added field; this caught a latent bug in
the second markForSynchronization hash call that was relying on
defaults for archived/confirmedReferences/dismissedReferences.
getSceneFileName still built `order-{rawName}-{id}` with the raw name,
so newly-allowed chars like `\` `/` `?` `*` `:` either split the path
(Windows treated `\` as a separator) or were rejected by the OS,
crashing scene creation. Switch it to the v2 `~`-delimited format with
encodeForFilename, matching SceneDatasource.buildSceneFileName.
Two scene files sharing one id crashed cleanupSceneOrder during
project open. validateScenePaths runs as part of loadSceneTree —
first file seen wins, later duplicates are refused and logged.
- Ships IBM Plex Mono (Regular/Medium/SemiBold, OFL) and routes
the mono Typography + every explicit FontFamily.Monospace site
through hammerMonoFontFamily(), so ← ↗ and other Unicode glyphs
render the same on every platform.
- Reverts the back-arrow icon shim (a4be47ba); ← renders correctly
in Plex Mono now.
- Swaps HdSearchField's ⌕ for Icons.Default.Search (U+2315 isn't
in Plex Mono).
- OutlineOverview: clicking a scene title dismisses the modal and
opens that scene in the editor; trailing ↗ marks the affordance.