macOS widgets
This commit is contained in:
parent
56bb319848
commit
26c704dc44
|
|
@ -9,6 +9,11 @@ import WidgetKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Intents
|
import Intents
|
||||||
|
|
||||||
|
extension String: Error {}
|
||||||
|
extension String: LocalizedError {
|
||||||
|
public var errorDescription: String? { return self }
|
||||||
|
}
|
||||||
|
|
||||||
extension Color {
|
extension Color {
|
||||||
init(hex: String) {
|
init(hex: String) {
|
||||||
let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
|
let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
|
||||||
|
|
@ -42,7 +47,8 @@ struct Provider: IntentTimelineProvider {
|
||||||
configuration: ConfigurationIntent(),
|
configuration: ConfigurationIntent(),
|
||||||
widgetData: WidgetData(url: "url", companyId: "", companies: [:], dateRanges: [:]),
|
widgetData: WidgetData(url: "url", companyId: "", companies: [:], dateRanges: [:]),
|
||||||
field: "Active Invoices",
|
field: "Active Invoices",
|
||||||
value: "$100.00")
|
value: "$100.00",
|
||||||
|
error: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSnapshot(for configuration: ConfigurationIntent,
|
func getSnapshot(for configuration: ConfigurationIntent,
|
||||||
|
|
@ -53,7 +59,8 @@ struct Provider: IntentTimelineProvider {
|
||||||
configuration: configuration,
|
configuration: configuration,
|
||||||
widgetData: WidgetData(url: "url", companyId: "", companies: [:], dateRanges: [:]),
|
widgetData: WidgetData(url: "url", companyId: "", companies: [:], dateRanges: [:]),
|
||||||
field: "Active Invoices",
|
field: "Active Invoices",
|
||||||
value: "$100.00")
|
value: "$100.00",
|
||||||
|
error: "")
|
||||||
|
|
||||||
completion(entry)
|
completion(entry)
|
||||||
}
|
}
|
||||||
|
|
@ -78,11 +85,8 @@ struct Provider: IntentTimelineProvider {
|
||||||
|
|
||||||
print("## VALUE: \(value)")
|
print("## VALUE: \(value)")
|
||||||
|
|
||||||
} catch WidgetError.message(let errorMessage) {
|
|
||||||
message = errorMessage;
|
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
message = "Unknown error"
|
message = "\(error)"
|
||||||
}
|
}
|
||||||
|
|
||||||
print("## getTimeline ERROR: \(message)")
|
print("## getTimeline ERROR: \(message)")
|
||||||
|
|
@ -92,7 +96,8 @@ struct Provider: IntentTimelineProvider {
|
||||||
configuration: configuration,
|
configuration: configuration,
|
||||||
widgetData: widgetData,
|
widgetData: widgetData,
|
||||||
field: label,
|
field: label,
|
||||||
value: value)
|
value: value,
|
||||||
|
error: message)
|
||||||
|
|
||||||
let nextUpdate = Calendar.current.date(
|
let nextUpdate = Calendar.current.date(
|
||||||
byAdding: DateComponents(minute: 15),
|
byAdding: DateComponents(minute: 15),
|
||||||
|
|
@ -114,12 +119,12 @@ struct Provider: IntentTimelineProvider {
|
||||||
|
|
||||||
|
|
||||||
if sharedDefaults == nil {
|
if sharedDefaults == nil {
|
||||||
throw WidgetError.message("Not connected")
|
throw "Not connected"
|
||||||
}
|
}
|
||||||
|
|
||||||
let shared = sharedDefaults!.string(forKey: "widget_data")
|
let shared = sharedDefaults!.string(forKey: "widget_data")
|
||||||
if shared == nil {
|
if shared == nil {
|
||||||
throw WidgetError.message("Not connected")
|
throw "Not connected"
|
||||||
}
|
}
|
||||||
//print("## Shared: \(shared!)")
|
//print("## Shared: \(shared!)")
|
||||||
|
|
||||||
|
|
@ -140,7 +145,7 @@ struct Provider: IntentTimelineProvider {
|
||||||
let currency = company?.currencies[currencyId!]
|
let currency = company?.currencies[currencyId!]
|
||||||
|
|
||||||
if (widgetData.url.isEmpty) {
|
if (widgetData.url.isEmpty) {
|
||||||
throw WidgetError.message("URL is blank")
|
throw "URL is blank"
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = widgetData.url + "/charts/totals_v2";
|
let url = widgetData.url + "/charts/totals_v2";
|
||||||
|
|
@ -160,7 +165,7 @@ struct Provider: IntentTimelineProvider {
|
||||||
//print("## URL: \(url)")
|
//print("## URL: \(url)")
|
||||||
|
|
||||||
if (token == "") {
|
if (token == "") {
|
||||||
throw WidgetError.message("API token is blank")
|
throw "API token is blank"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -308,6 +313,7 @@ struct SimpleEntry: TimelineEntry {
|
||||||
let widgetData: WidgetData?
|
let widgetData: WidgetData?
|
||||||
let field: String
|
let field: String
|
||||||
let value: String
|
let value: String
|
||||||
|
let error: String
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DashboardWidgetEntryView : View {
|
struct DashboardWidgetEntryView : View {
|
||||||
|
|
@ -320,6 +326,9 @@ struct DashboardWidgetEntryView : View {
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
if (!entry.error.isEmpty) {
|
||||||
|
Text(entry.error)
|
||||||
|
} else {
|
||||||
ZStack {
|
ZStack {
|
||||||
Rectangle().fill(accentColor)
|
Rectangle().fill(accentColor)
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
|
|
@ -359,6 +368,7 @@ struct DashboardWidgetEntryView : View {
|
||||||
.padding(.all)
|
.padding(.all)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@main
|
@main
|
||||||
|
|
@ -381,7 +391,8 @@ struct DashboardWidget_Previews: PreviewProvider {
|
||||||
configuration: ConfigurationIntent(),
|
configuration: ConfigurationIntent(),
|
||||||
widgetData: WidgetData(url: "url", companyId: "", companies: [:], dateRanges: [:]),
|
widgetData: WidgetData(url: "url", companyId: "", companies: [:], dateRanges: [:]),
|
||||||
field: "Active Invoices",
|
field: "Active Invoices",
|
||||||
value: "$100.00")
|
value: "$100.00",
|
||||||
|
error: "")
|
||||||
|
|
||||||
DashboardWidgetEntryView(entry: entry)
|
DashboardWidgetEntryView(entry: entry)
|
||||||
.previewContext(WidgetPreviewContext(family: .systemSmall))
|
.previewContext(WidgetPreviewContext(family: .systemSmall))
|
||||||
|
|
@ -452,9 +463,7 @@ struct ApiResultError: Codable {
|
||||||
let errors: [String: String]
|
let errors: [String: String]
|
||||||
}
|
}
|
||||||
|
|
||||||
enum WidgetError: Error {
|
|
||||||
case message(String)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ApiService {
|
struct ApiService {
|
||||||
|
|
||||||
|
|
@ -482,11 +491,11 @@ struct ApiService {
|
||||||
} else {
|
} else {
|
||||||
let result = try JSONDecoder().decode(ApiResultError.self, from: data)
|
let result = try JSONDecoder().decode(ApiResultError.self, from: data)
|
||||||
|
|
||||||
throw WidgetError.message("\(statusCode): \(result.message)")
|
throw "\(statusCode): \(result.message)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
throw WidgetError.message("\(error)")
|
throw "\(error)"
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue