Commit Graph

31 Commits

Author SHA1 Message Date
Guido Schmit
3137abcef2 fix: surface per-calendar sync errors from server
/api/caldav/events now returns an "errors" array alongside "events" for
calendars that failed to sync (e.g. expired credentials) while still
reporting success overall. Previously such failures were silently
swallowed, so a calendar could appear enabled/visible while showing zero
events with no explanation.

- CalendarRepository.fetchEvents now returns EventsResult(events, errors),
  parsing the new "errors" array the same way importIcs's Triple return
  handles multi-value results.
- CalendarUiState gains syncErrors, populated in loadRange's onSuccess.
- CalendarScreen shows a second error-style banner for sync errors,
  additive to the existing network-failure banner.
- CalendarFilterSheet shows a warning icon next to calendar rows whose
  source+name matches a sync error (best-effort suffix match, since the
  server's error name is "<account> – <calendar name>").
2026-07-02 18:27:00 +02:00
Guido Schmit
d2d5e2b19c feat(filter): sync calendar visibility to server for CalDAV/Google/HA
The filter-sheet Switch now calls setCalendarHiddenSynced(), which
updates local hiddenKeys immediately AND fires a sidebar_hidden PATCH
to the server for caldav/google/homeassistant calendars. This makes
the quick-hide consistent with the web sidebar across all devices.
CalendarFilterEntry gains a source field so the sheet knows which
backend to target.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 21:48:36 +02:00
Guido Schmit
740367b0b9 feat: show relative time in notifications + move default duration to profile settings
Notifications now show "in 30 Min. · Ort" instead of just the location,
giving users immediate context about how soon the event starts.

Default event duration picker moved from the View section to right below
the profile/privacy group, consistent with the iOS app arrangement.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 19:40:46 +02:00
Scarriffle
9ced441935 feat: event reminders UI, per-calendar mute, notifications, default duration
- Add reminder editor (presets + custom number+unit) wired through save
- Per-calendar reminder mute: filter-sheet toggle + greyed-out editor hint;
  reminders are kept, never deleted
- New AlarmManager-based NotificationScheduler + channel + POST_NOTIFICATIONS;
  skips muted calendars
- New synced setting default_event_duration_minutes for new events

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 10:02:46 +02:00
Guido Schmit
701db45f8a fix: set solid dark green adaptive icon background to eliminate ring
Transparent background caused Pixel launcher to inject its own tinted
ring. Replace with #16703D (sampled from iOS icon background) so the
launcher shape-clips cleanly without any visible halo.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 18:45:39 +02:00
Guido Schmit
9815866911 fix: add adaptive icon to remove launcher ring effect on Pixel devices
Without mipmap-anydpi-v26 XML, Pixel launcher wraps legacy PNGs in a
white ring template. Adding adaptive-icon XML with the iOS-matching
foreground PNG at correct per-density sizes (108dp canvas) eliminates
the nested-ring appearance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 18:36:17 +02:00
Guido Schmit
c6056fb7bd fix: CircularProgressIndicator no longer clipped in auth buttons
Use Modifier.size(20.dp) instead of height(20.dp) so the spinner is
constrained on both axes and doesn't get cut off horizontally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 18:28:19 +02:00
Guido Schmit
b172a8f055 fix: round dropdown menu corners via theme shapes
Material 3 menus use shapes.extraSmall (4dp default) which looked boxy;
bump to 14dp so all dropdown popups (view switcher, group switcher, ...)
get rounded corners matching the iOS look.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 21:39:03 +02:00
Guido Schmit
e7bed5c5a8 feat: day preview popup, smoother month scrolling, UI polish
- Long-press on a day now opens a preview popup (ported from the iOS
  DayContextPreviewView): all-day events as colored bars with tapered
  ends when they continue beyond the day, timed events as dot+time+title
  rows, plus quick actions (new event, week view, day view)
- Month scroll performance: stable item keys + contentType in the
  LazyColumn, remembered Instant.now()/theme colors, remembered callbacks
  so visible week rows stay skippable during recomposition
- Fix "+N" and "KW" labels overlapping the lowest event lane (row bottom
  padding 6dp -> 16dp, mirrors the iOS fix)
- Event detail: delete is now a quiet red text button instead of a
  full-width filled container
- Top bar: hairline divider so the bar/calendar boundary is visible
- FAB: explicit circular shape

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 20:37:49 +02:00
Guido Schmit
6654012cbb feat: reminders data layer (Android) — model, settings, repository
CalEvent gains `reminders` (parsed from the server); AppSettings/SettingsStore
gain `defaultReminderMinutes` (null = off) and it's sent via updateSettings;
createLocalEvent/updateLocalEvent/eventBody and CalendarViewModel.saveEvent
thread `reminders` through. UI (editor + settings picker) and the local
notification scheduling follow next.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 16:31:32 +02:00
Guido Schmit
807db6a57b feat: non-emoji group icons (Material icons) for consistent look (Android)
Group icons are semantic keys rendered as native Material icons (GroupIcons)
in the picker, group list, top-bar switcher and banner — mirroring iOS/web —
instead of OS emoji. Legacy emoji values render as a fallback. decorateGroup
fallback no longer prepends a glyph (server display_title is authoritative).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 20:24:48 +02:00
Guido Schmit
644b532104 feat: hide individual member calendars in the group view (Android)
The calendar filter, in group mode, lists the group's members (+ the shared
group calendar) with toggles to hide each individually. Filtering is client-side
via CalendarViewModel.hiddenGroupKeys (gm:<id> / gc), reset on group switch;
members + colours loaded from the group detail.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 18:10:11 +02:00
Guido Schmit
87fc8df146 feat: render server display_title for group events (consistent across clients)
CalEvent parses display_title; decorateGroup uses it (group icon + owner prefix
from the server) instead of the hardcoded glyph, with a fallback for older
servers. Raw title kept for editing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 17:54:23 +02:00
Guido Schmit
7a9bdba557 fix: Android Gruppen-Umschalter sichtbar + Menü überlappt Navigationsleiste nicht
Top-Bar-Gruppenumschalter ist jetzt eine tonale Pille (Akzentfarbe im
Gruppenmodus) statt eines flachen Icons – klar als Button erkennbar; das
Dropdown markiert die aktive Auswahl. Gruppen-Verwaltung: Tipp auf eine Gruppe
öffnet direkt deren Ansicht, Verwalten liegt aufs Zahnrad. Menü-Bottom-Sheet
respektiert jetzt das Navigationsleisten-Inset (+ Scroll-Fallback), sodass
Abmelden/Server wechseln nicht mehr hinter den Android-Buttons liegen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 23:08:42 +02:00
Guido Schmit
3352aa3be7 feat: Android Gruppen + kombinierte Ansicht direkt im Kalender
Neuer Gruppen-Verwaltungsscreen (Liste, Erstellen, Verwalten: Name, wählbares
Emoji-Icon, Mitglieder, server-definierte Mitgliederfarben, Löschen) über das
Menü. Top-Bar-Umschalter (Mein Kalender / Gruppen) + Akzent-Banner schalten den
Kalender in die kombinierte Gruppenansicht: Events laufen durch die normale
Cache-/Render-Pipeline (Monat/Woche/Tag/Termine), mit Namens-Präfix der
Besitzer und 👥 für Gruppentermine; im Gruppenmodus kein Sichtbarkeitsfilter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 22:36:26 +02:00
Guido Schmit
e0d1b24afc feat: Android Kalenderfarben, Sharing & iCal-Import/Export (lokale Kalender)
AccountsScreen überarbeitet: editierbare Farb-Punkte (lokal, iCal, sowie
Unterkalender von CalDAV/Google/HA via Farbwähler-Dialog); lokale Kalender
zeigen Gruppen-Marker + "geteilt von" und ein Aktionsmenü (Teilen/Importieren/
Exportieren/Löschen je nach Besitz & Berechtigung). Teilen-Sheet mit
Benutzersuche + Berechtigung; Import via OpenDocument, Export via CreateDocument.
Repository: importIcsFile(bytes) + Farb-Update-Methoden; ViewModel um Farb-,
Sharing- und Import/Export-Logik erweitert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 22:17:53 +02:00
Guido Schmit
716dd01abb feat: Android Profil-Kapitel in Einstellungen + Kalenderfarb-Endpunkte
Einstellungen zeigen jetzt ein Profil-Kapitel: Anzeigename (editierbar),
Anmeldename (read-only), E-Mail + Speichern; Privatsphäre (private Termine
beschäftigt/verbergen) und geteilter Kalender (Dropdown der eigenen lokalen
Kalender) — serverseitig geladen und gezielt gespeichert.
Datenebene um Farb-Endpunkte ergänzt (lokal/iCal PUT + setCalendarColor für
caldav/google/ha) als Basis für die Farbbearbeitung.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 22:07:06 +02:00
Guido Schmit
4a44c20b12 feat: Android Ersteller-Anzeige + Privat-Flag
Event-Detail zeigt "Erstellt von" (wenn != ich) + Privat-Hinweis; Editor hat
Privat-Toggle (nur lokale Kalender, durch saveEvent/Repo durchgereicht).
Login speichert userId + displayName (CredentialStore) für Vergleiche.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 21:54:19 +02:00
Guido Schmit
d10a4dc79f feat: Android Datenebene für Sharing/Gruppen/Import-Export/Ersteller
- Modelle: CalEvent (creator/isPrivate/owner/isGroupEvent/displayColor),
  LocalCalendar (owned/sharedBy/permission/group), AppSettings
  (privateEventVisibility/groupVisibleCalendarId), UserProfile (displayName);
  neue Modelle Group/GroupMember/DirectoryUser/CalendarShareEntry.
- API (Retrofit): Profil-Update, Sharing-CRUD, Gruppen-CRUD + combined,
  Mitglieder-Farbe, iCal Import (multipart)/Export, Kalenderfarbe pro Quelle,
  gezielte Settings-PUTs (private_visibility/group_visible).
- Repository: passende Methoden inkl. private-Flag bei lokalen Events.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 21:35:54 +02:00
Guido Schmit
9467fe7bb6 feat: dim past events when enabled (month bars, week/day grid, agenda)
Past events (endDate before now) are drawn at reduced opacity across the month
bars, the week/day time grid (timed + all-day) and the agenda list when the
'dim past events' setting is on.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 15:26:05 +02:00
Guido Schmit
bc93964e05 fix: single branded splash (invisible system icon), December title, first-open lag
- System splash now uses a transparent icon, so there is no system icon that
  shrinks into the in-app splash: just black, then the branded screen (icon +
  Calendarr name + copyright), held until data is loaded
- Month/quarter title uses TextStyle.FULL (format style) with a hard fallback;
  FULL_STANDALONE had the same desugar bug as the LLLL pattern (December showed
  only the year)
- First open: load the full +/- cacheMonths window behind the splash and only
  then reveal, so the app no longer enters mid-load and stutters

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 15:17:01 +02:00
Guido Schmit
cb51284bef fix: branded splash back, wider month range, December title bug
- Restore the branded in-app splash (Calendarr name + icon + © Scarriffle),
  held until the first events load; logo sized to match the system splash so it
  doesn't visibly jump, name/copyright fade in
- Month calendar now scrolls 10 years back / 50 years ahead (was ±18 months)
- Fix month/quarter title: use Month.getDisplayName instead of the 'LLLL'
  pattern, which dropped the month name (e.g. December showed only '2026')

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 15:07:37 +02:00
Guido Schmit
ba7daf8559 perf: unified splash held until loaded, smoother month scrolling, serialized loads
- Single system splash (core-splashscreen) kept on screen until the first
  events load (StartupState), then reveals the ready app — removes the
  two-stage 'icon then title' splash and the laggy half-loaded entry
- Month scrolling: dropped per-row BoxWithConstraints (measured grid width once
  via onSizeChanged) and resolve bar colours once during packing instead of
  every recomposition → much smoother scroll
- Serialize all event loads behind a Mutex and skip redundant state writes so
  scroll-triggered month loads no longer pile up / thrash the UI

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 14:53:06 +02:00
Guido Schmit
3734e17c3f feat: multi-day event bars, readiness-gated splash, top-bar spinner, 2-line titles, detail animation
- Month view now draws multi-day events as continuous bars (lane packing,
  per-week column span clipped at week boundaries, +N overflow) instead of a
  chip on every day; events bucketed per week once + memoized packing for
  smooth scrolling
- Startup: core-splashscreen covers the window from frame 0 (no warm-start
  flash); the in-app splash stays until the first events finish loading (loading
  starts behind the splash via an early-obtained CalendarViewModel + ready flow),
  so you no longer enter a laggy app
- Background load shows a small spinner in the top bar (removed the linear bar)
- Week/Day titles wrap to two smaller lines (no more truncation)
- Event detail opens with a slide+fade animation

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 14:40:23 +02:00
Guido Schmit
b8eb6597ec feat: HA/Google edit, full-page event detail, KW+zigzag divider, HSV picker, splash
- Home Assistant & Google events now editable/deletable (server PUT/DELETE
  endpoints wired; saveEvent had no HA/Google update branch -> created dupes)
- Event detail is now a full screen (Scaffold) instead of a bottom sheet:
  long notes scroll, action buttons no longer hidden behind the system nav bar;
  distinct calendar vs notes icons
- Month view: calendar-week number on Mondays, month-boundary divider with
  zigzag step (month_divider_color), month label in month_label_color,
  text/line contrast applied
- Compact top bar with smaller title; prev/next chevrons present in month view
  and scroll one month at a time
- Real HSV colour picker (SV field + hue slider + hex) for primary, accent,
  today, month-divider and month-label colours
- Black status/navigation bars; portrait-locked; crisp custom splash with app
  name, high-res icon and © Scarriffle

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 14:19:56 +02:00
Guido Schmit
608580fc7e fix: event colors/null parsing, edit+copy, settings chips, scroll perf, splash
- CalEvent parsing: handle Android's JSONObject.optString JSON-null quirk that
  returned the string "null" — this made every event blue (color "null" →
  fallback) and showed "null" for empty location/description. Now null-safe.
- Event detail: copy-to-calendar action; calendar row uses a calendar icon
  (was identical to the notes icon); empty location/notes rows hidden
- Event editor: copy mode (prefill from an existing event, save as new)
- Settings: hour height, text/line contrast are now button chips (like the
  cache range); color picker wraps, shows the current colour and a check mark
- Month scroll perf: precompute a day→events index once per change and only
  reload when the visible month actually changes (was filtering every cell
  every frame → laggy)
- Splash: dark window/splash background + inset launcher icon (was an ugly
  white box on startup)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 13:27:03 +02:00
Guido Schmit
c236db7fe9 feat: scrolling month calendar, green theme fixes, long-press create, event colors
- Month view rewritten as a continuous vertical scroll (iOS-style): no
  prev/next buttons, compact fixed-height week rows, month label on the 1st,
  top-bar title follows the visible month, Today scrolls back to today
- Long-press a day opens the event editor pre-filled with that date
- Theme: green container/tint colors so the FAB and accents are no longer the
  Material default purple
- Event colors: parse #RGB shorthand, and fall back to a stable per-calendar
  palette colour instead of a constant blue when the server omits a colour
- Top bar hides prev/next arrows in month view (scroll instead)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 13:08:54 +02:00
Guido Schmit
a1c36a8a03 fix: green brand theme, iOS launcher icon, password reveal, real login error
- Theme primary now the iOS brand green (#20A050), fixed app-wide (was tied
  to the server's blue primary_color)
- Launcher icon generated from the iOS AppIcon across all densities;
  dropped the placeholder adaptive icon
- PasswordField: eye toggle + brief last-character reveal; used on login,
  profile and CalDAV password inputs
- Login now surfaces the server's actual error detail (verified the JSON
  contract against the live server; a 401 is a genuine credential mismatch)
- CLAUDE.md: correct prod base URL to calendar.scarriffle.com

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 12:48:53 +02:00
Guido Schmit
aff6cef493 feat: full Compose UI (auth, calendar, events, accounts, settings, profile)
- Root navigation (server setup -> login+2FA -> calendar) with settings-driven theme
- CalendarViewModel mirroring iOS CalendarStore: range-based caching,
  background prefetch, hidden/banished calendar filters, event CRUD
- Five calendar views: Month, Week, Day, Quarter, Agenda (shared time grid)
- Event detail + editor sheets (platform date/time pickers, color override,
  writable-calendar picker) across local/caldav/google/homeassistant
- Calendar filter sheet (per-calendar show/hide)
- Accounts screen: add/delete CalDAV, local, iCal, Home Assistant; list Google
- Settings: view/week-start/language/colors/contrast/hour-height/cache range,
  synced to server
- Profile: email, password change, 2FA enable/disable
- gradlew build (lint + tests + assemble) passes

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 12:22:56 +02:00
Guido Schmit
676b7ee2c6 feat: data foundation (models, secure storage, Retrofit API, repository, L10n)
- java.time via core library desugaring (minSdk 24)
- Domain models: CalEvent, AppSettings, account/calendar models
- CredentialStore (EncryptedSharedPreferences) + SettingsStore
- Retrofit CalendarrApi covering all server endpoints
- CalendarRepository: auth, settings, accounts, events (org.json parsing
  for mixed-type payloads), writable calendars, visibility toggles
- Hilt DI (Moshi), dynamic-baseUrl ApiProvider, AuthInterceptor
- L10n (de/en) ported from iOS

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 11:53:34 +02:00
Guido Schmit
a015a45265 chore: get Android project building (toolchain, deps, manifest, launcher icon)
- Fix dependency versions (Retrofit 2.11, OkHttp 4.12, Compose BOM)
- Add Material Components for the app theme
- Add --add-exports/--add-opens for kapt on JDK 21
- Remove deprecated manifest package attr; add INTERNET permission
- Add adaptive launcher icon

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 11:44:48 +02:00