macOS widgets

This commit is contained in:
Hillel Coren 2023-06-27 17:01:04 +03:00
parent cbfc96ee4b
commit f72614a2f1
1 changed files with 134 additions and 114 deletions

View File

@ -66,31 +66,34 @@ struct Provider: IntentTimelineProvider {
Task { Task {
var rawValue = 0.0
var value = "Error"
var label = ""
let sharedDefaults = UserDefaults.init(suiteName: "group.com.invoiceninja.app") let sharedDefaults = UserDefaults.init(suiteName: "group.com.invoiceninja.app")
var widgetData: WidgetData? = nil var widgetData: WidgetData? = nil
if sharedDefaults == nil { if sharedDefaults != nil {
return
}
do { do {
let shared = sharedDefaults!.string(forKey: "widget_data") let shared = sharedDefaults!.string(forKey: "widget_data")
if shared == nil { if shared != nil {
return
}
//print("## Shared: \(shared!)") //print("## Shared: \(shared!)")
let decoder = JSONDecoder() let decoder = JSONDecoder()
widgetData = try decoder.decode(WidgetData.self, from: shared!.data(using: .utf8)!) widgetData = try decoder.decode(WidgetData.self, from: shared!.data(using: .utf8)!)
let companyId = configuration.company?.identifier ?? ""
let company = widgetData?.companies[companyId]
let currencyId = configuration.currency?.identifier ?? company?.currencyId
let currency = company?.currencies[currencyId!]
if (widgetData?.url == nil) { if (widgetData?.url == nil) {
return return
} }
let url = (widgetData?.url ?? "") + "/charts/totals_v2"; let url = (widgetData?.url ?? "") + "/charts/totals_v2";
let companyId = configuration.company?.identifier ?? ""
let company = widgetData?.companies[companyId]
var token = company?.token var token = company?.token
let (startDate, endDate) = getDateRange(dateRange: (configuration.dateRange?.identifier)!, let (startDate, endDate) = getDateRange(dateRange: (configuration.dateRange?.identifier)!,
firstMonthOfYear: company!.firstMonthOfYear) firstMonthOfYear: company!.firstMonthOfYear)
@ -110,34 +113,28 @@ struct Provider: IntentTimelineProvider {
return return
} }
guard let result = try? await ApiService.post(urlString: url,
let result = try await ApiService.post(urlString: url,
apiToken: token!, apiToken: token!,
startDate: startDate, startDate: startDate,
endDate: endDate) else { endDate: endDate)!
return
}
let currencyId = configuration.currency?.identifier ?? company?.currencyId
let currency = company?.currencies[currencyId!]
var value = 0.0
var label = ""
let data = result[currencyId ?? "1"] let data = result[currencyId ?? "1"]
if (data != nil) { if (data != nil) {
if (configuration.field == Field.active_invoices) { if (configuration.field == Field.active_invoices) {
if (data?.invoices?.invoicedAmount != nil) { if (data?.invoices?.invoicedAmount != nil) {
value = Double(data?.invoices?.invoicedAmount ?? "")! rawValue = Double(data?.invoices?.invoicedAmount ?? "")!
} }
label = "Active Invoices" label = "Active Invoices"
} else if (configuration.field == Field.outstanding_invoices) { } else if (configuration.field == Field.outstanding_invoices) {
if (data?.outstanding?.amount != nil) { if (data?.outstanding?.amount != nil) {
value = Double(data?.outstanding?.amount ?? "")! rawValue = Double(data?.outstanding?.amount ?? "")!
} }
label = "Outstanding Invoices" label = "Outstanding Invoices"
} else if (configuration.field == Field.completed_payments) { } else if (configuration.field == Field.completed_payments) {
if (data?.revenue?.paidToDate != nil) { if (data?.revenue?.paidToDate != nil) {
value = Double(data?.revenue?.paidToDate ?? "")! rawValue = Double(data?.revenue?.paidToDate ?? "")!
} }
label = "Completed Payments" label = "Completed Payments"
} }
@ -146,12 +143,23 @@ struct Provider: IntentTimelineProvider {
let formatter = NumberFormatter() let formatter = NumberFormatter()
formatter.numberStyle = .currency formatter.numberStyle = .currency
formatter.currencyCode = currency?.code ?? "USD" formatter.currencyCode = currency?.code ?? "USD"
value = formatter.string(from: NSNumber(value: rawValue))!
}
} catch {
print("## ERROR: \(error)")
//value = "\(error)"
}
}
print("## VALUE: \(value)")
let entry = SimpleEntry(date: Date(), let entry = SimpleEntry(date: Date(),
configuration: configuration, configuration: configuration,
widgetData: widgetData, widgetData: widgetData,
field: label, field: label,
value: formatter.string(from: NSNumber(value: value))!) value: value)
let nextUpdate = Calendar.current.date( let nextUpdate = Calendar.current.date(
byAdding: DateComponents(minute: 15), byAdding: DateComponents(minute: 15),
@ -164,14 +172,11 @@ struct Provider: IntentTimelineProvider {
) )
completion(timeline) completion(timeline)
} catch {
print(error)
}
} }
} }
func getDateRange(dateRange: String, firstMonthOfYear: Int = 1) -> (start: String, end: String) { func getDateRange(dateRange: String, firstMonthOfYear: Int = 1) -> (start: String, end: String) {
let today = Date() let today = Date()
@ -289,7 +294,7 @@ struct DashboardWidgetEntryView : View {
var accentColor: Color { var accentColor: Color {
let companyId = entry.configuration.company?.identifier ?? "" let companyId = entry.configuration.company?.identifier ?? ""
return Color(hex: (entry.widgetData?.companies[companyId]!.accentColor)!) return Color(hex: (entry.widgetData?.companies[companyId]?.accentColor ?? "#0000ff")!)
} }
var body: some View { var body: some View {
@ -362,7 +367,6 @@ struct DashboardWidget_Previews: PreviewProvider {
} }
} }
struct ApiResult: Codable { struct ApiResult: Codable {
let invoices: Invoices? let invoices: Invoices?
let revenue: Revenue? let revenue: Revenue?
@ -420,6 +424,14 @@ struct Expenses: Codable {
} }
} }
struct ApiResultError: Codable {
let message: String
let errors: [String: String]
}
enum ApiError: Error {
case message(String)
}
struct ApiService { struct ApiService {
@ -432,8 +444,11 @@ struct ApiService {
request.addValue("macOS Widget", forHTTPHeaderField: "X-CLIENT") request.addValue("macOS Widget", forHTTPHeaderField: "X-CLIENT")
do { do {
let (data, _) = try await URLSession.shared.data(for: request) let (data, response) = try await URLSession.shared.data(for: request)
if let httpResponse = response as? HTTPURLResponse {
let statusCode = httpResponse.statusCode
if statusCode >= 200 && statusCode < 300 {
//print("## Details WAS: \(String(describing: String(data: data, encoding: .utf8)))") //print("## Details WAS: \(String(describing: String(data: data, encoding: .utf8)))")
//print("## Details IS: \(String(describing: String(data: try! ApiService.fixData(data: data), encoding: .utf8)))") //print("## Details IS: \(String(describing: String(data: try! ApiService.fixData(data: data), encoding: .utf8)))")
@ -441,9 +456,14 @@ struct ApiService {
let result = try JSONDecoder().decode([String: ApiResult].self, from: ApiService.fixData(data: data)) let result = try JSONDecoder().decode([String: ApiResult].self, from: ApiService.fixData(data: data))
return result return result
} else {
let result = try JSONDecoder().decode(ApiResultError.self, from: data)
throw ApiError.message("\(statusCode): \(result.message)")
}
}
} catch { } catch {
print("Error: \(error)") throw ApiError.message("\(error)")
} }
return nil return nil