-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathRecordersWidget.swift
123 lines (106 loc) · 4.23 KB
/
RecordersWidget.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//
// RecordersWidget.swift
// RecordersWidget
//
// Created by Matt Greenfield on 28/6/20.
// Copyright © 2020 Matt Greenfield. All rights reserved.
//
import WidgetKit
import SwiftUI
import LocoKit
struct Provider: TimelineProvider {
public typealias Entry = SimpleEntry
func placeholder(in context: Context) -> SimpleEntry {
return SimpleEntry(date: Date())
}
public func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date())
completion(entry)
}
public func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let entries: [SimpleEntry] = [SimpleEntry(date: Date())]
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct SimpleEntry: TimelineEntry {
public let date: Date
}
struct RecordersWidgetEntryView: View {
@Environment(\.widgetFamily) var family
var entry: Provider.Entry
let appGroup = AppGroup(appName: .arcMini, suiteName: "group.ArcApp", readOnly: true)
var body: some View {
ZStack(alignment: .top) {
VStack(alignment: .leading) {
HStack {
Text("Arc Recorders").font(.system(size: 14, weight: .semibold))
.frame(height: 28)
}
ForEach(appGroup.apps.values.sorted { $0.appName.sortIndex < $1.appName.sortIndex }, id: \.updated) { appState in
if appState.isAlive || family == .systemSmall {
self.row(
leftText: appState.isAlive ? Text(appState.recordingState.rawValue) : Text("dead"),
rightText: Text(appState.appName.rawValue),
isActiveRecorder: appState.isAliveAndRecording, isAlive: appState.isAlive
).frame(height: 28)
} else {
self.row(
leftText: Text("dead (") + Text(appState.updated, style: .relative) + Text(" ago)"),
rightText: Text(appState.appName.rawValue),
isActiveRecorder: appState.isAliveAndRecording, isAlive: false
).frame(height: 28)
}
}
Spacer()
}
if appGroup.currentRecorder == nil {
HStack {
Spacer()
Image("warningIcon20").renderingMode(.template).foregroundColor(Color.red)
}
}
VStack {
Spacer()
Text(Date(), style: .relative)
.multilineTextAlignment(.center)
.font(.system(size: 8, weight: .regular))
.opacity(0.3)
}
}
.padding([.top, .leading, .trailing], 16)
.padding([.bottom], 4)
.widgetBackground(Color.clear)
}
func row(leftText: Text, rightText: Text, isActiveRecorder: Bool = false, isAlive: Bool = false) -> some View {
return HStack {
leftText.font(isActiveRecorder ? Font.system(.footnote).bold() : Font.system(.footnote)).opacity(isAlive ? 0.6 : 0.4)
Spacer()
rightText.font(Font.system(.footnote).bold())
// .opacity(isAlive ? 1 : 0.4)
}
}
}
@main
struct RecordersWidget: Widget {
private let kind: String = "RecordersWidget"
public var body: some WidgetConfiguration {
StaticConfiguration<RecordersWidgetEntryView>(kind: kind, provider: Provider()) { entry in
RecordersWidgetEntryView(entry: entry)
}
.configurationDisplayName("Arc Recorders")
.description("Status of Arc recorders.")
.supportedFamilies([.systemSmall])
.contentMarginsDisabled()
}
}
// workaround for iOS 17's required new background thing while still supporting iOS 16
extension View {
func widgetBackground(_ backgroundView: some View) -> some View {
if #available(iOSApplicationExtension 17.0, *) {
return containerBackground(for: .widget) { backgroundView }
} else {
return background(backgroundView)
}
}
}