Skip to content

feat(mac): widgets for next lecture, due cards and exams - #59

Merged
502Proxy merged 8 commits into
mainfrom
feat/widgets
Oct 28, 2026
Merged

502Proxy merged 8 commits into
mainfrom
feat/widgets

Conversation

@502Proxy

Copy link
Copy Markdown
Owner

Closes #49

What changes and why?

Widgets for the desktop and Notification Center. One commit per change:

  1. Shared contract: Shared/WidgetSnapshot.swift – the snapshot (next lectures, due cards per module, upcoming exams), WidgetSnapshotStore (App Group container, writes only changes) and StudyAppLink (studyapp:// deep links); WidgetSnapshotBuilder turns the app state into a snapshot. Shared/ is a new folder in the app target.
  2. Widget extension: new target StudyAppWidgets (Shared + Widgets folders) embedded via „Embed Foundation Extensions“; widgets „Nächste Vorlesung“ (small/medium), „Fällige Karteikarten“, „Klausur-Countdown“. The timeline adds entries at lecture starts/ends, so the widget switches to „Läuft“ without the app. App and extension share the App Group VF66Y42L4U.germany.oldenburg.mueller.tristan.StudyApp; the app registers the studyapp URL scheme. qa.sh build and release.sh check that the extension is in the bundle.
  3. App wiring: snapshot published on launch and every five minutes (widgets reload only on change); onOpenURL → AppNavigation.open(_:).
  4. Docs: FEATURES.md, ARCHITECTURE.md

⚠️ Please check on the Mac

  • The project file was edited by hand (new target, embed phase, dependency). I validated it with an OpenStep parser (all references resolve), but only the macOS CI build proves Xcode accepts it.
  • App Group with ad-hoc signing: the app is signed ad hoc. macOS may ask once whether StudyApp may access data of other apps (the shared container), or – in the worst case – deny the container to an unsigned extension. If widgets stay empty, the fix is signing with the Apple Development certificate of team VF66Y42L4U.

Tests

  • WidgetSnapshotTests (running/next lecture, change dates, store writes only changes, link round trip), WidgetSnapshotBuilderTests, WidgetLinkNavigationTests
  • 168 tests pass locally (Linux subset); SwiftLint clean (now also covers Shared/ and Widgets/)

Checklist

  • Linked issue, labels and milestone set
  • New logic has tests
  • Widgets added and tried on the desktop
  • Release notes: collected in the 1.12 release PR

Generated by Claude Code

WidgetSnapshot (next lectures, due cards per module, upcoming exams) is
the contract between the app and the widget extension; the app writes
it as JSON into the App Group container, widgets only read it.
WidgetSnapshotStore writes only changes, StudyAppLink encodes deep
links from widgets into the app, and WidgetSnapshotBuilder turns the
app's state into a snapshot. The new Shared folder belongs to the app
target (and later the widget target).

Refs #49

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmmqmKmX8VDSfoPbzTS1ew
A WidgetKit extension with three widgets – „Nächste Vorlesung“ (small
and medium, with due cards), „Fällige Karteikarten“ and
„Klausur-Countdown“ – reads the snapshot from the App Group container.
Its timeline adds an entry at every lecture start and end, so the
lecture widget turns from „Als Nächstes“ to „Läuft“ on its own; clicks
open the matching place through studyapp:// links.

The project gets the StudyAppWidgets target (Shared + Widgets folders),
embeds it into the app, and both share the App Group; the app registers
the studyapp URL scheme. The QA build and the release script check that
the extension is in the bundle.

Refs #49

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmmqmKmX8VDSfoPbzTS1ew
The app writes the widget snapshot on launch and with the five-minute
loop; widgets reload only when it changed. studyapp:// links from the
widgets open Today or a module section (slides resume reading).

Refs #49

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmmqmKmX8VDSfoPbzTS1ew
Refs #49

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmmqmKmX8VDSfoPbzTS1ew
@502Proxy 502Proxy added this to the 1.12 milestone Oct 28, 2026 — with Claude
@502Proxy 502Proxy added enhancement New feature or improvement area: mac Menu bar, widgets, Shortcuts, Spotlight labels Oct 28, 2026 — with Claude
# Conflicts:
#	App/StudyAppApp.swift
#	docs/FEATURES.md
# Conflicts:
#	Config/Info.plist
#	docs/FEATURES.md

Copy link
Copy Markdown
Owner Author

CI: derselbe „test runner hung before establishing connection“ wie seit ca. 13 Uhr überall, nicht von den Widgets verursacht. Gegenprobe auf einem alten grünen Stand läuft. Main ist inzwischen hineingemerged.


Generated by Claude Code

# Conflicts:
#	App/StudyAppApp.swift
#	docs/FEATURES.md
# Conflicts:
#	App/StudyAppApp.swift
#	Presentation/Navigation/AppNavigation.swift
#	docs/FEATURES.md
@502Proxy
502Proxy merged commit f241174 into main Oct 28, 2026
1 check passed

Copy link
Copy Markdown
Owner Author

Ursache des CI-Hängers gefunden: Die MenuBarExtra-Szene verhindert auf dem Runner, dass der Test-Host fertig startet (Probe-Läufe in #62). Der Fix aus #63 (leere Host-App unter XCTest) ist hier hineingemerged. Er wird zum No-op, sobald #63 auf main ist.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: mac Menu bar, widgets, Shortcuts, Spotlight enhancement New feature or improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(mac): widgets for next lecture, due cards and exams

2 participants