A bare apostrophe in "QTH定位器 2.0'dan" broke aapt resource
compilation (Invalid unicode escape sequence) and failed the release
build. Escape it as \' per Android string resource rules.
Three detail fixes plus branding, per user review:
1. Night mode visibility (roaming page): hardcoded reference blues
(#01DDFF/#0BACF1) collapse to black under the red ColorMatrix
filter (R channel only), making the page unreadable. Replace ALL
colors with MaterialTheme.colorScheme (background/surface/
surfaceVariant/onSurface/onSurfaceVariant/primary/error). GPS
status dots become themed circles (primary/error) so they survive
the red filter; red marker keeps the original pnt drawable.
2. Settings cards unclamped:
- OtherCard: fixed height(268.dp) squeezed the last toggle row
(spacing 42/42/42/15px on device); drop the fixed height.
- CardCredits: same 268dp + SpaceBetween overflowed, gluing the
last thanks entry to the warranty line; drop fixed height, use
spacedBy(8.dp) and insert 24dp before the warranty text.
3. Branding:
- Settings top title: "Look4Sat v%s" -> "Look4Sat Pro v%s" (en/tr);
title Text no longer marquees and wraps instead (heightIn(min=48)).
- APK asset name: look4sat-<ver>.apk -> Look4Sat-Pro-<ver>.apk.
- What's-new dialog (pass_whatsnew_message) rewritten in all three
locales (en/zh/tr) with this release's changes; zh gets its own
localized title "Look4Sat Pro 更新内容".
Verified: roaming/settings/passes/app compile, 11 unit tests pass.
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.
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.
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.
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
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.
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.
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
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.
- 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
- 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
- Fix cubic Bezier control points (proper Catmull-Rom to Bezier conversion)
- Refine AOS/LOS more robustly by walking from edge into the pass window
- Still 5s sampling for smooth curves
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
Use MaterialTheme.colorScheme.primary for satellite name
text in all three lists (Components, SatellitesScreen,
PassesScreen), matching the color that was previously
used for the catalog number.
Remove the NORAD catalog number (e.g. '44444 - ') prefix
from satellite names in three places:
- Pass list items (Components.kt)
- Satellite selection list (SatellitesScreen.kt)
- Pass detail view (PassesScreen.kt)
The number is still accessible via satellite details if needed.
- Add newColumnCount tracking to CwSpectrogram
- CwDecoder now processes each new column individually for timing
- Each column = 8ms at 8000 Hz sample rate
- Proper per-column iteration through spectrogram history
Complete rewrite inspired by Morse Expert / CW Skimmer (VE3NEA):
- CwFFT: radix-2 FFT (256-point) for time-frequency analysis
- CwSpectrogram: sliding-window waterfall (40 cols x 33 bins, 8ms resolution)
- CwBayesianDecoder: Gaussian probability replaces hard dit/dash thresholds
- CwChannelTracker: multi-channel peak detection (up to 3 signals)
- CwDecoder: integrates all components, monitors 200-1200 Hz simultaneously
Key advantages over v2 (ggmorse):
- Frequency-agnostic: full spectrum monitored, not locked to one tone
- Multi-channel: tracks multiple signals in parallel
- Bayesian: probability-based decisions, not hard ratios
- Doppler tolerant: frequency drift just moves energy between bins
- After initial pitch lock, re-scan every ~8 seconds in a narrow
±100 Hz window around the current pitch estimate
- Only re-lock if pitch change > 20 Hz (avoids jitter)
- Helps maintain lock when Doppler tracking has residual error
- Add CwDsp with FIR bandpass filter, envelope detection, Goertzel tone detector
- Add CwDecoder with real-time Morse timing analysis and character lookup
- Add CW state/actions to RadarState, wire into RadarViewModel
- Add collapsible CW decoder panel to transceivers page
- 19 unit tests covering DSP, Morse table, and decoder state
- Shares IAudioCapture with SSTV, auto-stops SSTV when CW starts
- Add DopplerFrequencyCalculator utility with passband mapping + Doppler correction
- Add MHz input UI with real-time 1Hz refresh during pass
- Add kHz offset for downlink frequency correction
- TX/RX fields on same row for compact layout
- 40 unit tests covering linear/FM/inverted transponders
I was setting the Tx frequency only when we were
in Tx mode, but the Icom 705 will accept the
command to set the Tx frequency even when in Rx mode, so
there is no need to check the PTT state before sending the command.
- Added support for Icom IC-705 radio model with split mode functionality.
- Updated RadioTrackingService to handle single-radio split mode and dual-radio configurations.
- Modified MainContainer to provide appropriate radio controllers based on selected model.
- Enhanced SettingsRepo to include split mode preference in radio control settings.
- Updated UI in SettingsDialog to allow toggling of split mode for IC-705 and adjust device selection accordingly.
- Improved handling of baud rates based on selected radio model.
- Added extended operations in IRadioController for IC-705 specific commands.