Commit Graph
20 Commits
Author SHA1 Message Date
mckero 9deb517874 fix(build): configure core domain source sets through container members
The second CI round got past the missing configure import but still
failed in the same file: bare name accessors inside sourceSets { }
(commonMain.dependencies { ... }, commonTest, jvmTest) are kotlin-dsl
script syntax generated for .kts files. Plugin source compiled as plain
Kotlin has no such accessors on its classpath, so the four dependency
blocks failed with receiver type mismatches while every real member call
around them - jvmToolchain, jvm(), the ios targets, binaries.framework -
already resolved.

Configure the source sets through the container API instead:
sourceSets.getByName("commonMain").dependencies { ... }. getByName,
dependencies and implementation are all members on types that ship with
KGP 2.4.10, verified against the gradle plugin jars byte for byte.
getByName is safe at this point because jvm() above has just created the
jvm source sets synchronously; commonMain and commonTest exist as soon
as the multiplatform plugin is applied.
2026-09-27 10:28:37 +01:00
mckero fa91e89024 fix(build): add missing gradle-kotlin-dsl import to the core domain convention plugin
The iOS CI run failed in both jobs before reaching any product code: the
convention plugin itself did not compile. CoreDomainPlugin.kt used the
reified extensions.configure<KotlinMultiplatformExtension> { } form, but
unlike every other plugin in this directory it was missing the
org.gradle.kotlin.dsl.configure import. Without it only the member
overloads taking an explicit type parameter resolve, so the extension
receiver cannot be inferred and all twenty subsequent unresolved
references - jvmToolchain, jvm(), iosArm64(), binaries.framework,
sourceSets with the commonMain/commonTest/jvmTest accessors - are one
cascading failure, not twenty bugs.

build-logic is the first thing both CI jobs compile, and it has never
been compiled anywhere before this run, so the workflow is doing exactly
what it was added for: catching what no local machine can check.
2026-09-27 10:07:08 +01:00
mckero 1a3c94f1e0 refactor(domain): make core:domain multiplatform so iOS can reuse it
The orbital maths, the satellite models and the repository contracts sat in a Kotlin/JVM
module, so an iOS target could not share a single line of them: java.lang.String.format,
InputStream, System.currentTimeMillis, java.util.Locale and org.json are all JVM-only, and
the tests that covered them used JUnit4. core:domain now declares jvm, iosArm64 and
iosSimulatorArm64 targets, its sources moved to commonMain/commonTest, and the JVM-only
pieces were replaced with multiplatform equivalents: java.lang.String.format by a shared
printf implementation, System.currentTimeMillis by kotlin.time.Clock, InputStream by
ByteArray, org.json by kotlinx-serialization, Locale by nothing at all. Tests that read
classpath resources (javaClass.classLoader) moved to jvmTest, because that is JVM-only
behaviour rather than a JVM-only API.

Auditing the migration against the old module turned up four things that were wrong rather
than merely ported:

- java.lang.String.format rounds the shortest decimal representation of a double half-up,
  not the binary value: "%.3f" of 0.5005 is "0.501", because the stored double is
  0.50049999999999994493. The shared implementation scaled in binary first and printed
  "0.500", which would have changed APRS position packets and the Wavelog frequency fields
  against the released Android app. It now takes the digits from the decimal representation
  and rounds them with integer arithmetic, and jvmTest compares it against
  String.format(Locale.ROOT, ...) over 40 000 sampled doubles plus the boundary cases, while
  commonTest pins literals so the iOS run checks the same digits.

- The queue mutators lost the kotlin.jvm.Synchronized monitor each of them had. It is not a
  JVM-only annotation - it is an optional expectation, so it still compiles in common code -
  but the stdlib deprecated it for common use in 1.8 and made it an error in 2.1. The monitor
  is a platform actual now: the JVM keeps the real monitor, since Compose and the upload
  coroutine both reach the queue there, and iOS carries a documented placeholder until the
  iOS side has a second thread to protect against.

- 107 assertions in DataParserTest and QthConverterTest were bare kotlin.assert calls, which
  a build without -ea skips silently: they are assertTrue now, so the iOS run cannot pass
  vacuously. The three Locale.setDefault cases (ar-EG, bn-BD, fa-IR) that used to guard APRS
  output against Eastern Arabic digits moved to jvmTest instead of being deleted with the
  Locale dependency - APRS-IS is an ASCII protocol, and Locale.setDefault does not exist on
  iOS.

- @Volatile on the LoTW name cache would not have compiled for iOS either: kotlin.jvm's
  variant is an error in common code since 2.1. kotlin.concurrent.Volatile is the
  multiplatform annotation, and it is the stronger form: it takes effect on Kotlin/Native
  rather than being ignored.

A second audit pass over the files the first one could not reach - the HTTP client, the
parsers, the queue and the injection - found three more:

- OkHttpHttpClient built its Request outside the try, so a URL OkHttp refuses to parse left
  postQso/testToken/getStation as an exception, and neither caller catches one. The client it
  replaced reported HTTP -1 and let the caller treat it as a failure; building the request
  inside the try restores that, and a transport failure reports -1 again rather than 0.

- WavelogQueue's readers were stricter than the org.json ones they replaced. A timestamp
  stored as 1234.0 (or "1234.0") read back as 0L instead of 1234 - a QSO uploaded as 1970 -
  and a field holding an object or array threw the whole list away instead of falling back.
  The readers coerce decimals, keep the old defaults and no longer throw, matching optLong,
  optInt, optString and optBoolean.

- The ADIF dates went through the JVM default locale before, so a device set to Arabic wrote
  Eastern Arabic digits into the QSO date. The shared formatter only ever produces ASCII,
  which the locale cases in AprsPacketDefaultLocaleTest pin down.

Verified locally with ./gradlew jvmTest (343 tests, 0 failures) and the multiplatform gate
in check-multiplatform.sh, which now also refuses JVM-only stdlib APIs that resolve in common
code but fail to compile for iOS: @Synchronized, kotlin.jvm.Volatile, synchronized(),
toUpperCase/toLowerCase/capitalize, BigDecimal. The iOS targets themselves need the macOS
runner in .github/workflows/ios-kmp.yml.
2026-09-27 08:55:49 +01:00
mckero abb73ffef7 build: bump to 4.6.2 (versionCode 469)
Carries the CW record fixes: the record no longer deletes its own text while decoding,
a drifting tone no longer wipes it instead of filling it, the archive path no longer
races itself when capture stops, and the decoded text can finally be copied off the
screen.

Also stops the APRS version string drifting, which the comment on it had predicted and
which had already happened again: it still read 4.6.0 while the app shipped 4.6.1, so
every station on the network was told the wrong version. AprsReporter now takes the
version as a parameter and the app module passes BuildConfig.VERSION_NAME, which
required turning on the buildConfig feature - AGP 8 does not generate the class
otherwise. The literal cannot fall out of step with the build again.
2026-08-27 15:41:07 +00:00
mckero 19926c58ac Revert "feat(ft8): 4.5.5 integrate FT8CN 0.93 (full port, original UI)"
This reverts commit 8a2b0a9aa3.
2026-08-05 07:47:18 +00:00
mckero 8a2b0a9aa3 feat(ft8): 4.5.5 integrate FT8CN 0.93 (full port, original UI)
Full FT8 mode integration (user chose scope C: complete port, keep
original visual style):

- feature/ft8 module: 213 Java classes from FT8CN 0.93 source
  (com.bg7yoz.ft8cn namespace preserved so code needs zero changes),
  DataBinding enabled, BuildConfig fields (APPLICATION_ID/VERSION_NAME/
  apkBuildTime) restored for AGP9
- libft8cn.so from the user's FT8CN_0.93 APK (armeabi-v7a, 1.53MB;
  differs from repo copy, APK version used)
- 237 res files + 58 assets + 4 local libs (MPAndroidChart spectrum,
  commons-net, nanohttpd, osmdroid map) copied verbatim
- Proguard keep rules for JNI classes (RegisterNatives)
- Entry: More menu "FT8" (default sub menu, after AMSAT) launches
  MainActivity via Intent (external activity, LAUNCHER filter removed
  to avoid double launcher)
- Manifest merged via module (RECORD_AUDIO/BT/location perms)
- Version 4.5.5/455 + What's new 5 languages (REPLACED per rule)
Verified: :feature:ft8:compileDebugJavaWithJavac + :app:compileDebugKotlin
BUILD SUCCESSFUL; check_strings 9 files OK.
2026-08-05 04:49:35 +00:00
mckero f7402a3531 feat(status): 4.5.3 AMSAT satellite status page + radar log pass divider
New feature/status module: fetches https://amsat.org/status/ and
renders a live status grid in the official site colors:
- Parser (AmSatParser): 47 satellites x 6 days x 12 two-hour slots,
  official colors (blue=Active, orange=TLM/Beacon, pink=Not Heard,
  deep-orange=Conflicting, gray=none); 598+ report details extracted
  from inline JS tooltips (callsign/date/time/grid)
- Three-level viz: color grid -> report count -> tap day cell opens
  report list dialog
- Manual refresh with spin animation + last-updated timestamp +
  legend row; loading/error states
- New "AMSAT" entry in the More menu (Screen.AmSat), integrated with
  page-order / hide-page settings (SettingsScreen screens list,
  defaultSubMenuOrder, allNavItems, migration for existing users)
- AmSatRepository via IRemoteSource.getStatusHtml() (UA header);
  shared remoteSource promoted to a lazy class property in MainContainer

Radar page Log tab: local entries now grouped by pass session with a
thick divider + satellite label between groups (matches the log page).

What's new updated in EN/ZH/TR/IN/ID. Version bumped to 4.5.3/453.
Not released (user gates all releases).
2026-08-04 15:57:41 +00:00
mckero 8bc1f16e2c feat(cw): wire CW decoder page into navigation (between Roaming and Map)
Compose integration of the ported CW decoder engine:
- CwDecodeScreen: AndroidView embedding the ported activity_main.xml,
  lifecycle delegated to the ported MainActivity controller (onCreate ->
  onResume, onDispose -> onPause/onDestroy), RECORD_AUDIO runtime
  permission flow (with permanent-denial -> app settings), original
  options_menu actions as a top button row (pause/clear/save/record/
  settings), double-back-to-exit preserved
- CwSettingsDialog: message_type (general_text/ham_radio_qso),
  text_font_size (7-99), and the 9 color keys (bg_color/text_color/...)
  reading/writing the same prefs keys as the original app
  (getPackageName()+"_preferences"), colors sourced from I2.b tables
- Navigation: Screen.CwDecode ("CwDecode") placed between Roaming and
  Map in the default order; defaultScreenOrder updated; ic_cw morse icon;
  nav_cw strings (en/zh/tr); app depends on :feature:cw

Verified: :feature:cw:compileDebugKotlin + :app:compileDebugKotlin
BUILD SUCCESSFUL (first pass, no errors).
2026-08-04 04:06:31 +00:00
mckero bfa5e5f474 feat(roaming): add Roaming page with 3x3 Maidenhead grid
Ports the QTH定位器 (com.us1pm.gridsquarelocator) location panel into Look4Sat as a new 'Roaming' page, restyled with the app's own look.

UI (top to bottom):
- Info header: GPS status dot, big 8-char locator, Lat/Lon rows with DMS + 5-decimal display, and a GPS 定位 button
- 3x3 grid panel: the current 4-char Maidenhead square (e.g. OL42) centered, surrounded by its 8 neighbors (OL33..OL51), with a red position marker in the center cell

Logic:
- QthConverter gains qthNeighbors(square) building the 3x3 grid with field/square carry at boundaries (AA00 wraps to RR99, IO91 crosses into J field), and qthToSquare(locator) extracting the 4-char square
- Verified against the decompiled app algorithm and the reference screenshot (OL42 grid matches exactly); 9 unit tests cover normal, boundary and field-wrap cases

Navigation:
- New bottom-nav item 'Roaming' between Match and Settings, with a crosshair icon
- New feature:roaming module (ViewModel + Compose screen) registered in the app

Build config:
- Lowered Gradle JVM heap from -Xmx6g to 768m: the 2GB build server froze on the old value; heavy release builds stay on GitHub Actions
2026-08-03 10:46:14 +00:00
mckero 2dfd76825b fix: fork under own applicationId com.rtbishop.look4sat.bg7nta
The official app signs com.rtbishop.look4sat with its own certificate. A fork sharing that applicationId cannot be installed over the official build (signature mismatch) and users saw overwrite/install failures.

- Add applicationId version catalog entry; namespace stays com.rtbishop.look4sat so source imports are untouched, applicationId becomes com.rtbishop.look4sat.bg7nta.
- Update PROPERTY_SATELLITE_DATA_OPTIMIZED meta-data to the fork id.
- Document the fork-applicationId requirement in the version catalog.
2026-08-03 08:38:21 +00:00
atsunatsu 1064dc739e feat: add mutual pass query with dual-station elevation curve
Port satlover.de dual-station pass matching feature:
- New feature/mutual module with mutual pass data model
- MutualViewModel: compute overlapping passes for two stations
- ElevationCurveChart: Canvas-based dual elevation curve with drag
- MutualScreen: input form + results with expandable cards
- Navigation: add Mutual tab to bottom navigation bar
- i18n: add Chinese/English strings for new feature
2026-08-02 21:22:42 +08:00
Arty Bishop 18c8ac1822 Merged RadarScreen and RadioControlScreen functionality 2026-05-30 14:14:40 +01:00
Arty Bishop 3df358b88c v4.2.2 - Kotlin Serialization, Navigation3, translation fixes 2026-04-24 17:24:00 +01:00
Arty Bishop 7d5bca300d Migrated to Compose Navigation3, updated dependencies 2026-04-24 17:20:23 +01:00
Arty Bishop fb2cd85b11 Migrated to KotlinX Serialization library for JSON parsing 2026-04-24 17:18:06 +01:00
jcmerg 2df0b9ba3d Add CAT radio control for full-duplex satellite operation (#207) 2026-04-10 11:21:52 +01:00
Arty Bishop 8c1df334d8 Added even more tweaks to convention plugins setup 2026-03-28 20:03:11 +00:00
Arty Bishop e2bf2a09a4 v4.1.1 - Fixes for landscape/split screen issues, by londre7 2026-03-22 11:07:23 +00:00
Arty Bishop 082b52c58b Added more tweaks to convention plugins setup 2026-03-18 15:59:55 +00:00
Arty Bishop 4d88214c1d Added basic convention plugins setup for modularization 2026-03-01 20:02:30 +00:00