| @@ -9,6 +9,7 @@ struct ContributionGraphEntry: TimelineEntry { |
| 9 | 9 | |
| 10 | 10 | enum State { |
| 11 | 11 | case placeholder |
| 12 | case disabled |
| 12 | 13 | case unavailable |
| 13 | 14 | case empty |
| 14 | 15 | case indexing |
| @@ -41,6 +42,10 @@ struct ContributionGraphTimelineProvider: TimelineProvider { |
| 41 | 42 | } |
| 42 | 43 | |
| 43 | 44 | private func loadEntry() async -> ContributionGraphEntry { |
| 45 | guard ContributionWidgetContextStore.isEnabled() else { |
| 46 | return ContributionGraphEntry(date: .now, actor: nil, state: .disabled, weeks: []) |
| 47 | } |
| 48 | |
| 44 | 49 | guard let actor = ContributionWidgetContextStore.loadActor(), !actor.isEmpty else { |
| 45 | 50 | return ContributionGraphEntry(date: .now, actor: nil, state: .unavailable, weeks: []) |
| 46 | 51 | } |
| @@ -91,6 +96,29 @@ private struct ContributionGraphWidgetView: View { |
| 91 | 96 | @Environment(\.widgetFamily) private var family |
| 92 | 97 | |
| 93 | 98 | var body: some View { |
| 99 | Group { |
| 100 | switch entry.state { |
| 101 | case .disabled: |
| 102 | messageView( |
| 103 | title: "Contributions Disabled", |
| 104 | detail: "Enable contribution graphs in Hutch settings to use this widget." |
| 105 | ) |
| 106 | case .unavailable: |
| 107 | messageView( |
| 108 | title: "Open Hutch", |
| 109 | detail: "Sign in and open your profile to load contribution data." |
| 110 | ) |
| 111 | default: |
| 112 | graphView |
| 113 | } |
| 114 | } |
| 115 | .widgetURL(URL(string: "hutch://home")) |
| 116 | .containerBackground(for: .widget) { |
| 117 | Color(.systemBackground) |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | private var graphView: some View { |
| 94 | 122 | GeometryReader { geometry in |
| 95 | 123 | let cellSize = ContributionGraphSizing.baseCellSize(availableHeight: geometry.size.height) |
| 96 | 124 | let layout = ContributionGraphSizing.layout(availableSize: geometry.size, cellSize: cellSize) |
| @@ -108,17 +136,27 @@ private struct ContributionGraphWidgetView: View { |
| 108 | 136 | .frame(width: actualSize.width, height: actualSize.height) |
| 109 | 137 | .frame(maxWidth: .infinity, maxHeight: .infinity) |
| 110 | 138 | } |
| 111 | | .widgetURL(URL(string: "hutch://home")) |
| 112 | | .containerBackground(for: .widget) { |
| 113 | | Color(.systemBackground) |
| 139 | } |
| 140 | |
| 141 | private func messageView(title: String, detail: String) -> some View { |
| 142 | VStack(spacing: 6) { |
| 143 | Text(title) |
| 144 | .font(family == .systemSmall ? .headline : .title3.weight(.semibold)) |
| 145 | .multilineTextAlignment(.center) |
| 146 | Text(detail) |
| 147 | .font(.caption) |
| 148 | .foregroundStyle(.secondary) |
| 149 | .multilineTextAlignment(.center) |
| 114 | 150 | } |
| 151 | .padding() |
| 152 | .frame(maxWidth: .infinity, maxHeight: .infinity) |
| 115 | 153 | } |
| 116 | 154 | |
| 117 | 155 | private func displayedWeeks(columnCount: Int) -> [ContributionGraphWeek] { |
| 118 | 156 | var baseWeeks = switch entry.state { |
| 119 | 157 | case .populated, .indexing, .empty: |
| 120 | 158 | entry.weeks |
| 121 | | case .placeholder, .unavailable: |
| 159 | case .placeholder, .disabled, .unavailable: |
| 122 | 160 | ContributionGraphSampleData.placeholderWeeks |
| 123 | 161 | } |
| 124 | 162 | |