macOS widgets

This commit is contained in:
Hillel Coren 2023-06-22 23:55:57 +03:00
parent efbf3cb73d
commit 5f819bd0b4
5 changed files with 174 additions and 20 deletions

View File

@ -9,6 +9,7 @@ import 'package:flutter/services.dart';
// Package imports:
import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'package:invoiceninja_flutter/data/models/dashboard_model.dart';
import 'package:invoiceninja_flutter/redux/auth/auth_actions.dart';
import 'package:invoiceninja_flutter/redux/reports/reports_actions.dart';
import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart';
@ -1405,20 +1406,27 @@ void _showAbout(BuildContext context) async {
),
]);
} else {
final json = jsonEncode(WidgetData(
url: formatApiUrl(state.authState.url),
companyId: state.account.defaultCompanyId,
dateRanges: Map.fromIterable(DateRange.values,
key: (dynamic item) => toSnakeCase('$item'),
value: (dynamic item) =>
localization.lookup('$item')),
companies: {
for (var userCompany in state.userCompanyStates
.where((state) => state.company.hasName))
userCompany.company.id:
WidgetCompany.fromUserCompany(
userCompanyState: userCompany,
staticState: state.staticState,
)
}));
print('## Set Widget Data: $json');
await UserDefaults.setString(
'widget_data',
jsonEncode(WidgetData(
url: formatApiUrl(state.authState.url),
companyId: state.account.defaultCompanyId,
companies: {
for (var userCompany
in state.userCompanyStates.where((state) => state.company.hasName))
userCompany.company.id:
WidgetCompany.fromUserCompany(
userCompanyState: userCompany,
staticState: state.staticState,)
})),
'group.com.invoiceninja.app');
'widget_data', json, 'group.com.invoiceninja.app');
await WidgetKit.reloadAllTimelines();
/*

View File

@ -101,22 +101,26 @@ class WidgetData {
this.url,
this.companies,
this.companyId,
this.dateRanges,
});
WidgetData.fromJson(Map<String, dynamic> json)
: url = json['url'],
companyId = json['company_id'],
companies = json['companies'];
companies = json['companies'],
dateRanges = json['date_ranges'];
Map<String, dynamic> toJson() => <String, dynamic>{
'companies': companies,
'company_id': companyId,
'url': url,
'date_ranges': dateRanges,
};
final String url;
final String companyId;
final Map<String, WidgetCompany> companies;
final Map<String, String> dateRanges;
}
class WidgetCompany {

View File

@ -1,10 +1,9 @@
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: [:])
var widgetData: WidgetData = WidgetData(url: "", companyId: "", companies: [:], dateRanges: [:])
if let sharedDefaults = sharedDefaults {
do {
@ -53,6 +52,25 @@ class IntentHandler: INExtension, ConfigurationIntentHandling {
let currency = company?.currencies[company!.currencyId];
return Currency(identifier: currency!.id, display: currency!.name)
}
func provideDateRangeOptionsCollection(for intent: ConfigurationIntent) async throws -> INObjectCollection<DateRange> {
let widgetData = loadWidgetData()
let dateRanges = widgetData.dateRanges.keys.map { dateRange in
DateRange(identifier: dateRange, display: widgetData.dateRanges[dateRange]!)
}
return INObjectCollection(items: dateRanges)
}
func defaultDateRange(for intent: ConfigurationIntent) -> DateRange? {
let widgetData = loadWidgetData()
let defaultDateRange = "last30_days";
let dateRamge = widgetData.dateRanges[defaultDateRange]!;
return DateRange(identifier: defaultDateRange, display: dateRamge)
}
override func handler(for intent: INIntent) -> Any {
return self

View File

@ -80,7 +80,7 @@
<key>INIntentIneligibleForSuggestions</key>
<true/>
<key>INIntentLastParameterTag</key>
<integer>9</integer>
<integer>11</integer>
<key>INIntentName</key>
<string>Configuration</string>
<key>INIntentParameters</key>
@ -219,6 +219,63 @@
<key>INIntentParameterType</key>
<string>Integer</string>
</dict>
<dict>
<key>INIntentParameterConfigurable</key>
<true/>
<key>INIntentParameterDisplayName</key>
<string>Date Range</string>
<key>INIntentParameterDisplayNameID</key>
<string>hGdezL</string>
<key>INIntentParameterDisplayPriority</key>
<integer>4</integer>
<key>INIntentParameterName</key>
<string>dateRange</string>
<key>INIntentParameterObjectType</key>
<string>DateRange</string>
<key>INIntentParameterObjectTypeNamespace</key>
<string>88xZPY</string>
<key>INIntentParameterPromptDialogs</key>
<array>
<dict>
<key>INIntentParameterPromptDialogCustom</key>
<true/>
<key>INIntentParameterPromptDialogType</key>
<string>Configuration</string>
</dict>
<dict>
<key>INIntentParameterPromptDialogCustom</key>
<true/>
<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/>
<key>INIntentParameterTag</key>
<integer>11</integer>
<key>INIntentParameterType</key>
<string>Object</string>
</dict>
</array>
<key>INIntentResponse</key>
<dict>
@ -376,6 +433,69 @@
</dict>
</array>
</dict>
<dict>
<key>INTypeDisplayName</key>
<string>Date Range</string>
<key>INTypeDisplayNameID</key>
<string>cJBTgC</string>
<key>INTypeLastPropertyTag</key>
<integer>99</integer>
<key>INTypeName</key>
<string>DateRange</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>

View File

@ -14,7 +14,7 @@ struct Provider: IntentTimelineProvider {
SimpleEntry(date: Date(),
configuration: ConfigurationIntent(),
widgetData: WidgetData(url: "url", companyId: "", companies: [:]),
widgetData: WidgetData(url: "url", companyId: "", companies: [:], dateRanges: [:]),
field: "Active Invoices",
value: "$100.00")
}
@ -25,7 +25,7 @@ struct Provider: IntentTimelineProvider {
let entry = SimpleEntry(date: Date(),
configuration: configuration,
widgetData: WidgetData(url: "url", companyId: "", companies: [:]),
widgetData: WidgetData(url: "url", companyId: "", companies: [:], dateRanges: [:]),
field: "Active Invoices",
value: "$100.00")
@ -146,11 +146,13 @@ struct WidgetData: Decodable, Hashable {
let url: String
let companyId: String
let companies: [String: WidgetCompany]
let dateRanges: [String: String]
enum CodingKeys: String, CodingKey {
case url
case companyId = "company_id"
case companies
case dateRanges = "date_ranges"
}
}
@ -158,6 +160,7 @@ struct WidgetCompany: Decodable, Hashable {
let id: String
let name: String
let token: String
let firstMonthOfYear: Int
let accentColor: String
let currencyId: String
let currencies: [String: WidgetCurrency]
@ -166,6 +169,7 @@ struct WidgetCompany: Decodable, Hashable {
case id
case name
case token
case firstMonthOfYear = "first_month_of_year"
case accentColor = "accent_color"
case currencyId = "currency_id"
case currencies
@ -257,7 +261,7 @@ struct DashboardWidget_Previews: PreviewProvider {
static var previews: some View {
let entry = SimpleEntry(date: Date(),
configuration: ConfigurationIntent(),
widgetData: WidgetData(url: "url", companyId: "", companies: [:]),
widgetData: WidgetData(url: "url", companyId: "", companies: [:], dateRanges: [:]),
field: "Active Invoices",
value: "$100.00")