From afcff10862ff67c4680a6c56a369ca002c768a7e Mon Sep 17 00:00:00 2001 From: Kima Date: Mon, 2 Dec 2024 23:13:26 +0100 Subject: [PATCH] some progress in cloud sync and paypal support almost done --- refilc/lib/api/client.dart | 2 +- refilc/lib/database/init.dart | 1 + refilc/lib/models/settings.dart | 60 +++++++++++++------ .../lib/plus/components/plan_card.dart | 47 +++++++++++++-- .../lib/plus/plus_screen.i18n.dart | 21 ++++++- .../lib/screens/login/qwid_login.dart | 2 +- .../settings/submenu/cloud_sync_screen.dart | 4 +- refilc_plus | 2 +- 8 files changed, 108 insertions(+), 31 deletions(-) diff --git a/refilc/lib/api/client.dart b/refilc/lib/api/client.dart index 93bfd7a..73f079f 100644 --- a/refilc/lib/api/client.dart +++ b/refilc/lib/api/client.dart @@ -395,7 +395,7 @@ class FilcAPI { } // cloud sync - static Future cloudSync(Map data, String token) async { + static Future cloudSync(Map data, String token) async { try { var client = http.Client(); diff --git a/refilc/lib/database/init.dart b/refilc/lib/database/init.dart index a693315..75826e6 100644 --- a/refilc/lib/database/init.dart +++ b/refilc/lib/database/init.dart @@ -58,6 +58,7 @@ const settingsDB = DatabaseStruct("settings", { "unseen_new_features": String, "cloud_sync_enabled": int, "cloud_sync_token": String, + "local_updated_at": String, // quick settings "q_timetable_lesson_num": int, "q_timetable_sub_tiles": int, "q_subjects_sub_tiles": int, diff --git a/refilc/lib/models/settings.dart b/refilc/lib/models/settings.dart index f05ff87..bc75a50 100644 --- a/refilc/lib/models/settings.dart +++ b/refilc/lib/models/settings.dart @@ -111,6 +111,7 @@ class SettingsProvider extends ChangeNotifier { List _unseenNewFeatures; bool _cloudSyncEnabled; String _cloudSyncToken; + DateTime _updatedAt; // quick settings bool _qTimetableLessonNum; bool _qTimetableSubTiles; @@ -188,6 +189,7 @@ class SettingsProvider extends ChangeNotifier { required List unseenNewFeatures, required bool cloudSyncEnabled, required String cloudSyncToken, + required DateTime updatedAt, required bool qTimetableLessonNum, required bool qTimetableSubTiles, required bool qSubjectsSubTiles, @@ -262,6 +264,7 @@ class SettingsProvider extends ChangeNotifier { _unseenNewFeatures = unseenNewFeatures, _cloudSyncEnabled = cloudSyncEnabled, _cloudSyncToken = cloudSyncToken, + _updatedAt = updatedAt, _qTimetableLessonNum = qTimetableLessonNum, _qTimetableSubTiles = qTimetableSubTiles, _qSubjectsSubTiles = qSubjectsSubTiles; @@ -355,6 +358,7 @@ class SettingsProvider extends ChangeNotifier { unseenNewFeatures: jsonDecode(map["unseen_new_features"]).cast(), cloudSyncEnabled: map['cloud_sync_enabled'] == 1, cloudSyncToken: map['cloud_sync_token'], + updatedAt: DateTime.tryParse(map['local_updated_at']) ?? DateTime.now(), qTimetableLessonNum: map['q_timetable_lesson_num'] == 1, qTimetableSubTiles: map['q_timetable_sub_tiles'] == 1, qSubjectsSubTiles: map['q_subjects_sub_tiles'] == 1, @@ -436,6 +440,7 @@ class SettingsProvider extends ChangeNotifier { "unseen_new_features": jsonEncode(_unseenNewFeatures), "cloud_sync_enabled": _cloudSyncEnabled ? 1 : 0, "cloud_sync_token": _cloudSyncToken, + "local_updated_at": _updatedAt.toIso8601String(), "q_timetable_lesson_num": _qTimetableLessonNum ? 1 : 0, "q_timetable_sub_tiles": _qTimetableSubTiles ? 1 : 0, "q_subjects_sub_tiles": _qSubjectsSubTiles ? 1 : 0, @@ -521,6 +526,7 @@ class SettingsProvider extends ChangeNotifier { unseenNewFeatures: ['grade_exporting'], cloudSyncEnabled: false, cloudSyncToken: '', + updatedAt: DateTime.now(), qTimetableLessonNum: true, qTimetableSubTiles: true, qSubjectsSubTiles: true, @@ -597,6 +603,7 @@ class SettingsProvider extends ChangeNotifier { List get unseenNewFeatures => _unseenNewFeatures; bool get cloudSyncEnabled => _cloudSyncEnabled; String get cloudSyncToken => _cloudSyncToken; + DateTime get updatedAt => _updatedAt; bool get qTimetableLessonNum => _qTimetableLessonNum; bool get qTimetableSubTiles => _qTimetableSubTiles; bool get qSubjectsSubTiles => _qSubjectsSubTiles; @@ -885,6 +892,8 @@ class SettingsProvider extends ChangeNotifier { if (qSubjectsSubTiles != null && qSubjectsSubTiles != _qSubjectsSubTiles) { _qSubjectsSubTiles = qSubjectsSubTiles; } + // change updated at time + _updatedAt = DateTime.now(); // store or not if (store) await _database?.store.storeSettings(this); notifyListeners(); @@ -894,19 +903,22 @@ class SettingsProvider extends ChangeNotifier { required Map map, bool store = true, }) async { + print(map); + await update( store: store, language: map["language"], - startPage: Pages.values[map["start_page"]], + startPage: Pages.values[map["start_page"] ?? _startPage.index], rounding: map["rounding"], - theme: ThemeMode.values[map["theme"]], - accentColor: AccentColor.values[map["accent_color"]], + theme: ThemeMode.values[map["theme"] ?? _theme.index], + accentColor: + AccentColor.values[map["accent_color"] ?? _accentColor.index], gradeColors: [ - Color(map["grade_color1"]), - Color(map["grade_color2"]), - Color(map["grade_color3"]), - Color(map["grade_color4"]), - Color(map["grade_color5"]), + Color(map["grade_color1"] ?? _gradeColors[0].value), + Color(map["grade_color2"] ?? _gradeColors[1].value), + Color(map["grade_color3"] ?? _gradeColors[2].value), + Color(map["grade_color4"] ?? _gradeColors[3].value), + Color(map["grade_color5"] ?? _gradeColors[4].value), ], newsEnabled: map["news"] == 1, seenNews: map["seen_news"], @@ -918,11 +930,13 @@ class SettingsProvider extends ChangeNotifier { notificationsBitfield: map["notifications_bitfield"], notificationPollInterval: map["notification_poll_interval"], developerMode: map["developer_mode"] == 1, - vibrate: VibrationStrength.values[map["vibration_strength"]], + vibrate: + VibrationStrength.values[map["vibration_strength"] ?? _vibrate.index], abWeeks: map["ab_weeks"] == 1, swapABweeks: map["swap_ab_weeks"] == 1, - updateChannel: UpdateChannel.values[map["update_channel"]], - config: Config.fromJson(jsonDecode(map["config"])), + updateChannel: + UpdateChannel.values[map["update_channel"] ?? _updateChannel.index], + config: Config.fromJson(jsonDecode(map["config"] ?? "{}")), xFilcId: map["x_filc_id"], analyticsEnabled: map["analytics_enabled"] == 1, graphClassAvg: map["graph_class_avg"] == 1, @@ -933,13 +947,19 @@ class SettingsProvider extends ChangeNotifier { gradeOpeningFun: map["grade_opening_fun"] == 1, iconPack: Map.fromEntries( IconPack.values.map((e) => MapEntry(e.name, e)))[map["icon_pack"]]!, - customAccentColor: Color(map["custom_accent_color"]), - customBackgroundColor: Color(map["custom_background_color"]), - customHighlightColor: Color(map["custom_highlight_color"]), - customIconColor: Color(map["custom_icon_color"]), - customTextColor: Color(map["custom_text_color"]), + customAccentColor: + Color(map["custom_accent_color"] ?? _customAccentColor.value), + customBackgroundColor: + Color(map["custom_background_color"] ?? _customBackgroundColor.value), + customHighlightColor: + Color(map["custom_highlight_color"] ?? _customHighlightColor.value), + customIconColor: + Color(map["custom_icon_color"] ?? _customIconColor.value), + customTextColor: + Color(map["custom_text_color"] ?? _customTextColor.value), shadowEffect: map["shadow_effect"] == 1, - premiumScopes: jsonDecode(map["premium_scopes"]).cast(), + premiumScopes: + jsonDecode(map["premium_scopes"] ?? _premiumScopes).cast(), premiumAccessToken: map["premium_token"], premiumLogin: map["premium_login"], lastAccountId: map["last_account_id"], @@ -947,7 +967,8 @@ class SettingsProvider extends ChangeNotifier { renamedSubjectsItalics: map["renamed_subjects_italics"] == 1, renamedTeachersEnabled: map["renamed_teachers_enabled"] == 1, renamedTeachersItalics: map["renamed_teachers_italics"] == 1, - liveActivityColor: Color(map["live_activity_color"]), + liveActivityColor: + Color(map["live_activity_color"] ?? _liveActivityColor), welcomeMessage: map["welcome_message"], appIcon: map["app_icon"], currentThemeId: map['current_theme_id'], @@ -970,7 +991,8 @@ class SettingsProvider extends ChangeNotifier { newColors: map['new_colors'] == 1, uwuMode: map['uwu_mode'] == 1, newPopups: map['new_popups'] == 1, - unseenNewFeatures: jsonDecode(map["unseen_new_features"]).cast(), + unseenNewFeatures: + jsonDecode(map["unseen_new_features"] ?? "[]").cast(), cloudSyncEnabled: map['cloud_sync_enabled'] == 1, cloudSyncToken: map['cloud_sync_token'], qTimetableLessonNum: map['q_timetable_lesson_num'] == 1, diff --git a/refilc_mobile_ui/lib/plus/components/plan_card.dart b/refilc_mobile_ui/lib/plus/components/plan_card.dart index f8aba19..a672de0 100644 --- a/refilc_mobile_ui/lib/plus/components/plan_card.dart +++ b/refilc_mobile_ui/lib/plus/components/plan_card.dart @@ -98,11 +98,48 @@ class PlusPlanCard extends StatelessWidget { onTap: () { // pop dialog Navigator.of(context).pop(); - // start payment process - Navigator.of(context) - .push(MaterialPageRoute(builder: (context) { - return PremiumActivationView(product: id); - })); + // show payment option selector + showDialog( + context: context, + builder: (context) => AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12.0)), + title: Text('payment_method'.i18n), + content: Text('select_payment_method'.i18n), + actions: [ + ActionButton( + label: "stripe".i18n, + onTap: () { + // pop dialog + Navigator.of(context).pop(); + // start payment process + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return PremiumActivationView( + product: id, + paymentProvider: "stripe", + ); + })); + }, + ), + ActionButton( + label: "paypal".i18n, + onTap: () { + // pop dialog + Navigator.of(context).pop(); + // start payment process + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return PremiumActivationView( + product: id, + paymentProvider: "paypal", + ); + })); + }, + ), + ], + ), + ); }, ), ], diff --git a/refilc_mobile_ui/lib/plus/plus_screen.i18n.dart b/refilc_mobile_ui/lib/plus/plus_screen.i18n.dart index 902ba64..ac0db01 100644 --- a/refilc_mobile_ui/lib/plus/plus_screen.i18n.dart +++ b/refilc_mobile_ui/lib/plus/plus_screen.i18n.dart @@ -47,11 +47,16 @@ extension SettingsLocalization on String { "rfp_16": "Private leaks and informations about upcoming features", "rfp_17": "Grade exporting", "rfp_18": "Viewing exported grades", - // docs popup + // docs and payment method popup "docs": "Documents", "docs_acceptance": "By pressing the \"Next\" button, you accept reFilc's Terms and Conditions for subscriptions (available at the following link: filc.one/pay-terms) and our Privacy Policy (available at the following link: filc.one/pay-privacy).", "next": "Next", + "payment_method": "Payment Method", + "select_payment_method": + "Please select a preferred payment method! Credit card payments are handled by Stripe, which also supports Apple Pay, Google Pay and Revolut Pay.", + "stripe": "Credit Card", + "paypal": "PayPal", // other "and": " and ", "every": "Every ", @@ -106,11 +111,16 @@ extension SettingsLocalization on String { "rfp_16": "Privát betekintések és információk közelgő újításokról", "rfp_17": "Jegy exportálás", "rfp_18": "Exportált jegyek megtekintése", - // docs popup + // docs and payment method popup "docs": "Dokumentumok", "docs_acceptance": "A \"Tovább\" gombra kattintva elfogadod a reFilc előfizetésekkel kapcsolatos Általános Szerződési Feltételeit (elérhető az alábbi link-en: filc.one/pay-terms), valamint Adatkezelési Tájékoztatónkat (elérhető az alábbi link-en: filc.one/pay-privacy).", "next": "Tovább", + "payment_method": "Fizetési mód", + "select_payment_method": + "Kérlek válassz egy fizetési módot! A bankkártyás fizetést a Stripe biztosítja, mely támogat Apple Pay-t, Google Pay-t és Revolut Pay-t is.", + "stripe": "Bankkártya", + "paypal": "PayPal", // other "and": " és ", "every": "Minden ", @@ -167,11 +177,16 @@ extension SettingsLocalization on String { "rfp_16": "Private Leaks und Informationen über kommende Funktionen", "rfp_17": "Notenexport", "rfp_18": "Anzeigen exportierter Noten", - // docs popup + // docs and payment method popup "docs": "Dokumente", "docs_acceptance": "Durch Drücken der Schaltfläche \"Weiter\" akzeptieren Sie die Allgemeinen Geschäftsbedingungen von reFilc für Abonnements (verfügbar unter folgendem Link: filc.one/pay-terms) und unsere Datenschutzrichtlinie (verfügbar unter folgendem Link: filc.one/pay-privacy).", "next": "Weiter", + "payment_method": "Zahlungsmethode", + "select_payment_method": + "Bitte wählen Sie eine bevorzugte Zahlungsmethode aus! Kreditkartenzahlungen werden von Stripe abgewickelt, der auch Apple Pay, Google Pay und Revolut Pay unterstützt.", + "stripe": "Kreditkarte", + "paypal": "PayPal", // other "and": " und ", "every": "Jeder ", diff --git a/refilc_mobile_ui/lib/screens/login/qwid_login.dart b/refilc_mobile_ui/lib/screens/login/qwid_login.dart index cc1428e..a19269e 100644 --- a/refilc_mobile_ui/lib/screens/login/qwid_login.dart +++ b/refilc_mobile_ui/lib/screens/login/qwid_login.dart @@ -103,7 +103,7 @@ class _QwIDLoginWidgetState extends State )) ..loadRequest( Uri.parse( - 'https://qwid.qwit.dev/oauth2/authorize?client_id=c3b871fb-d922-4e23-b94d-b31f294c9253&scope=*&redirect_uri=https://api.refilc.hu/v4/oauth2/callback/app/qwid&response_type=code'), // &institute_code=${widget.selectedSchool} + 'https://qwid.qwit.dev/oauth2/authorize?client_id=99aa103a-0bd7-43e0-8421-3bb0b2f6adb1&scope=*&redirect_uri=https://api.refilc.hu/v4/oauth2/callback/app/qwid&response_type=code'), // &institute_code=${widget.selectedSchool} ); } diff --git a/refilc_mobile_ui/lib/screens/settings/submenu/cloud_sync_screen.dart b/refilc_mobile_ui/lib/screens/settings/submenu/cloud_sync_screen.dart index 222ade5..0d9ad67 100644 --- a/refilc_mobile_ui/lib/screens/settings/submenu/cloud_sync_screen.dart +++ b/refilc_mobile_ui/lib/screens/settings/submenu/cloud_sync_screen.dart @@ -1,4 +1,6 @@ // import 'package:refilc/models/settings.dart'; +import 'dart:convert'; + import 'package:refilc/api/client.dart'; import 'package:refilc/api/providers/database_provider.dart'; import 'package:refilc/api/providers/user_provider.dart'; @@ -193,7 +195,7 @@ class CloudSyncSettingsScreenState extends State { } else { FilcAPI.cloudSync( { - "settings": settingsProvider.toMap(), + "settings": jsonEncode(settingsProvider.toMap()), // "device_ids": [ // settingsProvider.xFilcId, // ], diff --git a/refilc_plus b/refilc_plus index bc6ccd9..800f5ce 160000 --- a/refilc_plus +++ b/refilc_plus @@ -1 +1 @@ -Subproject commit bc6ccd961b8e3edf35d279d32c78113fbd1d7a5a +Subproject commit 800f5ce92daafb002990cb7838e8ce4b28bc1a7d