macOS widgets
This commit is contained in:
parent
7b2fb20407
commit
7e1ae1f0d2
|
|
@ -1406,11 +1406,17 @@ void _showAbout(BuildContext context) async {
|
|||
]);
|
||||
} else {
|
||||
await UserDefaults.setString(
|
||||
'widgetData',
|
||||
'widget_data',
|
||||
jsonEncode(WidgetData(
|
||||
url: formatApiUrl(state.authState.url),
|
||||
tokens: state.apiTokens,
|
||||
)),
|
||||
url: formatApiUrl(state.authState.url),
|
||||
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');
|
||||
await WidgetKit.reloadAllTimelines();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,13 @@ import 'dart:convert';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:invoiceninja_flutter/constants.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/company_model.dart';
|
||||
import 'package:invoiceninja_flutter/main_app.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/company/company_selectors.dart';
|
||||
import 'package:invoiceninja_flutter/redux/company/company_state.dart';
|
||||
import 'package:invoiceninja_flutter/redux/static/static_state.dart';
|
||||
import 'package:invoiceninja_flutter/utils/platforms.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:widget_kit_plugin/user_defaults/user_defaults.dart';
|
||||
|
|
@ -91,17 +95,90 @@ class _WindowManagerState extends State<WindowManager> with WindowListener {
|
|||
}
|
||||
|
||||
class WidgetData {
|
||||
WidgetData({this.url, this.tokens});
|
||||
WidgetData({this.url, this.companies});
|
||||
|
||||
WidgetData.fromJson(Map<String, dynamic> json)
|
||||
: url = json['url'],
|
||||
tokens = json['tokens'];
|
||||
|
||||
final String url;
|
||||
final Map<String, String> tokens;
|
||||
companies = json['companies'];
|
||||
|
||||
Map<String, dynamic> toJson() => <String, dynamic>{
|
||||
'tokens': tokens,
|
||||
'companies': companies,
|
||||
'url': url,
|
||||
};
|
||||
|
||||
final String url;
|
||||
final Map<String, WidgetCompany> companies;
|
||||
}
|
||||
|
||||
class WidgetCompany {
|
||||
WidgetCompany(
|
||||
{this.id,
|
||||
this.name,
|
||||
this.token,
|
||||
this.accentColor,
|
||||
this.currencyId,
|
||||
this.currencies});
|
||||
|
||||
WidgetCompany.fromUserCompany(
|
||||
{UserCompanyState userCompanyState, StaticState staticState})
|
||||
: id = userCompanyState.userCompany.company.id,
|
||||
name = userCompanyState.userCompany.company.displayName,
|
||||
token = userCompanyState.userCompany.token.token,
|
||||
accentColor = userCompanyState.userCompany.settings.accentColor,
|
||||
currencyId = userCompanyState.userCompany.company.currencyId,
|
||||
currencies = {
|
||||
for (var currencyId in getCurrencyIds(
|
||||
userCompanyState.userCompany.company,
|
||||
userCompanyState.clientState.map,
|
||||
userCompanyState.groupState.map,
|
||||
).where((currencyId) => currencyId != kCurrencyAll))
|
||||
currencyId: WidgetCurrency(
|
||||
id: currencyId,
|
||||
name: staticState.currencyMap[currencyId].name,
|
||||
exchangeRate: staticState.currencyMap[currencyId].exchangeRate,
|
||||
)
|
||||
};
|
||||
|
||||
WidgetCompany.fromJson(Map<String, dynamic> json)
|
||||
: id = json['id'],
|
||||
name = json['name'],
|
||||
token = json['token'],
|
||||
accentColor = json['accent_color'],
|
||||
currencies = json['currencies'],
|
||||
currencyId = json['currency_id'];
|
||||
|
||||
Map<String, dynamic> toJson() => <String, dynamic>{
|
||||
'id': id,
|
||||
'name': name,
|
||||
'token': token,
|
||||
'accent_color': accentColor,
|
||||
'currencies': currencies,
|
||||
'currency_id': currencyId,
|
||||
};
|
||||
|
||||
final String id;
|
||||
final String name;
|
||||
final String token;
|
||||
final String accentColor;
|
||||
final String currencyId;
|
||||
final Map<String, WidgetCurrency> currencies;
|
||||
}
|
||||
|
||||
class WidgetCurrency {
|
||||
WidgetCurrency({this.id, this.name, this.exchangeRate});
|
||||
|
||||
WidgetCurrency.fromJson(Map<String, dynamic> json)
|
||||
: id = json['id'],
|
||||
name = json['name'],
|
||||
exchangeRate = json['exchange_rate'];
|
||||
|
||||
Map<String, dynamic> toJson() => <String, dynamic>{
|
||||
'id': id,
|
||||
'name': name,
|
||||
'exchange_rate': exchangeRate,
|
||||
};
|
||||
|
||||
final String id;
|
||||
final String name;
|
||||
final double exchangeRate;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,11 +12,14 @@ class IntentHandler: INExtension, ConfigurationIntentHandling {
|
|||
func provideCompanyOptionsCollection(for intent: ConfigurationIntent) async throws -> INObjectCollection<Company> {
|
||||
|
||||
let sharedDefaults = UserDefaults.init(suiteName: "group.com.invoiceninja.app")
|
||||
var exampleData: WidgetData = WidgetData(url: "", tokens:[:])
|
||||
var exampleData: WidgetData = WidgetData(url: "", companies: [:])
|
||||
|
||||
if sharedDefaults != nil {
|
||||
do {
|
||||
let shared = sharedDefaults!.string(forKey: "widgetData")
|
||||
let shared = sharedDefaults!.string(forKey: "widget_data")
|
||||
|
||||
print("## Shared: \(shared!)")
|
||||
|
||||
if shared != nil {
|
||||
let decoder = JSONDecoder()
|
||||
exampleData = try decoder.decode(WidgetData.self, from: shared!.data(using: .utf8)!)
|
||||
|
|
@ -26,11 +29,11 @@ class IntentHandler: INExtension, ConfigurationIntentHandling {
|
|||
}
|
||||
}
|
||||
|
||||
let companies = exampleData.tokens.keys.map { token in
|
||||
let companies = exampleData.companies.values.map { company in
|
||||
|
||||
let company = Company(
|
||||
identifier: token,
|
||||
display: exampleData.tokens[token] ?? ""
|
||||
identifier: company.token,
|
||||
display: company.name
|
||||
)
|
||||
//company.symbol = asset.symbol
|
||||
//company.name = asset.name
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@ import Intents
|
|||
|
||||
struct Provider: IntentTimelineProvider {
|
||||
func placeholder(in context: Context) -> SimpleEntry {
|
||||
SimpleEntry(date: Date(), configuration: ConfigurationIntent(), widgetData: WidgetData(url: "url", tokens: ["plk": "ply"]), field: "Invoices", value: 0)
|
||||
SimpleEntry(date: Date(), configuration: ConfigurationIntent(), widgetData: WidgetData(url: "url", companies: [:]), field: "Invoices", value: 0)
|
||||
}
|
||||
|
||||
func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
|
||||
let entry = SimpleEntry(date: Date(), configuration: configuration, widgetData: WidgetData(url: "url", tokens: ["sk": "sy"]), field: "Invoices", value: 0)
|
||||
let entry = SimpleEntry(date: Date(), configuration: configuration, widgetData: WidgetData(url: "url", companies: [:]), field: "Invoices", value: 0)
|
||||
completion(entry)
|
||||
}
|
||||
|
||||
|
|
@ -35,10 +35,10 @@ struct Provider: IntentTimelineProvider {
|
|||
|
||||
if sharedDefaults != nil {
|
||||
do {
|
||||
let shared = sharedDefaults!.string(forKey: "widgetData")
|
||||
let shared = sharedDefaults!.string(forKey: "widget_data")
|
||||
if shared != nil {
|
||||
|
||||
//print("## Shared: \(shared!)")
|
||||
print("## Shared: \(shared!)")
|
||||
|
||||
let decoder = JSONDecoder()
|
||||
exampleData = try decoder.decode(WidgetData.self, from: shared!.data(using: .utf8)!)
|
||||
|
|
@ -48,8 +48,9 @@ struct Provider: IntentTimelineProvider {
|
|||
let url = (exampleData?.url ?? "") + "/charts/totals_v2";
|
||||
var token = configuration.company?.identifier ?? ""
|
||||
|
||||
if (token == "") {
|
||||
token = exampleData?.tokens.keys.first ?? "";
|
||||
if (token == "" && !(exampleData?.companies.isEmpty)!) {
|
||||
let company = exampleData?.companies.values.first;
|
||||
token = company?.token ?? ""
|
||||
}
|
||||
|
||||
print("## company.name: \(configuration.company?.displayString ?? "")")
|
||||
|
|
@ -95,7 +96,37 @@ struct Provider: IntentTimelineProvider {
|
|||
|
||||
struct WidgetData: Decodable, Hashable {
|
||||
let url: String
|
||||
let tokens: [String: String]
|
||||
let companies: [String: WidgetCompany]
|
||||
}
|
||||
|
||||
struct WidgetCompany: Decodable, Hashable {
|
||||
let id: String
|
||||
let name: String
|
||||
let token: String
|
||||
let accentColor: String
|
||||
let currencyId: String
|
||||
let currencies: [String: WidgetCurrency]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case name
|
||||
case token
|
||||
case accentColor = "accent_color"
|
||||
case currencyId = "currency_id"
|
||||
case currencies
|
||||
}
|
||||
}
|
||||
|
||||
struct WidgetCurrency: Decodable, Hashable {
|
||||
let id: String
|
||||
let name: String
|
||||
let exchangeRate: Double
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case name
|
||||
case exchangeRate = "exchange_rate"
|
||||
}
|
||||
}
|
||||
|
||||
struct SimpleEntry: TimelineEntry {
|
||||
|
|
@ -154,7 +185,7 @@ struct DashboardWidget: Widget {
|
|||
|
||||
struct DashboardWidget_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
DashboardWidgetEntryView(entry: SimpleEntry(date: Date(), configuration: ConfigurationIntent(), widgetData: WidgetData(url: "url", tokens: ["pk": "py"]), field: "Invoices", value: 0))
|
||||
DashboardWidgetEntryView(entry: SimpleEntry(date: Date(), configuration: ConfigurationIntent(), widgetData: WidgetData(url: "url", companies: [:]), field: "Invoices", value: 0))
|
||||
.previewContext(WidgetPreviewContext(family: .systemSmall))
|
||||
//.environment(\.sizeCategory, .extraLarge)
|
||||
//.environment(\.colorScheme, .dark)
|
||||
|
|
|
|||
Loading…
Reference in New Issue