summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-04-11 19:55:28 -0500
committerChristian Cleberg <[email protected]>2026-04-11 19:55:28 -0500
commitb25ac7621d1a7a2bbdf19588d855da531a185c55 (patch)
treef48e93644369d76d301265a4f7f3c3cdc54aeef6
parentba773aaa9da5798a458ee58f7ce37db070ada7d8 (diff)
downloadhutch-2.12.1.tar.gz
hutch-2.12.1.tar.bz2
hutch-2.12.1.zip
fix: respect contribution graphs toggle in widgetv2.12.1
Mirror the contributionGraphsEnabled setting to shared app group defaults so the widget extension can read it. Show a descriptive message when contributions are disabled instead of placeholder data.
-rw-r--r--Hutch/Views/Settings/SettingsView.swift3
-rw-r--r--HutchWidgetExtension/ContributionGraphWidget.swift46
-rw-r--r--Shared/ContributionWidgetContext.swift10
3 files changed, 55 insertions, 4 deletions
diff --git a/Hutch/Views/Settings/SettingsView.swift b/Hutch/Views/Settings/SettingsView.swift
index a249807..4fb3f9c 100644
--- a/Hutch/Views/Settings/SettingsView.swift
+++ b/Hutch/Views/Settings/SettingsView.swift
@@ -49,6 +49,9 @@ struct SettingsView: View {
Section {
Toggle("Swipe actions", isOn: $swipeActionsEnabled)
Toggle("Contribution graphs", isOn: $contributionGraphsEnabled)
+ .onChange(of: contributionGraphsEnabled) { _, newValue in
+ ContributionWidgetContextStore.setEnabled(newValue)
+ }
} header: {
Text("Behavior")
} footer: {
diff --git a/HutchWidgetExtension/ContributionGraphWidget.swift b/HutchWidgetExtension/ContributionGraphWidget.swift
index c690f54..5dbf6a2 100644
--- a/HutchWidgetExtension/ContributionGraphWidget.swift
+++ b/HutchWidgetExtension/ContributionGraphWidget.swift
@@ -9,6 +9,7 @@ struct ContributionGraphEntry: TimelineEntry {
enum State {
case placeholder
+ case disabled
case unavailable
case empty
case indexing
@@ -41,6 +42,10 @@ struct ContributionGraphTimelineProvider: TimelineProvider {
}
private func loadEntry() async -> ContributionGraphEntry {
+ guard ContributionWidgetContextStore.isEnabled() else {
+ return ContributionGraphEntry(date: .now, actor: nil, state: .disabled, weeks: [])
+ }
+
guard let actor = ContributionWidgetContextStore.loadActor(), !actor.isEmpty else {
return ContributionGraphEntry(date: .now, actor: nil, state: .unavailable, weeks: [])
}
@@ -91,6 +96,29 @@ private struct ContributionGraphWidgetView: View {
@Environment(\.widgetFamily) private var family
var body: some View {
+ Group {
+ switch entry.state {
+ case .disabled:
+ messageView(
+ title: "Contributions Disabled",
+ detail: "Enable contribution graphs in Hutch settings to use this widget."
+ )
+ case .unavailable:
+ messageView(
+ title: "Open Hutch",
+ detail: "Sign in and open your profile to load contribution data."
+ )
+ default:
+ graphView
+ }
+ }
+ .widgetURL(URL(string: "hutch://home"))
+ .containerBackground(for: .widget) {
+ Color(.systemBackground)
+ }
+ }
+
+ private var graphView: some View {
GeometryReader { geometry in
let cellSize = ContributionGraphSizing.baseCellSize(availableHeight: geometry.size.height)
let layout = ContributionGraphSizing.layout(availableSize: geometry.size, cellSize: cellSize)
@@ -108,17 +136,27 @@ private struct ContributionGraphWidgetView: View {
.frame(width: actualSize.width, height: actualSize.height)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
- .widgetURL(URL(string: "hutch://home"))
- .containerBackground(for: .widget) {
- Color(.systemBackground)
+ }
+
+ private func messageView(title: String, detail: String) -> some View {
+ VStack(spacing: 6) {
+ Text(title)
+ .font(family == .systemSmall ? .headline : .title3.weight(.semibold))
+ .multilineTextAlignment(.center)
+ Text(detail)
+ .font(.caption)
+ .foregroundStyle(.secondary)
+ .multilineTextAlignment(.center)
}
+ .padding()
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
}
private func displayedWeeks(columnCount: Int) -> [ContributionGraphWeek] {
var baseWeeks = switch entry.state {
case .populated, .indexing, .empty:
entry.weeks
- case .placeholder, .unavailable:
+ case .placeholder, .disabled, .unavailable:
ContributionGraphSampleData.placeholderWeeks
}
diff --git a/Shared/ContributionWidgetContext.swift b/Shared/ContributionWidgetContext.swift
index 3fadc8a..2404698 100644
--- a/Shared/ContributionWidgetContext.swift
+++ b/Shared/ContributionWidgetContext.swift
@@ -9,11 +9,21 @@ enum ContributionGraphWidgetConfiguration {
enum ContributionWidgetContextStore {
private static let actorKey = "contributionWidget.actor"
+ private static let enabledKey = "contributionWidget.enabled"
static func loadActor(defaults: UserDefaults? = sharedDefaults()) -> String? {
defaults?.string(forKey: actorKey)
}
+ static func isEnabled(defaults: UserDefaults? = sharedDefaults()) -> Bool {
+ defaults?.object(forKey: enabledKey) == nil ? true : defaults?.bool(forKey: enabledKey) ?? true
+ }
+
+ static func setEnabled(_ enabled: Bool, defaults: UserDefaults? = sharedDefaults()) {
+ defaults?.set(enabled, forKey: enabledKey)
+ reloadWidgetTimelines()
+ }
+
static func saveActor(_ actor: String, defaults: UserDefaults? = sharedDefaults()) {
defaults?.set(actor, forKey: actorKey)
reloadWidgetTimelines()