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

30 Commits

Author SHA1 Message Date
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)
v1.0.0
2026-05-22 19:05:40 +05:30
avinal d02edde30e Add README, task format docs, fix archived memos API
- README.md: introduction, features, build/install, tech stack,
  disclaimer, acknowledgements, logo at top
- TASK_FORMAT.md: full task syntax reference with examples,
  validation rules, typo detection, notification behavior
- Fix archived memos: use state query param instead of CEL filter
- LOGO.md: remove triangle variant, keep circle only
- logo-circle.svg tracked for README rendering

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context)
2026-05-22 18:47:31 +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 8c3ab59f2f Fix notification scheduling, custom reminder picker, 125 tests
Notification fixes:
- Removed scheduledIds skip — alarms always recomputed on each worker
  run (AlarmManager deduplicates via FLAG_UPDATE_CURRENT)
- Tasks with dueTime but no dueDate now assume today
- Worker runs once immediately on app launch + periodic 15min
- Added debug logging to trace task/alarm computation
- "check reminders now" button in settings triggers immediate check

Custom reminder picker:
- Number input field (digits only) + unit selector (min/hr/day/week)
- Replaces the preset-only list with free-form input
- "save" validates > 0 before applying, "clear" removes reminder

ReminderScheduler extracted to commonMain (testable):
- 18 tests covering: completed/no-date skip, due time alarms,
  default 8am/8pm, duration offsets (min/hr/day/week),
  past alarm filtering, multiple tasks, label preservation

125 tests total, all passing.

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-21 20:00:48 +05:30
avinal 9bebc628bd Add archived view, comment delete, accessibility, entity tests
Archived memos:
- "view archived memos" in explorer navigates to memo list with
  archived filter active
- Fetches archived memos from API (state == ARCHIVED)
- MemoCard shows "restore" instead of "archive" in context menu
- Restore calls updateMemo(state=NORMAL), upserts to local cache
- Compose card hidden when viewing archived
- Filter banner shows "archived memos" with clear option

Comment deletion:
- Each comment shows "delete" link next to creator/date
- Calls deleteMemo on the comment (child memo) and removes locally

Accessibility:
- Task group collapse icons now have contentDescription
  ("Expand"/"Collapse")

Test suite: 107 tests (5 new entity mapper tests)
- MemoEntityMappersTest: round-trip field preservation, empty tags,
  cachedAt, all visibility variants, timestamp fidelity

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-21 19:31:23 +05:30
avinal cc379c1828 Add loading indicator, error display, archived memos API
Loading state:
- CircularProgressIndicator shown during first fetch instead of
  "no memos yet". isInitialLoading flag in MemoListUiState cleared
  after first emission from observeMemos().

Error display:
- Failed refresh/load errors shown as red text in memo list
- Previously errors were captured but never displayed to user

Archived memos:
- listArchivedMemos() API endpoint added (filter: state == ARCHIVED)
- "view archived memos" link in explorer page (placeholder for full UI)

102 tests passing.

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-21 17:31:36 +05:30
avinal 25a5c51b0a Fix 6 bugs: wire settings, dedup toggle, timeouts, leak, react
1. Default visibility now used in compose card (reads from DataStore)
2. Week start day wired to explorer calendar (rotates day labels,
   adjusts Zeller offset)
3. Task toggle deduplicated: both MemoListViewModel and
   MemoDetailViewModel now use TaskParser.toggleTaskInContent
   instead of manual string replacement
4. reactToMemo refetches single memo instead of all memos
5. AppDependencies stores Job reference, cancels before re-init
6. HTTP timeouts added: 30s request/socket, 15s connect

102 tests passing.

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-21 17:25:57 +05:30
avinal 2f60ac3e13 Add settings, align task detail, reminder duration, live preview
Task detail sheet:
- "open in memo" and "close" aligned on same line (left/right)
- Due date+time, reminder, priority, tags as labeled rows with
  bordered value boxes (accent when set, muted when not)
- No presets for date/time — tap opens DatePicker/TimePicker
- Reminder picker: duration options (15min to 1week)
- Tag editor: text field for #tag input
- Dialog stays open after selections, "close" to dismiss

Reminder as duration (!Nunit):
- !30min, !1hr, !2day, !1week parsed into ReminderDuration
- Notification worker: alarm at dueTime - duration offset
- Shown in task list metadata row

Live preview in compose card:
- Shows parsed metadata chips as you type
- Auto-checklist: Enter after task line inserts "- [ ] "

Settings additions:
- Default visibility (tap cycles: private → protected → public)
- Default reminder (tap cycles: none → 15min → 30min → 1hr → 1day)
- Week starts on (tap cycles through days, for calendar)
- All new settings persisted in DataStore

Parser rewritten:
- Removed @labels entirely (@ not a Memos concept)
- Natural dates without prefix: today, tomorrow, yesterday
- Word boundary checks: mp3 ≠ p3, todaying ≠ today
- ISO date colons don't match as time
- !reminder not parsed as due time

102 tests (64 parser, 16 mapper, 7 serialization, 7 backup,
5 visibility, 3 apiResult), all passing.

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-21 16:46:44 +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 3070651652 Fix pull-to-refresh cache sync and AMOLED dialog visibility
Refresh now does a full sync:
- Fetches ALL pages from the API (loops until nextPageToken is empty)
- Clears the entire local cache before inserting fresh data
- Deleted/archived memos on server are now properly removed locally

AMOLED theme dialog fix:
- surface raised from #000000 to #161616 (dialogs no longer invisible)
- surfaceContainer at #1E1E1E for popup/dialog backgrounds
- surfaceContainerHigh at #222222 for elevated surfaces
- outline brightened to #444444 for better border visibility
- All AlertDialog containerColor changed to surfaceContainer

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-20 12:40:34 +05:30
avinal 4f9e0014ae Remove stale no-op statement in AuthRepository.login
Co-Authored-By: Claude Opus 4.6 (1M context)

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-19 19:05:20 +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 70910f7788 Add project metadata and Gradle wrapper
- PLAN.md: architecture design document
- .idea/: Android Studio project configuration
- Gradle wrapper: v9.4.1 with daemon JVM properties

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-19 17:12:08 +05:30
avinal 5f2c1c02b2 Add tasks pivot and Metro settings screen
Tasks screen:
- Group by: Due Date, List/Topic, Priority, Source Memo, Status
- Sort by: Due Date, Priority (within groups)
- Collapsible groups with count badges
- Accent-colored checkboxes with content-based task identification
- Task detail bottom sheet: edit due date, priority, open source memo
- Completed tasks in collapsed group at bottom

Settings screen:
- Metro-style large section headers (24sp Light)
- Accent color picker: grid of 20 WP8 color circles
- Theme toggle: dark / light / amoled
- Account info display, sign-out with confirmation

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-19 17:11:42 +05:30
avinal 9b5e18939b Add memo screens: panorama feed, detail, editor, explorer
MainScreen: WP Panorama-style navigation with parallax-scrolling pivot
headers (explore/memos/tasks/settings). Headers drift at 50% of swipe
speed. Active title in accent color, inactive fades with distance.

MemoListScreen: cardless feed with inline compose bar (expandable text
field, + insert menu, visibility picker, accent "post" button).
Pull-to-refresh, date-based filtering from explorer calendar.

MemoDetailScreen: full content view with markdown rendering, attachment
display, reactions. Back link, retry on load failure.

MemoEditorScreen: Metro-style editor with 32sp Light title, accent
underline text field, dirty state tracking, discard confirmation dialog.

ExplorerPage: activity calendar (month heatmap with navigation arrows),
search bar, tag list with counts. Calendar dates link to memos page
with date filter instead of opening detail screen.

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-19 17:11:03 +05:30
avinal 0377095eaa Add navigation and Metro-style login screen
Navigation:
- Type-safe routes: Login, Main, MemoDetail, MemoEditor
- Slide + fade transitions (300ms) for forward/back navigation
- Login uses fade-only transition
- Auth-gated start destination (isLoggedIn flow)

Login screen (Metro design):
- "sign in" title in 54sp Light weight, left-aligned
- Underline-only text fields with accent color focus indicator
- Solid accent-colored sign-in button
- PAT-based authentication against any Memos server URL

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-19 17:10:39 +05:30
avinal 3b4e45484f Add shared UI components: markdown, memo card, attachments, reactions
MarkdownText: custom Compose renderer supporting headings, bold (**/__),
italic (*/_), strikethrough (~~), inline code with accent background,
fenced code blocks with syntax highlighting (keywords/strings/comments/numbers),
task checkboxes, bullet lists, blockquotes, links, bare URLs, #tag pills.
All text colors respect theme (onBackground/onSurfaceVariant).

MemoCard: chrome-free content block with parallax-aware layout.
Long-press context menu (Metro AlertDialog style): pin, edit, copy, archive, delete.
Inline editing with accent-colored text field and visibility picker.
Compact mode with "show more/less" for long memos.

AttachmentGrid: full-width image rendering via Coil with FillWidth scaling.
ReactionBar: grouped emoji display with count badges.
RelativeTimestamp: "just now", "5m ago", "yesterday", "Jan 15" formatting.

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-19 17:10:00 +05:30
avinal 3b1d996574 Add Windows Phone Metro theme system
Color system:
- Dark (#1F1F1F bg), Light (white bg), AMOLED (pure black bg)
- All 20 WP8 accent colors (Lime through Taupe)
- User-selectable accent color persisted in DataStore
- Default: Cobalt (#0050EF)

Typography (WP scale):
- 54sp Light for page titles, 32sp Light for pivot headers
- 24sp Light for section headers, 17sp body, 15sp normal, 14sp small
- SemiBold for emphasis, Light for large display text

Flat surfaces only — no elevation, no tonal surfaces, no Material chrome.

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-19 17:09:37 +05:30
avinal d64ffded84 Add Todoist-style task parser
Extract tasks from memo markdown content:
- Checkbox syntax: - [ ] / - [x] detection
- Due dates: @today, @tomorrow, @yesterday, YYYY-MM-DD format
- Priorities: p1, p2, p3 as standalone tokens
- Labels: @word (excluding date keywords)
- Lists: #word (first letter must be alpha)
- Stable task IDs via content hash (survives line reordering)
- Content-based line matching for safe toggle/edit operations
- reconstructLine() rebuilds task line after metadata edits

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-19 17:09:20 +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 e842355a6b Add Room database with multiplatform support
- MemoEntity with JSON-serialized attachments and reactions columns
- MemoDao: observe all/by-id, upsert, delete operations via Flow
- Entity-domain mappers with JSON serialization for nested data
- DatabaseFactory: expect/actual pattern for platform-specific builders
- Android: Room.databaseBuilder with context
- iOS: Room.databaseBuilder with NSHomeDirectory path
- BundledSQLiteDriver for consistent cross-platform SQLite
- Destructive migration fallback for schema changes

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-19 17:08:18 +05:30
avinal b65673093a Add data layer: Memos API client, domain models, repository
API client (Ktor):
- Auth via Bearer token HttpSend interceptor
- CRUD endpoints: listMemos, getMemo, createMemo, updateMemo, deleteMemo
- PATCH uses updateMask as query parameter (gRPC-Gateway format)
- Reaction upsert/delete endpoints
- ApiResult sealed class for error handling

Domain models:
- Memo with string IDs (Memos uses short UUIDs, not integers)
- Attachment, Reaction, User, Task, MemoVisibility
- MemoRepository: offline-first with Room cache, 5-min TTL
- AuthRepository: PAT login, token validation

DTOs match actual Memos API JSON (camelCase, no @SerialName needed).

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

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
2026-05-19 17:07:50 +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
avinal 8dd6c10320 Initialize Compose Multiplatform project with AGP 9
Set up two-module structure for AGP 9 compatibility:
- composeApp: KMP shared library (com.android.kotlin.multiplatform.library)
- androidApp: Thin Android app shell (com.android.application)

Configure all dependencies in version catalog: CMP 1.11.0, Kotlin 2.3.21,
Ktor 3.4.3, Room 2.8.4, Coil 3.4.0, kotlinx-serialization/datetime/coroutines,
AndroidX Navigation 2.9.2, Lifecycle 2.10.0, DataStore 1.2.1, WorkManager 2.11.1.

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

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