diff options
| author | Christian Cleberg <[email protected]> | 2026-07-17 08:36:05 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-07-17 10:12:36 -0500 |
| commit | b4b94d54cbed9334a28cdcd70d3a8a0fd06e04ef (patch) | |
| tree | 8fa4b408729da32ec2c547081ec2bba13b893fa2 /DomainDigWidget | |
| parent | 065e1e77ff00e8f9c8785393b5eba6c3e0bb2bb1 (diff) | |
| download | domain-dig-b4b94d54cbed9334a28cdcd70d3a8a0fd06e04ef.tar.gz domain-dig-b4b94d54cbed9334a28cdcd70d3a8a0fd06e04ef.tar.bz2 domain-dig-b4b94d54cbed9334a28cdcd70d3a8a0fd06e04ef.zip | |
Implement v4.6.0: sweep Live Activity, share extension, iPad split view, actionable notifications
- Sweep Live Activity: SweepActivityAttributes (Shared/), lock-screen + Dynamic
Island UI in the widget extension, driven by SweepActivityController wired into
the batch pipeline (begin/update/end); NSSupportsLiveActivities in Info.plist.
- Share extension (DomainDigShareExtension): accepts a web URL from the share
sheet, extracts the host, and hands it to the app via the App Group inbox
(DomainDigShareInbox); the app consumes it on activation and inspects it.
- iPad layout: RootTabView uses NavigationSplitView in the regular size class
and the tab bar in compact.
- Actionable notifications: per-domain threadIdentifier grouping, a Re-inspect
action, and tap routing into the domain detail via the intent router.
- Bump version to 4.6.0 (build 38) across app, widget, and share targets.
Diffstat (limited to 'DomainDigWidget')
| -rw-r--r-- | DomainDigWidget/DomainDigWidgetBundle.swift | 1 | ||||
| -rw-r--r-- | DomainDigWidget/SweepLiveActivity.swift | 96 |
2 files changed, 97 insertions, 0 deletions
diff --git a/DomainDigWidget/DomainDigWidgetBundle.swift b/DomainDigWidget/DomainDigWidgetBundle.swift index 483995c..8c12c90 100644 --- a/DomainDigWidget/DomainDigWidgetBundle.swift +++ b/DomainDigWidget/DomainDigWidgetBundle.swift @@ -5,5 +5,6 @@ import WidgetKit struct DomainDigWidgetBundle: WidgetBundle { var body: some Widget { DomainDigPortfolioWidget() + SweepLiveActivity() } } diff --git a/DomainDigWidget/SweepLiveActivity.swift b/DomainDigWidget/SweepLiveActivity.swift new file mode 100644 index 0000000..b99a070 --- /dev/null +++ b/DomainDigWidget/SweepLiveActivity.swift @@ -0,0 +1,96 @@ +import ActivityKit +import SwiftUI +import WidgetKit + +struct SweepLiveActivity: Widget { + var body: some WidgetConfiguration { + ActivityConfiguration(for: SweepActivityAttributes.self) { context in + // Lock Screen / banner presentation. + SweepActivityBannerView(context: context) + .padding() + .activityBackgroundTint(Color(.systemBackground).opacity(0.85)) + } dynamicIsland: { context in + DynamicIsland { + DynamicIslandExpandedRegion(.leading) { + Label(context.attributes.title, systemImage: "arrow.trianglehead.2.clockwise") + .font(.caption) + .foregroundStyle(.secondary) + } + DynamicIslandExpandedRegion(.trailing) { + Text("\(context.state.completed)/\(context.state.total)") + .font(.caption) + .monospacedDigit() + } + DynamicIslandExpandedRegion(.bottom) { + VStack(alignment: .leading, spacing: 4) { + ProgressView(value: context.state.fractionComplete) + .tint(.cyan) + if let current = context.state.currentDomain { + Text(current) + .font(.caption2) + .foregroundStyle(.secondary) + .lineLimit(1) + } + } + } + } compactLeading: { + Image(systemName: "arrow.trianglehead.2.clockwise") + .foregroundStyle(.cyan) + } compactTrailing: { + Text("\(context.state.completed)/\(context.state.total)") + .font(.caption2) + .monospacedDigit() + } minimal: { + ProgressView(value: context.state.fractionComplete) + .progressViewStyle(.circular) + .tint(.cyan) + } + } + } +} + +private struct SweepActivityBannerView: View { + let context: ActivityViewContext<SweepActivityAttributes> + + var body: some View { + VStack(alignment: .leading, spacing: 8) { + HStack { + Label(context.attributes.title, systemImage: "arrow.trianglehead.2.clockwise") + .font(.caption) + .fontWeight(.semibold) + .foregroundStyle(.secondary) + Spacer() + Text("\(context.state.completed) of \(context.state.total)") + .font(.caption) + .monospacedDigit() + } + + ProgressView(value: context.state.fractionComplete) + .tint(.cyan) + + HStack { + if let current = context.state.currentDomain { + Text(current) + .font(.caption2) + .foregroundStyle(.secondary) + .lineLimit(1) + } else { + Text(context.state.completed >= context.state.total ? "Finished" : "Working…") + .font(.caption2) + .foregroundStyle(.secondary) + } + Spacer() + if context.state.changed > 0 { + Text("\(context.state.changed) changed") + .font(.caption2) + .foregroundStyle(.orange) + } + if context.state.warnings > 0 { + Text("\(context.state.warnings) warnings") + .font(.caption2) + .foregroundStyle(.red) + } + } + } + } +} |
