Skip to content

Release/v0.1.1 - #7

Merged
albert-gee merged 33 commits into
mainfrom
release/v0.1.1
Jul 21, 2026
Merged

Release/v0.1.1#7
albert-gee merged 33 commits into
mainfrom
release/v0.1.1

Conversation

@albert-gee

Copy link
Copy Markdown
Contributor

No description provided.

* Add keyboard shortcuts feature and translation support

* Add support for new keyboard shortcuts and localization enhancements

* Refactor mini calendar logic and layout, add helper methods for date calculations, and enhance test coverage

* Update keyboard shortcut for "New Event" from "C" to "E" and adjust related tests
…blocks and missing time zone errors, along with related tests

Issue: Calendar operations are permanently poisoned by task replay. The shared DAO returns every pending entity type, but the task replayer treats calendar operations as unknown and blocks them until year

Fix:
- Task replay now processes only task and task_list rows, leaving calendar operations untouched: lib/src/features/sync/pending_ops_replayer.dart:43.
- Calendar replay recovers operations previously poisoned with unknown_operation and parked at year 9999: lib/src/features/sync/calendar_pending_ops_replayer.dart:124.
…lendar repository

Issue: Incremental calendar state is unreachable after every run. Exact now ± range timestamps form part of the state key, so the next run uses a different key, performs another initial fetch, and inserts another row. Microsoft additionally starts from ordinary /calendarView, while missing-row reconciliation only runs for full=true, leaving remote deletions stale.

Fix:
- Added stable, monthly-anchored sync windows and state IDs, including cleanup of legacy range-keyed rows in lib/src/features/calendar/data/calendar_repository.dart:304.
- Reused cursors within the same window and safely established a new baseline when the month changes in lib/src/features/sync/calendar_sync_engine.dart:58.
Microsoft primary calendars now start with /me/calendarView/delta; secondary calendars use ordinary calendarView with full missing-event reconciliation in lib/src/microsoft_calendar/microsoft_calendar_api_client.dart:209.
- Added opaque delta-link paging, tombstone handling, and expired-state recovery.
…TP client

Issue: HTTP retries can duplicate tasks, events, lists, and invitations. RetryingHttpClient replays every method—including POST—on 429/5xx and is shared by all four provider clients. A write committed before a provider returns 500 can be issued four times without an idempotency key

Fix: - lib/src/google_tasks/http/retrying_http_client.dart:22 now retries only safe HTTP methods: GET, HEAD, OPTIONS, and TRACE.
- POST, PATCH, PUT, and DELETE return after one attempt on both 429 and 5xx, preventing transport-level duplicate resources and invitations.
- Reads retain exponential backoff.

This conservative policy follows HTTP safe-method semantics (https://www.rfc-editor.org/rfc/rfc9110.html#section-9.2.1). Provider-specific idempotency exists for Google Calendar event IDs (https://developers.google.com/workspace/calendar/api/guides/create-events) and Microsoft event transactionId (https://learn.microsoft.com/en-us/graph/api/resources/event?view=graph-rest-1.0), but not universally across task/list APIs.
… 429/5xx responses

Issue: Google recurring occurrences are not synchronized. Both initial and token sync force singleEvents:false, while the available instance endpoint has no production caller and the schedule layer does not expand recurrence rules. Future occurrences therefore do not populate the schedule.

Fix:
- Initial and incremental requests now use singleEvents=true in lib/src/google_calendar/google_calendar_api_client.dart:276.
- Legacy Google cursors force one new baseline, then persist a versioned query marker in lib/src/features/sync/calendar_sync_engine.dart:8.
- Synchronized recurrence masters are retired once expanded instances arrive, preventing duplicate first occurrences via lib/src/features/calendar/data/calendar_repository.dart:651.
…nd enable/disable state

Issue: Moving an existing event to another calendar is exposed but unsupported. The editor permits selecting any visible account/ source; persistence rewrites the local destination but queues event.patch with the original provider event ID. Replay PATCHes that ID in the destination, normally producing 404 and leaving the original remote event intact.

Fix:
- Existing events now expose only their original calendar, with the selector disabled in lib/src/features/calendar/presentation/event_editor.dart:379.
- Repository calls now reject account, provider, source, or provider-calendar changes before modifying the row or queuing an operation in lib/src/features/calendar/data/calendar_repository.dart:459.
- New events can still select any visible calendar.
- Added same-account, cross-account, and cross-provider regressions.
…ee management, and improved JSON handling in schedule and calendar operations.

Issue: clearing recurrence or the final attendee never reaches either provider. Empty values become null, then both serializers remove null fields from the PATCH, meaning the remote recurrence and guest remain unchanged while local state says otherwise. See lib/src/ features/calendar/data/calendar_repository.dart:683, lib/src/ google_calendar/google_calendar_mapper.dart:100, and lib/src/ microsoft_calendar/microsoft_calendar_mapper.dart:94.

Fix:
- Added explicit clear intent through queueing, replay, and conflict detection.
- Google now sends recurrence: [] and attendees: [].
- Microsoft now sends explicit recurrence: null and attendees: [].
- Untouched recurrence, attendees, and Microsoft categories are omitted from PATCH requests.
- Existing recurrence and attendees are hydrated into both editor paths, including nested Microsoft attendee addresses.
- Recurring occurrences hide the series-level recurrence control, and repository-level attempts are rejected because recurrence changes must target the master event. This matches Google’s recurring-event guidance (https://developers.google.com/workspace/calendar/api/guides/recurringevents) and Microsoft’s event update semantics (https://learn.microsoft.com/en-us/graph/api/event-update?view=graph-rest-1.0).
…ATCH behavior, and prevent remote-local state mismatches
…g for pending operations

Issue: Back-to-back offline edits self-conflict. Both edits capture the same server baseline; replaying the first changes the server, after which the second identifies that first local write as a remote conflict and blocks the newer value. This affects tasks and events.

Fix:
- Same-entity edits now form a FIFO dependency chain.
- Successful writes selectively rebase only fields they changed, preserving detection of genuine remote conflicts elsewhere.
- Intermediate provider responses no longer overwrite newer optimistic local values.
- Task mutation and queue insertion are now atomic.
…istent error handling

Issue: The Microsoft adapter leaked MicrosoftTodoApiError through the GoogleTasksApiClient interface, causing replay’s generic handler to retry permanent errors indefinitely.

Fix:
- Normalized all Microsoft To Do API failures to GoogleTasksApiError in lib/src/microsoft_todo/api/microsoft_todo_google_tasks_adapter.dart:21, preserving status, code, message, and raw response.
- Permanent 400/403/non-delete 404 errors are now blocked.
- 429/5xx errors retain retry backoff.
- Delete 404 reconciles local deletion and removes the operation.
…r handling

- Consolidated account connection logic into a single `_connectAccount` method for clarity and maintainability.
- Added explicit handling for connecting providers and ensured proper state updates to prevent conflicts during simultaneous connections.
- Updated UI to reflect connecting state per provider, disabling interactions during ongoing connections.
- Replaced `_reconnect` with `_connectAccount` to unify behavior for account reconnections.
- Renamed `_authErrorMessage` to `authErrorMessage` for consistency.
- Integrated account subscription to monitor changes in signed-in accounts.
- Enhanced notification scheduling logic to filter by signed-in account IDs.
- Added `_reconcileNotifications` method to manage notification insertion, updates, and deletions efficiently.
- Refactored upcoming event and task notifications to leverage account-based filtering and batch reconciliation.
…ve persistence handling

- Replaced `_save` with `_mutate` method for consistent state updates.
- Introduced `_AppSettingsMutation` typedef to streamline mutation logic.
- Added `_persistAfter` to manage sequential persistence safely.
- Updated state management during loading to merge pending mutations.
- Ensured proper disposal handling to prevent updates post-disposal.
- lib/src/schedule/schedule_range.dart:4 now uses civil-date arithmetic for day, week, and month boundaries.
- lib/src/features/schedule/presentation/schedule_month_view.dart:327 reconstructs each next local midnight, preventing shifted or duplicated dates.

Added forced America/Vancouver DST regressions in test/features/schedule/schedule_dst_test.dart:1, covering 23/25-hour days, 167/169-hour weeks, month boundaries, and unique grid dates.
…ng, and task mutation tests

- Ensured app waits for settings readiness before tray startup.
- Introduced `trayServiceFactory` for better tray service customization and testing.
- Wrapped task creation and mutation with `setState` calls to refresh UI.
- Added unit and widget tests for task creation and completion in `ScheduleWorkspace`.
…e components. Same-day timed events receive a next-day exclusive end using DST-safe civil-date construction in lib/src/features/calendar/presentation/event_editor.dart:716.
…derOn: false. Removed that inference in lib/src/microsoft_calendar/microsoft_calendar_mapper.dart:94, so reminder state is now independent of all-day status. Added disabled and enabled regressions in test/microsoft_calendar/microsoft_calendar_mapper_test.dart:114.
- Added conditional logic for maintaining state integrity during `upsertSource` and `setSourceSelected` operations.
- Integrated notification scheduling updates to account for source visibility, selection, and deletion.
- Enhanced `_notificationScheduleService` to filter sources by account, selection, visibility, and deletion state.
…e handling

- Added "Send Feedback" option to the About dialog (lib/src/app/busymax_about_dialog.dart).
- Integrated feedback API via `FeedbackApiClient` and `FeedbackSubmissionService`.
- Updated localizations with support for feedback-related terms in multiple languages (e.g., send feedback, category, errors).
- Modified settings and schedule screens to pass the `feedbackSubmissionService`.
- Enabled conditional disabling of cancel buttons in header components for better UX.
- Configured feedback backend endpoint in the build config (lib/src/config/build_config.dart).
@albert-gee albert-gee self-assigned this Jul 21, 2026
@albert-gee
albert-gee merged commit 07a56ec into main Jul 21, 2026
1 check passed
@albert-gee
albert-gee deleted the release/v0.1.1 branch July 21, 2026 23:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant