max / goingson
- Co-Authored-By
- Claude Opus 4.7 (1M context) <noreply@anthropic.com>
70 files changed,
+531 insertions,
-139 deletions
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | # GoingsOn Todo | |
| 2 | 2 | ||
| 3 | - | v0.3.1. Audit grade A (Run 24). ~773 tests. ~74K LOC. Rust 2024 edition. | |
| 3 | + | v0.3.3 (iOS-only bump for icon fix; desktop still at 0.3.1). Audit grade A (Run 24). ~773 tests. ~74K LOC. Rust 2024 edition. | |
| 4 | 4 | ||
| 5 | 5 | Completed items: [todo_done.md](./todo_done.md) | |
| 6 | 6 | ||
| @@ -21,10 +21,12 @@ | |||
| 21 | 21 | ||
| 22 | 22 | ### Mobile (iOS TestFlight — keep in scope, near completion) | |
| 23 | 23 | See `todo_mobile.md` for full breakdown. Launch requires: | |
| 24 | + | - [x] iOS TestFlight upload working — v0.3.3 delivered 2026-05-17 (icon fix; v0.3.1 had Tauri default logo) | |
| 24 | 25 | - [ ] Android emulator smoke (`cargo tauri android dev`) + CRUD verified on mobile WebView | |
| 25 | - | - [ ] Physical device testing (iOS + Android) | |
| 26 | + | - [ ] Physical device testing (iOS + Android) — run mobile P0+P2 checklist in `docs/human_testing.md` | |
| 26 | 27 | - [ ] Safe area insets across device models, keyboard-doesn't-obscure-inputs, background/foreground transitions | |
| 27 | - | - [ ] iOS internal testing: invite phone Apple ID, add to TestFlight Internal group, install + smoke-test | |
| 28 | + | - [ ] iOS internal testing: invite phone Apple ID into ASC Users and Access (Developer role), add to TestFlight Internal group, install + smoke-test on v0.3.3 | |
| 29 | + | - [ ] Resolve Missing Compliance prompt on v0.3.3 build (encryption answer — HTTPS-only exempt). **Plist key added 2026-05-18** in `gen/apple/goingson-desktop_iOS/Info.plist` (`ITSAppUsesNonExemptEncryption = false`); future uploads won't re-prompt. The currently-stuck v0.3.3 build still needs the answer set once via App Store Connect UI (TestFlight → build → Encryption: "Uses only exempt encryption"). | |
| 28 | 30 | - [ ] Add Privacy Policy page to GoingsOn project on MNW (URL: `https://makenot.work/p/goingson#section-privacy-policy`) | |
| 29 | 31 | - [ ] iOS External Testing: add build, fill Beta App Information, submit for Beta App Review, enable Public Link | |
| 30 | 32 | - [ ] Android release: Google Play Developer account ($25), release AAB, Play Console listing, submit |
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | # GoingsOn - Mobile Port | |
| 2 | 2 | ||
| 3 | - | Done: Phases 1-7 (CSS, touch, navigation, views, build config, tab bar, distribution setup). Active: None. Next: Testing + release. | |
| 3 | + | Done: Phases 1-7 (CSS, touch, navigation, views, build config, tab bar, distribution setup); touch-native UX rework (paint, reschedule, week carousel); polish (tap targets, scroll lock, modal cutoffs, icon, provider hints, segmented events view). Active: None. Next: Internal TestFlight install + smoke test on a real device. | |
| 4 | 4 | ||
| 5 | 5 | --- | |
| 6 | 6 | ||
| @@ -18,6 +18,23 @@ | |||
| 18 | 18 | - [x] Keyboard doesn't obscure inputs in modals — 2026-05-16: `wireKeyboardScrollIntoView()` in `mobile.js` uses `visualViewport` to scroll focused inputs into view on keyboard show. Verify on device. | |
| 19 | 19 | - [x] Background/foreground transitions work correctly — 2026-05-16: `visibilitychange` handler in `app.js` invalidates caches and refreshes view/sync indicator/day-plan time when app was hidden >30s. Verify resume behavior on device. | |
| 20 | 20 | ||
| 21 | + | ### UX Rework (Touch-Native Interactions) | |
| 22 | + | Mobile UX audit 2026-05-17 — desktop interactions that don't translate. | |
| 23 | + | - [x] **Drag-to-paint event creation** — 2026-05-18: `day-planning-render.js` skips `onmousedown`/`onmouseenter` on touch. Tap opens picker with 30-min default; long-press opens picker with 1-hour default. Both snap to 30-min boundaries on touch to absorb finger imprecision. Wired in `wireTouchInteractions` in `day-planning.js`. | |
| 24 | + | - [x] **Drag-to-reschedule events** — 2026-05-18: `onmousedown` on `.timeline-item` is gated to non-touch. Tap opens the item; long-press opens an action sheet (Open / Reschedule / Unschedule for tasks; Edit time for events/blocks). Reschedule reuses `openScheduleTaskModal`. | |
| 25 | + | - [x] **Dense month/week calendar grids** — 2026-05-18: Month grid tap targets enlarged (64px min-height, larger date numbers); tap-to-expand behavior kept. Week view: single-day swipe carousel at `max-width: 600px` (`renderMobileDay` in `events-calendar.js`); arrows step by 1 day on mobile, 7 on desktop. | |
| 26 | + | ||
| 27 | + | ### UX Rework (additional, 2026-05-18) | |
| 28 | + | - [x] **Day plan timeline tap targets** — `--timeline-slot-h` CSS variable drives `.timeline-slot` height. Default 12px; 22px under `max-width: 600px` (88px/hour on mobile). JS reads it via `GoingsOn.dayPlanRender.getSlotHeight()` so positioning math stays in sync. | |
| 29 | + | - [x] **Horizontal scroll lock** — `html, body { overflow-x: hidden; touch-action: pan-y }` under mobile media query. `.pill-nav` opts back in to `pan-x` for its own scroller. | |
| 30 | + | - [x] **Modal/overlay cutoff behind tab bar** — `.modal-overlay`, `.bulk-actions-bar`, `.filter-bar.mobile-visible` all lifted to sit above the 52px mobile tab bar. Modal `max-height` capped to actual usable viewport. | |
| 31 | + | - [x] **App icon on iOS** — regenerated with `--ios-color "#E8F4F8"` then `#1B365D` so the icon background extends edge-to-edge under iOS's corner mask instead of looking "set-in". | |
| 32 | + | - [x] **Welcome modal mobile copy** — `app.js` `showWelcome` branches on `GoingsOn.touch.isTouchDevice`: step 1 says "tap the + tab", step 2 says "tap or long-press the timeline to schedule"; keyboard-shortcut hint hidden on touch. | |
| 33 | + | - [x] **Email provider hints** — `email-accounts.js` now shows a per-provider call-out beneath the email field once the domain is detected. Covers iCloud/me/mac (app-specific password + link), Fastmail, Gmail, Yahoo, AOL, Outlook (conditional), Proton (Bridge required). | |
| 34 | + | - [x] **Time tab subtab labels** — renamed to **Day / Week / Month / Timer / Events** in `index.html` (was Day Plan / Weekly Review / Monthly Review / Focus Timer / Events). Shared markup → applies to desktop and mobile. | |
| 35 | + | - [x] **Events view flattened** — removed the inner List/Month/Week toggle and the calendar grid containers. Events view is now a segmented flat list: Recurring (templates only, expandable, at top) → Upcoming → Past (collapsible). `events.js` `load()` splits the response into three buckets via `recurrence !== 'None' && !isRecurringInstance` filter; new `renderEventRow` `isRecurring` branch shows the recurrence pattern in place of the date column. | |
| 36 | + | - [x] **iOS missing commands** — `lib.rs` (mobile entry point) was missing several commands present in desktop `main.rs`. Added: `get_monthly_review`, `upsert_monthly_goal`, `update_monthly_goal_status`, `delete_monthly_goal`, `save_monthly_reflection`, `sync_get_tiers`, `list_themes`, `get_theme`, `get_custom_themes_dir`, `import_theme`, `export_theme`. Both handler lists must be kept in sync going forward. | |
| 37 | + | ||
| 21 | 38 | ### Platform Features (Future) | |
| 22 | 39 | - [ ] Push notifications via Tauri plugin | |
| 23 | 40 | - [ ] Haptic feedback for actions |
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | <html lang="en"> | |
| 3 | 3 | <head> | |
| 4 | 4 | <meta charset="UTF-8"> | |
| 5 | - | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| 5 | + | <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> | |
| 6 | 6 | <title>Compose Email</title> | |
| 7 | 7 | <link rel="stylesheet" href="css/styles.css"> | |
| 8 | 8 | <style> |
| @@ -234,11 +234,11 @@ | |||
| 234 | 234 | <!-- Time Tab Group --> | |
| 235 | 235 | <div id="time-view" class="view tab-group hidden"> | |
| 236 | 236 | <div class="pill-nav" role="tablist" aria-label="Time views"> | |
| 237 | - | <button class="pill active" data-subview="day-plan">Day Plan</button> | |
| 238 | - | <button class="pill" data-subview="weekly-review">Weekly Review</button> | |
| 239 | - | <button class="pill" data-subview="monthly-review">Monthly Review</button> | |
| 237 | + | <button class="pill active" data-subview="day-plan">Day</button> | |
| 238 | + | <button class="pill" data-subview="weekly-review">Week</button> | |
| 239 | + | <button class="pill" data-subview="monthly-review">Month</button> | |
| 240 | + | <button class="pill" data-subview="timer" title="Pomodoro-style focus sessions">Timer</button> | |
| 240 | 241 | <button class="pill" data-subview="events">Events</button> | |
| 241 | - | <button class="pill" data-subview="timer" title="Pomodoro-style focus sessions">Focus Timer</button> | |
| 242 | 242 | </div> | |
| 243 | 243 | ||
| 244 | 244 | <!-- Day Plan Sub-View --> | |
| @@ -344,14 +344,7 @@ | |||
| 344 | 344 | <div id="events-view" class="subview hidden" role="tabpanel" aria-labelledby="events-tab"> | |
| 345 | 345 | <div class="page-header"> | |
| 346 | 346 | <h2 class="page-title">Events</h2> | |
| 347 | - | <div style="display: flex; align-items: center; gap: 1rem;"> | |
| 348 | - | <div class="view-toggle" id="events-view-toggle"> | |
| 349 | - | <button class="view-toggle-btn active" data-mode="list" onclick="GoingsOn.events.setViewMode('list')">List</button> | |
| 350 | - | <button class="view-toggle-btn" data-mode="month" onclick="GoingsOn.events.setViewMode('month')">Month</button> | |
| 351 | - | <button class="view-toggle-btn" data-mode="week" onclick="GoingsOn.events.setViewMode('week')">Week</button> | |
| 352 | - | </div> | |
| 353 | - | <button class="btn btn-primary" onclick="GoingsOn.events.openNew()" title="New event (n)">+ New Event <kbd class="kbd-hint">n</kbd></button> | |
| 354 | - | </div> | |
| 347 | + | <button class="btn btn-primary" onclick="GoingsOn.events.openNew()" title="New event (n)">+ New Event <kbd class="kbd-hint">n</kbd></button> | |
| 355 | 348 | </div> | |
| 356 | 349 | <div id="events-bulk-bar" class="bulk-actions-bar hidden"> | |
| 357 | 350 | <span class="bulk-count">0 selected</span> | |
| @@ -360,7 +353,24 @@ | |||
| 360 | 353 | <button class="btn btn-sm" onclick="GoingsOn.events.clearEventSelection()">Cancel</button> | |
| 361 | 354 | </div> | |
| 362 | 355 | <div class="events-list" id="events-list"> | |
| 363 | - | <div class="event-table-virtual" id="event-table" role="grid" aria-label="Events list"> | |
| 356 | + | <details class="past-events-section" id="recurring-events-section" open style="display: none;"> | |
| 357 | + | <summary class="past-events-toggle"> | |
| 358 | + | <span class="past-events-label">Recurring</span> | |
| 359 | + | <span class="past-events-count" id="recurring-events-count">0</span> | |
| 360 | + | </summary> | |
| 361 | + | <div class="event-table-virtual" id="recurring-event-table"> | |
| 362 | + | <div class="event-header-row" role="row"> | |
| 363 | + | <div class="event-cell" role="columnheader">Pattern</div> | |
| 364 | + | <div class="event-cell" role="columnheader">Time</div> | |
| 365 | + | <div class="event-cell" role="columnheader">Event</div> | |
| 366 | + | <div class="event-cell" role="columnheader">Location</div> | |
| 367 | + | <div class="event-cell" role="columnheader"></div> | |
| 368 | + | </div> | |
| 369 | + | <div class="event-list-container" id="recurring-event-list-container"></div> | |
| 370 | + | </div> | |
| 371 | + | </details> | |
| 372 | + | <h3 class="events-section-heading" id="future-events-heading" style="display: none;">Upcoming</h3> | |
| 373 | + | <div class="event-table-virtual" id="event-table" role="grid" aria-label="Upcoming events"> | |
| 364 | 374 | <div class="event-header-row" role="row"> | |
| 365 | 375 | <div class="event-cell" role="columnheader">Date</div> | |
| 366 | 376 | <div class="event-cell" role="columnheader">Time</div> | |
| @@ -393,27 +403,6 @@ | |||
| 393 | 403 | </div> | |
| 394 | 404 | </details> | |
| 395 | 405 | </div> | |
| 396 | - | <!-- Month Calendar View --> | |
| 397 | - | <div id="events-month-view" class="events-calendar-container hidden"> | |
| 398 | - | <div class="calendar-nav"> | |
| 399 | - | <button class="btn btn-secondary" onclick="GoingsOn.eventsCalendar.prevMonth()">←</button> | |
| 400 | - | <button class="btn btn-secondary" onclick="GoingsOn.eventsCalendar.goToThisMonth()">This Month</button> | |
| 401 | - | <button class="btn btn-secondary" onclick="GoingsOn.eventsCalendar.nextMonth()">→</button> | |
| 402 | - | <span class="calendar-nav-label" id="month-calendar-label"></span> | |
| 403 | - | </div> | |
| 404 | - | <div id="month-calendar-grid"></div> | |
| 405 | - | <div id="month-day-detail" class="month-day-detail hidden"></div> | |
| 406 | - | </div> | |
| 407 | - | <!-- Week Calendar View --> | |
| 408 | - | <div id="events-week-view" class="events-calendar-container hidden"> | |
| 409 | - | <div class="calendar-nav"> | |
| 410 | - | <button class="btn btn-secondary" onclick="GoingsOn.eventsCalendar.prevWeek()">←</button> | |
| 411 | - | <button class="btn btn-secondary" onclick="GoingsOn.eventsCalendar.goToThisWeek()">This Week</button> | |
| 412 | - | <button class="btn btn-secondary" onclick="GoingsOn.eventsCalendar.nextWeek()">→</button> | |
| 413 | - | <span class="calendar-nav-label" id="week-calendar-label"></span> | |
| 414 | - | </div> | |
| 415 | - | <div id="week-calendar-grid"></div> | |
| 416 | - | </div> | |
| 417 | 406 | </div> | |
| 418 | 407 | </div><!-- /time-view --> | |
| 419 | 408 | ||
| @@ -574,7 +563,6 @@ | |||
| 574 | 563 | </nav> | |
| 575 | 564 | <div id="mobile-more-popover" class="mobile-more-popover" role="menu" aria-hidden="true" aria-label="More options"> | |
| 576 | 565 | <button role="menuitem" onclick="GoingsOn.settings.open(); GoingsOn.navigation.closeMorePopover();">Settings</button> | |
| 577 | - | <button role="menuitem" onclick="GoingsOn.keyboard.showShortcuts(); GoingsOn.navigation.closeMorePopover();">Shortcuts</button> | |
| 578 | 566 | </div> | |
| 579 | 567 | ||
| 580 | 568 | <!-- Action Bottom Sheet (mobile context menus) --> |
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file