diff --git a/firka/lib/helpers/settings/setting.dart b/firka/lib/helpers/settings/setting.dart index e62ce6a..3c84f39 100644 --- a/firka/lib/helpers/settings/setting.dart +++ b/firka/lib/helpers/settings/setting.dart @@ -327,7 +327,15 @@ class SettingsStore { developerOptsEnabled, null, null, "Developer", false, never), }), always); - + items["profile_settings"] = SettingsGroup( + 0, + LinkedHashMap.of({ + "back": SettingsBackHeader(0, l10n.s_your_account, always), + "e_kreta_accounts": SettingsHeaderSmall(0, l10n.s_acc_kreta, always), + "e_padding": SettingsPadding(0, 8, always), + "e_kreta_account_picker": SettingsKretenAccountPicker(0, always), + }), + never); appIcons = { "ace": l10n.ic_ace, "ace_f": l10n.ic_ace_f, @@ -676,6 +684,45 @@ class SettingsAppIconPreview implements SettingsItem { Future save(IsarCollection model) async {} } +class SettingsKretenAccountPicker implements SettingsItem { + @override + Id key; + @override + FirkaIconType? iconType; + @override + Object? iconData; + @override + bool Function() visibilityProvider; + @override + Future Function() postUpdate = () async {}; + String title = ""; + String icon = ""; + int accountIndex = 0; + + SettingsKretenAccountPicker(this.key, this.visibilityProvider); + + @override + Future load(IsarCollection model) async { + var v = await model.get(key); + if (v == null || v.valueIndex == null) { + accountIndex = 0; + } else { + accountIndex = v.valueIndex!; + } + } + + @override + Future save(IsarCollection model) async { + var v = AppSettingsModel(); + v.id = key; + v.valueIndex = accountIndex; + + await model.put(v); + + initData.settingsUpdateNotifier.update(); + } +} + class SettingsAppIconPicker implements SettingsItem { @override Id key; diff --git a/firka/lib/l10n b/firka/lib/l10n index 1370e9b..5329e7e 160000 --- a/firka/lib/l10n +++ b/firka/lib/l10n @@ -1 +1 @@ -Subproject commit 1370e9bcba26bac2635c17edb696b22e565bf6da +Subproject commit 5329e7efd298f5cbae203f08f254c9f481e53c38 diff --git a/firka/lib/main.dart b/firka/lib/main.dart index 678ab81..d085372 100644 --- a/firka/lib/main.dart +++ b/firka/lib/main.dart @@ -63,7 +63,7 @@ class AppInitialization { final PackageInfo packageInfo; final DeviceInfo devInfo; late KretaClient client; - int tokenCount; + List tokens; bool hasWatchListener = false; Uint8List? profilePicture; SettingsStore settings; @@ -74,7 +74,7 @@ class AppInitialization { required this.isar, required this.devInfo, required this.packageInfo, - required this.tokenCount, + required this.tokens, required this.settings, required this.l10n, }); @@ -154,13 +154,51 @@ void initTheme(AppInitialization data) { } } +Future _initData(AppInitialization init) async { + await init.settings.load(init.isar.appSettingsModels); + initLang(init); + initTheme(init); + init.settings = SettingsStore(init.l10n); + await init.settings.load(init.isar.appSettingsModels); + + var dispatcher = SchedulerBinding.instance.platformDispatcher; + + dispatcher.onPlatformBrightnessChanged = () { + globalUpdate.update(); + initTheme(init); + }; + + resetOldTimeTableCache(init.isar); + resetOldHomeworkCache(init.isar); + + if (init.tokens.isNotEmpty) { + final i = (init.settings.group("profile_settings")["e_kreta_account_picker"] + as SettingsKretenAccountPicker) + .accountIndex; + init.client = KretaClient( + (await init.isar.tokenModels.where().findAll())[i], init.isar); + + await WidgetCacheHelper.updateWidgetCache(appStyle, init.client); + } + + final dataDir = await getApplicationDocumentsDirectory(); + var pfpFile = File(p.join(dataDir.path, "profile.webp")); + + if (await pfpFile.exists()) { + init.profilePicture = await pfpFile.readAsBytes(); + } +} + Future initializeApp() async { - if (initDone) return initData; + if (initDone) { + await _initData(initData); + return initData; + } final isar = await initDB(); - final tokenCount = await isar.tokenModels.count(); + final tokens = await isar.tokenModels.where().findAll(); if (kDebugMode) { - print('Token count: $tokenCount'); + print('Token count: ${tokens.length}'); } var devInfoFetched = false; @@ -190,46 +228,17 @@ Future initializeApp() async { isar: isar, devInfo: devInfo, packageInfo: await PackageInfo.fromPlatform(), - tokenCount: tokenCount, + tokens: tokens, settings: SettingsStore(AppLocalizationsHu()), l10n: AppLocalizationsHu(), ); + await _initData(init); + init.settingsUpdateNotifier.addListener(() { debugPrint("Settings updated"); }); - await init.settings.load(init.isar.appSettingsModels); - initLang(init); - initTheme(init); - init.settings = SettingsStore(init.l10n); - await init.settings.load(init.isar.appSettingsModels); - - var dispatcher = SchedulerBinding.instance.platformDispatcher; - - dispatcher.onPlatformBrightnessChanged = () { - globalUpdate.update(); - initTheme(init); - }; - - resetOldTimeTableCache(isar); - resetOldHomeworkCache(isar); - - // TODO: Account selection - if (tokenCount > 0) { - init.client = - KretaClient((await isar.tokenModels.where().findFirst())!, isar); - - await WidgetCacheHelper.updateWidgetCache(appStyle, init.client); - } - - final dataDir = await getApplicationDocumentsDirectory(); - var pfpFile = File(p.join(dataDir.path, "profile.webp")); - - if (await pfpFile.exists()) { - init.profilePicture = await pfpFile.readAsBytes(); - } - return init; } @@ -310,7 +319,7 @@ class InitializationScreen extends StatelessWidget { switch (msg["id"]) { case "ping": - if (initData.tokenCount > 0) { + if (initData.tokens.isNotEmpty) { debugPrint("[Phone -> Watch]: pong"); watch.sendMessage({"id": "pong"}); navigatorKey.currentState?.push( @@ -324,7 +333,7 @@ class InitializationScreen extends StatelessWidget { }); } - if (snapshot.data!.tokenCount == 0) { + if (snapshot.data!.tokens.isEmpty) { screen = LoginScreen( initData, key: ValueKey('loginScreen'), diff --git a/firka/lib/ui/phone/pages/extras/extras.dart b/firka/lib/ui/phone/pages/extras/extras.dart index 5613cec..07867ad 100644 --- a/firka/lib/ui/phone/pages/extras/extras.dart +++ b/firka/lib/ui/phone/pages/extras/extras.dart @@ -91,6 +91,28 @@ void showExtrasBottomSheet(BuildContext context, AppInitialization data) { ], right: [], ), + ), + GestureDetector( + onTap: () { + Navigator.pop(context); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => DefaultAssetBundle( + bundle: FirkaBundle(), + child: SettingsScreen( + data, + data.settings.items + .group("profile_settings"))))); + }, + child: FirkaCard( + left: [ + Text(data.l10n.s_your_account, + style: appStyle.fonts.B_16R.apply( + color: appStyle.colors.textPrimary)) + ], + right: [], + ), ) ], ), diff --git a/firka/lib/ui/phone/screens/debug/debug_screen.dart b/firka/lib/ui/phone/screens/debug/debug_screen.dart index 83813eb..c569630 100644 --- a/firka/lib/ui/phone/screens/debug/debug_screen.dart +++ b/firka/lib/ui/phone/screens/debug/debug_screen.dart @@ -214,7 +214,7 @@ class _DebugScreen extends FirkaState { await isar.tokenModels.clear(); }); - widget.data.tokenCount = 0; + widget.data.tokens = List.empty(growable: true); Navigator.push( context, diff --git a/firka/lib/ui/phone/screens/settings/settings_screen.dart b/firka/lib/ui/phone/screens/settings/settings_screen.dart index 11eb66f..fe770b6 100644 --- a/firka/lib/ui/phone/screens/settings/settings_screen.dart +++ b/firka/lib/ui/phone/screens/settings/settings_screen.dart @@ -1,5 +1,6 @@ import 'dart:collection'; +import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart'; import 'package:firka/helpers/db/models/app_settings_model.dart'; import 'package:firka/helpers/image_preloader.dart'; import 'package:firka/helpers/ui/firka_button.dart'; @@ -14,6 +15,7 @@ import 'package:majesticons_flutter/majesticons_flutter.dart'; import '../../../../helpers/firka_bundle.dart'; import '../../../../helpers/firka_state.dart'; import '../../../../helpers/settings/setting.dart'; +import '../../widgets/login_webview.dart'; class SettingsScreen extends StatefulWidget { final AppInitialization data; @@ -494,6 +496,88 @@ class _SettingsScreenState extends FirkaState { continue; } + if (item is SettingsKretenAccountPicker) { + for (var i = 0; i < widget.data.tokens.length; i++) { + final token = widget.data.tokens[i]; + final jwt = JWT.decode(token.idToken!); + + widgets.add(GestureDetector( + child: SizedBox( + height: 52, + child: FirkaCard( + left: [ + Text( + jwt.payload["name"], + style: appStyle.fonts.B_16R + .apply(color: appStyle.colors.textPrimary), + ), + SizedBox(width: 8), + Text( + jwt.payload["role"], + style: appStyle.fonts.B_16R + .apply(color: appStyle.colors.textTertiary), + ) + ], + right: [ + i != item.accountIndex + ? SizedBox() + : Checkbox( + value: true, + fillColor: WidgetStateProperty.resolveWith( + (Set states) { + return appStyle.colors.secondary; + }), + onChanged: (_) async { + setState(() { + // item.activeIndex = i; + }); + + await widget.data.isar.writeTxn(() async { + await item + .save(widget.data.isar.appSettingsModels); + }); + debugPrint('Settings saved'); + }) + ], + ), + ), + onTap: () async { + if (i != item.accountIndex) { + await widget.data.isar.writeTxn(() async { + item.accountIndex = i; + + await item.save(widget.data.isar.appSettingsModels); + }); + + runApp(InitializationScreen()); + } + }, + )); + widgets.add(SizedBox(height: 8)); + } + + widgets.add(GestureDetector( + child: FirkaCard(left: [ + Text( + widget.data.l10n.s_acc_add, + style: appStyle.fonts.B_16R + .apply(color: appStyle.colors.textPrimary), + ) + ]), + onTap: () { + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (BuildContext context) { + return LoginWebviewWidget(widget.data, + username: widget.data.client.model.studentId.toString(), + schoolId: widget.data.client.model.iss!); + }, + ); + }, + )); + continue; + } } return widgets; diff --git a/firka/lib/ui/phone/widgets/login_webview.dart b/firka/lib/ui/phone/widgets/login_webview.dart index d5b9da3..fb9a9ad 100644 --- a/firka/lib/ui/phone/widgets/login_webview.dart +++ b/firka/lib/ui/phone/widgets/login_webview.dart @@ -1,6 +1,7 @@ import 'package:firka/main.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:isar/isar.dart'; import 'package:webview_flutter/webview_flutter.dart'; import '../../../helpers/api/client/kreta_client.dart'; @@ -65,7 +66,7 @@ class _LoginWebviewWidgetState extends FirkaState { }); widget.data.client = KretaClient(tokenModel, isar); - widget.data.tokenCount = await isar.tokenModels.count(); + widget.data.tokens = await isar.tokenModels.where().findAll(); if (!mounted) return NavigationDecision.prevent;