Skip to content

feat(reminder): wire real engine into the app, drop remaining mocks - #261

Closed
LUPENGHAN wants to merge 6 commits into
1024XEngineer:mainfrom
LUPENGHAN:feature/reminder-wiring
Closed

feat(reminder): wire real engine into the app, drop remaining mocks#261
LUPENGHAN wants to merge 6 commits into
1024XEngineer:mainfrom
LUPENGHAN:feature/reminder-wiring

Conversation

@LUPENGHAN

Copy link
Copy Markdown
Contributor

Closes #257
替代 #245(原来的整体合并 PR,会关掉并指向这个拆分序列)

拆分 #245 的第 4/4 层:接线 + 呈现层,依赖 #260(设备适配器 + SQLite 数据层)先合。这一层落地之后提醒功能才是真的接通的。

标了 draft:分支历史包含 #258/#259/#260 还没合的提交,diff 会显示四层加起来的内容,等前面三个合了再转 ready。这个分支已经单独跑过完整验证:tsc --noEmiteslintnpm run test(34 个套件、257 个用例)全绿。

范围

  • features/reminder/presentation/**AlertReminderPresenteruseReminderPermissionsOnLaunch
  • app/AppProviders.tsxapp/AppRoot.tsxapp/composition/createAppServices.tsMockReminderApplication 换成真的 LocalReminderApplication,全部端口指向真实适配器
  • 删除最后一个 Mock(MockReminderPresenter

顺带修的一个真 bug

useReminderPermissionsOnLaunch.ts 的权限申请链在原来的合并后基本上弹完第一个权限就卡住:promptNext() 里除了"用户确认悬浮窗/全屏通知/电池优化"这条兜底分支,其它每条分支(直接请求通知、跳设置、弹框拒绝、定位授权成功/失败)都在 try 块里直接 return,导致 try/finally 后面那行"继续弹下一个权限"的 setTimeout 全是死代码。已修(挪进 finally),顺带把旧的 mock 版测试换成新的(5 个用例),这个 bug 就是靠新写的测试才抓到的。

拆分顺序

  1. feat(reminder): add native alarm and Baidu location modules #258 — 原生模块 + 脚手架
  2. feat(reminder): add reminder engine core (domain + application) #259 — 提醒引擎核心
  3. feat(reminder): wire device adapters and SQLite data layer #260 — 设备适配器 + SQLite 数据层
  4. 这个 PR — 接线 + 呈现层

Native Android modules for the reminder engine's device layer:
timeflow-alarm (AlarmManager scheduling, ring UI, boot rescheduling)
and timeflow-baidu-location (continuous positioning bridge). Includes
the Expo config plugins that wire them into the native build,
app.config.js (replaces static app.json so the Baidu API key can come
from an env var), and the new package deps/patches these modules need.

No app code references these yet -- pure addition, nothing wired in.
Three unrelated bugs in the already-merged voice/location-search path
(PR 1024XEngineer#243), fixed together since they're small and independent of the
reminder engine work in this stack:
- reuse a recent position during voice handshake instead of blocking
  on a fresh fix (backend location tools + realtime agent)
- preserve newly-started TTS after an interruption instead of letting
  the old stream clobber it
- remove stale push-to-talk listeners left on the shared WebSocket
  connection after a session ends
LocalReminderApplication and its ports (AlarmSchedulerPort,
LocationMonitorPort, DeviceCapabilityPort, NotificationChannels,
ReminderDeliveryPort, ReminderApplicationPort), plus the domain layer
(reminder.ts, strengthDelivery.ts) that drives arm/fire/confirm state
transitions and recurring-schedule advancement.

Pure logic layer: no device-specific adapters yet, nothing wired into
the app. shared/time gains format.ts (used by the delivery strength
calc); MockClock/MockTimeListener are removed since nothing in this
stack still needs a fake clock once the real engine lands.
Device-side adapters implementing the ports added in the previous
commit: ExpoAudioPlayback, ExpoSystemNotification, NativeAlarmScheduler
(+ TimeflowAlarmBridge), NativeDeviceCapability, ReactNativeAlertDialog,
ReactNativeVibration, ExpoLocationMonitor (system geofencing) +
NativeLocationMonitor (Baidu continuous polling, not currently wired
into the app -- see createAppServices comment in a later commit),
IntervalTimeListener. frontend/index.ts registers the geofence
TaskManager task at module scope so headless launches pick it up.

Data layer: SqliteLocalScheduleReader / SqliteReminderStateStore read
and persist against the real local database instead of in-memory
fixtures; LocalScheduleWriter's post-write refresh hooks into the new
reader. InMemoryLocalScheduleReader is kept as a non-persisted
alternative implementation of the same port.

Removes the Mock* adapters these replace. Also removes two dangling
test files (nativeAlarmScheduler.test.ts, nativeDeviceCapability.test.ts)
that were written against the old mock-backed versions of these classes
and don't apply to the real implementations -- this is a real coverage
gap, not covered by a replacement here.
Swaps the composition root over to the real implementations added in
the previous three commits: LocalReminderApplication replaces
MockReminderApplication, SqliteLocalScheduleReader/SqliteReminderStateStore
replace their Mock counterparts, and every device port
(audio/notification/vibration/alarm/location) now points at its real
adapter. ExpoLocationMonitor (system geofencing) is used for location
monitoring; NativeLocationMonitor (Baidu SDK) stays in the repo but
unwired -- see the comment in createAppServices.ts for how to switch.

AppProviders/AppRoot gain the reminder permission-request flow
(useReminderPermissionsOnLaunch, now driven by an injected AlertDialogPort
instead of calling Alert.alert directly, with a settings-page fallback
for denied background-location permission) and rebuild() the engine
once permissions change.

Removes MockReminderPresenter, the last remaining Mock* adapter.
Every branch in promptNext() except the overlay/full_screen/battery
confirm-and-continue path returns from inside the try block, so the
setTimeout(runPrompt, 250) that was meant to advance to the next
missing permission -- placed after the try/finally -- was dead code
for those branches. In practice: grant notifications, and exact_alarm
(the next permission in line) would just never get prompted; same for
any declined dialog, or a granted/denied location permission. Moved
the continuation check into the finally block so it always runs
regardless of which branch returned.

Also replaces the old mock-based useReminderPermissionsOnLaunch test
(deleted upstream when this hook's signature changed to take an
injected AlertDialogPort + onPermissionsUpdated callback, with no
replacement written) and drops the now-redundant .gitkeep placeholders
left over from directories that have had real files in them since
earlier commits in this stack.
@vercel

vercel Bot commented Aug 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
timeflow Ready Ready Preview Aug 17, 2026 12:30am

@LUPENGHAN

Copy link
Copy Markdown
Contributor Author

拆分粒度还是太粗(这个都还有 55 个文件改动),先撤回去重新想怎么拆,关掉这个。

@LUPENGHAN LUPENGHAN closed this Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

拆分提醒功能 4/4:接线 + 呈现层(替代 #245)

1 participant