Commit Graph
100 Commits
Author SHA1 Message Date
atsunatsu e162de7c19 build: release version 4.4.8-ba7opf.11.7 (582) 2026-10-09 03:05:03 +08:00
atsunatsu 63e2ea88b7 feat(satellites): AMSAT Live FM 组补 IO-86 / LAPAN-A2
Sources.amSatFmCatnums 加 IO-86 / LAPAN-A2 (40931):SatNOGS 有 V/U FM 话音转发器
"V/U FM Voice (PL 88.5Hz)" 145.880 / 435.880;R4UAB 名 "LAPAN-A2 (IO-86)"、
SatNOGS 3LE 名 "LAPAN-A2"、AMSAT 名 "IO-86"。LoTW 别名表早就有 LAPAN-A2 → IO-86
(ARRL 官方名),所以这颗星只是筛选里看不到,上传链路本来通。

同一集合共用三处:卫星页与互通页的 FM 筛选、雷达页 Log 的 useRepeater 判定
(voiceRepeater() 排序下唯一含 "voice" 的 FM 双工行命中,记账固定取
145.880 / 435.880 名义对;APRS/SSDV 两行是 AFSK、Mode X 无上行,都进不了候选)。

测试:SelectionRepoSearchTest 的 FM 虚拟类型用例扩到三颗(67291 / 98205 / 40931)。
2026-10-09 03:04:59 +08:00
atsunatsu ddca54e7e6 build: release version 4.4.8-ba7opf.11.6 (581) 2026-10-09 01:54:56 +08:00
atsunatsu e19d22714b feat(satellites): AMSAT Live FM 组补 RS95S 与 UNNE-1B
Sources.amSatFmCatnums 加两颗:RS95S / QMR-KWT-2 (67291)、UNNE-1B (98205)。
两星在 SatNOGS 都有 V/U FM 转发器("V/U FM Transponder CTCSS 67.0 Hz"
145.920/436.950,与 "Mode V/U - FM Repeater (Voice + (A)FSK)"),因此归入
卫星页「AMSAT Live FM」虚拟类型筛选。该集合是三处共用的一份口径:卫星页与
互通页的 FM 筛选、以及雷达页 Log(FM 星按名义 voice repeater 频率对记账,
两颗星都有该行,不会回落到算器/所选频点)。

98205 是 SatNOGS 的分析编号(国际编号 26227BL,T-18 由 OTV OSSIE 释放),
Space-Track 正式编目后会换号,届时需回改这一条;已在 KDoc 标注,ephem-watch
cron(6b1544af4470)会盯到编号变化。

测试:SelectionRepoSearchTest 新增一例,断言 FM 虚拟类型命中 67291 与 98205
(全量 ./gradlew test 通过)。
2026-10-09 01:47:52 +08:00
atsunatsu 623d859c97 test(mutual): 钉死 fixture 时间基准,消除时段性 flaky
fixture 用 2024-03-09 固定 ISS TLE + System.currentTimeMillis() 起点;SGP4 带阻力衰减 942 天后高度仅 ≈262km,12h 窗口内可能无广州过境 → 3 条依赖过境窗的用例时段性失败(Gradle 缓存 FROM-CACHE 会掩盖上一次的真跑)。

- TestOrbits.FIXTURE_BASE(2024-03-10T00:00Z,历元后约 18h)取代默认 System.currentTimeMillis()

- MutualViewModel 墙钟可注入:nowMillis: () -> Long = System::currentTimeMillis(第 4 个默认参数,生产行为逐位不变;工厂具名构造零改动)

- 断言里的 now 改用同一基准;prefill/scroll 测试不碰时间未动

修后::feature:mutual 28/28,全量 ./gradlew test 451/451。
2026-10-08 12:36:40 +08:00
atsunatsu 08803e0f55 feat(logbook): LoTW 卫星别名补 RS95S(QMR-KWT 2)+内置 config.tq6 升 11.35
RS-95S(QMR-KWT 2,NORAD 67291)QSO 上传时发现:别名表无该星、内置 config 11.34 也无此官方名(11.34 里没有 RS95S,会被 every-alias-target 校验挡住)。

- config.tq6 11.34 → 11.35(ARRL 现行版本,新增 RS95S=QMR-KWT-2)

- 别名表补 QMRKWT2→RS95S(SatNOGS 名 QMR-KWT 2)与 RS95S→RS95S(兼容 RS-95S 连字符写法,resolve 的包含回退逐字符比会漏)

- 单测补断言:QMR-KWT 2 lookup / RS-95S+QMR-KWT 2 resolve / 用真实 config 解析 RS95S
2026-10-08 12:36:35 +08:00
atsunatsu 6f1c0a2d23 build: release version 4.4.8-ba7opf.11.5 (580) 2026-10-08 02:27:47 +08:00
atsunatsu 74e7e19cf2 feat(satellites): 勾选置顶显示——已选/可用分组+顶部计数条(对齐上游) 2026-10-08 02:26:56 +08:00
atsunatsu bb001b4d38 fix(logbook): ADIF 网格字段方向修正——VUCC_GRIDS 归对方、MY_VUCC_GRIDS 归己方(编解码双向) 2026-10-08 02:26:51 +08:00
atsunatsu 9ea83cb161 build: release version 4.4.8-ba7opf.11.4 (579) 2026-10-07 00:19:31 +08:00
atsunatsu d7d5918f0a fix(lotw): 呼号冲突批量全阻时也进预览,呼号不符改为显示记录≠证书
整批记录都被呼号冲突挡住(0 条可传)时,统计闸门直接弹「N QSO(s) can't be uploaded」
消息并返回,带【改写为…】【换一张证书】两个动作的预览弹窗根本走不到,那批记录无从
处理。现在只要原因里有呼号冲突就放行到预览:0 条可传也出预览(显示 0 QSO(s) + 冲突
提示 + 两个动作),上传键置灰——以前点确认会返回“预览已过期”。其它原因的 0 条可传
批次保持原消息弹窗不变。

「MY callsign does not match the certificate」的示例值由某条记录的对方呼号改为
「记录呼号 ≠ 证书呼号」,把需要协调的两个值都打出来(旧文案读起来像证书呼号)。

空预览不再显示空的日期区间。

新增 LoTWUploadMessagesTest 3 例:冲突批量必须进预览、无冲突的 0 条可传批次保持消息、
有待传记录时不走冲突兜底;仓库层用例新增:全阻批量仍返回带冲突清单的预览、且无载荷
时确认安全地按“过期”失败。
2026-10-07 00:19:27 +08:00
atsunatsu b2e9454ee4 build: release version 4.4.8-ba7opf.11.3 (578) 2026-10-06 22:14:05 +08:00
atsunatsu ea3e04d5db fix(lotw): 空呼号记录按证书上传并回填,呼号冲突可选改写或换证书
证书装好之前记录的 QSO 自己呼号存空,签名时被判 CALLSIGN_MISMATCH,整批上传失败。
现在这类记录改用当前证书呼号签名,不再拒签:预览提示「其中 N 条记录没有呼号,将按证书
XXX 上传」,上传成功后仅把这些记录的空呼号回填为证书呼号(只填空值,经 save() 写入以
保持去重键一致,不动时间/频率/模式/对方呼号/上传状态与确认状态)。

自己呼号非空且与证书不同的记录仍拒签(不冒签他人记录),但预览给出两个选择:
「改写为 XXX」把冲突记录的自己呼号改成当前证书呼号后即可重传;「换一张证书」在设置页
关掉日志本并打开 LoTW 配置导入另一张证书(雷达页提示去设置页导入)。

新增单测:空呼号签名与计数、冲突记录 id、markUploaded 只填空值、rewriteMyCallsign 只改
冲突记录;并修正测试夹具 MemStorage.read 返回共享数组(被调用方 fill(0) 后破坏已存证书,
与文件存储行为不一致)导致的问题。
2026-10-06 22:13:59 +08:00
atsunatsu 68e1925784 fix(lotw): 空密码 PBES2 证书回落自研解析器,修复 p12 导入误报无效
平台 KeyStore 对空密码 PBES2 文件不抛异常但给不出私钥条目,原逻辑随即报「不是有效的 LoTW 证书文件」。现在平台读取器抛异常、无私钥条目或取不出密钥时,只要文件是 PBES2 就回落自研解析器,两条都失败才报错;非 PBES2 旧式 p12 报错分类不变。新增 5 个单测(空密码回落、平台可用回归、错密码、非 p12、超限)。
2026-10-06 22:13:47 +08:00
atsunatsu 1e563f9cb0 build: release version 4.4.8-ba7opf.11.1 (576) 2026-10-06 16:33:36 +08:00
atsunatsu f8d3c5b185 feat(map): DXCC 通联详情副行显示实体字头
- dxcc.json 全部 280 实体新增 pfx 字段(Club Log cty.csv 实体主字头):
  多字头实体显示惯例实体字头(中国=BY/美国=K/亚俄=UA9), Somalia 覆盖为 6O,
  共享 DXCC 号的子图斑行(维也纳国际中心 206)不参与选取
- RegionQsoDialog 副行 'DXCC 318 · ' → 'BY · '(无字头回退数字码);
  标题/布局/WAZ 'CQ ZONE n'/WAPC-WAJA-WAS 裸代码均不变
- DxccAssetTest +1 守卫: 280 实体字头非空 + 14 组码→字头钉死
2026-10-06 16:33:33 +08:00
atsunatsu 917788041c build: release version 4.4.8-ba7opf.11 (575) 2026-10-06 14:16:29 +08:00
atsunatsu 58bc96c441 fix(map): DXCC 领土缺口补齐、父国填色挖洞、挪威斯瓦尔巴粗环删除
- 领土缺口: Natural Earth 把 Somaliland/N. Cyprus 画成独立图斑, 6O 索马里与
  5B 塞浦路斯的北部领土此前无任何边界(不画框/不填绿); 按 NE 1:110m 并入父国
  环并溶解内部界线(单例外框), 与埃塞/吉布提/肯尼亚零重叠
- 父国填色挖洞: 新增 fill_rings(父领土−子实体, shapely 差集), worked 填充改
  偶奇挖洞, 通父国不再涂绿独立子实体: 南非→莱索托, 中国→香港, 马来西亚→新加坡,
  法国→安道尔/摩纳哥, 意大利→圣马力诺/梵蒂冈, 奥+瑞→列支敦士登, 西班牙→
  直布罗陀/安道尔, 古巴→关塔那摩湾; 描边/命中/其他奖状资产不变
- 双线修复: 删除 Norway 残留的 3 个斯瓦尔巴粗环(NE Norway 几何自带), 斯瓦尔巴
  只剩精环单线, 通 LA 不再误涂绿 JW
- DxccAssetTest +3 守卫(合并领土探针/填色挖洞钉对/Norway 无 >73°N 残环)
2026-10-06 14:15:53 +08:00
atsunatsu 7a7d742b54 build: release version 4.4.8-ba7opf.10.1 (574) 2026-10-06 03:19:28 +08:00
atsunatsu 146d47455f feat(map): 海上群岛按整体包络命中(点岛间海面即弹实体详情)
- 新增第三类命中目标:≥2 分离环且单岛跨度 ≤2.5° 的散布群岛,整体包络即命中区
  (±40px 触点余量),点岛链之间的海面归该实体
- 优先级:小实体 80px 目标 > 陆地多边形点内 > 群岛包络;主大陆+零星岛(日/英/印尼)
  不进群岛模式,行为不变
- 包络按单一展开经度框计算,反经线群岛(斐济式)不横扫
- 测试 6→10:包络命中、包络内小实体优先、主大陆排除、反经线包络连续
2026-10-06 03:18:57 +08:00
atsunatsu a7d99862d9 build: release version 4.4.8-ba7opf.10 (573)
gradle 内存调优:-Xmx3g/2 workers/parallel=false(WSL 8GB VM 下 lintVital OOM 修复)
2026-10-06 02:19:45 +08:00
atsunatsu a24acc2bfd feat(map): 奖状区域点击弹通联详情 + 过小区域圆点渲染/放大命中 + DXCC 资产补齐 88 区
- DXCC/WAPC/WAJA/WAS/WAZ 点区域弹只读通联详情(复用 VUCC 样式,隐藏匹配/标记站)
- 弹窗标题与 VUCC 统一(等宽字体、同 48dp 头部行高=同 6dp 顶距,回归测试钉死)
- WAZ 标题 CQ ZONE <n>,DXCC 副行带 DXCC <code> 前缀
- 投影过小区块渲染圆点(已通=绿)+ 标签常显;≤80px 区域点击命中放大,小实体优先
- dxcc.json 231→278 区:B 批岛屿 + 47 实体(威克/中途岛/扬马延/布韦/斯瓦尔巴/
  圣赫勒拿/毛里求斯/塞舌尔/佛得角/科摩罗/留尼汪/科索沃/斯普拉特利/黄岩岛等)
- THIRD_PARTY_NOTICES: Natural Earth 来源补 10m map units/rivers
2026-10-06 02:19:32 +08:00
atsunatsu ad970eec77 fix(radar): 计算器 offset 改为跟随驱动计算器的转发器读写
per-satellite offset 原先只在 SelectTransmitter 里载入、并按 selectedUuid
的 catnum 保存:重开雷达页读不回(看起来"没保存"),选中被 toggle 掉后
catnum 为 null 静默丢写;且计算器页 chip 仅在 dedupe 后多于一条时渲染,
单转发器卫星(JO-97/RS-44/FO-29/AO-73/QO-100/TO-108/FO-82/QB50P1/
UKUBE-1)根本没有 chip 可点,永远触发不了载入——上游 rt-bishop 在 PR #237
评审时预言过这个加载问题。

改为 offset 跟随"驱动计算器的转发器":该转发器变化(打开/换星)即载入
已存值,按其 catnum 保存,与收发机选中状态解耦;同时删掉 loadPassData 里
的 workaround 载入与 SelectTransmitter 里的 offset 读写,单一来源、与上游
PR #265 同形便于后续合并。存储格式(satelliteOffsets 单 JSON)不变,
已存的值补丁后直接生效。

验证::feature:radar:compileDebugKotlin 与 :feature:radar:test 通过;
:core:domain:test up-to-date(domain 未改动)。
2026-10-05 20:42:08 +08:00
atsunatsu 5c12d64824 feat(settings): LoTW 省份选择入口常驻 + 导入前预解析填充选项
- 省份入口从第一帧就在台站区:DXCC 未知时显示「导入证书后可选」占位,不可展开
- 选中 p12 后 400ms 防抖静默预解析(previewCertificate,只读不落库,密码副本用后清零),
  点「确认导入」之前下拉即可选省份;错密码/非 p12 静默保持占位,导入报错行为不变
- 修复导入成功不刷新 stationMeta:此前导入完成后省份下拉要关掉重开对话框才出现
- 无省份字段的国家(德国等)维持隐藏;后缀 seq 防慢预览覆盖新结果
- 新增 LoTWUploadRepositoryPreviewTest 2 例(TQSL 风格空密码夹具 test_tqsl_empty.p12,
  实测解析 DXCC 318、不落库、错密码映射 CERTIFICATE_PASSWORD);en/zh 文案
2026-10-05 18:05:42 +08:00
atsunatsu 881ca442ff fix(map): DXCC 资产重建——俄罗斯拆欧/亚、提取子实体、英国四实体、德巴改现行码
- dxcc.json(176→189区): 沿乌拉尔山/河(OSM relation 21368163 + NE 乌拉尔河)
  把整只俄罗斯切成 European Russia(54)/Asiatic Russia(15)——修复亚洲俄罗斯
  永不填绿; 从父国环提取 Alaska/Hawaii/East Malaysia/French Guiana/Corsica/
  Crete/Sardinia/Kaliningrad/Franz Josef 9 子实体; 英国拆 England(223)/
  Scotland(279)/Wales(294)/N.Ireland(265) 四实体; Germany 81→230、
  Palestine 196→510 改为 ADIF 现行码(81/196 已删除, LoTW 导出现行码永不匹配)
- 新增 DxccAssetTest 5 例: 必备码齐全/ADIF名/环完整性/26城侧归属/禁用
  ADIF 3.1.7 全部62个已删除码; build.gradle 补 testImplementation org.json
- THIRD_PARTY_NOTICES: 补 OSM(ODbL) 与 Natural Earth(公共领域) 数据出处
2026-10-05 17:13:50 +08:00
atsunatsu f35d78186c fix(map): 多格台址覆盖单格台址时通联计入单格统计(方案A单向覆盖)
- scopedToStation 由 key 精确匹配改为网格集合包含(记录 MY 网格集 ⊇ 选中台址网格集):
  选中 OL62 时 OL62/63(四格点同理)的通联一并计入;反向不泄漏(选中宽台址不见单格记录)
- stationGroups 每组 worked 改经 scopedToStation 推导——地图填绿/VUCC 计数/选择器计数/
  首通标签/点格子弹窗详情五出口单源;分组条目仍只列实际拥有的台址
- GridQsoStationScopeTest 改写精确匹配断言 + 新增覆盖/不泄漏/集合包含 3 例(共 14),
  全量 test 通过
2026-10-05 15:06:19 +08:00
atsunatsu 09539ff13a feat(wavelog): 二选一互斥模式 + p12 空密码导入修复(4.4.8-ba7opf.9.4, 569)
- LoTW/Wavelog 互斥:isReady 即 Wavelog 模式,LoTW 卡置灰+说明,上传按模式分流(雷达页/日志本),自动 LoTW 同步门控;配置切换弹警告、可清除配置
- 同步重做:get_contacts_adif 每台址游标,增量/全量双按钮,只增不删,URL 变更增量降级全量;同步刷新日志本+地图 workedGrids/gridQsos/roamedGrids
- 日志本台址选择器(全部/各台址)+ Wavelog 上传预览弹窗;Qso 增 wavelogStation,DB v4→v5
- 删旧 WavelogRepository/wavelogSettings 链路,换 WavelogSyncRepository + WavelogSync 纯函数
- p12 修复:导入按钮放开空密码(isEnabled=!busy)+ 密码框留空提示;Pkcs12ReaderTest +4 用例
- 单测六模块全绿;版本 4.4.8-ba7opf.9.4 (569)
2026-10-05 14:57:46 +08:00
atsunatsu 1fa7dd2d88 merge: 合入 fork 9.2 发布线(AMSAT 冲突修复并入;版本保持 9.2/567)
# Conflicts:
#	gradle/libs.versions.toml
2026-10-05 03:56:52 +08:00
atsunatsu f0fc788ebe build: candidate version 4.4.8-ba7opf.8.2 (565) 2026-10-05 03:54:26 +08:00
atsunatsu 6f83740983 feat(amsat): 时隙判定照官网链(严格多数/并列=冲突/crew 紫)+ 弹窗「冲突」徽标
- 旧逻辑取槽内最新一条报告取色 → 官网图例「Conflicting」永不显示
- 判定链照 AMSAT 官方源码 index.php:crew>0 取紫;严格多数取色;并列/无多数=「冲突」
- SatSlot 新增 isConflicted 字段;弹窗冲突槽内全部报告加「冲突/Conflicting」小徽标(随系统语言)
- 天格子外观不变(B 未采纳);AmSatRepositoryTest +4 用例(共 9 例)
2026-10-05 03:54:22 +08:00
atsunatsu e7c0df0954 build: release version 4.4.8-ba7opf.9.2 (567) 2026-10-05 02:44:18 +08:00
atsunatsu 5a8c4281a3 feat(wavelog): upload rides the LoTW flow — auto-sync + catch-up (option A)
Standalone Wavelog upload entries are gone: the batch is prepared alongside the LoTW preview (count shown in both preview dialogs), posted right after the LoTW confirm in the radar, settings-logbook and resubmit flows, and the backlog flushes when LoTW has nothing pending. Failures stay unmarked and retry on the next upload.
2026-10-05 02:19:11 +08:00
atsunatsu a459cfb046 fix(map): scope first-call labels to the selected operated grid (台址) 2026-10-05 02:19:06 +08:00
atsunatsu 7589f3f37d fix(map): scope grid QSO detail to the selected operated grid (台址)
The VUCC grid-detail dialog listed every station location's QSOs even when a specific operated grid was selected; only 'All' should combine them. The 台址 grid-set key derivation is now shared between the selector's grouping and the dialog filter (core/domain extensions + unit tests).
2026-10-05 02:02:55 +08:00
atsunatsu 6a263d8422 build: candidate version 4.4.8-ba7opf.9.1 (566) 2026-10-05 01:37:27 +08:00
atsunatsu 1558919482 feat(wavelog): upload UI — settings block, radar log button, logbook dialog 2026-10-05 01:37:01 +08:00
atsunatsu 9e5b9b6ac6 feat(wavelog): v1 upload repository (probe/prepare/classify) + DI wiring 2026-10-05 01:22:48 +08:00
atsunatsu c050e7bb9b feat(wavelog): wavelog export option + upload helpers (ADIF, candidates, messages) 2026-10-05 01:22:44 +08:00
atsunatsu 73ac41ff85 feat(wavelog): separate upload settings block (model, repo, fakes) 2026-10-05 01:22:40 +08:00
atsunatsu 733f660d78 feat(wavelog): per-record Wavelog upload state (model, migration, dao, repo) 2026-10-05 01:22:34 +08:00
atsunatsu cbe3e50f86 build: release version 4.4.8-ba7opf.8 (563) 2026-10-04 11:57:03 +08:00
atsunatsu 38b29e3015 build: candidate version 4.4.8-ba7opf.7.2 (562) 2026-10-04 02:32:42 +08:00
atsunatsu 1a3a05c8b6 feat(sources): 默认 TLE 源对齐上游(9 项),保留 fork 新增源
新默认顺序(上游"most specific → most generic",fork 新增源保持原位):
LAPAN-A2 → ARISS → R4UAB → AutoTLE(GitHub) → AutoTLE(Mirror) → Classified
→ Amsat → All (CelesTrak active) → SatNOGS;Other 占位保留。
删掉 22 个 CelesTrak 分类组与 McCants inttles.zip(上游 4.4.4 起即如此,
单一 active 组已覆盖),同步请求数 32 → 9。

转发器源顺序维持 SatNOGS → R4UAB(与上游相反)并注明实测理由:两源同源
(共享 2760 uuid),去重先到先得,SatNOGS 副本更新鲜且独有最新星的发射机。
2026-10-04 02:32:39 +08:00
atsunatsu 1e33a10fb4 fix(satellites): All 类型名单为空时回退为不筛选
CelesTrak 对重复下载(2 小时内数据未更新)返回 403,同步会把该源的
type id 名单写成空串,选 All 时 resolveTypeIds 得空集 → 列表一条不剩。
现在只有 "All"(= CelesTrak active 全集)在名单为空时回退为不筛选(显示
全部卫星);其它源名类型与三个虚拟类型(AMSAT Live FM/Linear、Live SSTV)
保持"空即显示空"。Sources 增加 allSourceType 常量并注明背景。

Tests: SelectionRepoSearchTest 新增 2 例(All 空→显示全部、其它源空→仍空)
2026-10-04 02:32:31 +08:00
atsunatsu 6546e32360 docs(agents): release notes must be bilingual (English first, then Chinese) 2026-10-03 03:28:35 +08:00
atsunatsu c86893f6b1 build: release version 4.4.8-ba7opf.6 (560) 2026-10-03 03:07:19 +08:00
atsunatsu cad085c25b feat(settings): 数据源分组补提示,说明该顺序只影响卫星名
轨道元素改为按历元取最新后,列表顺序只决定显示名;UI 不说明的话用户会
误以为顺序仍决定用哪份轨道(本轮实测的困惑即来自此)。补两组提示项并在
分组标题下小字展示(排版与上游一致:onSurfaceVariant,top 2dp/bottom 8dp):

- 卫星数据(中文):轨道数据优先取列表最新星历,此顺序仅影响卫星名称
- 收发器数据:仍为"列表靠前优先"(tx 记录按 uuid 去重取首个源),提示沿用
  上游措辞;es/ru/si/tr/uk 五种语言同样沿用上游译文
2026-10-03 03:02:11 +08:00
atsunatsu cba5eb7efe feat(data): 多源星历按历元取最新(对齐上游),源顺序只影响卫星名
采用上游 6f3e3351 的合并口径:同一 NORAD 号的轨道元素取历元最新者,名字取
列表中第一个提供该星的源,源顺序因此退化为命名偏好。fork 此前是
flatMap + distinctBy{catnum}(列表靠前者全胜)——实测 R4UAB 的元素平均比
CelesTrak 旧 8.4h(78 颗共有业余星中 67 颗更旧),却因排在列表前面而抢占。

- OrbitalData:暴露 epochDaynum / timeToDaynum / epochToDaynum(跨源比较必须
  走 daynum,原始 YYDDD 跨十年不可比)
- DatabaseRepo:新增 mergeEntries(历元最新元素 + 首个提供者的名字)、
  insertFresherEntries(只写入更新过的元素,并对未更新者原地改名,使重排源
  顺序立即生效)、pruneStaleEntries(30 天无源刷新的星清理)
- updateFromRemote 改为按源分别解析;保留 fork 的 importedTypeIds 类型映射
  (按每源结果统计,供筛选 chips 与自定义源使用);全部源失败时保留上次成功
  时间戳,下次启动重试
- updateTLEFromFile 走同一合并链路(手工导入同样只升不降)
- 新增 5 个单测(含 prune 与失败保时间戳),fixture 历元改为当前(旧历元
  会被新 prune 规则清掉);两个 fake 补齐 ILocalSource 新接口

测试:core:domain 171 / core:data 121 全绿。
2026-10-03 03:02:00 +08:00
atsunatsu 74c245a7d2 build: release version 4.4.8-ba7opf.4 (557) 2026-10-02 23:37:15 +08:00
atsunatsu 135ecb861d feat(map): 网格通联详情呼号列加宽(次数列不再等分,字样位置不变)
工作网格 QSO 详情弹窗里,中间那一列(通联行的「n QSO」、标记行的「标记」)
原来和左右两列一样占 weight(1f)(各 1/3 宽),而该列文字是居中的,字样两侧的
空白被白白占用。现改为按内容宽度占位(去掉 weight(1f)),左右两列仍各占
weight(1f):两外列等分剩余宽度 ⇒ 中列起点正好落在原居中字样的左边界,
因此

- 「n QSO」「标记」字形位置与之前逐像素一致,日期与展开箭头(右对齐)不动;
- 省出的中列左半空白全部交给呼号列,呼号列宽度由 W/3 增至 (W - 字样宽)/2,
  411dp 屏约 +33dp,长呼号(含 /P、活动特别呼号)多显示约 3 个字符,
  并可一直排到「n QSO」字样左侧才省略。

仅影响地图页「网格通联详情」弹窗内的两类行;设置页日志本行本就是
「呼号 weight + 尾部标签 wrap-content」,口径已一致,未改动。
2026-10-02 23:37:06 +08:00
atsunatsu 1fd1459ddf build: release version 4.4.8-ba7opf.3 (555) 2026-10-02 13:31:18 +08:00
atsunatsu 56a788138b feat(lotw): 漫游核验改用「当前定位 vs 证书台址」,移除记录网格核对
- 新增 LoTWPositionWarning + positionWarning(currentGrid, stationGrids):当前定位网格不在
  证书台址网格集内 → 提示(4 位归一;任一侧缺失不报)
- ISettingsRepo.getCurrentGrid():只读取「≤24h 系统最后已知定位」与「存储台址」中较新者,
  不写任何设置(避开 setStationPosition 的写副作用)
- 上传前核对弹窗(雷达 / 日志本两入口)改由 VM 在 prepare 后计算;雷达记录页新增提示行
  (stationMismatch,点击=跳转改台址并预填当前格)
- 移除旧「记录 vs 台址」核对:uploadGridWarning / LoTWGridWarning / preview.gridWarning 及
  相关 UI / 字符串全删;LoTWPositionWarningDialog 重命名替代 LoTWGridWarningDialog
- 测试:LoTWPositionWarningTest ×5 替代 LoTWGridWarningTest;domain 171 / data 116 / mutual 28 全绿
2026-10-02 13:31:13 +08:00
atsunatsu 2e704ee1d3 build: release version 4.4.8-ba7opf.3 (554) 2026-10-02 12:02:03 +08:00
atsunatsu 5b7c7d6df5 feat(logbook): 窗口外录入 + 网格显示链 + 双倍修复 + 上传前核对 + 重传选择 + 报错拆分
.2.5–.3 调试系列收口:

- 雷达窗口外录入:不在过境窗口内按 Log 时按当前过境中点落点(弹窗确认,可事后编辑改时间)
- 网格显示链:上传盖章(markUploaded 记录台址网格集)+ 日志本行尾 / 雷达页「自己的格子」+
  QSL 槽对方网格(绿 #4CD964)+ 缩写规则统一(gridsLabel 上移 core:presentation);
  QsoDatabase v2→v3 增列 theirVuccGrids
- 全量同步「双倍」三层修复:键无关身份±60s 镜像折叠、matchableMode 归一(MFSK→FT4)、
  双确认对按 contentScore 折叠
- 上传前核对:批记录网格与台址完全不交集 → 弹窗(修改台址带预填跳转 / 忽略),预览被闸住
- 重传选中:日志本长按多选(含已上传/已确认)→ prepare(resubmit=true) → 成功后网格盖章更新;
  退出日志本重置选择(需重新长按)
- 报错拆分:QSO_FUTURE(记录时间在未来)与 QSO_DATE(超出证书范围)分开提示
- 全 App 弹窗样式统一(深色圆角 sheet)

测试:domain 172 / data 116 全绿。
2026-10-02 12:01:57 +08:00
atsunatsu d13af978af build: release version 4.4.8-ba7opf.2.4 (549) 2026-09-29 17:58:10 +08:00
atsunatsu b48e23804f feat(radar): 生成通联记录帖子只含当前过境窗口
generatePost 的筛选从最近 24 小时改为当前过境窗口(aos..los),
与日志列表 recent 同一套过滤逻辑,不再混入其他过境的 QSO
2026-09-29 17:58:07 +08:00
atsunatsu a2b3ce5d69 docs: 补充第三方声明(MIT 合规)
- GridGeometry.kt 头部注明移植自 OrbitDeckiOS(Paul Stoetzer, N8HM, MIT)
- 新增 THIRD_PARTY_NOTICES.md:OrbitDeckiOS (MIT) + Material Design Icons (Apache-2.0)
2026-09-29 15:45:55 +08:00
atsunatsu 6ef994e4cd build: release version 4.4.8-ba7opf.2.3 (548) 2026-09-29 12:12:50 +08:00
atsunatsu 4c3fdeaa9c feat(gridfinder): VUCC 网格寻线实地导航 + LoTW 上传台址预填联动 + 移除地图入口
- GridGeometry 网格线/点几何 + QthConverter grid4/grid8;golden vectors 单测
- 独立定位流 ILocationRepo/LocationRepo(stop 时 removeUpdates),不自动写台址
- feature/gridfinder 模块:罗盘表盘、极坐标近距图、线上/点上精度门控(连续 3 次 ≤6.1m)
- 「设为 LoTW 上传台址」:跳证书配置页并预填当前网格(1/2/4 格),只改台站 grid 字段
- 地图页入口移除,设置页单入口;顶部间距改 ScreenColumn 结构(与设置页同构)
- 术语统一「最近网格点」(中英)
2026-09-29 12:12:47 +08:00
atsunatsu 33a7f23d7a fix(settings): Project Wiki 入口整行可点击; build: release version 4.4.8-ba7opf.1.1 (544) 2026-09-29 01:35:55 +08:00
atsunatsu fb4f14f75d feat(wiki): 更新后的 What's New 卡片改为展示 Project Wiki(与设置页入口共用内容) 2026-09-29 01:25:50 +08:00
atsunatsu 473c3bf228 build: release version 4.4.8-ba7opf.1 (543) 2026-09-29 01:11:20 +08:00
atsunatsu 2110bf0cd6 feat(settings): 设置页新增 Project Wiki 入口(fork 增量功能与用法说明) 2026-09-29 01:11:16 +08:00
atsunatsu 95d2d792cc build: release version 4.4.8-ba7opf.0 (542) 2026-09-28 23:49:10 +08:00
atsunatsu dd29c6681c feat(v448): IC-705 读频、昼夜分界极性、AMSAT/更新检查适配、许可证头批量(v4.4.8 移植) 2026-09-28 23:49:07 +08:00
atsunatsu 45cd72faf7 feat(settings): 致谢与声明卡、版本卡打开检查更新、浅色主题、品牌与 GPL 头 2026-09-28 23:46:52 +08:00
atsunatsu 5acf71b2a6 feat(logbook): LoTW 日志本官方名统一、上传候选集、编辑已传记录新建、记录分钟/kHz 规范化 2026-09-28 23:46:47 +08:00
atsunatsu 1871c05002 build: release version 4.4.7-ba7opf.17.8 (531) 2026-09-27 21:26:16 +08:00
atsunatsu e9f58f76f6 feat(radar): keep the full-screen circle width share in small windows
The radar circle is a square, so it is limited by the shorter side of
the card it is drawn in: the small-window layout gave the radar card a
height of ~156dp in a 411x450 window, which shrank the circle to ~36% of
the page width while the full-screen layout shows ~84%.

- measure the real window with BoxWithConstraints instead of trusting the
  window size class, which can still report the full screen while the app
  runs in a split/floating window
- when the classic 1:1 split would give the radar less than 75% of the
  page width, use a fill layout: the radar takes the largest square that
  fits, a usable pager block is reserved under it while that keeps the
  circle at its full-screen share, otherwise the pager collapses into a
  48dp translucent tab strip with a tappable panel
- keep the normal two-row top area in the vertical layout: TimerRow and
  NextPassRow both carry weight(1f) internally, so putting them in a
  single row splits that row into two 50% blocks
- extract the geometry into pure Dp functions (useFillRadarLayout,
  radarFillSizes) covered by unit tests
2026-09-27 21:26:12 +08:00
atsunatsu 800494b978 feat(radar): fill radar in split-screen via measured window size
The previous compact-mode trigger used currentWindowAdaptiveInfo(),
which reports the full-screen size class in split-screen / multi-window,
so the radar never enlarged there. Measure the actual window bounds with
BoxWithConstraints: compact (radar weight 1f fills all space, pager fixed
132dp strip) when maxWidth < 600dp && maxHeight < 480dp.

build: release version 4.4.7-ba7opf.17.6 (529)
2026-09-27 20:13:13 +08:00
atsunatsu f1091acbbd build: release version 4.4.7-ba7opf.17.4 (527) 2026-09-27 18:32:28 +08:00
atsunatsu 99bf3d34a9 feat(radar): enlarge radar in split-screen/small windows
When the window is vertical (narrow) and too short for split-screen or a
small floating window, give the radar card 1.6/0.6 weight instead of the
usual 1:1 so the square radar plot stays large. The pager card shrinks
but all its pages are scrollable, so nothing is clipped. Full-screen
vertical layout (enough height) is unchanged.
2026-09-27 18:32:24 +08:00
atsunatsu 1dd185971f fix(lotw): precise uploaded marking; surface skipped/unavailable counts
P2 — markUploaded now only marks the records that actually made it
into the accepted TQ8 batch (preview.submittedIds), never the whole
candidate list. Previously, un-signable records skipped by prepare()
were still marked UP after any accepted upload, falsely showing them
as uploaded.

P4 — surface why records did not upload:
- When audit finds nothing pending, distinguish unavailable records
  (invalid call/date — check logbook) from unknown-result records
  (not retried automatically) instead of a blanket 'no pending'.
- Upload preview dialogs (Log tab + logbook) show a breakdown line:
  N already uploaded/duplicate · N unknown result · N un-uploadable.
2026-09-27 17:46:21 +08:00
atsunatsu fe85703e56 fix(lotw): decouple QSO records from certificate station; skip un-signable records
- Remove LOCATION_MISMATCH check: the recorded myGrid never enters the
  TQ8 (the tSTATION grid is signed from the current certificate station),
  so a portable/ADIF-imported record with a different grid must not block
  upload. Logging and uploading are now fully decoupled from the
  certificate location.
- Fingerprint now covers the CONTACT only (call, date, band, mode,
  satellite, freq), excluding station fields: changing grid/zones/county/
  IOTA no longer invalidates ledger entries, so already-uploaded contacts
  are not re-queued and rejected as duplicates.
- prepare(): catch un-signable contacts per-record instead of aborting
  the whole batch; count them as skipped and upload the rest.
- audit(): count lotwUploaded records as uploaded (ledger-loss fallback).
2026-09-27 17:35:34 +08:00
atsunatsu caddba5b81 fix(settings): load LoTW certificate status at startup
The LoTW upload card read uiState.lotwCertificate which was only
populated when the config dialog was opened (LoadLoTWUploadStatus).
On first entry to the settings screen it stayed null, showing
'certificate not imported' even though a certificate was stored.
Load certificate + station once in init so the card is correct
from the first frame.
2026-09-27 17:07:02 +08:00
atsunatsu 52b733a450 fix(lotw): support more PBES2 variants, classify import errors for users
- Pkcs12Reader: AES-192/AES-128/DES-EDE3-CBC ciphers, PBKDF2
  SHA1/SHA256/SHA384/SHA512 PRFs, keyLength defaulting per cipher,
  error messages reduced to algorithm names
- LoTWKeyMaterial: map BadPadding -> wrong password, IllegalState
  (unsupported algorithm) -> format error with algorithm name,
  IllegalArgumentException -> invalid file
- Import dialog: user-facing messages with algorithm name embedded,
  no more raw OpenSSL/BoringSSL error strings
- Tests: AES-192, DES-EDE3 fixtures, wrong-password BadPadding check
2026-09-27 01:20:07 +08:00
atsunatsu 474762cbd3 i18n: credit BG5JSU for LoTW upload support 2026-09-26 18:54:14 +08:00
atsunatsu 8fe88fbc93 test(lotw): PBES2 reader and region-field config tests 2026-09-26 18:33:59 +08:00
atsunatsu 7728b5c38f build: release version 4.4.7-ba7opf.17 (523) 2026-09-26 18:33:47 +08:00
atsunatsu a769f7dea7 feat(logbook): Room persistence, UP/QSL markers, one-click upload, swipe-delete, calculator-frequency logging 2026-09-26 18:33:38 +08:00
atsunatsu 3be2e4b9e8 feat(lotw): PBES2 .p12 parsing, station region fields, upload error codes 2026-09-26 18:33:25 +08:00
atsunatsu 5957f30af2 build: bump version to 4.4.7-ba7opf.17.3 (513) 2026-09-25 23:50:52 +08:00
atsunatsu d8d0825f54 feat: show clear error when p12 certificate import fails
The import previously swallowed all exceptions silently. Now the upload
config dialog shows a specific message for: wrong password, expired
certificate, invalid file, and unknown failures.
2026-09-25 23:50:48 +08:00
atsunatsu bc5a8e4bba chore: restore gradle.properties to original build settings (-Xmx6g, parallel, 4 workers) 2026-09-25 23:13:57 +08:00
atsunatsu 851bc25d73 build: bump version to 4.4.7-ba7opf.17.2 (512) 2026-09-25 23:03:23 +08:00
atsunatsu 238511aa78 fix: logbook mode display + bottom-sheet dialogs
- displayMode no longer trusts a stale submode for non-MFSK modes: FM/CW/SSB
  records (including ones persisted with the old default submode=FT4) now show
  their real mode; only MODE=MFSK uses the FT4 submode. QsoRecord defaults
  changed mode=MFSK->FM, submode=FT4->''.
- LoTW report bridge sets submode=FT4 for MODE=MFSK so confirmations still
  match local FT4 records.
- Logbook and LoTW upload config dialogs now use SharedDialog (bottom-sheet),
  matching the LoTW confirmed-grids dialog style.
2026-09-25 23:03:20 +08:00
atsunatsu e606afb0f3 build: bump version to 4.4.7-ba7opf.17.1 (511) 2026-09-25 22:56:39 +08:00
atsunatsu e19f098aa5 fix: p12 import — pick file first, then password (matches normal usage)
The Choose .p12 button was gated on a non-blank password, which forced users
to type the password before selecting the file. Now the file picker is always
available; after selection the filename is shown, then the password field and
an Import button appear.
2026-09-25 22:56:36 +08:00
atsunatsu 797b1c19f7 build: bump version to 4.4.7-ba7opf.17 (510) 2026-09-25 22:37:31 +08:00
atsunatsu 8e549cd43c feat: LoTW upload + logbook (port from Iu-yang1's fork)
- Port TQ8 signing/upload pipeline (core/data/lotw: LoTWConfig, LoTWKeyMaterial,
  LoTWSigner, LoTWStorage, LoTWUploadRepository) with bundled ARRL config.tq6
- Multi-grid station locations: primary grid in GRIDSQUARE + full set in
  MY_VUCC_GRIDS (unsigned tSTATION extra, IOTA precedent); signer matches
  myGrid against the whole grid set
- Satellite-name normalization: SatNOGS names ("SO-50 (SaudiOSCAR 50)") resolve
  to official LoTW names by exact-then-substring match
- Logbook storage: separate QsoDatabase (version 1, no migration on existing
  installs), QsoRepository with dedupe/confirmation merge; LoTW sync (manual +
  auto) feeds confirmations into the logbook and marks local uploads confirmed
- Radar Log tab: single-callsign recording, per-satellite mode preset
  (CW/SSB/FT4), English social post generation (copy/share), LoTW upload with
  one-shot preview confirmation + receipts ledger
- Settings: 日志本 section (records + confirmation state, delete on tap) above
  LoTW config; LoTW upload config (TrustedQSL .p12 import + password, station
  grid list incl. IOTA/CQZ/ITUZ)
- i18n strings (en/zh)
2026-09-25 22:37:20 +08:00
atsunatsu d33629f015 build: bump version to 4.4.7-ba7opf.16 (509) 2026-09-25 15:02:28 +08:00
atsunatsu 7081ffaa60 Merge remote-tracking branch 'fork/main' 2026-09-25 14:50:56 +08:00
atsunatsu 091d3e867b build: bump version to 4.4.7-ba7opf.15.11 (508) 2026-09-25 14:20:46 +08:00
atsunatsu 26e50ddab5 feat(map,lotw): multi-grid station locations (台址) in roamed stripes and operated-grid selector
A LoTW station location (台址) can span several grid squares: the report
emits <MY_VUCC_GRIDS> (comma-separated, MY_GRIDSQUARE often absent) on
those records, but the app parsed only <MY_GRIDSQUARE>, so every extra
grid of a multi-grid 台址 silently vanished from both the blue roamed
stripes and the operated-grid (VUCC) selector.

- GridQso gains myGrids (full own-grid set), myCallsign and stationKey
  (MY_* station snapshot); myGrid stays as the first grid for back-compat.
- parseConfirmedGridQsos parses MY_VUCC_GRIDS + the MY_* snapshot fields;
  parseRoamedGrids parses MY_VUCC_GRIDS too and uppercases (lowercase
  grids never matched the overlay labels).
- SettingsRepo persists mgs/mc/sk; old data falls back to single-grid sets.
- MapScreen groups the selector's 台址名单 by the 台址's full grid set:
  a multi-grid 台址 is one entry listing all its grids (e.g. 'OM60,PM01'),
  and selecting it fills every worked grid worked from any of them.
  Identical grid sets merge (VUCC-equivalent), so partial MY_* snapshots
  can't split one 台址 into duplicate entries. Own grid still never
  striped.

Verified against real reports: BH6RJD (807 SAT QSOs) yields 7 台址
including 4 multi-grid ones; BA7OPF's own data stays a single 'OL62'
entry. 28 LoTW parser tests pass (5 new).
2026-09-25 14:10:17 +08:00
atsunatsu 5f90eebab4 fix: correct AO-123 in hardcoded FM list to ASRTU-1 (61781)
User correction: AO-123 is ASRTU-1 (NORAD 61781, launched 2024-11-04,
in orbit), not Fox-1D (43137, re-entered 2024-02). Update the hardcoded
FM set and its tests to include ASRTU-1.
2026-09-24 12:57:25 +08:00
atsunatsu 70ada0d608 fix: revert AMSAT live data route; hardcode FM/Linear satellite lists
User decision: drop the AMSAT live-page fetch pipeline entirely (page
parsing, amateur whitelist, ISS module disambiguation, timeout fallbacks,
amSatListsVersion re-resolution) and hardcode the FM/Linear lists instead.

- Sources: remove amSatLiveUrls + amSatActiveUrls; add
  amSatFmCatnums = {SO-50 27607, ISS ZARYA 25544, AO-123 43137} and
  amSatLinearCatnums = {RS-44 44909, FO-29 24278, AO-7 7530,
  AO-73 39444, JO-97 43803}
- SelectionRepo: virtual types resolve FM/Linear from hardcoded sets;
  SSTV stays (amateur-only mode query + R/B debris exclusion)
- MutualViewModel: FM/Linear chips filter by the hardcoded sets
- DatabaseRepo/SettingsRepo/ISettingsRepo: AMSAT list fetch/persist
  removed; DataParser AMSAT parse helpers removed
- Tests: AMSAT pipeline tests dropped; selection/mutual tests re-targeted
  at the hardcoded lists
2026-09-24 12:41:52 +08:00
atsunatsu 317f6d877f build: bump version to 4.4.7-ba7opf.15.8 (505) 2026-09-24 11:38:21 +08:00
atsunatsu 865fa9c6f2 fix: AMSAT live page timeouts wiped FM/Linear lists; add fallback
Root cause of the recurring empty AMSAT Live filters: OkHttp defaults to a
10s read timeout and amsat.org's live pages take 7-10s+ from many
networks — every sync timed out, fmNames/linearNames stayed empty, and
(with no previous list, e.g. right after clearing data) the filters were
written as EMPTY. The stale pre-whitelist FM list survived only because
older syncs had occasionally succeeded and the failure path preserved it.

Fix:
1. OkHttp timeouts raised (connect 20s / read 30s / write 30s / call 60s)
   in MainContainer.provideRemoteSource so slow AMSAT pages actually load.
2. updateAmSatLiveLists gains a last-resort fallback: when the AMSAT page
   is down AND there is no previous list to clean, derive FM/Linear from
   the local transceivers (FM / SSB,CW,USB,LSB modes) intersected with
   the amateur whitelist, so a network timeout never wipes the filters.
   ISS module aliases stay excluded by the whitelist intersection.

Regression test: page fails + empty previous list -> fallback yields
{25544} (26700 excluded by whitelist).
2026-09-24 11:37:50 +08:00
atsunatsu a082abb72c build: bump version to 4.4.7-ba7opf.15.7 (504) 2026-09-24 11:11:31 +08:00
atsunatsu a2e41a0c1a fix: don't crash the AMSAT list update on unknown satellite names
resolvePerName crashed with NoSuchElementException (all.first()) when an
AMSAT live-page name had no matching local entry (TEVEL2-1..9, RS95S, any
brand-new sat not yet in the local TLE). The exception was swallowed by
updateAmSatLiveLists' runCatching, so the FM/Linear lists were NEVER
rewritten — they stayed at the stale pre-whitelist snapshot containing
all five ISS modules, which is why ISS kept showing as DESTINY despite the
15.4/15.5/15.6 disambiguation fixes.

Fix: return an empty set for names with no local match (correct skip
semantics) so the rest of the page still resolves and the ISS module
collapse runs. Regression test covers the real AMSAT page mix (ISS +
unknown names).
2026-09-24 11:11:04 +08:00