Use widget space by family
This commit is contained in:
12
TESTING.md
12
TESTING.md
@@ -235,13 +235,15 @@ answer before uploading it to App Store Connect.
|
||||
- [ ] Upgrade over a build with an existing server. Launch Gotcha once, then
|
||||
add both **Recent Activity** and **Open Pull Requests** from the system
|
||||
widget gallery; the saved server and Keychain token work without re-entry.
|
||||
- [ ] Both widgets are offered only in the large system size and use native
|
||||
- [ ] Both widgets are offered in medium and large system sizes and use native
|
||||
widget margins, typography, tint, relative update time, and light/dark
|
||||
appearances without clipping at the largest accessibility text size.
|
||||
- [ ] Recent Activity shows up to six latest activity rows for its configured
|
||||
server. Open Pull Requests shows up to five open pull requests. Loading,
|
||||
empty, missing-server, and API-error states remain legible and do not
|
||||
expose account data while the device is locked.
|
||||
- [ ] In medium size, Recent Activity shows up to three latest activity rows
|
||||
and Open Pull Requests shows up to two open pull requests. In large size,
|
||||
they show up to ten and five rows respectively. Confirm both the widget
|
||||
gallery previews and live configured timelines use those family-specific
|
||||
row counts. Loading, empty, missing-server, and API-error states remain
|
||||
legible and do not expose account data while the device is locked.
|
||||
- [ ] Add a second server profile, long-press each widget, choose **Edit
|
||||
Widget**, and assign a different server to each. The displayed server
|
||||
name and rows update independently; deleting a selected server changes
|
||||
|
||||
@@ -20,46 +20,23 @@ private struct ActivityProvider: AppIntentTimelineProvider {
|
||||
ActivityEntry(
|
||||
date: .now,
|
||||
serverName: "My Server",
|
||||
rows: [
|
||||
ActivityRow(
|
||||
icon: .push,
|
||||
title: "Pushed to main in owner/project",
|
||||
detail: "",
|
||||
meta: "Just now",
|
||||
target: .commit,
|
||||
owner: "owner",
|
||||
repository: "project",
|
||||
number: 0,
|
||||
sha: ""
|
||||
),
|
||||
ActivityRow(
|
||||
icon: .issue,
|
||||
title: "Opened an issue in owner/project",
|
||||
detail: "",
|
||||
meta: "5m ago",
|
||||
target: .issue,
|
||||
owner: "owner",
|
||||
repository: "project",
|
||||
number: 1,
|
||||
sha: ""
|
||||
),
|
||||
],
|
||||
rows: activityPlaceholderRows(for: context.family),
|
||||
message: nil
|
||||
)
|
||||
}
|
||||
|
||||
func snapshot(for configuration: ActivityWidgetIntent, in context: Context) async -> ActivityEntry {
|
||||
context.isPreview ? placeholder(in: context) : await load(configuration)
|
||||
context.isPreview ? placeholder(in: context) : await load(configuration, family: context.family)
|
||||
}
|
||||
|
||||
func timeline(for configuration: ActivityWidgetIntent, in context: Context) async -> Timeline<ActivityEntry> {
|
||||
Timeline(
|
||||
entries: [await load(configuration)],
|
||||
entries: [await load(configuration, family: context.family)],
|
||||
policy: .after(Date.now.addingTimeInterval(15 * 60))
|
||||
)
|
||||
}
|
||||
|
||||
private func load(_ configuration: ActivityWidgetIntent) async -> ActivityEntry {
|
||||
private func load(_ configuration: ActivityWidgetIntent, family: WidgetFamily) async -> ActivityEntry {
|
||||
guard
|
||||
let selection = configuration.server,
|
||||
let server = WidgetEnvironment.server(for: selection)
|
||||
@@ -72,7 +49,8 @@ private struct ActivityProvider: AppIntentTimelineProvider {
|
||||
)
|
||||
}
|
||||
do {
|
||||
let page = try await WidgetEnvironment.core().widgetActivity(serverId: server.id, limit: 6)
|
||||
let limit = activityLimit(for: family)
|
||||
let page = try await WidgetEnvironment.core().widgetActivity(serverId: server.id, limit: limit)
|
||||
return ActivityEntry(
|
||||
date: .now,
|
||||
serverName: page.serverName,
|
||||
@@ -95,42 +73,23 @@ private struct PullsProvider: AppIntentTimelineProvider {
|
||||
PullsEntry(
|
||||
date: .now,
|
||||
serverName: "My Server",
|
||||
rows: [
|
||||
PullRow(
|
||||
number: 42,
|
||||
owner: "owner",
|
||||
repository: "project",
|
||||
state: .open,
|
||||
title: "project #42\nImprove the activity screen",
|
||||
summary: "",
|
||||
meta: "Open · developer · Just now"
|
||||
),
|
||||
PullRow(
|
||||
number: 41,
|
||||
owner: "owner",
|
||||
repository: "project",
|
||||
state: .open,
|
||||
title: "project #41\nFix repository navigation",
|
||||
summary: "",
|
||||
meta: "Open · developer · 10m ago"
|
||||
),
|
||||
],
|
||||
rows: pullPlaceholderRows(for: context.family),
|
||||
message: nil
|
||||
)
|
||||
}
|
||||
|
||||
func snapshot(for configuration: PullsWidgetIntent, in context: Context) async -> PullsEntry {
|
||||
context.isPreview ? placeholder(in: context) : await load(configuration)
|
||||
context.isPreview ? placeholder(in: context) : await load(configuration, family: context.family)
|
||||
}
|
||||
|
||||
func timeline(for configuration: PullsWidgetIntent, in context: Context) async -> Timeline<PullsEntry> {
|
||||
Timeline(
|
||||
entries: [await load(configuration)],
|
||||
entries: [await load(configuration, family: context.family)],
|
||||
policy: .after(Date.now.addingTimeInterval(15 * 60))
|
||||
)
|
||||
}
|
||||
|
||||
private func load(_ configuration: PullsWidgetIntent) async -> PullsEntry {
|
||||
private func load(_ configuration: PullsWidgetIntent, family: WidgetFamily) async -> PullsEntry {
|
||||
guard
|
||||
let selection = configuration.server,
|
||||
let server = WidgetEnvironment.server(for: selection)
|
||||
@@ -143,7 +102,8 @@ private struct PullsProvider: AppIntentTimelineProvider {
|
||||
)
|
||||
}
|
||||
do {
|
||||
let page = try await WidgetEnvironment.core().widgetPulls(serverId: server.id, limit: 5)
|
||||
let limit = pullLimit(for: family)
|
||||
let page = try await WidgetEnvironment.core().widgetPulls(serverId: server.id, limit: limit)
|
||||
return PullsEntry(
|
||||
date: .now,
|
||||
serverName: page.serverName,
|
||||
@@ -161,6 +121,64 @@ private struct PullsProvider: AppIntentTimelineProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private func activityLimit(for family: WidgetFamily) -> UInt32 {
|
||||
family == .systemMedium ? 3 : 10
|
||||
}
|
||||
|
||||
private func pullLimit(for family: WidgetFamily) -> UInt32 {
|
||||
family == .systemMedium ? 2 : 5
|
||||
}
|
||||
|
||||
private func activityPlaceholderRows(for family: WidgetFamily) -> [ActivityRow] {
|
||||
let samples: [(ActivityIcon, String, String)] = [
|
||||
(.push, "Pushed to main in owner/project", "Just now"),
|
||||
(.issue, "Opened an issue in owner/project", "5m ago"),
|
||||
(.pullRequest, "Merged a pull request in owner/project", "12m ago"),
|
||||
(.branch, "Created branch feature/widget", "25m ago"),
|
||||
(.tag, "Published tag v1.0.0", "40m ago"),
|
||||
(.release, "Published a release in owner/project", "1h ago"),
|
||||
(.repository, "Created repository owner/new-project", "2h ago"),
|
||||
(.push, "Pushed to release in owner/project", "3h ago"),
|
||||
(.issue, "Closed an issue in owner/project", "4h ago"),
|
||||
(.pullRequest, "Opened a pull request in owner/project", "5h ago"),
|
||||
]
|
||||
return samples.prefix(Int(activityLimit(for: family))).enumerated().map { index, sample in
|
||||
ActivityRow(
|
||||
icon: sample.0,
|
||||
title: sample.1,
|
||||
detail: "",
|
||||
meta: sample.2,
|
||||
target: .commit,
|
||||
owner: "owner",
|
||||
repository: "project",
|
||||
number: Int64(index),
|
||||
sha: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private func pullPlaceholderRows(for family: WidgetFamily) -> [PullRow] {
|
||||
let titles = [
|
||||
"Improve the activity screen",
|
||||
"Fix repository navigation",
|
||||
"Add compact widget layouts",
|
||||
"Refresh server configuration",
|
||||
"Polish issue filters",
|
||||
]
|
||||
return titles.prefix(Int(pullLimit(for: family))).enumerated().map { index, title in
|
||||
let number = Int64(42 - index)
|
||||
return PullRow(
|
||||
number: number,
|
||||
owner: "owner",
|
||||
repository: "project",
|
||||
state: .open,
|
||||
title: "project #\(number)\n\(title)",
|
||||
summary: "",
|
||||
meta: "Open · developer · \(index * 10)m ago"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private struct WidgetHeader: View {
|
||||
let title: String
|
||||
let symbol: String
|
||||
@@ -298,7 +316,7 @@ struct ActivityWidget: Widget {
|
||||
}
|
||||
.configurationDisplayName("Recent Activity")
|
||||
.description("See the latest activity from a configured Gitea or Forgejo server.")
|
||||
.supportedFamilies([.systemLarge])
|
||||
.supportedFamilies([.systemMedium, .systemLarge])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,7 +329,7 @@ struct PullsWidget: Widget {
|
||||
}
|
||||
.configurationDisplayName("Open Pull Requests")
|
||||
.description("See open pull requests from a configured Gitea or Forgejo server.")
|
||||
.supportedFamilies([.systemLarge])
|
||||
.supportedFamilies([.systemMedium, .systemLarge])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user