krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

Commit d7844b8e4e

d7844b8e4ec2611cf9a71ee4d83406d81e0141d3

parent: 08c0099083

Verified · cmc

cmc <hello@cleberg.net> · 2026-10-09 05:46 UTC

iOS: widget extension

OrgstarWidgets, embedded in the app with the app group: Today (small,
medium, large), Up Next on the Lock Screen (rectangular, inline,
circular), and the clock's Live Activity on the Lock Screen and in the
Dynamic Island.

Layout: unified · split

Sources/OrgstarWidgets/AgendaTimeline.swift added +96
@@ -0,0 +1,96 @@
1import OrgApp
2import SwiftUI
3import WidgetKit
4
5struct AgendaEntry: TimelineEntry {
6 let date: Date
7 /// Nil until the app has written one.
8 let snapshot: AgendaSnapshot?
9}
10
11/// The app's agenda snapshot, with an entry for each time what's left of the day changes.
12struct AgendaProvider: TimelineProvider {
13 func placeholder(in context: Context) -> AgendaEntry {
14 AgendaEntry(date: .now, snapshot: .sample(.now))
15 }
16
17 func getSnapshot(in context: Context, completion: @escaping (AgendaEntry) -> Void) {
18 let snapshot = Self.load()
19 completion(AgendaEntry(date: .now, snapshot: snapshot ?? (context.isPreview ? .sample(.now) : nil)))
20 }
21
22 func getTimeline(in context: Context, completion: @escaping (Timeline<AgendaEntry>) -> Void) {
23 completion(Self.timeline(Self.load(), now: .now))
24 }
25
26 static func load() -> AgendaSnapshot? {
27 AgendaSnapshot.file().flatMap(AgendaSnapshot.read)
28 }
29
30 static func timeline(_ snapshot: AgendaSnapshot?, now: Date, calendar: Calendar = .current) -> Timeline<AgendaEntry> {
31 let changes = snapshot?.changes(after: now, calendar: calendar)
32 ?? [calendar.date(byAdding: .day, value: 1, to: calendar.startOfDay(for: now))!]
33 let entries = ([now] + changes).map { AgendaEntry(date: $0, snapshot: snapshot) }
34 return Timeline(entries: entries, policy: .atEnd)
35 }
36}
37
38extension AgendaSnapshot.Hex {
39 func color(_ scheme: ColorScheme) -> Color {
40 Self.parse(scheme == .dark ? dark : light) ?? .primary
41 }
42
43 /// `#rrggbb` or `#rrggbbaa`.
44 static func parse(_ hex: String) -> Color? {
45 let digits = hex.dropFirst()
46 guard hex.first == "#", digits.count == 6 || digits.count == 8, let value = UInt64(digits, radix: 16) else { return nil }
47 let full = digits.count == 6 ? value << 8 | 0xFF : value
48 func part(_ shift: UInt64) -> Double { Double(full >> shift & 0xFF) / 255 }
49 return Color(.sRGB, red: part(24), green: part(16), blue: part(8), opacity: part(0))
50 }
51}
52
53extension AgendaSnapshot {
54 func color(_ key: String, _ scheme: ColorScheme) -> Color? {
55 colors[key]?.color(scheme)
56 }
57
58 /// A day for the gallery and previews.
59 static func sample(_ now: Date, calendar: Calendar = .current) -> AgendaSnapshot {
60 let midnight = calendar.startOfDay(for: now)
61 func at(_ hour: Int, _ minute: Int = 0) -> Date { midnight.addingTimeInterval(Double(hour * 3600 + minute * 60)) }
62 let red = Hex(light: "#d70015", dark: "#ff6961")
63 let orange = Hex(light: "#c93400", dark: "#ff9f0a")
64 let gray = Hex(light: "#6c6c70", dark: "#98989d")
65 let blue = Hex(light: "#0a66d8", dark: "#409cff")
66 func row(
67 _ title: String, _ gutter: String, status: String = "normal", todo: String? = nil, todoColor: Hex? = nil,
68 priority: String? = nil, category: String = "work", start: Date? = nil, end: Date? = nil
69 ) -> Row {
70 Row(
71 id: title, gutter: gutter, status: status, title: title, category: category, todo: todo, priority: priority, isDone: false,
72 isEvent: false, start: start, end: end, path: nil, offset: nil,
73 statusColor: status == "overdue" ? red : status == "due-soon" ? orange : gray, todoColor: todoColor,
74 priorityColor: priority == nil ? nil : red, categoryColor: Hex(light: "#2e6b8f", dark: "#7fb8d9")
75 )
76 }
77 let today = Day(
78 day: 0, date: midnight, header: "Today",
79 overdue: [row("Send the forms", "3d late", status: "overdue", todo: "TODO", todoColor: red, category: "home")],
80 rows: [
81 row("Standup", "09:30", start: at(9, 30)),
82 row("Review the draft", "11:00–12:00", todo: "NEXT", todoColor: blue, priority: "A", start: at(11), end: at(12)),
83 row("Dentist", "14:00", category: "home", start: at(14)),
84 row("File expenses", "Due today", status: "due-soon", todo: "TODO", todoColor: red),
85 ]
86 )
87 let tomorrow = Day(
88 day: 1, date: calendar.date(byAdding: .day, value: 1, to: midnight)!, header: "Tomorrow", overdue: [],
89 rows: [row("Plan the week", "Scheduled", todo: "TODO", todoColor: red)]
90 )
91 return AgendaSnapshot(
92 generated: now, days: [today, tomorrow],
93 colors: ["agenda-today": Hex(light: "#007aff", dark: "#0a84ff"), "agenda-time": gray, "foreground": Hex(light: "#1f2328", dark: "#e6edf3")]
94 )
95 }
96}
Sources/OrgstarWidgets/ClockActivityWidget.swift added +84
@@ -0,0 +1,84 @@
1import ActivityKit
2import AppIntents
3import OrgApp
4import SwiftUI
5import WidgetKit
6
7/// The running clock on the Lock Screen and in the Dynamic Island: the heading and the time
8/// so far, which ticks by itself.
9struct ClockActivityWidget: Widget {
10 var body: some WidgetConfiguration {
11 ActivityConfiguration(for: ClockActivityAttributes.self) { context in
12 HStack(spacing: 12) {
13 Image(systemName: "stopwatch").font(.title2).foregroundStyle(.orange)
14 VStack(alignment: .leading, spacing: 2) {
15 Text("Clocked in").font(.caption).foregroundStyle(.secondary)
16 Text(context.state.heading).font(.headline).lineLimit(2)
17 }
18 Spacer(minLength: 0)
19 VStack(alignment: .trailing, spacing: 6) {
20 ElapsedText(state: context.state).font(.title3.weight(.semibold))
21 ClockOutButton()
22 }
23 }
24 .padding()
25 .widgetURL(AppLink.clock.url)
26 } dynamicIsland: { context in
27 DynamicIsland {
28 DynamicIslandExpandedRegion(.leading) {
29 Image(systemName: "stopwatch").font(.title2).foregroundStyle(.orange)
30 }
31 DynamicIslandExpandedRegion(.trailing) {
32 ElapsedText(state: context.state).font(.title3.weight(.semibold)).frame(width: 84, alignment: .trailing)
33 }
34 DynamicIslandExpandedRegion(.center) {
35 Text(context.state.heading).font(.headline).lineLimit(1)
36 }
37 DynamicIslandExpandedRegion(.bottom) {
38 ClockOutButton()
39 }
40 } compactLeading: {
41 Image(systemName: "stopwatch").foregroundStyle(.orange)
42 } compactTrailing: {
43 ElapsedText(state: context.state).frame(maxWidth: 56)
44 } minimal: {
45 Image(systemName: "stopwatch").foregroundStyle(.orange)
46 }
47 .widgetURL(AppLink.clock.url)
48 }
49 }
50}
51
52/// Time since the clock started, `1:05:09`.
53struct ElapsedText: View {
54 let state: ClockActivityAttributes.ContentState
55
56 var body: some View {
57 Text(timerInterval: state.startedAt...Date.distantFuture, countsDown: false)
58 .monospacedDigit()
59 .lineLimit(1)
60 .minimumScaleFactor(0.7)
61 .multilineTextAlignment(.trailing)
62 }
63}
64
65struct ClockOutButton: View {
66 var body: some View {
67 Button(intent: ClockOutIntent()) {
68 Label("Clock Out", systemImage: "stop.fill").font(.caption.weight(.semibold))
69 }
70 .tint(.orange)
71 }
72}
73
74#Preview("Lock Screen", as: .content, using: ClockActivityAttributes(path: "/notes/work.org", start: "2026-10-09 Fri 09:00")) {
75 ClockActivityWidget()
76} contentStates: {
77 ClockActivityAttributes.ContentState(heading: "Review the draft", startedAt: .now.addingTimeInterval(-3725))
78}
79
80#Preview("Expanded", as: .dynamicIsland(.expanded), using: ClockActivityAttributes(path: "/notes/work.org", start: "2026-10-09 Fri 09:00")) {
81 ClockActivityWidget()
82} contentStates: {
83 ClockActivityAttributes.ContentState(heading: "Review the draft", startedAt: .now.addingTimeInterval(-3725))
84}
Sources/OrgstarWidgets/OrgstarWidgets.swift added +19
@@ -0,0 +1,19 @@
1import AppIntents
2import OrgApp
3import SwiftUI
4import WidgetKit
5
6/// The agenda on the Home Screen and the Lock Screen, and the running clock's Live Activity.
7@main
8struct OrgstarWidgets: WidgetBundle {
9 var body: some Widget {
10 TodayWidget()
11 UpNextWidget()
12 ClockActivityWidget()
13 }
14}
15
16/// The App Intents OrgApp declares: the Live Activity's Clock Out button.
17struct OrgstarWidgetIntents: AppIntentsPackage {
18 static var includedPackages: [any AppIntentsPackage.Type] { [OrgAppIntents.self] }
19}
Sources/OrgstarWidgets/TodayWidget.swift added +168
@@ -0,0 +1,168 @@
1import OrgApp
2import SwiftUI
3import WidgetKit
4
5/// Today's agenda on the Home Screen: what's next (small), today's list (medium), today and
6/// tomorrow (large).
7struct TodayWidget: Widget {
8 var body: some WidgetConfiguration {
9 StaticConfiguration(kind: "sh.krz.orgstar.today", provider: AgendaProvider()) { entry in
10 TodayView(entry: entry)
11 }
12 .configurationDisplayName("Today")
13 .description("What's left of today's agenda.")
14 .supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
15 }
16}
17
18struct TodayView: View {
19 let entry: AgendaEntry
20 @Environment(\.widgetFamily) private var family
21 @Environment(\.colorScheme) private var scheme
22
23 var body: some View {
24 Group {
25 if let snapshot = entry.snapshot {
26 content(snapshot)
27 } else {
28 Text("Open Orgstar to show your agenda here.")
29 .font(.caption)
30 .foregroundStyle(.secondary)
31 .frame(maxWidth: .infinity, maxHeight: .infinity)
32 }
33 }
34 .widgetURL(AppLink.agenda.url)
35 .containerBackground(for: .widget) {
36 entry.snapshot?.color("agenda-background", scheme) ?? Color(uiColor: .systemBackground)
37 }
38 }
39
40 @ViewBuilder
41 private func content(_ snapshot: AgendaSnapshot) -> some View {
42 let upcoming = snapshot.upcoming(at: entry.date)
43 VStack(alignment: .leading, spacing: family == .systemSmall ? 4 : 6) {
44 header(snapshot)
45 switch family {
46 case .systemSmall:
47 rows(Array(upcoming.prefix(3)), snapshot, compact: true, empty: "Nothing left today")
48 case .systemLarge:
49 rows(Array(upcoming.prefix(6)), snapshot, compact: false, empty: "Nothing left today")
50 if let tomorrow = snapshot.day(after: entry.date) {
51 let next = (tomorrow.rows + tomorrow.overdue).filter { !$0.isDone }
52 Divider()
53 Text("Tomorrow").font(.caption.weight(.semibold)).foregroundStyle(.secondary)
54 rows(Array(next.prefix(max(2, 9 - min(upcoming.count, 6)))), snapshot, compact: false, empty: "Nothing scheduled")
55 }
56 default:
57 rows(Array(upcoming.prefix(4)), snapshot, compact: false, empty: "Nothing left today")
58 }
59 Spacer(minLength: 0)
60 }
61 .frame(maxWidth: .infinity, alignment: .leading)
62 }
63
64 private func header(_ snapshot: AgendaSnapshot) -> some View {
65 let open = snapshot.openCount(at: entry.date)
66 let overdue = snapshot.overdueCount(at: entry.date)
67 return HStack(alignment: .firstTextBaseline, spacing: 6) {
68 Text(entry.date, format: family == .systemSmall ? .dateTime.weekday(.abbreviated).day() : .dateTime.weekday(.wide).day().month())
69 .font(.subheadline.weight(.semibold))
70 .foregroundStyle(snapshot.color("agenda-today", scheme) ?? .accentColor)
71 Spacer(minLength: 0)
72 if overdue > 0, family != .systemSmall {
73 Text("\(overdue) overdue")
74 .font(.caption2.weight(.semibold))
75 .foregroundStyle(snapshot.day(at: entry.date)?.overdue.first?.statusColor?.color(scheme) ?? .red)
76 }
77 Text(family == .systemSmall ? "\(open)" : "\(open) open")
78 .font(.caption2.weight(.semibold))
79 .foregroundStyle(.secondary)
80 }
81 }
82
83 @ViewBuilder
84 private func rows(_ rows: [AgendaSnapshot.Row], _ snapshot: AgendaSnapshot, compact: Bool, empty: String) -> some View {
85 if rows.isEmpty {
86 Text(empty).font(.caption).foregroundStyle(.secondary)
87 }
88 ForEach(rows) { row in
89 if compact {
90 SmallRow(row: row)
91 } else if let link = row.link {
92 Link(destination: link.url) { WideRow(row: row) }
93 } else {
94 WideRow(row: row)
95 }
96 }
97 }
98}
99
100/// The gutter over the title.
101struct SmallRow: View {
102 let row: AgendaSnapshot.Row
103 @Environment(\.colorScheme) private var scheme
104
105 var body: some View {
106 VStack(alignment: .leading, spacing: 0) {
107 Text(row.gutter)
108 .font(.caption2.weight(.medium).monospacedDigit())
109 .foregroundStyle(row.statusColor?.color(scheme) ?? .secondary)
110 Text(row.title).font(.caption).lineLimit(1)
111 }
112 }
113}
114
115/// The gutter, keyword and priority badges, the title and the category's dot.
116struct WideRow: View {
117 let row: AgendaSnapshot.Row
118 @Environment(\.colorScheme) private var scheme
119
120 var body: some View {
121 HStack(spacing: 6) {
122 Text(row.gutter)
123 .font(.caption2.weight(.medium).monospacedDigit())
124 .foregroundStyle(row.statusColor?.color(scheme) ?? .secondary)
125 .lineLimit(1)
126 .frame(width: 72, alignment: .leading)
127 if let todo = row.todo {
128 let color = row.todoColor?.color(scheme) ?? .secondary
129 Text(todo)
130 .font(.system(size: 9, weight: .bold))
131 .foregroundStyle(color)
132 .padding(.horizontal, 4)
133 .padding(.vertical, 1)
134 .background(color.opacity(0.14), in: Capsule())
135 }
136 if let priority = row.priority {
137 let color = row.priorityColor?.color(scheme) ?? .orange
138 Text(priority)
139 .font(.system(size: 9, weight: .bold))
140 .foregroundStyle(color)
141 .frame(width: 14, height: 14)
142 .overlay(Circle().strokeBorder(color, lineWidth: 1))
143 }
144 Text(row.title).font(.caption).lineLimit(1)
145 Spacer(minLength: 0)
146 Circle().fill(row.categoryColor?.color(scheme) ?? .secondary).frame(width: 6, height: 6)
147 }
148 }
149}
150
151#Preview("Small", as: .systemSmall) {
152 TodayWidget()
153} timeline: {
154 AgendaEntry(date: .now, snapshot: .sample(.now))
155}
156
157#Preview("Medium", as: .systemMedium) {
158 TodayWidget()
159} timeline: {
160 AgendaEntry(date: .now, snapshot: .sample(.now))
161}
162
163#Preview("Large", as: .systemLarge) {
164 TodayWidget()
165} timeline: {
166 AgendaEntry(date: .now, snapshot: .sample(.now))
167 AgendaEntry(date: .now, snapshot: nil)
168}
Sources/OrgstarWidgets/UpNextWidget.swift added +83
@@ -0,0 +1,83 @@
1import OrgApp
2import SwiftUI
3import WidgetKit
4
5/// The agenda on the Lock Screen: the next entry (rectangular), the next entry or the count
6/// (inline), today's open entries (circular).
7struct UpNextWidget: Widget {
8 var body: some WidgetConfiguration {
9 StaticConfiguration(kind: "sh.krz.orgstar.up-next", provider: AgendaProvider()) { entry in
10 UpNextView(entry: entry)
11 }
12 .configurationDisplayName("Up Next")
13 .description("The next agenda entry, or how many are open today.")
14 .supportedFamilies([.accessoryRectangular, .accessoryInline, .accessoryCircular])
15 }
16}
17
18struct UpNextView: View {
19 let entry: AgendaEntry
20 @Environment(\.widgetFamily) private var family
21
22 private var next: AgendaSnapshot.Row? { entry.snapshot?.upcoming(at: entry.date).first }
23 private var open: Int { entry.snapshot?.openCount(at: entry.date) ?? 0 }
24
25 var body: some View {
26 content
27 .widgetURL((next?.link ?? .agenda).url)
28 .containerBackground(for: .widget) { Color.clear }
29 }
30
31 @ViewBuilder
32 private var content: some View {
33 switch family {
34 case .accessoryInline:
35 if let next {
36 Text("\(next.gutter) \(next.title)")
37 } else {
38 Text(open == 0 ? "Agenda clear" : "\(open) open today")
39 }
40 case .accessoryCircular:
41 ZStack {
42 AccessoryWidgetBackground()
43 VStack(spacing: -2) {
44 Text("\(open)").font(.title2.weight(.semibold)).widgetAccentable()
45 Text("open").font(.caption2)
46 }
47 }
48 .accessibilityLabel("\(open) open today")
49 default:
50 if let next {
51 VStack(alignment: .leading, spacing: 0) {
52 Text(next.gutter).font(.headline).widgetAccentable().lineLimit(1)
53 Text(next.title).font(.body).lineLimit(2)
54 }
55 .frame(maxWidth: .infinity, alignment: .leading)
56 } else {
57 VStack(alignment: .leading, spacing: 0) {
58 Text("Agenda").font(.headline).widgetAccentable()
59 Text(entry.snapshot == nil ? "Open Orgstar" : "Nothing left today").font(.body)
60 }
61 .frame(maxWidth: .infinity, alignment: .leading)
62 }
63 }
64 }
65}
66
67#Preview("Rectangular", as: .accessoryRectangular) {
68 UpNextWidget()
69} timeline: {
70 AgendaEntry(date: .now, snapshot: .sample(.now))
71}
72
73#Preview("Inline", as: .accessoryInline) {
74 UpNextWidget()
75} timeline: {
76 AgendaEntry(date: .now, snapshot: .sample(.now))
77}
78
79#Preview("Circular", as: .accessoryCircular) {
80 UpNextWidget()
81} timeline: {
82 AgendaEntry(date: .now, snapshot: .sample(.now))
83}
ios/Orgstar.xcodeproj/project.pbxproj +134
@@ -9,6 +9,8 @@
99/* Begin PBXBuildFile section */
1010 1B78003BBCE8A4B809333342 /* OrgApp in Frameworks */ = {isa = PBXBuildFile; productRef = A2BE626BBE45EA52880B6169 /* OrgApp */; };
1111 1E5861C0EFE1D96CDC21A22F /* OrgApp in Frameworks */ = {isa = PBXBuildFile; productRef = BA239181876756F7732397EB /* OrgApp */; };
12 2BE799BF03ED43EAA6849F53 /* OrgApp in Frameworks */ = {isa = PBXBuildFile; productRef = EDEF22C5B4F393296F1D17BB /* OrgApp */; };
13 76BC65EF4BE629390064AE36 /* OrgstarWidgets.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = B54C32C5D364C02EE21DB092 /* OrgstarWidgets.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
1214 80E85E72A5B727A15D7123D4 /* OrgstarQuickLook.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 54F0339BC26341A6010C1386 /* OrgstarQuickLook.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
1315 9BE045FD696469CA8D19F22C /* OrgHighlight in Frameworks */ = {isa = PBXBuildFile; productRef = 47D54A361A74FE9E2B0722BB /* OrgHighlight */; };
1416 A05D351FCD8FE36B6A58E035 /* OrgstarShare.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D128CD70D4E88FAA82D23FD9 /* OrgstarShare.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
@@ -16,6 +18,13 @@
1618/* End PBXBuildFile section */
1719
1820/* Begin PBXContainerItemProxy section */
21 21312AB4CA947625620BE69C /* PBXContainerItemProxy */ = {
22 isa = PBXContainerItemProxy;
23 containerPortal = 46F86FAA6BBF9AC94A7E4595 /* Project object */;
24 proxyType = 1;
25 remoteGlobalIDString = E87BE20AFDC99FD25E1A163F;
26 remoteInfo = OrgstarWidgets;
27 };
1928 5932E50A667F73AEF6E5FB26 /* PBXContainerItemProxy */ = {
2029 isa = PBXContainerItemProxy;
2130 containerPortal = 46F86FAA6BBF9AC94A7E4595 /* Project object */;
@@ -41,6 +50,7 @@
4150 files = (
4251 A05D351FCD8FE36B6A58E035 /* OrgstarShare.appex in Embed Foundation Extensions */,
4352 80E85E72A5B727A15D7123D4 /* OrgstarQuickLook.appex in Embed Foundation Extensions */,
53 76BC65EF4BE629390064AE36 /* OrgstarWidgets.appex in Embed Foundation Extensions */,
4454 );
4555 name = "Embed Foundation Extensions";
4656 runOnlyForDeploymentPostprocessing = 0;
@@ -52,6 +62,9 @@
5262 1025FACEDEC31014F0AFA230 /* OrgstarShare/OrgstarShare.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OrgstarShare/OrgstarShare.entitlements; sourceTree = "<group>"; };
5363 48A21BB1AB1E70D4429DCDE4 /* OrgstarQuickLook/Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = OrgstarQuickLook/Info.plist; sourceTree = "<group>"; };
5464 54F0339BC26341A6010C1386 /* OrgstarQuickLook.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = OrgstarQuickLook.appex; sourceTree = BUILT_PRODUCTS_DIR; };
65 6C2E41672FBF640AB5554A2B /* OrgstarWidgets/Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = OrgstarWidgets/Info.plist; sourceTree = "<group>"; };
66 B54C32C5D364C02EE21DB092 /* OrgstarWidgets.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = OrgstarWidgets.appex; sourceTree = BUILT_PRODUCTS_DIR; };
67 C0AFAE84CB7F8B19772BF250 /* OrgstarWidgets/OrgstarWidgets.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OrgstarWidgets/OrgstarWidgets.entitlements; sourceTree = "<group>"; };
5568 D128CD70D4E88FAA82D23FD9 /* OrgstarShare.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = OrgstarShare.appex; sourceTree = BUILT_PRODUCTS_DIR; };
5669 D72184D78ACF70837216BCBF /* OrgstarShare/Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = OrgstarShare/Info.plist; sourceTree = "<group>"; };
5770 ECD4A6B56983444E4E07CE63 /* Orgstar.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Orgstar.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -97,6 +110,11 @@
97110 path = ../Sources/OrgstarMobile;
98111 sourceTree = "<group>";
99112 };
113 DE99BDA1BB90EEDFA8FF4CC2 /* ../Sources/OrgstarWidgets */ = {
114 isa = PBXFileSystemSynchronizedRootGroup;
115 path = ../Sources/OrgstarWidgets;
116 sourceTree = "<group>";
117 };
100118/* End PBXFileSystemSynchronizedRootGroup section */
101119
102120/* Begin PBXFrameworksBuildPhase section */
@@ -125,6 +143,14 @@
125143 );
126144 runOnlyForDeploymentPostprocessing = 0;
127145 };
146 AE22603FB5DE3C5FFFBBC68E /* Frameworks */ = {
147 isa = PBXFrameworksBuildPhase;
148 buildActionMask = 2147483647;
149 files = (
150 2BE799BF03ED43EAA6849F53 /* OrgApp in Frameworks */,
151 );
152 runOnlyForDeploymentPostprocessing = 0;
153 };
128154/* End PBXFrameworksBuildPhase section */
129155
130156/* Begin PBXGroup section */
@@ -134,6 +160,7 @@
134160 ECD4A6B56983444E4E07CE63 /* Orgstar.app */,
135161 D128CD70D4E88FAA82D23FD9 /* OrgstarShare.appex */,
136162 54F0339BC26341A6010C1386 /* OrgstarQuickLook.appex */,
163 B54C32C5D364C02EE21DB092 /* OrgstarWidgets.appex */,
137164 );
138165 name = Products;
139166 sourceTree = "<group>";
@@ -144,6 +171,7 @@
144171 6425CB8F177EDFF8EE2BD447 /* ../Sources/OrgstarShare */,
145172 2412EC8ED6427B76498FCD18 /* ../Sources/OrgstarQuickLook */,
146173 7E85FA5E5BA11D0F6891693E /* ../Sources/OrgstarMobile */,
174 DE99BDA1BB90EEDFA8FF4CC2 /* ../Sources/OrgstarWidgets */,
147175 40FCC6CF7BFC065FCDD48D4E /* Support */,
148176 0A2C978E52A76F0AA9F68BB5 /* Products */,
149177 );
@@ -157,6 +185,8 @@
157185 D72184D78ACF70837216BCBF /* OrgstarShare/Info.plist */,
158186 1025FACEDEC31014F0AFA230 /* OrgstarShare/OrgstarShare.entitlements */,
159187 48A21BB1AB1E70D4429DCDE4 /* OrgstarQuickLook/Info.plist */,
188 6C2E41672FBF640AB5554A2B /* OrgstarWidgets/Info.plist */,
189 C0AFAE84CB7F8B19772BF250 /* OrgstarWidgets/OrgstarWidgets.entitlements */,
160190 );
161191 name = Support;
162192 sourceTree = "<group>";
@@ -178,6 +208,7 @@
178208 dependencies = (
179209 7F4807D68646366ED2DCA5C2 /* PBXTargetDependency */,
180210 B35F6E044645C7D88B689DC1 /* PBXTargetDependency */,
211 D82DF00DA5607ABDDF199065 /* PBXTargetDependency */,
181212 );
182213 fileSystemSynchronizedGroups = (
183214 7E85FA5E5BA11D0F6891693E /* ../Sources/OrgstarMobile */,
@@ -237,6 +268,29 @@
237268 productReference = 54F0339BC26341A6010C1386 /* OrgstarQuickLook.appex */;
238269 productType = "com.apple.product-type.app-extension";
239270 };
271 E87BE20AFDC99FD25E1A163F /* OrgstarWidgets */ = {
272 isa = PBXNativeTarget;
273 buildConfigurationList = 14080276016DB67528B057D6 /* Build configuration list for PBXNativeTarget "OrgstarWidgets" */;
274 buildPhases = (
275 296E85448BDDDD3245D3D432 /* Sources */,
276 AE22603FB5DE3C5FFFBBC68E /* Frameworks */,
277 EA6C64E8D42ADCFBC3B131FF /* Resources */,
278 );
279 buildRules = (
280 );
281 dependencies = (
282 );
283 fileSystemSynchronizedGroups = (
284 DE99BDA1BB90EEDFA8FF4CC2 /* ../Sources/OrgstarWidgets */,
285 );
286 name = OrgstarWidgets;
287 packageProductDependencies = (
288 EDEF22C5B4F393296F1D17BB /* OrgApp */,
289 );
290 productName = OrgstarWidgets;
291 productReference = B54C32C5D364C02EE21DB092 /* OrgstarWidgets.appex */;
292 productType = "com.apple.product-type.app-extension";
293 };
240294/* End PBXNativeTarget section */
241295
242296/* Begin PBXProject section */
@@ -267,6 +321,7 @@
267321 4E815AD2268DF19F304A2880 /* Orgstar iOS */,
268322 92364A1473ECC9B162FEAE51 /* OrgstarShare */,
269323 BBA37636EB6BBA564493899D /* OrgstarQuickLook */,
324 E87BE20AFDC99FD25E1A163F /* OrgstarWidgets */,
270325 );
271326 };
272327/* End PBXProject section */
@@ -293,9 +348,23 @@
293348 );
294349 runOnlyForDeploymentPostprocessing = 0;
295350 };
351 EA6C64E8D42ADCFBC3B131FF /* Resources */ = {
352 isa = PBXResourcesBuildPhase;
353 buildActionMask = 2147483647;
354 files = (
355 );
356 runOnlyForDeploymentPostprocessing = 0;
357 };
296358/* End PBXResourcesBuildPhase section */
297359
298360/* Begin PBXSourcesBuildPhase section */
361 296E85448BDDDD3245D3D432 /* Sources */ = {
362 isa = PBXSourcesBuildPhase;
363 buildActionMask = 2147483647;
364 files = (
365 );
366 runOnlyForDeploymentPostprocessing = 0;
367 };
299368 347F295A9254F751A96C2737 /* Sources */ = {
300369 isa = PBXSourcesBuildPhase;
301370 buildActionMask = 2147483647;
@@ -330,6 +399,11 @@
330399 target = BBA37636EB6BBA564493899D /* OrgstarQuickLook */;
331400 targetProxy = D0655711FB3B470A356B2D36 /* PBXContainerItemProxy */;
332401 };
402 D82DF00DA5607ABDDF199065 /* PBXTargetDependency */ = {
403 isa = PBXTargetDependency;
404 target = E87BE20AFDC99FD25E1A163F /* OrgstarWidgets */;
405 targetProxy = 21312AB4CA947625620BE69C /* PBXContainerItemProxy */;
406 };
333407/* End PBXTargetDependency section */
334408
335409/* Begin XCBuildConfiguration section */
@@ -419,6 +493,29 @@
419493 };
420494 name = Release;
421495 };
496 7BCEB4BC70BB3B62775CDCFB /* Debug */ = {
497 isa = XCBuildConfiguration;
498 buildSettings = {
499 CODE_SIGN_ENTITLEMENTS = OrgstarWidgets/OrgstarWidgets.entitlements;
500 CODE_SIGN_STYLE = Automatic;
501 CURRENT_PROJECT_VERSION = 1;
502 DEVELOPMENT_TEAM = ZCNAX3VL9D;
503 GENERATE_INFOPLIST_FILE = NO;
504 INFOPLIST_FILE = OrgstarWidgets/Info.plist;
505 IPHONEOS_DEPLOYMENT_TARGET = 26.0;
506 LD_RUNPATH_SEARCH_PATHS = (
507 "$(inherited)",
508 "@executable_path/Frameworks",
509 "@executable_path/../../Frameworks",
510 );
511 MARKETING_VERSION = 0.1.0;
512 PRODUCT_BUNDLE_IDENTIFIER = sh.krz.orgstar.widgets;
513 PRODUCT_NAME = "$(TARGET_NAME)";
514 SKIP_INSTALL = YES;
515 TARGETED_DEVICE_FAMILY = "1,2";
516 };
517 name = Debug;
518 };
422519 942C95A5D90B164020736D83 /* Debug */ = {
423520 isa = XCBuildConfiguration;
424521 buildSettings = {
@@ -478,6 +575,29 @@
478575 };
479576 name = Debug;
480577 };
578 E2365A4C43B017487EC51861 /* Release */ = {
579 isa = XCBuildConfiguration;
580 buildSettings = {
581 CODE_SIGN_ENTITLEMENTS = OrgstarWidgets/OrgstarWidgets.entitlements;
582 CODE_SIGN_STYLE = Automatic;
583 CURRENT_PROJECT_VERSION = 1;
584 DEVELOPMENT_TEAM = ZCNAX3VL9D;
585 GENERATE_INFOPLIST_FILE = NO;
586 INFOPLIST_FILE = OrgstarWidgets/Info.plist;
587 IPHONEOS_DEPLOYMENT_TARGET = 26.0;
588 LD_RUNPATH_SEARCH_PATHS = (
589 "$(inherited)",
590 "@executable_path/Frameworks",
591 "@executable_path/../../Frameworks",
592 );
593 MARKETING_VERSION = 0.1.0;
594 PRODUCT_BUNDLE_IDENTIFIER = sh.krz.orgstar.widgets;
595 PRODUCT_NAME = "$(TARGET_NAME)";
596 SKIP_INSTALL = YES;
597 TARGETED_DEVICE_FAMILY = "1,2";
598 };
599 name = Release;
600 };
481601 F25EF7827B5210B4D9103995 /* Debug */ = {
482602 isa = XCBuildConfiguration;
483603 buildSettings = {
@@ -501,6 +621,15 @@
501621/* End XCBuildConfiguration section */
502622
503623/* Begin XCConfigurationList section */
624 14080276016DB67528B057D6 /* Build configuration list for PBXNativeTarget "OrgstarWidgets" */ = {
625 isa = XCConfigurationList;
626 buildConfigurations = (
627 7BCEB4BC70BB3B62775CDCFB /* Debug */,
628 E2365A4C43B017487EC51861 /* Release */,
629 );
630 defaultConfigurationIsVisible = 0;
631 defaultConfigurationName = Release;
632 };
504633 30435AE6E633F256CC883684 /* Build configuration list for PBXProject "Orgstar" */ = {
505634 isa = XCConfigurationList;
506635 buildConfigurations = (
@@ -567,6 +696,11 @@
567696 package = A46A1BCE0B67C45BEC8F435B /* XCLocalSwiftPackageReference ".." */;
568697 productName = OrgApp;
569698 };
699 EDEF22C5B4F393296F1D17BB /* OrgApp */ = {
700 isa = XCSwiftPackageProductDependency;
701 package = A46A1BCE0B67C45BEC8F435B /* XCLocalSwiftPackageReference ".." */;
702 productName = OrgApp;
703 };
570704/* End XCSwiftPackageProductDependency section */
571705 };
572706 rootObject = 46F86FAA6BBF9AC94A7E4595 /* Project object */;
ios/OrgstarWidgets/Info.plist added +25
@@ -0,0 +1,25 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3<plist version="1.0">
4<dict>
5 <key>CFBundleIdentifier</key>
6 <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
7 <key>CFBundleName</key>
8 <string>$(PRODUCT_NAME)</string>
9 <key>CFBundleDisplayName</key>
10 <string>Orgstar</string>
11 <key>CFBundleExecutable</key>
12 <string>$(EXECUTABLE_NAME)</string>
13 <key>CFBundlePackageType</key>
14 <string>XPC!</string>
15 <key>CFBundleShortVersionString</key>
16 <string>$(MARKETING_VERSION)</string>
17 <key>CFBundleVersion</key>
18 <string>$(CURRENT_PROJECT_VERSION)</string>
19 <key>NSExtension</key>
20 <dict>
21 <key>NSExtensionPointIdentifier</key>
22 <string>com.apple.widgetkit-extension</string>
23 </dict>
24</dict>
25</plist>
ios/OrgstarWidgets/OrgstarWidgets.entitlements added +8
@@ -0,0 +1,8 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3<plist version="1.0">
4<dict>
5 <key>com.apple.security.application-groups</key>
6 <array><string>group.sh.krz.orgstar</string></array>
7</dict>
8</plist>