macOS widgets
This commit is contained in:
parent
d8aefa096e
commit
8f6e27cb77
|
|
@ -16,7 +16,7 @@ class WidgetData {
|
|||
this.companies,
|
||||
this.companyId,
|
||||
this.dateRanges,
|
||||
this.fields,
|
||||
this.dashboardFields,
|
||||
});
|
||||
|
||||
WidgetData.fromState(AppState state, AppLocalization localization)
|
||||
|
|
@ -30,7 +30,7 @@ class WidgetData {
|
|||
staticState: state.staticState,
|
||||
)
|
||||
},
|
||||
fields = Map.fromIterable(<String>[
|
||||
dashboardFields = Map.fromIterable(<String>[
|
||||
DashboardUISettings.FIELD_ACTIVE_INVOICES,
|
||||
DashboardUISettings.FIELD_OUTSTANDING_INVOICES,
|
||||
DashboardUISettings.FIELD_COMPLETED_PAYMENTS,
|
||||
|
|
@ -47,21 +47,21 @@ class WidgetData {
|
|||
companyId = json['company_id'],
|
||||
companies = json['companies'],
|
||||
dateRanges = json['date_ranges'],
|
||||
fields = json['fields'];
|
||||
dashboardFields = json['dashboard_fields'];
|
||||
|
||||
Map<String, dynamic> toJson() => <String, dynamic>{
|
||||
'companies': companies,
|
||||
'company_id': companyId,
|
||||
'url': url,
|
||||
'date_ranges': dateRanges,
|
||||
'fields': fields,
|
||||
'dashboard_Fields': dashboardFields,
|
||||
};
|
||||
|
||||
final String url;
|
||||
final String companyId;
|
||||
final Map<String, WidgetCompany> companies;
|
||||
final Map<String, String> dateRanges;
|
||||
final Map<String, String> fields;
|
||||
final Map<String, String> dashboardFields;
|
||||
}
|
||||
|
||||
class WidgetCompany {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ import Intents
|
|||
class IntentHandler: INExtension, ConfigurationIntentHandling {
|
||||
private func loadWidgetData() -> WidgetData {
|
||||
let sharedDefaults = UserDefaults(suiteName: "group.com.invoiceninja.app")
|
||||
var widgetData: WidgetData = WidgetData(url: "", companyId: "", companies: [:], dateRanges: [:], fields: [:])
|
||||
var widgetData: WidgetData = WidgetData(url: "",
|
||||
companyId: "",
|
||||
companies: [:],
|
||||
dateRanges: [:],
|
||||
dashboardFields: [:])
|
||||
|
||||
if let sharedDefaults = sharedDefaults {
|
||||
do {
|
||||
|
|
@ -71,7 +75,24 @@ class IntentHandler: INExtension, ConfigurationIntentHandling {
|
|||
return DateRange(identifier: defaultDateRange, display: dateRamge)
|
||||
}
|
||||
|
||||
|
||||
func provideDashboardFieldOptionsCollection(for intent: ConfigurationIntent) async throws -> INObjectCollection<DashboardField> {
|
||||
let widgetData = loadWidgetData()
|
||||
|
||||
|
||||
let fields = widgetData.dashboardFields.keys.sorted().map { field in
|
||||
DashboardField(identifier: field, display: widgetData.dashboardFields[field]!)
|
||||
}
|
||||
|
||||
return INObjectCollection(items: fields)
|
||||
}
|
||||
|
||||
func defaultDashboardField(for intent: ConfigurationIntent) -> DashboardField? {
|
||||
let widgetData = loadWidgetData()
|
||||
let defaultField = "total_active_invoices";
|
||||
let field = widgetData.dashboardFields[defaultField]!;
|
||||
return DashboardField(identifier: defaultField, display: field)
|
||||
}
|
||||
|
||||
override func handler(for intent: INIntent) -> Any {
|
||||
return self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,67 +3,13 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>INEnums</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INEnumDisplayName</key>
|
||||
<string>Field</string>
|
||||
<key>INEnumDisplayNameID</key>
|
||||
<string>a7k58J</string>
|
||||
<key>INEnumGeneratesHeader</key>
|
||||
<true/>
|
||||
<key>INEnumName</key>
|
||||
<string>Field</string>
|
||||
<key>INEnumType</key>
|
||||
<string>Regular</string>
|
||||
<key>INEnumValues</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INEnumValueDisplayName</key>
|
||||
<string>unknown</string>
|
||||
<key>INEnumValueDisplayNameID</key>
|
||||
<string>lwYuqc</string>
|
||||
<key>INEnumValueName</key>
|
||||
<string>unknown</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INEnumValueDisplayName</key>
|
||||
<string>Active Invoices</string>
|
||||
<key>INEnumValueDisplayNameID</key>
|
||||
<string>z5NmCf</string>
|
||||
<key>INEnumValueIndex</key>
|
||||
<integer>1</integer>
|
||||
<key>INEnumValueName</key>
|
||||
<string>active_invoices</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INEnumValueDisplayName</key>
|
||||
<string>Outstanding Invoices</string>
|
||||
<key>INEnumValueDisplayNameID</key>
|
||||
<string>KMErB0</string>
|
||||
<key>INEnumValueIndex</key>
|
||||
<integer>2</integer>
|
||||
<key>INEnumValueName</key>
|
||||
<string>outstanding_invoices</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INEnumValueDisplayName</key>
|
||||
<string>Completed Payments</string>
|
||||
<key>INEnumValueDisplayNameID</key>
|
||||
<string>HEngYv</string>
|
||||
<key>INEnumValueIndex</key>
|
||||
<integer>3</integer>
|
||||
<key>INEnumValueName</key>
|
||||
<string>completed_payments</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<array/>
|
||||
<key>INIntentDefinitionModelVersion</key>
|
||||
<string>1.2</string>
|
||||
<key>INIntentDefinitionNamespace</key>
|
||||
<string>88xZPY</string>
|
||||
<key>INIntentDefinitionSystemVersion</key>
|
||||
<string>21G115</string>
|
||||
<string>21G651</string>
|
||||
<key>INIntentDefinitionToolsBuildVersion</key>
|
||||
<string>14C18</string>
|
||||
<key>INIntentDefinitionToolsVersion</key>
|
||||
|
|
@ -80,7 +26,7 @@
|
|||
<key>INIntentIneligibleForSuggestions</key>
|
||||
<true/>
|
||||
<key>INIntentLastParameterTag</key>
|
||||
<integer>11</integer>
|
||||
<integer>12</integer>
|
||||
<key>INIntentName</key>
|
||||
<string>Configuration</string>
|
||||
<key>INIntentParameters</key>
|
||||
|
|
@ -168,17 +114,12 @@
|
|||
<string>t2MezO</string>
|
||||
<key>INIntentParameterDisplayPriority</key>
|
||||
<integer>3</integer>
|
||||
<key>INIntentParameterEnumType</key>
|
||||
<string>Field</string>
|
||||
<key>INIntentParameterEnumTypeNamespace</key>
|
||||
<string>88xZPY</string>
|
||||
<key>INIntentParameterMetadata</key>
|
||||
<dict>
|
||||
<key>INIntentParameterMetadataDefaultValue</key>
|
||||
<string>active_invoices</string>
|
||||
</dict>
|
||||
<key>INIntentParameterName</key>
|
||||
<string>field</string>
|
||||
<string>dashboardField</string>
|
||||
<key>INIntentParameterObjectType</key>
|
||||
<string>DashboardField</string>
|
||||
<key>INIntentParameterObjectTypeNamespace</key>
|
||||
<string>88xZPY</string>
|
||||
<key>INIntentParameterPromptDialogs</key>
|
||||
<array>
|
||||
<dict>
|
||||
|
|
@ -197,7 +138,7 @@
|
|||
<key>INIntentParameterPromptDialogCustom</key>
|
||||
<true/>
|
||||
<key>INIntentParameterPromptDialogFormatString</key>
|
||||
<string>There are ${count} options matching ‘${field}’.</string>
|
||||
<string>There are ${count} options matching ‘${dashboardField}’.</string>
|
||||
<key>INIntentParameterPromptDialogFormatStringID</key>
|
||||
<string>3UOOUA</string>
|
||||
<key>INIntentParameterPromptDialogType</key>
|
||||
|
|
@ -207,17 +148,19 @@
|
|||
<key>INIntentParameterPromptDialogCustom</key>
|
||||
<true/>
|
||||
<key>INIntentParameterPromptDialogFormatString</key>
|
||||
<string>Just to confirm, you wanted ‘${field}’?</string>
|
||||
<string>Just to confirm, you wanted ‘${dashboardField}’?</string>
|
||||
<key>INIntentParameterPromptDialogFormatStringID</key>
|
||||
<string>4sG08t</string>
|
||||
<key>INIntentParameterPromptDialogType</key>
|
||||
<string>Confirmation</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>INIntentParameterSupportsDynamicEnumeration</key>
|
||||
<true/>
|
||||
<key>INIntentParameterTag</key>
|
||||
<integer>2</integer>
|
||||
<integer>12</integer>
|
||||
<key>INIntentParameterType</key>
|
||||
<string>Integer</string>
|
||||
<string>Object</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterConfigurable</key>
|
||||
|
|
@ -248,26 +191,6 @@
|
|||
<key>INIntentParameterPromptDialogType</key>
|
||||
<string>Primary</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterPromptDialogCustom</key>
|
||||
<true/>
|
||||
<key>INIntentParameterPromptDialogFormatString</key>
|
||||
<string>There are ${count} options matching ‘${dateRange}’.</string>
|
||||
<key>INIntentParameterPromptDialogFormatStringID</key>
|
||||
<string>M1c9EE</string>
|
||||
<key>INIntentParameterPromptDialogType</key>
|
||||
<string>DisambiguationIntroduction</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterPromptDialogCustom</key>
|
||||
<true/>
|
||||
<key>INIntentParameterPromptDialogFormatString</key>
|
||||
<string>Just to confirm, you wanted ‘${dateRange}’?</string>
|
||||
<key>INIntentParameterPromptDialogFormatStringID</key>
|
||||
<string>YL2DLe</string>
|
||||
<key>INIntentParameterPromptDialogType</key>
|
||||
<string>Confirmation</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>INIntentParameterSupportsDynamicEnumeration</key>
|
||||
<true/>
|
||||
|
|
@ -496,6 +419,69 @@
|
|||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INTypeDisplayName</key>
|
||||
<string>Field</string>
|
||||
<key>INTypeDisplayNameID</key>
|
||||
<string>VFh9Fr</string>
|
||||
<key>INTypeLastPropertyTag</key>
|
||||
<integer>99</integer>
|
||||
<key>INTypeName</key>
|
||||
<string>DashboardField</string>
|
||||
<key>INTypeProperties</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INTypePropertyDefault</key>
|
||||
<true/>
|
||||
<key>INTypePropertyDisplayPriority</key>
|
||||
<integer>1</integer>
|
||||
<key>INTypePropertyName</key>
|
||||
<string>identifier</string>
|
||||
<key>INTypePropertyTag</key>
|
||||
<integer>1</integer>
|
||||
<key>INTypePropertyType</key>
|
||||
<string>String</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INTypePropertyDefault</key>
|
||||
<true/>
|
||||
<key>INTypePropertyDisplayPriority</key>
|
||||
<integer>2</integer>
|
||||
<key>INTypePropertyName</key>
|
||||
<string>displayString</string>
|
||||
<key>INTypePropertyTag</key>
|
||||
<integer>2</integer>
|
||||
<key>INTypePropertyType</key>
|
||||
<string>String</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INTypePropertyDefault</key>
|
||||
<true/>
|
||||
<key>INTypePropertyDisplayPriority</key>
|
||||
<integer>3</integer>
|
||||
<key>INTypePropertyName</key>
|
||||
<string>pronunciationHint</string>
|
||||
<key>INTypePropertyTag</key>
|
||||
<integer>3</integer>
|
||||
<key>INTypePropertyType</key>
|
||||
<string>String</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INTypePropertyDefault</key>
|
||||
<true/>
|
||||
<key>INTypePropertyDisplayPriority</key>
|
||||
<integer>4</integer>
|
||||
<key>INTypePropertyName</key>
|
||||
<string>alternativeSpeakableMatches</string>
|
||||
<key>INTypePropertySupportsMultipleValues</key>
|
||||
<true/>
|
||||
<key>INTypePropertyTag</key>
|
||||
<integer>4</integer>
|
||||
<key>INTypePropertyType</key>
|
||||
<string>SpeakableString</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ struct Provider: IntentTimelineProvider {
|
|||
do {
|
||||
return try getWidgetData()
|
||||
} catch {
|
||||
return WidgetData(url: "url", companyId: "", companies: [:], dateRanges: [:], fields: [:])
|
||||
return WidgetData(url: "url", companyId: "", companies: [:], dateRanges: [:], dashboardFields: [:])
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
@ -74,7 +74,6 @@ struct Provider: IntentTimelineProvider {
|
|||
SimpleEntry(date: Date(),
|
||||
configuration: ConfigurationIntent(),
|
||||
widgetData: widgetData,
|
||||
field: "Active Invoices",
|
||||
value: "$100.00",
|
||||
error: "")
|
||||
}
|
||||
|
|
@ -86,7 +85,6 @@ struct Provider: IntentTimelineProvider {
|
|||
let entry = SimpleEntry(date: Date(),
|
||||
configuration: configuration,
|
||||
widgetData: widgetData,
|
||||
field: "Active Invoices",
|
||||
value: "$100.00",
|
||||
error: "")
|
||||
|
||||
|
|
@ -109,7 +107,7 @@ struct Provider: IntentTimelineProvider {
|
|||
do {
|
||||
widgetData = try getWidgetData()
|
||||
|
||||
(label, value) = try await getTimelineData(for: configuration, widgetData: widgetData!)
|
||||
value = try await getTimelineData(for: configuration, widgetData: widgetData!)
|
||||
|
||||
print("## VALUE: \(value)")
|
||||
|
||||
|
|
@ -123,7 +121,6 @@ struct Provider: IntentTimelineProvider {
|
|||
let entry = SimpleEntry(date: Date(),
|
||||
configuration: configuration,
|
||||
widgetData: widgetData,
|
||||
field: label,
|
||||
value: value,
|
||||
error: message)
|
||||
|
||||
|
|
@ -141,11 +138,10 @@ struct Provider: IntentTimelineProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func getTimelineData(for configuration: ConfigurationIntent, widgetData:WidgetData) async throws -> (String, String) {
|
||||
func getTimelineData(for configuration: ConfigurationIntent, widgetData:WidgetData) async throws -> (String) {
|
||||
|
||||
var rawValue = 0.0
|
||||
var value = "Error"
|
||||
var label = ""
|
||||
|
||||
let companyId = configuration.company?.identifier ?? ""
|
||||
let company = widgetData.companies[companyId]
|
||||
|
|
@ -188,22 +184,19 @@ struct Provider: IntentTimelineProvider {
|
|||
throw "Data not found"
|
||||
}
|
||||
|
||||
switch configuration.field {
|
||||
case .active_invoices:
|
||||
switch configuration.dashboardField?.identifier {
|
||||
case "total_active_invoices":
|
||||
if let invoicedAmount = data?.invoices?.invoicedAmount, let value = Double(invoicedAmount) {
|
||||
rawValue = value
|
||||
}
|
||||
label = "Active Invoices"
|
||||
case .outstanding_invoices:
|
||||
case "total_outstanding_invoices":
|
||||
if let amount = data?.outstanding?.amount, let value = Double(amount) {
|
||||
rawValue = value
|
||||
}
|
||||
label = "Outstanding Invoices"
|
||||
case .completed_payments:
|
||||
case "total_completed_payments":
|
||||
if let paidToDate = data?.revenue?.paidToDate, let value = Double(paidToDate) {
|
||||
rawValue = value
|
||||
}
|
||||
label = "Completed Payments"
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
|
@ -214,7 +207,7 @@ struct Provider: IntentTimelineProvider {
|
|||
formatter.currencyCode = currency?.code ?? "USD"
|
||||
value = formatter.string(from: NSNumber(value: rawValue))!
|
||||
|
||||
return (label, value)
|
||||
return value
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -278,14 +271,14 @@ struct WidgetData: Decodable, Hashable {
|
|||
let companyId: String
|
||||
let companies: [String: WidgetCompany]
|
||||
let dateRanges: [String: String]
|
||||
let fields: [String: String]
|
||||
let dashboardFields: [String: String]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case url
|
||||
case companyId = "company_id"
|
||||
case companies
|
||||
case dateRanges = "date_ranges"
|
||||
case fields
|
||||
case dashboardFields = "dashboard_fields"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -327,7 +320,6 @@ struct SimpleEntry: TimelineEntry {
|
|||
let date: Date
|
||||
let configuration: ConfigurationIntent
|
||||
let widgetData: WidgetData?
|
||||
let field: String
|
||||
let value: String
|
||||
let error: String
|
||||
}
|
||||
|
|
@ -358,7 +350,7 @@ struct DashboardWidgetEntryView : View {
|
|||
|
||||
HStack {
|
||||
VStack {
|
||||
Text(entry.field)
|
||||
Text(entry.configuration.dashboardField?.displayString ?? "")
|
||||
.font(.body)
|
||||
.bold()
|
||||
.lineLimit(2)
|
||||
|
|
@ -413,7 +405,11 @@ struct DashboardWidget_Previews: PreviewProvider {
|
|||
do {
|
||||
return try getWidgetData()
|
||||
} catch {
|
||||
return WidgetData(url: "url", companyId: "", companies: [:], dateRanges: [:], fields: [:])
|
||||
return WidgetData(url: "url",
|
||||
companyId: "",
|
||||
companies: [:],
|
||||
dateRanges: [:],
|
||||
dashboardFields: [:])
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
@ -421,7 +417,6 @@ struct DashboardWidget_Previews: PreviewProvider {
|
|||
let entry = SimpleEntry(date: Date(),
|
||||
configuration: ConfigurationIntent(),
|
||||
widgetData: widgetData,
|
||||
field: "Active Invoices",
|
||||
value: "$100.00",
|
||||
error: "")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue