Commit Graph
885 Commits
Author SHA1 Message Date
mckero 0ecccc4746 feat(roaming): port QTH定位器 2.0 page and logic verbatim
The roaming page was repeatedly rebuilt by hand and the red marker
still rendered at the wrong spot on the user's device. Per the user's
explicit instruction the whole page is now a faithful, line-by-line
port of the reference app (QTH定位器 2.0, com.us1pm.gridsquarelocator)
with zero UI or logic changes.

UI (res/layout/main.xml, byte-verified via aapt2 dump):
- 25dp holo-blue GPS bar: "GPS" 14sp, green/red status dot 15dp
  (original mipmaps copied as drawables), centered date, right time,
  translucent-yellow "设置启用GPS" button that opens location settings
- Latitude/longitude rows: 16sp black labels, right-aligned decimal
  values, DMS label format "纬度  22° 18' 50" N" exactly as reference
- 43sp bold black locator, centered, with progress spinner + notice
- 3x3 continuous grid: 60/200/60dp columns, middle row fixed 205dp,
  edge cells #0BACF1, center cell 200x200dp holo-blue (#01DDFF as
  shown on the user's device), center label 100x80dp 30sp bold white
  (textColorHighlight) centered, bottom "制作:US1PM  汉化:BA7LCE"
- Red marker: original pnt.png (red square with white outline),
  10x10dp, absolutely positioned by the reference lookup tables
  (lon 3rd pair a..x -> leftMargin -2..190dp, lat 3rd pair a..x ->
  topMargin 190..-2dp, screen-Y inverted)

Logic (MainActivity.java showLocation/checkEnabled/onResume):
- 8-char locator via the reference range-lookup tables
- 3x3 neighbor grid via parseInt3 five-branch logic incl. all four
  corner-carry tables (00/09/99/90)
- Live GPS + network updates 10s/10m while the page is shown,
  provider filtered to gps/network, checkEnabled three-state
  (green dot / red dot + settings button) exactly like the reference
- Time = cached hour prefix + fix minutes; date "dd MMM yyyy"

Dropped only the Play-store ad banner (conflicts with GPL project).

Verified: 11 unit tests pass (locator, marker lookup, grid, DMS,
time, all edge branches); feature + app modules compile.

RoamingState.kt removed - state and math now live in RoamingScreen.kt.
2026-08-03 14:29:44 +00:00
mckero 88d1498eac fix(roaming): red marker tracks fix in BOTH axes via 3rd-pair lookup
The marker's vertical position was hardcoded (10dp below the label) — markerY never participated, so the dot could only move horizontally and could not reflect where the GPS fix sits inside the 4-char square.

Now the marker is positioned in both axes from the cell's top-left corner:
- x = markerX * cellWidth, y = markerY * cellHeight (screen Y)
- markerX/markerY come from the 3rd character pair via the reference lookup tables (lon a=-2..x=190 as leftMargin; lat a=190..x=-2 as topMargin, i.e. latitude inverted on screen)
- Verified numerically against the decompiled tables: a=0/1.0, i=0.333/0.667, x=0.958/0.042 — matching within 3% (the reference table is slightly non-uniform)

Label stays at upper-middle (28sp bold); marker is only drawn when a valid locator exists.
2026-08-03 12:55:37 +00:00
mckero 31ae04329d fix(roaming): clock ticker moves the header time; GPS mirrors station pos
Two bugs from the last release:

1. The header clock was frozen: Date() was only evaluated during recomposition, and with no state changes the time never moved. Added a 1s LaunchedEffect ticker that updates a now-state, so the date/time text re-renders and actually advances — matching the reference app, which refreshes the clock on every location callback.

2. GPS indicator: replaced the 10-minute freshness check with a direct 'has a real fix' check (timestamp > 0 and coords non-zero). The page mirrors the station position (站位) from the shared StateFlow, so the GPS dot is green whenever the station has a fix — GPS shows exactly what the station GPS says, nothing more.
2026-08-03 12:48:17 +00:00
mckero eae6304124 feat(roaming): faithful continuous-table grid layout, not card-based
Reworks the Roaming grid to structurally match the reference app instead of a card-style panel:

- Removed the outer ElevatedCard, rounded cells, cell gaps and inner padding: the 3x3 grid is now one continuous table that fills the panel, cells connected edge-to-edge.
- Cells separated by 2dp divider lines that run the full width/height of each row/column, crossing at right angles like a real coordinate grid (the reference app's continuous separator lines).
- Cells are square-cornered (no rounded corners), background fills each cell fully.
- Column widths 21.4% : 56.2% : 21.4%, row heights 31.5% : 35.9% : 31.7% retained.
- Center cell: OL42 is larger (28sp bold) and placed at upper-middle; the red marker sits BELOW the text with a 10dp gap, horizontally offset by the 3rd-pair fraction — never overlapping the label, matching the reference 'text above, marker below' layout.
- Surrounding labels bumped to 16sp Medium (larger/stronger than before).
- Info header also switched from an ElevatedCard to a flat continuous block so the page reads as one continuous surface, like the reference.

The grid proportions, locator algorithm, marker mapping and boundary logic were already faithful; this change makes the visual structure faithful too.
2026-08-03 12:32:45 +00:00
mckero 97c6d609ac fix(roaming): drop auto GPS polling, show station position directly
Reverts the auto-update machinery after review — the page now simply mirrors the station position (站位) from the shared settingsRepo.stationPosition StateFlow, exactly what the Settings page shows:

- RoamingScreen: removed the LocationManager listeners, the 30s re-request loop, the provider filter and the location-disabled hint. No polling, no auto-updates; coordinates are whatever the station GPS says.
- Settings: removed the '漫游位置实时更新' toggle (stateOfRoamingLive, key, action, strings en/zh/tr) that caused the 'Other' card to overflow — the sixth unlabeled switch clipped past the card's rounded bottom edge was that row overflowing a fixed-height card. Card height back to 268.dp, five rows fit again.

Verified: core:domain tests, roaming/settings/app compile clean; zero references to RoamingLive remain.
2026-08-03 12:24:07 +00:00
mckero 44c442ddd3 feat(roaming): port live GPS tracking and location-disabled hint
Completes the port of the QTH定位器 app's location logic (read from the decompiled MainActivity):

1. Live location updates: a LocationListener registers GPS+NETWORK providers (10s / 10m, matching the reference onResume) while the Roaming page is visible and removes itself on dispose. Every fix is pushed through settingsRepo.setStationPosition, so the shared stationPosition StateFlow updates the Settings page and the map in lockstep — the page now refreshes in real time instead of only showing stale cached coordinates.

2. Provider filtering: only gps/network fixes are accepted, mirroring the reference showLocation() guard that rejects passive fixes.

3. Location-disabled hint: when GPS is off or permission is missing, the header shows a tappable '定位未开启,点击前往系统设置' row that opens ACTION_LOCATION_SOURCE_SETTINGS — the port of the reference btnLocationSettings button. The GPS status dot now has three states: fresh fix (primary), provider on but stale (error), provider off (outline).

4. Periodic recovery: a 30s re-request loop (honoring the 漫游位置实时更新 toggle) re-arms the location request after the chip falls idle.

Not ported (conflict, deliberate): the reference app's Play-store ad banner, 'New! Grid Square with map' promo and GP_IN preferences — commercial advertising does not belong in a GPL satellite tracker.
2026-08-03 11:59:31 +00:00
mckero f9250ec1f1 fix(roaming): live coords from shared flow, marker by locator pair, versioned apk
Addresses three review findings:

1. Coordinates now come straight from settingsRepo.stationPosition in the screen (collectAsStateWithLifecycle) — the exact same StateFlow the Settings page shows. Previously a separate ViewModel re-derived them, and it could lag behind the Settings page (user: '设置页更新了站位但漫游页死活不更新'). With the shared source the two pages can never disagree. RoamingViewModel removed; state derivation moved to RoamingState.fromPosition().

2. Red marker placement ported faithfully from the QTH定位器 app: it is driven by the 3rd character pair of the 8-char locator (the 'ih' in OL42ih45), mapped to a 0..1 fraction (lon a=west..x=east, lat inverted a=south..x=north), then scaled to the actual center-cell size. The grid now uses the reference proportions (columns 21.4/56.2/21.4, rows 31.5/35.9/31.7) and fills the screen, so the marker lands accurately on any device.

3. Workflow now uploads a versioned APK (look4sat-<version>.apk instead of look4sat.apk).

Also: Settings 'Other' card rows got vertical spacing (Arrangement.spacedBy) so the new roaming toggle is not glued to the night-mode row.
2026-08-03 11:49:46 +00:00
mckero bff3e1af09 chore: bump version to 4.4.7
Next release: versionCode 446 -> 447, versionName 4.4.6 -> 4.4.7. Includes the reworked Roaming page (faithful QTH定位器 port, live-update toggle, night-mode-safe theme colors).
2026-08-03 11:27:25 +00:00
mckero 6dbe30b3f6 feat(roaming): faithful QTH定位器 port, live-update toggle, night-mode safe
Rework the Roaming page after user review. It is now a faithful port of the QTH定位器 location panel, not a loose re-skin:

UI (matching the reference layout):
- GPS status dot (real: green when a fresh fix exists, outline when stale/missing) + date + time header
- Lat/Lon rows with DMS and 5-decimal display, big 8-char locator centered below
- 3x3 grid of neighboring 4-char squares with the reference proportions: center column ~2.6x wider (21.4% : 56.2% : 21.4%) and center row the tallest (31.5% : 35.9% : 31.7%); red position marker now placed at the fractional position of the fix inside the center cell (was fixed center)
- No oversized GPS button: live updating is now a Settings toggle '漫游位置实时更新' (stateOfRoamingLive, default on) that drives periodic location refresh

Style & night-mode safety:
- All colors come from MaterialTheme.colorScheme (surfaceVariant/secondaryContainer/error) — no hardcoded cyan/blue from the original app. The red night filter (ColorMatrix keeping only the R channel) blanked the old hardcoded palette; theme colors survive it.
- Chinese nav label '漫游' added to values-zh (was missing, showing English 'Roaming')

Settings:
- OtherSettings.stateOfRoamingLive persisted (default true), toggle row in Other card, height adjusted

Verified: feature:roaming, feature:settings, app compile clean.
2026-08-03 11:18:35 +00:00
mckero 8a920acead build: revert gradle heap cap, keep CI builds unconstrained
The 768m heap cap broke GitHub Actions (KSP OutOfMemoryError: Metaspace) because CI runners read the same gradle.properties. Restore -Xmx6g for CI; the 2GB local server should pass a one-off -Dorg.gradle.jvmargs instead.
2026-08-03 10:49:59 +00:00
mckero 929f652b8e chore: bump version to 4.4.6
Next release: versionCode 445 -> 446, versionName 4.4.5 -> 4.4.6. Adds the Roaming page (QTH定位器-style 3x3 Maidenhead grid) between Match and Settings, credits BG7NTA & the original author in the thanks title, and caps local Gradle heap for the 2GB build server.
v4.4.6
2026-08-03 10:47:39 +00:00
mckero 610768501e build: add roaming module gradle file, cap local JVM heap
Include feature:roaming/build.gradle.kts (missed from the module commit) and keep the reduced Gradle heap (-Xmx768m) so local light builds don't freeze the 2GB server.
2026-08-03 10:46:32 +00:00
mckero 427e6e1862 i18n: credit BG7NTA and original author in thanks title
The settings outro title now reads 'BG7NTA & the original author would like to thank' (en) / 'BG7NTA 与原作者感谢' (zh) / 'BG7NTA ve orijinal yazar teşekkür eder' (tr), alongside the BA7OPF/BG7NTA entries added to the credits list.
2026-08-03 10:46:20 +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 213425379c merge: merge atsunatsu/main (mutual radar overlay arrows)
Merge upstream commit 2298d8ee 'feat: add mutual radar overlay arrows'. Clean auto-merge: upstream changed RadarView.kt arrow drawing, our sweep optimization stayed intact. No conflicts.

First v4.4.5 was built from c3444aed; this release rebuilds from the merged tree.
v4.4.5
2026-08-03 10:04:09 +00:00
mckero c3444aed24 chore: bump version to 4.4.5
Next release: versionCode 444 -> 445, versionName 4.4.4 -> 4.4.5, following the upstream scheme without suffix. Includes the station panel layout fix, 5-decimal coordinates, and credits additions already merged on main.
2026-08-03 09:43:10 +00:00
mckero 368bd199e5 fix: station panel layout wraps QTH to its own line
With 5-decimal coordinates the Lat/Lon/Qth row overflowed, pushing the QTH value to a wrapped line. Split into two rows: Lat + Lon on the first line, Qth on the second.

Also append BA7OPF (pass matching feature) and BG7NTA to the credits list in en/zh/tr string resources.
2026-08-03 09:33:40 +00:00
atsunatsu 2298d8eea4 feat: add mutual radar overlay arrows 2026-08-03 17:27:48 +08:00
mckero 7bb0bbbb46 build: load release signing config from local keystore.properties
Conditionally applies the BG7NTA signingConfig when keystore.properties exists (gitignored). CI signs via apksigner with GitHub Secrets, so this only affects local builds.
2026-08-03 09:25:53 +00:00
mckero deec5581ae feat: rebrand to Look4Sat Pro, bump version to 4.4.4
App display name changed from Look4Sat to Look4Sat Pro (fork identity). Version follows upstream scheme without suffix: 4.4.3 -> 4.4.4, versionCode 443 -> 444.
v4.4.4
2026-08-03 09:20:41 +00:00
mckero 1de5632428 feat: increase station coordinate precision to 5 decimals
Station lat/lon was stored rounded to 4 decimals (~11 m). Bump to 5 decimals (~1.1 m), slightly better than GPS hardware accuracy without showing noise.

- SettingsRepo.setStationPosition: round(4) -> round(5)
- QthConverter.qthToPosition: round(4) -> round(6) so 10-char locators fully roundtrip
- Update QthConverterTest expected values to 6-decimal precision
v4.4.3-bg7nta-p1
2026-08-03 09:14:13 +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.
v4.4.3-bg7nta
2026-08-03 08:38:21 +00:00
mckero 06fc8bc2fb ci: set GH_TOKEN for release creation step
gh CLI in Actions requires GH_TOKEN to authenticate. Use the built-in github.token.
2026-08-03 08:15:20 +00:00
mckero 75322390b8 ci: allow specifying release tag on manual dispatch
workflow_dispatch defaults TAG_NAME to the branch name (main), which breaks gh release create. Accept an optional tag_name input and fall back to github.ref_name for tag-triggered runs.
2026-08-03 08:12:20 +00:00
mckero d1312f1f09 ci: add manual workflow_dispatch trigger
Allow triggering the release build from the Actions tab in case tag events are not picked up.
2026-08-03 08:06:19 +00:00
mckero 75acbbd633 ci: simplify release workflow for fork builds
Remove Google Play upload (needs SERVICE_ACCOUNT_JSON we don't have) and AAB signing. Use built-in GITHUB_TOKEN instead of RELEASE_TOKEN secret. Pin actions to stable versions (checkout@v4, setup-java@v4, setup-gradle@v4). Builds assembleRelease, signs APK via apksigner with KEY_STORE secrets, creates GitHub release with APK. Triggered by v** tags.
2026-08-03 08:03:16 +00:00
mckero a37fb8f773 feat(domain): support 6/8/10-char Maidenhead grid square conversion
Port the 8-char (4-pair) Maidenhead grid algorithm from the
"QTH定位器 2.0" app (com.us1pm.gridsquarelocator) into QthConverter
so locator precision matches common grid tools instead of being
truncated to 6 chars.

Previously positionToQth() emitted only 6-char locators and
qthToPosition() discarded everything past the 6th character via
take(6), losing the finer 30" x 15" resolution carried by 8-char
grid squares.

What changed:
- positionToQth(lat, lon, precision = 8) now emits 8-char locators
  by default; precision = 6 / 10 available for backwards
  compatibility and maximum resolution (1.25" x 0.625").
- qthToPosition() parses 6/8/10-char locators and returns the center
  of the finest encoded cell (30" x 15" for 8-char, 1.25" x 0.625"
  for 10-char) instead of the 6-char cell center.
- Locator validation regex tightened: 6/8/10 chars accepted,
  4-char strings like "JN58" are now rejected as invalid.
- Boundary clamping added so lat = 90 / lon = 180 no longer overflow
  the A-R / 0-9 / a-x alphabet (previously produced invalid chars).

Also fixed a pre-existing compile error in RadarView.kt: a delegated
property was assigned after declaration ("by" on an already declared
val). Converted the sweep angle to an if/else expression.

Verification:
- QthConverterTest extended to 5 test cases covering 6/8/10-char
  roundtrips, invalid input, boundary coordinates and roundtrip
  stability.
- Cross-checked against a Python reference model of the decompiled
  APK algorithm: 20k random roundtrips at 8 and 10 chars, 0 failures.
- :core:domain:test green; :app:compileDebugKotlin passes.
2026-08-03 07:25:31 +00:00
mckero 9d0d971500 refine: AOS binary-search refinement, getRadios signature cleanup
Refine AOS crossing to ~500ms via binary search instead of linear stepping; simplify getRadios to take satPos; tidy radar view/viewmodel.
2026-08-03 06:47:49 +00:00
atsunatsu 1813e1bfa4 fix: refine mutual pass matching and radar overlay v4.4.3-ba7opf.2 2026-08-03 13:04:42 +08:00
atsunatsu bd09ad22ff chore: remove .hermes from git tracking, add to gitignore v4.4.3-ba7opf.1 2026-08-03 08:55:04 +08:00
atsunatsu 7e90071c4d fix: revert radar pager to Transceivers tab, default minElev to 0
- Radar pager now defaults to Transceivers tab (initialPage=0)
- Transceivers don't auto-expand (selectedUuid defaults to null)
- Mutual page default minElev changed from settings value to 0.0
- Display filters out portions below the minElev threshold
2026-08-03 03:58:45 +08:00
atsunatsu d1cc944be2 feat: filter mutual page curves to minElev window (satlover.de style)
Elevation curve chart and mutual radar plot now only show the portion
where both stations are above their respective minimum elevation.
The curves are filtered at display time, the pass search still uses
the 0° horizon boundary for consistency with the Passes page.
2026-08-03 03:47:25 +08:00
atsunatsu fb28283679 feat: default pager to SSTV, remove radar plot drag, filter B track by elevation>0 2026-08-03 03:44:37 +08:00
atsunatsu 81ae8772d2 feat: add 'current exact position' button for station A
Removed the automatic posA=stationPos override. Added a button
'当前精确位置' below the grid input that fills in the exact station
position from settings (lat/lon + grid). Users can now freely edit
the position fields and use the button when they want the exact
position.
2026-08-03 03:32:03 +08:00
atsunatsu 571145838d fix: gridToLatLon normalization bug + bidirectional grid/latlon sync
Root cause: gridToLatLon used (lon+180)%360-180 and (lat+90)%180-90
for normalization, treating grid values as from prime meridian/equator
when they are actually from IDL/South Pole. A 6-char grid like OL62AA
(112°E, 22°N) was returning -67.96°, -67.98° (Atlantic Ocean).

Also added bidirectional sync: entering a grid auto-fills lat/lon,
entering lat/lon auto-fills the 6-char grid, so users can verify.
2026-08-03 03:27:15 +08:00
atsunatsu 017b178f2e fix: use refineEdge with exact station position to get correct AOS/LOS boundaries 2026-08-03 03:15:39 +08:00
atsunatsu 670444858c fix: use getElevation for elevation sampling (same function as getLeoPass)
getFullPosition and getElevation both call calculateObs internally,
but the elevation values reported by the user (-60°) suggest they may
differ. Now elevation is computed via getElevation (same as getLeoPass),
while getFullPosition is only used for azimuth.
2026-08-03 03:13:11 +08:00
atsunatsu 7bdff5df81 fix: use passes list with corrected station position, fallback to independent search 2026-08-03 03:08:35 +08:00
atsunatsu df083840ac fix: use independent search algorithm directly, no passes list reuse
The passes list AOS/LOS times can be stale or computed for a different
station position, causing elevation curves to show -60° at pass start.
The independent search (refineEdge + sampleMutualPass) always computes
elevation for the actual positions. With posA now set to the exact
station position, the pass times should match the main page.
2026-08-03 03:03:08 +08:00
atsunatsu a0279bac17 fix: use pass AOS/LOS times directly without refineEdge
The refineEdge function re-computed boundaries using the grid-center
position (posA), which differs from the exact station position that
the passes list was computed with. This caused all passes to be
filtered out. Now we trust the pass list's AOS/LOS times directly
and just sample the elevation/azimuth curves.
2026-08-03 02:47:09 +08:00
atsunatsu 3d630041e1 chore: add debug info when mutual pass search finds nothing
Shows pass count and satellite count in the error message to help
diagnose why the main pass list yields no results.
2026-08-03 02:27:01 +08:00
atsunatsu ea92d3c150 fix: add fallback pass search when main pass list yields no results
If the main pass list (satelliteRepo.passes) is empty or the common
window check filters everything out, fall back to the independent
search algorithm so the user always gets results.
2026-08-03 02:23:51 +08:00
atsunatsu 86ee3dcbac fix: reuse main page pass list for mutual search
findMutualPasses was computing passes independently with its own
search algorithm, which produced different results from the main
page's getLeoPass. Now it directly reuses satelliteRepo.passes,
which is the same list shown on the main passes page. The only
additional computation is refining the common window for station B
and sampling elevation/azimuth curves.
2026-08-03 02:16:15 +08:00
atsunatsu 43788ba7a7 fix: mutual pass search now matches main radar pass definition
Root cause: mutual search used the min-elevation threshold (default 10°)
as the AOS/LOS boundary, while the main radar uses the 0° horizon
(getLeoPass). With identical stations the windows therefore never
matched. Also, an in-progress pass was counted as a new one.

- AOS/LOS boundaries now at the 0° horizon (refined to 1s)
- Skip in-progress mutual windows at search start (like getLeoPass)
- Filter requires BOTH stations to reach their min elevation
- Default min elevation follows the main radar passes setting
2026-08-03 02:04:13 +08:00
atsunatsu 1a3f1bb34c fix: radar track rendering bugs
- Elevation ring labels were inverted (90/60/30 from outer to inner);
  now 30/60/90 correctly from outer ring to center
- Split track paths at the 0/360° azimuth wrap in both MutualRadarView
  and main RadarView, so passes crossing due north no longer draw a
  line straight across the plot
2026-08-03 01:53:37 +08:00
atsunatsu 998c98267b fix: draw full station-B track on main radar, live dot on top
Track line is no longer time-limited (always shows the whole mutual
arc). The station-B live position is drawn separately on the line
using the same pulsing-dot mode as the local station.
2026-08-03 01:29:17 +08:00
atsunatsu 28fa373db0 feat: bidirectional drag sync between elevation curve and radar track
- ElevationCurveChart is now controlled (progress + onProgressChange)
- MutualRadarView shows shared time-cursor positions for both stations
  and is draggable/tappable to move the cursor
- MutualPassCard owns a single dragProgress feeding both charts, so
  dragging either chart moves the other in sync
2026-08-03 00:58:09 +08:00
atsunatsu 4ca33c37ad feat: keep mutual state across nav + overlay station-B track on main radar
- MutualViewModel is Activity-scoped, so returning from Radar keeps query results
- TrackSampleData gains time field for live cut-off
- Removed standalone mutual card from radar page
- RadarViewCompose draws optional dashed station-B track + current dot
- RadarScreen builds trackB from mutual data up to current time
2026-08-03 00:55:05 +08:00
atsunatsu bd42e643ea feat: dual-station radar track plot (satlover/satmatch style)
- MutualPass now carries TrackSample (azimuth/elevation for both stations)
- New MutualRadarView: polar plot with elevation rings (30/60/90),
  cardinal spokes, solid A-track vs dashed B-track, AOS/LOS markers
- Shown in expanded mutual pass card and radar page mutual card
2026-08-03 00:21:20 +08:00
atsunatsu 4baf3821e5 fix: elevation curve x-axis float precision loss
Absolute epoch millis (~1.7e12) exceeds Float precision (ULP ~131s
at that magnitude), so 5s-spaced samples collapsed onto identical
x coordinates, producing a stepped/jagged curve. Use Long relative
time deltas (sample - start) before converting to Float.
2026-08-02 23:36:59 +08:00