1
0
mirror of https://github.com/avinal/nikki.git synced 2026-07-03 21:40:09 +05:30

15 Commits

Author SHA1 Message Date
avinal 6b1d798c95 Add Fastlane metadata and F-Droid build config
Fastlane structure:
- short_description.txt (< 80 chars)
- full_description.txt (feature list)
- changelogs/1.txt (v1.0.0 release notes)
- images/icon.png (512x512 from logo SVG)

Build config:
- dependenciesInfo disabled (F-Droid requirement)

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context)
2026-06-05 15:09:48 +05:30
avinal 81b895fcc1 Add share intent, relative dates, task count badge
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)
2026-06-05 15:09:48 +05:30
avinal ad536d1e3d Fix 5 notification reliability issues
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)
2026-06-05 15:09:47 +05:30
avinal d2be80bc7d Add CI/CD workflows and release signing config
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)
2026-05-22 19:05:40 +05:30
avinal 375c5616b2 Allow cleartext HTTP for self-hosted servers
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)
2026-05-22 17:38:02 +05:30
avinal b8d4f52e22 Fix 5 security issues flagged in review
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)
2026-05-22 17:35:37 +05:30
avinal 44b00736db Rename app to Nikki, add about section with logo and author info
- App name: Memos App → Nikki (from Japanese 日記, diary)
- Theme: Theme.MemosApp → Theme.Nikki
- Composable: MemosAppTheme → NikkiTheme
- Backup filename: memos-backup.json → nikki-backup.json
- Settings about section: 96dp logo, app name, version,
  one-liner summary, author, and GitHub issues link
- Notification subtext fallback: "nikki"

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context)
2026-05-22 17:04:02 +05:30
avinal 91b6a479a4 Add parser doctor, offline queue, tag inheritance, logo, MIT license
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>
2026-05-22 16:40:58 +05:30
avinal 0512c9a698 Auto sync setting, pretty notifications, background permissions,
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>
2026-05-21 21:14:27 +05:30
avinal 4416d7e98b Add time parsing, exact alarm notifications, boot reschedule
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>
2026-05-21 14:24:11 +05:30
avinal e165be9f6c Add task notifications, JSON backup, and comprehensive test suite
Notifications:
- TaskCheckWorker (WorkManager, 15-min periodic) scans cached memos for
  tasks due today or overdue, fires Android notifications
- TaskNotificationManager: notification channel, tap-to-open intent
- Notification deduplication via SharedPreferences (notified task IDs)
- Toggle in settings (on/off persisted in DataStore)
- POST_NOTIFICATIONS permission requested on API 33+

JSON Backup:
- BackupManager: export all memos to JSON, import from JSON
- Export: saves to device via Android SAF (CreateDocument)
- Import: reads JSON file, creates memos via API, refreshes cache
- Backup format: version, exportedAt, memoCount, array of BackupMemo
- Export/import buttons in settings with status feedback

Test Suite (67 tests, all passing):
- TaskParserTest (29): checkbox parsing, priorities, dates, labels, lists,
  stable IDs, toggle/replace, line indices, edge cases
- DtoMappersTest (16): ID extraction, timestamps, visibility, properties,
  attachments, reactions, comment count from relations
- DtoSerializationTest (7): JSON deserialization, unknown fields, relation
  object refs, attachment size strings
- BackupManagerTest (7): export/import round-trip, version, memo count,
  invalid JSON handling
- MemoVisibilityTest (5): fromApiString, toApiString, round-trip
- ApiResultTest (3): Success, Error, NetworkError sealed class

Co-Authored-By: Claude Opus 4.6 (1M context)

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-21 13:44:01 +05:30
avinal 099ff25ed3 Fix warnings, update deps, Metro-style task detail, comment counts
Warnings fixed:
- Removed unused imports (FieldMask, UpdateMemoRequest, LocalUriHandler,
  LocalPlatformContext, Composable in Color.kt)
- Removed unused Android color resources (old Material purple/teal)
- Replaced proguard-rules.pro with clean Compose/KMP config
- Fixed RelationDto to match actual API (memo/relatedMemo are objects)

Dependencies bumped:
- Ktor 3.4.3 → 3.5.0, Activity Compose 1.10.1 → 1.13.0
- Core KTX 1.16.0 → 1.18.0, SQLite 2.5.1 → 2.6.2
- WorkManager 2.11.1 → 2.11.2, JUnit 1.1.5 → 1.3.0, Espresso 3.5.1 → 3.7.0

Features:
- TaskDetailSheet converted to Metro AlertDialog style (no Material chips)
- MemoDetailScreen: edit button, created/updated timestamps at top
- Comment count shown on MemoCard header (computed from COMMENT relations)
- Explorer tag table: combined columns for memo count + task count per tag

Co-Authored-By: Claude Opus 4.6 (1M context)

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-19 19:04:02 +05:30
avinal 8c15660fce Add media upload, clickable links, tables, comments, share
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>
2026-05-19 18:24:45 +05:30
avinal 5759ab3738 Add dependency wiring, token storage, and app entry points
- 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>
2026-05-19 17:08:37 +05:30
avinal f685856b9e Add module build configs and platform expect/actual stubs
- composeApp/build.gradle.kts: KMP targets (android + iOS), all dependencies
- androidApp/build.gradle.kts: Android app with compose compiler
- Platform.kt expect/actual for Android and iOS
- Android resources: launcher icons, themes, manifest

Co-Authored-By: Claude Opus 4.6 (1M context)

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-19 17:06:41 +05:30