Skip to content

feature: enhance the gui#28

Merged
Charliechen114514 merged 26 commits into
mainfrom
feat/phase-f-control-center-notifications
Jul 10, 2026
Merged

feature: enhance the gui#28
Charliechen114514 merged 26 commits into
mainfrom
feat/phase-f-control-center-notifications

Conversation

@Charliechen114514

Copy link
Copy Markdown
Member

No description provided.

Route a "notify" IPCMessage to a new notifyReceived(payload) signal on
IPCServer, so external apps can post desktop notifications via
IPCClient::send(path, "notify", {...}). Dispatch stays registry-based and
unchanged; "raise" remains backward compatible. Adds ipc_notify_test
covering routing, raise compatibility, and JSON wire round-trip.
Add an in-process notification store: a minimal Notification record (id,
title, message, app_id, timestamp) and a process-wide NotificationService
singleton owning the active list, emitting posted/dismissed/cleared/
dndChanged signals. Do-Not-Disturb is backed by the ConfigStore
"notification.dnd.enabled" key so the control-center switch (later commit)
and the banner suppress decision share one source. The model is in-memory
only; persistence and grouping are deferred. Adds unit tests covering
post/dismiss/clear-all, newest-first ordering, signal emission, and DND
suppression round-tripped through the real ConfigStore.
Add the notification UI surfaces on top of NotificationService:

- NotificationCardWidget: self-painted rounded card (title, message,
  app/time meta, dismiss hotspot) following the active Material theme.
- NotificationBanner: frameless top-right toast that slides/fades in via
  the QuarkWidgets MD3 animation pair, shows the newest card, and
  auto-hides after 5s (ESC + dismiss hotspot close it early).
- NotificationCenterPanel: right-edge slide-in panel listing every active
  notification; subscribes to the service and rebuilds live, with a
  header "Clear all" hotspot.

All three reuse the AppLauncher frameless-child + enter/exit fade/slide
pattern (no Qt::Popup, so it does not fight the WM on windowless targets).
Add ControlCenter, a frameless quick-settings popup reusing the AppLauncher
pattern (MD3 fade/slide enter-exit, rounded surface). Holds:

- Brightness + volume sliders (0-100, UI-only this phase; hardware backends
  arrive with aels-power / aels-network).
- Wi-Fi + Bluetooth toggles (UI-only this phase).
- DND toggle wired to NotificationService::setDndEnabled -> ConfigStore
  "notification.dnd.enabled", so it drives banner suppression for real.
- Theme toggle button: switches the active Material theme via
  ThemeManager::setThemeTo (live).
- Screenshot placeholder button.

Sliders use qw::widget::material::Slider, toggles Switch, buttons Button
(QuarkWidgets MD3). Hardware-backed controls + real brightness/volume are
deferred to the embedded pivot.
Add two click entry points to the status bar:

- timeClicked(): emitted when the clock region is hit (Split style: the
  time rect before the icon cluster; Centered: anywhere not on an icon).
- notifyIconClicked(): emitted when the new leftmost icon cell is hit.

The notification icon is drawn as a vector bell + unread badge
(QPainterPath, no PNG mask) so it carries no compiled-resource dependency;
the badge lights whenever NotificationService has active notifications.
mousePressEvent mirrors paintEvent's cluster geometry (now 5 cells) for
hit testing. cfdesktop_statusbar links cfdesktop_notification for the count.
Connect the new Phase F components into the desktop shell:

- Construct NotificationService (singleton), ControlCenter,
  NotificationCenterPanel, NotificationBanner as children of the desktop.
- StatusBar::timeClicked toggles the control center; notifyIconClicked
  toggles the notification center (popup/hidePanel with availableGeometry).
- NotificationService::notificationPosted drives the banner (only when
  not DND-suppressed).
- IPCServer::notifyReceived routes external "notify" payloads into
  NotificationService::post (title/message/app_id).
- cf_desktop_components aggregates cfdesktop_notification +
  cfdesktop_control_center so their symbols resolve into CFDesktop_shared.

Outside-click dismissal is deferred (matches AppLauncher: ESC + the status
bar toggle close either popup).
Mark MS6 Step B2 (control center) + the notification minimal closed loop
as landed in current.md, milestone_06, and 11_notification_control:
ControlCenter MS6 panel, NotificationService (in-process singleton),
banner, notification center, statusbar click signals + vector bell icon,
and IPC notify routing. Deferred items (hardware backends, persistence,
grouping, standalone notification process, outside-click dismiss) are
called out explicitly so the next pass knows what's left.
- Add a "Send test notification" button that posts a "Hello World"
  Notification via NotificationService, so the banner + notification center
  can be verified end-to-end without an IPC client. Drop once real producers
  exist.
- Replace the fixed 360 px panel height with layout sizeHint() bounded to the
  work area; the fixed height clipped the bottom switch/button row.
- Banner: anchor top-center instead of top-right; slow the enter animation
  one motion-token tier (fade mediumEnter, slide longEnter).
- ControlCenter: blockSignals around popup()->setChecked(DND) so the
  programmatic sync does not re-fire toggled -> setDndEnabled, which had
  silently written dnd.enabled=true to ConfigStore and suppressed every
  banner post.
…aceholder

The right-column lower area was rewritten in MS6 Step C as the
NetStatus + LocalTemp gadget grid; the file header still described it as
a placeholder app-grid area.
Phase 2 step 1: resolve bare stack addresses into (function, file, line)
triples.

- CrashReport gains ResolvedFrame + resolved_frames; toJson serializes it.
- symbolizer.cpp runs addr2line (one shot, -f -C) via popen on Linux at
  finalize time (normal context, not signal-safe); non-Linux returns empty
  (Windows dbghelp deferred). parseAddr2LineOutput is split out for testing.
- CrashHandler::finalizePendingReports takes an exe_path; when non-empty it
  fills resolved_frames. Defaults to "" so existing callers/tests unchanged.
- CrashHandlerStage passes QCoreApplication::applicationFilePath().
- crash_symbolizer_test covers parsing (function/file:line split, "??",
  truncation, empty).

raw_frames kept intact; existing crash tests unchanged.
Phase 2 step 2: surface a finalized crash report on screen.

- CrashReporterDialog: frameless + fade/slide popup (AppLauncher pattern)
  that reads a crash .json (signal/time, resolved_frames or raw frames,
  last_logs), with a Copy-to-clipboard and a "Don't show again" action.
- seen_marker: writes/reads a sibling <stem>.seen file so a report is shown
  only once per crash.
- New cfdesktop_crash_reporter STATIC lib, aggregated into cf_desktop_components.

Wired into the boot chain in the next commit.
After the desktop is shown, scan <exe>/crashes for the newest .json
without a sibling .seen marker and pop a CrashReporterDialog (centered)
showing the symbolized stack. One report per boot; "Don't show again"
writes the .seen so it is not shown again. Deferred 1.5s so the desktop
settles first.
Phase 12 minimal version: a frameless + fade/slide popup (AppLauncher
pattern) holding a TabView with three tabs.

- Wallpaper: animation-enabled switch + switch-interval/transition-duration
  sliders, backed by ConfigStore domain("wallpaper") (disable_animation,
  switch_interval_ms, animation_duration_ms). Values persist; the live
  wallpaper engine picks them up on its next start.
- Theme: Light/Dark buttons via ThemeManager::setThemeTo (live; every panel
  re-themes via themeChanged).
- About: version + stack + repo link.

The remaining Phase 12 tabs (display/sound/network/bluetooth/input/apps/
accessibility) and a font/icon subsystem are deferred until their backends
exist. Wired into the control center in the next commit.
Add a "Settings" button to the control center (emits settingsRequested) and
wire it in CFDesktopEntity to toggle the SettingsWindow popup, mirroring the
control-center / notification-center toggle pattern.
Mark the three follow-ups landed in current.md, 12_theme_settings_lockscreen
(settings minimal loop; 6 tabs + theme pack + lockscreen deferred), and
CRASH_HANDLE_STEP (Phase 2 addr2line + reporter; watchdog/Windows deferred).
…h about

Rewrite the three tabs so they are not rough:

- Wallpaper: every setting is a rounded gradient card (mirrors the home-page
  gadget cards). Sliders show their current value ("12000 ms") live. All six
  wallpaper keys exposed now — animation switch, interval, duration, switch
  mode (fixed/gradient/movement), order (sequential/random), easing — each
  as its own card. Wrapped in a QScrollArea so six cards fit.
- Theme: the active theme's button is disabled as a "you are here" indicator;
  clicking the other re-highlights live.
- About: rich text with larger title, version, stack, and a clickable repo
  link (setOpenExternalLinks).
- TabView: QSS-styled tab bar (selected tab in primary purple).

Also reword the CrashReporter unsymbolized-frames line to "runtime addresses
— full symbolization deferred": the PIE/ASLR base-resolution fix is deferred
to focus Settings this round.
…ntly)

WallPaperEngine now watches the "wallpaper" ConfigStore domain; any change
(Settings window slider/radio/switch) fires onConfigChanged -> stop + start,
which reloads config and re-evaluates the disable/mode/size guards. The
watcher handle is unwatched in the destructor. Settings changes now apply
immediately instead of only on the next engine start.
The wallpaper test main never initialized ConfigStore; WallPaperEngine's
loadConfig() queried the uninitialized singleton — UB that GCC happened to
mask (returned defaults). Adding the live-reload watch shifted the UB enough
to return garbage (animationDurationMs()=513 instead of 2000).

Initialize ConfigStore with MockPathProvider in the test main so queries
return real defaults. This is the real fix; "GCC passed" never meant no UB
(the CI triple-compiler matrix is what reliably catches it).
- Theme: replace the broken setEnabled(false) "current" indicator (it made
  the active button unclickable, so toggling back did nothing) with a
  variant highlight — the active theme is Filled, the other is Tonal, and
  both stay clickable. setVariant flips on click.
- About: the card was stranded at the top with a stretch below ("看着很小");
  now the card fills the tab (addWidget(card, 1)) and the text block is
  vertically centered (addStretch above/below inside the card).
setThemeTo("light"/"dark") was a no-op: MaterialApplication registers the
themes under the token names "theme.material.light"/"theme.material.dark"
(MATERIAL_THEME_LIGHT/DARK in core/token/theme_name), and
ThemeManager::setThemeTo silently returns when the name is not in factories_.
So theme switching never actually worked — not in the settings tab, not in
the control center theme button. Use the token constants in both places.
… widgets)

MaterialApplication registers the Material themes but never updates the Qt
application palette, so MD3 controls (which paint from theme tokens) went
dark while plain Qt widgets (QScrollArea, QTabWidget pane, QLabel/QTextEdit
defaults) stayed light/white — the notification center list and the settings
tab contents showed white on a dark panel ("分家").

Add a themeChanged -> QGuiApplication::setPalette hook in CFDesktopEntity
that swaps Window/Base/Text/etc. between a dark and a light palette, plus an
initial sync (MaterialApplication's setThemeTo(DEFAULT, false) did not emit).
Bump the QSS font sizes across the three tabs so they are readable:
card titles 13->16, value readouts 12->14, hints 11->13, radio labels
add an explicit 14, tab bar padding 8/20 -> 10/24 + font 14, about body
13->15 and title 18->22.
Replace the card-with-hint layout with what was asked for: a single 32px
"Theme" title (color follows the app palette via QLabel WindowText, so it
reads on both light and dark) and the Light/Dark buttons below. No card,
no hint paragraph.
QGuiApplication::setPalette alone did not recolor existing QLabels (they
kept black text on the dark background). After setting the app palette,
also walk the desktop widget tree and setPalette(p) on each widget so
QLabels pick up the new WindowText immediately.
@Charliechen114514
Charliechen114514 merged commit 1fd9bf8 into main Jul 10, 2026
6 checks passed
@Charliechen114514
Charliechen114514 deleted the feat/phase-f-control-center-notifications branch July 10, 2026 07:24
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