Share intent receiver:
- ACTION_SEND text/plain intent filter in manifest
- Shared text pre-fills compose card via MainActivity → App →
AppNavHost → MainScreen → MemoListScreen
Relative dates in task parser:
- "next monday" through "next sunday" (picks next occurrence)
- "next week" (7 days from today)
- "in N days" / "in N day" (arbitrary future offset)
- All cleaned from display text
Task count badge on pivot header:
- Small number next to "tasks" title showing overdue + due-today
- Uses accent color, only visible when count > 0
Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context)
1. Remove println debug statement from ReminderScheduler
2. Drop scheduledIds tracking — AlarmManager deduplicates via
FLAG_UPDATE_CURRENT, and the tracking prevented rescheduling
when a task's due time was edited
3. TaskCheckWorker uses live app DB via liveMemosProvider when
available, falls back to opening its own DB only when the
app process isn't running (boot receiver, background check)
4. Default notify time synced from DataStore to SharedPreferences
via syncNotifyTime() — both DirectAlarmScheduler and
TaskCheckWorker now read from the same source via
readDefaultNotifyTime() helper
5. TaskReminderReceiver triggers runTaskCheckNow() after each
alarm fires, so the next alarm is scheduled immediately
instead of waiting up to 15 min for WorkManager
Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context)
Build workflow: runs tests + assembles debug APK on pull requests.
Release workflow: builds signed APK and uploads to GitHub release.
Signing config reads keystore from env vars (set by CI secrets).
Keystore files excluded from git.
Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context)
Memos instances may run on local networks, Tailscale (100.x),
or other private infrastructure without TLS. The app defaults
to HTTPS in the login flow; HTTP requires explicit user input.
Android's domain-config doesn't support IP/CIDR matching, so
cleartext is permitted globally with documentation.
Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context)
1. Filter injection: escape quotes/backslashes in search query
before interpolating into API filter parameter
2. Backup data leak: configure backup_rules.xml and
data_extraction_rules.xml to exclude sharedprefs, database,
and datastore files from cloud backup and device transfer
3. Cleartext traffic: add network_security_config.xml with
cleartextTrafficPermitted=false, referenced from manifest
4. Debug logging: remove all Log.d() calls from
TaskCheckWorker, DirectAlarmScheduler, TaskReminderReceiver
that logged task content and scheduling details
5. Token obfuscation: XOR + Base64 obfuscation for credentials
stored in DataStore. Prefixed with "OBF:" for seamless
migration of existing plaintext values on next login.
Not cryptographic — prevents casual file inspection.
Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context)
Parser doctor:
- validateContent() with error/warning severity levels
- Errors: invalid date, invalid priority, reminder without due,
invalid reminder unit
- Warnings: time without date, past date, multiple metadata,
typo detection with correction suggestions
- 21 new tests in ParserDoctorTest
Tag inheritance:
- extractTasks() accepts memoTags parameter
- Tasks without #tags inherit memo-level tags
Offline queue:
- PendingSyncEntity + PendingSyncDao for queued edits
- MemoRepository queues failed API calls, drains on next sync
- Sync status banner: "synced N min ago" / "offline · N pending"
UI:
- Parser doctor banner in tasks tab with inline highlighting
- Error/warning dots on task rows
- Pivot headers with absolute positioning and measured widths
- Logo in settings about section (Canvas-drawn circle variant)
Other:
- MIT license
- Logo design spec (LOGO.md)
- Concentric circle logo: pink circle, black+teal 47° annular wedge
- .gitignore updated for dev artifacts
144 tests passing.
Co-Authored-By: Claude Opus 4.6 (1M context)
Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
reliable alarm scheduling
Auto sync:
- Configurable interval: 1/2/5/10/15/30/60 min (default 5)
- MemoRepository.syncIntervalMinutes updated live from DataStore
- Setting shown under "memos" section in settings
Notifications by priority:
- p1: 🔴 alarm sound, long vibration, wakes screen, bypasses DND
- p2: 🟠 notification sound, medium vibration, heads-up
- p3: 🔵 notification sound, short vibration
- none: silent, no vibration
- BigTextStyle with priority tag, colored accent bar
- 4 separate Android notification channels
Background reliability:
- FOREGROUND_SERVICE, WAKE_LOCK, REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
- Battery optimization exemption requested on first launch
- DirectAlarmScheduler: schedules alarms directly from app process
using live Room data (bypasses WorkManager DB sync issue)
- onContentChanged fires direct scheduling on every memo create/update
- TaskReminderReceiver moved to androidApp module for reliable
cold-start instantiation
- WorkManager kept as 15-min backup for server-side changes
123 tests passing.
Co-Authored-By: Claude Opus 4.6 (1M context)
Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
Time parsing:
- 12-hour format: 5pm, 2:30pm, 11am, 12am (midnight), 12pm (noon)
- 24-hour format: 14:30, 9:00, 17:00
- Time extracted alongside date: "@today 3pm p1 #work"
- Time cleaned from display text
- dueTime field added to Task domain model (LocalTime?)
Notification scheduling:
- Tasks with specific time: AlarmManager.setExactAndAllowWhileIdle at
that exact time
- Tasks with date only: two alarms at 8am and 8pm on the due date
- SecurityException fallback to inexact alarm if permission denied
- TaskAlarmReceiver fires notification when alarm triggers
- BootReceiver re-schedules WorkManager on device reboot
Permissions added:
- SCHEDULE_EXACT_ALARM, USE_EXACT_ALARM for AlarmManager
- RECEIVE_BOOT_COMPLETED for reschedule after reboot
Test suite: 76 tests (38 TaskParser, 16 DtoMappers, 7 Serialization,
7 Backup, 5 Visibility, 3 ApiResult), all passing.
9 new time parsing tests: 12h am/pm, 12h with minutes, 24h, midnight,
noon, no time returns null, time+date combo, time cleaned from text.
Co-Authored-By: Claude Opus 4.6 (1M context)
Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
Media upload:
- Android file picker via ActivityResultContracts.GetContent
- Upload attachment API (base64 content to /api/v1/attachments)
- Uploaded attachments linked to memo via CreateMemoRequest.attachments
- Upload status shown in compose card ("uploading...", "N attachment(s) ready")
Markdown improvements:
- Clickable links: URLs and [text](url) open in browser via LinkAnnotation
- Table rendering: pipe-delimited markdown tables with header row
- Fixed underscore italic (_text_) and bold (__text__) variants
Comments:
- Comments section at bottom of MemoDetailScreen
- List existing comments via /api/v1/memos/{id}/comments
- Add new comments with text input + send button
- Comments rendered with full markdown
Share:
- "share" option in memo long-press context menu
- Android share intent with memo content as plain text
Also:
- Task toggle now works in memo feed (onTaskToggle callback wired)
- Tag clicks in explorer filter memos page
- Search from explorer filters memos page instead of navigating
- All three filter types (date/tag/search) shown as banner with "clear"
Co-Authored-By: Claude Opus 4.6 (1M context)
Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
- AppDependencies: manual DI container with lazy singletons
- TokenStore: DataStore-backed persistence for server URL, access token,
theme preference, and accent color selection
- DataStoreFactory: multiplatform DataStore creation
- LocalAppDependencies: CompositionLocal for DI access in composables
- App.kt: root composable with theme + Coil ImageLoader (Ktor engine)
- MainActivity: creates AppDependencies, provides via CompositionLocal
- Coil configured with authenticated Ktor HttpClient for private images
Co-Authored-By: Claude Opus 4.6 (1M context)
Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>