Commit Graph

10 Commits

Author SHA1 Message Date
RomanNum3ral aaaa034d95
Add Photos gallery (grid browse + full-screen viewer); tidy Agenda top bar
New Photos section reachable from Agenda's overflow menu: reuses
FilesRepository's WebDAV browsing (folders + image-filtered files) in
a grid, with a swipeable full-screen viewer (HorizontalPager) on tap.
Thumbnails/full images load via Coil with a custom OkHttpClient that
injects the same Basic Auth used everywhere else - no new network
client needed, just two small synchronous accessors added to
FilesRepository (rawFileUrl/basicAuthHeader) since Coil needs a plain
URL + header rather than a suspend call.

Also moved Talk/Files/Photos/Calendars into an overflow menu on
Agenda's top bar - it had grown to 7 icons across this session and
the title had started wrapping to two lines.

Real bug found and fixed live: the photo viewer's close button was
completely untappable (visually present, but taps never registered).
Root cause was the same class of issue as an earlier Snackbar gotcha
this session - MainActivity calls enableEdgeToEdge(), so content
without explicit inset padding draws (and the close button's touch
target sat) underneath the real system status bar, which intercepted
the taps before the app ever saw them. Fixed with statusBarsPadding()
and by moving the button into its own row above the pager instead of
overlaid on top of it.
2026-07-18 16:16:48 -04:00
RomanNum3ral b8fdd9b421
Add Nextcloud Files browsing (browse/download/upload/delete/rename)
New Files section reachable from Agenda's top bar: a WebDAV browser
against /remote.php/dav/files/<user>/ with folder navigation, file
download-and-open (via FileProvider + a viewer Intent), upload from
the system file picker, delete, create folder, and rename (WebDAV
MOVE). Extends DavXml's existing multistatus parser with
getcontentlength/getlastmodified rather than writing a second parser,
since the response/propstat/status merging logic it already has is
the fiddly part.

Verified live against the real account: browsed real folders/files,
created and deleted a test folder, and confirmed a file downloads
and reaches a view Intent correctly (no viewer app installed on the
emulator to actually open it, but the FileProvider hand-off worked).
2026-07-18 14:02:22 -04:00
RomanNum3ral 2bf9a32ead
Add Nextcloud Talk text chat (read/send, no calls)
New Talk section reachable from Agenda's top bar: a conversation
list and a per-room chat screen with send + live updates via the
Talk chat API's long-poll (lookIntoFuture=1). No call/WebRTC
signaling - text only, per the scoped-down request for this item.

Uses the same OCS app-password auth as CalDAV. One real gotcha:
Nextcloud Talk versions each feature area of its OCS API
independently - Room/Call are at api/v4 on this server, but the
Chat endpoints are still api/v1; hitting v4/chat/{token} returns a
misleading generic "invalid query" 404 even fully authenticated.
2026-07-18 13:29:15 -04:00
RomanNum3ral 33d6469bbe
Add Authentik/SSO login via Nextcloud Login Flow v2; fix Tasks widget minHeight
Login Flow v2 opens Nextcloud's own browser login page in a Custom Tab
(androidx.browser), so any SSO backend configured server-side (Authentik
via user_oidc) and WebAuthn hardware-key prompts work without NCal
implementing OIDC/OAuth2 itself - the flow ends with a normal app
password, stored the same way as manual login.

The Tasks widget's minHeight was pinned exactly to its 4-row default
size (Android's 70*cells-30 formula), leaving no slack to ever resize
shorter. Lowered to 110dp (2 rows) so it can actually be resized to a
2x3 layout, which was verified to render cleanly.
2026-07-18 13:01:46 -04:00
RomanNum3ral d31894f980
Bump Gradle to 8.13 and Android Gradle Plugin to 8.13.2
AGP 8.13.2 requires Gradle >= 8.13; this was left uncommitted from a
prior session and the working tree had drifted from what the project
actually needs to build.
2026-07-18 13:01:14 -04:00
RomanNum3ral f3f8d76cda
Add monthly-ordinal recurrence support ("the 3rd Thursday", "the last Friday")
Extends the Repeats picker's BYDAY support (which deliberately excluded
ordinaled rules) to cover FREQ=MONTHLY with a single ordinaled BYDAY, via
RFC 5545's ByDay(num, weekday) - "the 3rd Thursday of the month" or "the
last Friday", not just a fixed day-of-month.

- CalendarItem.recurrenceByDayOrdinal (1..4, or -1 for "last") pairs with the
  existing recurrenceByDay field, reused as a singleton for this mode.
- RecurrenceUtils gets a new walker using TemporalAdjusters.dayOfWeekInMonth,
  correctly skipping months where the Nth weekday doesn't exist (RFC 5545:
  no occurrence that month, not a rollover) and correctly preserving local
  time-of-day across DST boundaries.
- Repeats picker: a 2-item "Monthly on day N" vs "Monthly on the Nth
  <weekday>" dropdown, weekday always derived from the current Starts/Due
  date rather than picked separately.

Verified live against the real Nextcloud server (created a "3rd Friday"
event, confirmed it round-tripped to the correct RRULE and resolved to the
correct date next month) and cleaned up afterward.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 05:56:25 -04:00
RomanNum3ral 3d0f6589a9
Add offline resilience, undo-delete, search, week view, BYDAY recurrence, import/export, and single-occurrence recurring edits
Closes out the full post-launch feature backlog:
- Offline write resilience for save/delete, with automatic flush on reconnect
- Undo-after-delete via a snackbar, with a fresh-UID recreate (Nextcloud's
  trashbin rejects reusing a just-deleted item's UID)
- Custom (non-preset) reminder offsets
- Search across events and tasks
- Week view alongside the existing Agenda/Month views
- BYDAY support in the Repeats picker ("every Mon/Wed/Fri"), including a
  proper RRULE evaluator extension for it
- Import/export .ics via the system share sheet and file picker
- Single-occurrence recurring-event editing/deleting ("this event only" vs
  "all events") via RFC 5545 RECURRENCE-ID overrides and EXDATE

A repository-wide write mutex now serializes sync against save/delete/undo,
fixing a real race where a background sync could clobber a just-written item.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-17 18:53:39 -04:00
RomanNum3ral 79cc6925e8
Fix the two remaining known limitations: recurring item date editing, field-by-field conflict merge
- CalendarItem gains recurrenceMasterStart/End/Due, the true unresolved
  master date, tracked separately from start/end/due (which hold the
  resolved next occurrence for a recurring item). The edit screen now shows
  and edits the real master date for recurring items instead of disabling
  those fields outright, with a note that the change applies to the whole
  series. Verified against a real recurring event on-device.
- New util/ConflictDiff.kt computes exactly which user-editable fields
  differ between a local edit and the server's version after a 412. The
  conflict dialog is now a per-field mine/theirs picker (with "All
  mine"/"All theirs" shortcuts) instead of an all-or-nothing choice.
- Extracted statusLabel() to util/StatusLabels.kt so both the edit screen
  and the new conflict diff can share it.
- Two more test files (ConflictDiffTest, extended IcsMapperTest).
2026-07-17 08:51:35 -04:00
RomanNum3ral 14ee70d71d
Fix remaining known limitations: recurrence editing, subtask tree parity, conflict resolution
- Recurrence picker (Daily/Weekly/Monthly/Yearly, interval, end condition) for
  both events and tasks, backed by a real RRULE. Fixes a latent bug from the
  prior RRULE-preservation change: editing a recurring item was writing the
  resolved *next occurrence* back as the master DTSTART, silently shifting the
  whole series forward on every edit - start/end/due are now correctly
  read-only for recurring items instead.
- Periodic background sync (WorkManager, ~30 min, network-gated) so widgets
  stay fresh without opening the app; auto-refresh on app open too.
- Tasks widget now renders the same parent/child tree as the in-app Tasks
  screen (util/TaskTree.kt shared by both) instead of a flat due-date list.
- Conflict resolution: a stale save (HTTP 412) shows both versions and lets
  you keep your edit or take theirs, instead of just an error banner.
- First test suite for the project (IcsMapperTest, TaskTreeTest).
2026-07-16 21:02:48 -04:00
RomanNum3ral 75f5e6024b Initial commit: NCal, a native Nextcloud CalDAV client for Android
One app for both events and tasks, talking directly to Nextcloud's CalDAV
endpoint - no DAVx5, no Google Play Services, no third-party services.
Encrypted at rest (SQLCipher DB, EncryptedSharedPreferences, Keystore-backed
widget state), HTTPS-only networking, home screen widgets, reminders,
subtasks, and full VTODO field support (status/priority/%complete/location/url).
2026-07-16 18:19:03 -04:00