Merge branch 'master' into notifications

This commit is contained in:
Márton Kiss 2023-06-10 22:46:40 +02:00 committed by GitHub
commit 9e914974b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 551 additions and 243 deletions

View File

@ -204,7 +204,7 @@ SPEC CHECKSUMS:
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95 file_picker: ce3938a0df3cc1ef404671531facef740d03f920
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_custom_tabs: 7a10a08686955cb748e5d26e0ae586d30689bf89 flutter_custom_tabs: 7a10a08686955cb748e5d26e0ae586d30689bf89
flutter_image_compress: 5a5e9aee05b6553048b8df1c3bc456d0afaac433 flutter_image_compress: 5a5e9aee05b6553048b8df1c3bc456d0afaac433
@ -218,14 +218,14 @@ SPEC CHECKSUMS:
live_activities: 9ff56a06a2d43ecd68f56deeed13b18a8304789c live_activities: 9ff56a06a2d43ecd68f56deeed13b18a8304789c
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
open_file: 02eb5cb6b21264bd3a696876f5afbfb7ca4f4b7d open_file: 02eb5cb6b21264bd3a696876f5afbfb7ca4f4b7d
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8 path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce
quick_actions_ios: 9e80dcfadfbc5d47d9cf8f47bcf428b11cf383d4 quick_actions_ios: 9e80dcfadfbc5d47d9cf8f47bcf428b11cf383d4
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866 SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866
SDWebImageWebPCoder: 18503de6621dd2c420d680e33d46bf8e1d5169b0 SDWebImageWebPCoder: 18503de6621dd2c420d680e33d46bf8e1d5169b0
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780 SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a uni_links: d97da20c7701486ba192624d99bffaaffcfc298a

View File

@ -7,6 +7,7 @@ import 'package:filcnaplo/models/release.dart';
import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/models/supporter.dart'; import 'package:filcnaplo/models/supporter.dart';
import 'package:filcnaplo_kreta_api/models/school.dart'; import 'package:filcnaplo_kreta_api/models/school.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:connectivity_plus/connectivity_plus.dart';
@ -68,7 +69,9 @@ class FilcAPI {
http.Response res = await http.get(Uri.parse(config), headers: headers); http.Response res = await http.get(Uri.parse(config), headers: headers);
if (res.statusCode == 200) { if (res.statusCode == 200) {
if (kDebugMode) {
print(jsonDecode(res.body)); print(jsonDecode(res.body));
}
return Config.fromJson(jsonDecode(res.body)); return Config.fromJson(jsonDecode(res.body));
} else if (res.statusCode == 429) { } else if (res.statusCode == 429) {
res = await http.get(Uri.parse(config)); res = await http.get(Uri.parse(config));

View File

@ -57,14 +57,15 @@ Future loginApi({
String nonceStr = await Provider.of<KretaClient>(context, listen: false) String nonceStr = await Provider.of<KretaClient>(context, listen: false)
.getAPI(KretaAPI.nonce, json: false); .getAPI(KretaAPI.nonce, json: false);
Nonce nonce = getNonce(nonceStr, username.replaceAll(' ', '') + ' ', instituteCode); Nonce nonce =
getNonce(nonceStr, '${username.replaceAll(' ', '')} ', instituteCode);
headers.addAll(nonce.header()); headers.addAll(nonce.header());
Map? res = await Provider.of<KretaClient>(context, listen: false) Map? res = await Provider.of<KretaClient>(context, listen: false)
.postAPI(KretaAPI.login, .postAPI(KretaAPI.login,
headers: headers, headers: headers,
body: User.loginBody( body: User.loginBody(
username: username.replaceAll(' ', '') + ' ', username: '${username.replaceAll(' ', '')} ',
password: password, password: password,
instituteCode: instituteCode, instituteCode: instituteCode,
)); ));
@ -83,7 +84,7 @@ Future loginApi({
.getAPI(KretaAPI.student(instituteCode)); .getAPI(KretaAPI.student(instituteCode));
Student student = Student.fromJson(studentJson!); Student student = Student.fromJson(studentJson!);
var user = User( var user = User(
username: username.replaceAll(' ', '') + ' ', username: '${username.replaceAll(' ', '')} ',
password: password, password: password,
instituteCode: instituteCode, instituteCode: instituteCode,
name: student.name, name: student.name,

View File

@ -2,7 +2,6 @@ import 'dart:io';
import 'package:filcnaplo/database/query.dart'; import 'package:filcnaplo/database/query.dart';
import 'package:filcnaplo/database/store.dart'; import 'package:filcnaplo/database/store.dart';
import 'package:sqflite/sqflite.dart';
// ignore: depend_on_referenced_packages // ignore: depend_on_referenced_packages
import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart';

View File

@ -47,7 +47,9 @@ class LiveCardProvider extends ChangeNotifier {
// Check if live card is enabled .areActivitiesEnabled() // Check if live card is enabled .areActivitiesEnabled()
_liveActivitiesPlugin.areActivitiesEnabled().then((value) { _liveActivitiesPlugin.areActivitiesEnabled().then((value) {
// Console log // Console log
if (kDebugMode) {
print("Live card enabled: $value"); print("Live card enabled: $value");
}
if (value) { if (value) {
_liveActivitiesPlugin.init(appGroupId: "group.refilc.livecard"); _liveActivitiesPlugin.init(appGroupId: "group.refilc.livecard");

View File

@ -5,28 +5,36 @@ import 'dart:io';
import 'package:filcnaplo/api/providers/database_provider.dart'; import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/database/struct.dart'; import 'package:filcnaplo/database/struct.dart';
import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo/models/settings.dart';
import 'package:sqflite/sqflite.dart';
// ignore: depend_on_referenced_packages // ignore: depend_on_referenced_packages
import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart';
const settingsDB = DatabaseStruct("settings", { const settingsDB = DatabaseStruct("settings", {
"language": String, "start_page": int, "rounding": int, "theme": int, "accent_color": int, "news": int, "news_state": int, "developer_mode": int, "language": String, "start_page": int, "rounding": int, "theme": int,
"update_channel": int, "config": String, "custom_accent_color": int, "custom_background_color": int, "custom_highlight_color": int, // general "accent_color": int, "news": int, "news_state": int, "developer_mode": int,
"grade_color1": int, "grade_color2": int, "grade_color3": int, "grade_color4": int, "grade_color5": int, // grade colors "update_channel": int, "config": String, "custom_accent_color": int,
"custom_background_color": int, "custom_highlight_color": int, // general
"grade_color1": int, "grade_color2": int, "grade_color3": int,
"grade_color4": int, "grade_color5": int, // grade colors
"vibration_strength": int, "ab_weeks": int, "swap_ab_weeks": int, "vibration_strength": int, "ab_weeks": int, "swap_ab_weeks": int,
"notifications": int, "notifications_bitfield": int, "notification_poll_interval": int, // notifications "notifications": int, "notifications_bitfield": int,
"x_filc_id": String, "graph_class_avg": int, "presentation_mode": int, "bell_delay": int, "bell_delay_enabled": int, "notification_poll_interval": int, // notifications
"grade_opening_fun": int, "icon_pack": String, "premium_scopes": String, "premium_token": String, "premium_login": String, "x_filc_id": String, "graph_class_avg": int, "presentation_mode": int,
"last_account_id": String, "renamed_subjects_enabled": int, "renamed_subjects_italics":int, "bell_delay": int, "bell_delay_enabled": int,
"grade_opening_fun": int, "icon_pack": String, "premium_scopes": String,
"premium_token": String, "premium_login": String,
"last_account_id": String, "renamed_subjects_enabled": int,
"renamed_subjects_italics": int,
}); });
// DON'T FORGET TO UPDATE DEFAULT VALUES IN `initDB` MIGRATION OR ELSE PARENTS WILL COMPLAIN ABOUT THEIR CHILDREN MISSING // DON'T FORGET TO UPDATE DEFAULT VALUES IN `initDB` MIGRATION OR ELSE PARENTS WILL COMPLAIN ABOUT THEIR CHILDREN MISSING
// YOU'VE BEEN WARNED!!! // YOU'VE BEEN WARNED!!!
const usersDB = DatabaseStruct("users", { const usersDB = DatabaseStruct("users", {
"id": String, "name": String, "username": String, "password": String, "institute_code": String, "student": String, "role": int, "id": String, "name": String, "username": String, "password": String,
"institute_code": String, "student": String, "role": int,
"nickname": String, "picture": String // premium only "nickname": String, "picture": String // premium only
}); });
const userDataDB = DatabaseStruct("user_data", { const userDataDB = DatabaseStruct("user_data", {
"id": String, "grades": String, "timetable": String, "exams": String, "homework": String, "messages": String, "notes": String, "id": String, "grades": String, "timetable": String, "exams": String,
"homework": String, "messages": String, "notes": String,
"events": String, "absences": String, "group_averages": String, "events": String, "absences": String, "group_averages": String,
// renamed subjects // non kreta data // renamed subjects // non kreta data
"renamed_subjects": String, "renamed_subjects": String,
@ -34,7 +42,8 @@ const userDataDB = DatabaseStruct("user_data", {
"last_seen_grade": int, "last_seen_grade": int,
}); });
Future<void> createTable(Database db, DatabaseStruct struct) => db.execute("CREATE TABLE IF NOT EXISTS ${struct.table} ($struct)"); Future<void> createTable(Database db, DatabaseStruct struct) =>
db.execute("CREATE TABLE IF NOT EXISTS ${struct.table} ($struct)");
Future<Database> initDB(DatabaseProvider database) async { Future<Database> initDB(DatabaseProvider database) async {
Database db; Database db;
@ -50,9 +59,11 @@ Future<Database> initDB(DatabaseProvider database) async {
await createTable(db, usersDB); await createTable(db, usersDB);
await createTable(db, userDataDB); await createTable(db, userDataDB);
if ((await db.rawQuery("SELECT COUNT(*) FROM settings"))[0].values.first == 0) { if ((await db.rawQuery("SELECT COUNT(*) FROM settings"))[0].values.first ==
0) {
// Set default values for table Settings // Set default values for table Settings
await db.insert("settings", SettingsProvider.defaultSettings(database: database).toMap()); await db.insert("settings",
SettingsProvider.defaultSettings(database: database).toMap());
} }
// Migrate Databases // Migrate Databases
@ -60,7 +71,8 @@ Future<Database> initDB(DatabaseProvider database) async {
await migrateDB( await migrateDB(
db, db,
struct: settingsDB, struct: settingsDB,
defaultValues: SettingsProvider.defaultSettings(database: database).toMap(), defaultValues:
SettingsProvider.defaultSettings(database: database).toMap(),
); );
await migrateDB( await migrateDB(
db, db,
@ -68,7 +80,8 @@ Future<Database> initDB(DatabaseProvider database) async {
defaultValues: {"role": 0, "nickname": "", "picture": ""}, defaultValues: {"role": 0, "nickname": "", "picture": ""},
); );
await migrateDB(db, struct: userDataDB, defaultValues: { await migrateDB(db, struct: userDataDB, defaultValues: {
"grades": "[]", "timetable": "[]", "exams": "[]", "homework": "[]", "messages": "[]", "notes": "[]", "events": "[]", "absences": "[]", "grades": "[]", "timetable": "[]", "exams": "[]", "homework": "[]",
"messages": "[]", "notes": "[]", "events": "[]", "absences": "[]",
"group_averages": "[]", "group_averages": "[]",
// renamed subjects // non kreta data // renamed subjects // non kreta data
"renamed_subjects": "{}", "renamed_subjects": "{}",
@ -99,7 +112,8 @@ Future<void> migrateDB(
// go through each row and add missing keys or delete non existing keys // go through each row and add missing keys or delete non existing keys
await Future.forEach<Map<String, Object?>>(originalRows, (original) async { await Future.forEach<Map<String, Object?>>(originalRows, (original) async {
bool migrationRequired = struct.struct.keys.any((key) => !original.containsKey(key) || original[key] == null) || bool migrationRequired = struct.struct.keys.any(
(key) => !original.containsKey(key) || original[key] == null) ||
original.keys.any((key) => !struct.struct.containsKey(key)); original.keys.any((key) => !struct.struct.containsKey(key));
if (migrationRequired) { if (migrationRequired) {

View File

@ -157,11 +157,15 @@ void backgroundHeadlessTask(HeadlessTask task) {
String taskId = task.taskId; String taskId = task.taskId;
bool isTimeout = task.timeout; bool isTimeout = task.timeout;
if (isTimeout) { if (isTimeout) {
if (kDebugMode) {
print("[BackgroundFetch] Headless task timed-out: $taskId"); print("[BackgroundFetch] Headless task timed-out: $taskId");
}
BackgroundFetch.finish(taskId); BackgroundFetch.finish(taskId);
return; return;
} }
if (kDebugMode) {
print('[BackgroundFetch] Headless event received.'); print('[BackgroundFetch] Headless event received.');
}
NotificationsHelper().backgroundJob(); NotificationsHelper().backgroundJob();
BackgroundFetch.finish(task.taskId); BackgroundFetch.finish(task.taskId);
} }

View File

@ -366,66 +366,88 @@ class SettingsProvider extends ChangeNotifier {
if (startPage != null && startPage != _startPage) _startPage = startPage; if (startPage != null && startPage != _startPage) _startPage = startPage;
if (rounding != null && rounding != _rounding) _rounding = rounding; if (rounding != null && rounding != _rounding) _rounding = rounding;
if (theme != null && theme != _theme) _theme = theme; if (theme != null && theme != _theme) _theme = theme;
if (accentColor != null && accentColor != _accentColor) if (accentColor != null && accentColor != _accentColor) {
_accentColor = accentColor; _accentColor = accentColor;
if (gradeColors != null && gradeColors != _gradeColors) }
if (gradeColors != null && gradeColors != _gradeColors) {
_gradeColors = gradeColors; _gradeColors = gradeColors;
if (newsEnabled != null && newsEnabled != _newsEnabled) }
if (newsEnabled != null && newsEnabled != _newsEnabled) {
_newsEnabled = newsEnabled; _newsEnabled = newsEnabled;
}
if (newsState != null && newsState != _newsState) _newsState = newsState; if (newsState != null && newsState != _newsState) _newsState = newsState;
if (notificationsEnabled != null && if (notificationsEnabled != null &&
notificationsEnabled != _notificationsEnabled) notificationsEnabled != _notificationsEnabled) {
_notificationsEnabled = notificationsEnabled; _notificationsEnabled = notificationsEnabled;
}
if (notificationsBitfield != null && if (notificationsBitfield != null &&
notificationsBitfield != _notificationsBitfield) notificationsBitfield != _notificationsBitfield) {
_notificationsBitfield = notificationsBitfield; _notificationsBitfield = notificationsBitfield;
if (developerMode != null && developerMode != _developerMode) }
if (developerMode != null && developerMode != _developerMode) {
_developerMode = developerMode; _developerMode = developerMode;
}
if (notificationPollInterval != null && if (notificationPollInterval != null &&
notificationPollInterval != _notificationPollInterval) { notificationPollInterval != _notificationPollInterval) {
_notificationPollInterval = notificationPollInterval; _notificationPollInterval = notificationPollInterval;
} }
if (vibrate != null && vibrate != _vibrate) _vibrate = vibrate; if (vibrate != null && vibrate != _vibrate) _vibrate = vibrate;
if (abWeeks != null && abWeeks != _abWeeks) _abWeeks = abWeeks; if (abWeeks != null && abWeeks != _abWeeks) _abWeeks = abWeeks;
if (swapABweeks != null && swapABweeks != _swapABweeks) if (swapABweeks != null && swapABweeks != _swapABweeks) {
_swapABweeks = swapABweeks; _swapABweeks = swapABweeks;
if (updateChannel != null && updateChannel != _updateChannel) }
if (updateChannel != null && updateChannel != _updateChannel) {
_updateChannel = updateChannel; _updateChannel = updateChannel;
}
if (config != null && config != _config) _config = config; if (config != null && config != _config) _config = config;
if (xFilcId != null && xFilcId != _xFilcId) _xFilcId = xFilcId; if (xFilcId != null && xFilcId != _xFilcId) _xFilcId = xFilcId;
if (graphClassAvg != null && graphClassAvg != _graphClassAvg) if (graphClassAvg != null && graphClassAvg != _graphClassAvg) {
_graphClassAvg = graphClassAvg; _graphClassAvg = graphClassAvg;
}
if (goodStudent != null) _goodStudent = goodStudent; if (goodStudent != null) _goodStudent = goodStudent;
if (presentationMode != null && presentationMode != _presentationMode) if (presentationMode != null && presentationMode != _presentationMode) {
_presentationMode = presentationMode; _presentationMode = presentationMode;
}
if (bellDelay != null && bellDelay != _bellDelay) _bellDelay = bellDelay; if (bellDelay != null && bellDelay != _bellDelay) _bellDelay = bellDelay;
if (bellDelayEnabled != null && bellDelayEnabled != _bellDelayEnabled) if (bellDelayEnabled != null && bellDelayEnabled != _bellDelayEnabled) {
_bellDelayEnabled = bellDelayEnabled; _bellDelayEnabled = bellDelayEnabled;
if (gradeOpeningFun != null && gradeOpeningFun != _gradeOpeningFun) }
if (gradeOpeningFun != null && gradeOpeningFun != _gradeOpeningFun) {
_gradeOpeningFun = gradeOpeningFun; _gradeOpeningFun = gradeOpeningFun;
}
if (iconPack != null && iconPack != _iconPack) _iconPack = iconPack; if (iconPack != null && iconPack != _iconPack) _iconPack = iconPack;
if (customAccentColor != null && customAccentColor != _customAccentColor) if (customAccentColor != null && customAccentColor != _customAccentColor) {
_customAccentColor = customAccentColor; _customAccentColor = customAccentColor;
}
if (customBackgroundColor != null && if (customBackgroundColor != null &&
customBackgroundColor != _customBackgroundColor) customBackgroundColor != _customBackgroundColor) {
_customBackgroundColor = customBackgroundColor; _customBackgroundColor = customBackgroundColor;
}
if (customHighlightColor != null && if (customHighlightColor != null &&
customHighlightColor != _customHighlightColor) customHighlightColor != _customHighlightColor) {
_customHighlightColor = customHighlightColor; _customHighlightColor = customHighlightColor;
if (premiumScopes != null && premiumScopes != _premiumScopes) }
if (premiumScopes != null && premiumScopes != _premiumScopes) {
_premiumScopes = premiumScopes; _premiumScopes = premiumScopes;
if (premiumAccessToken != null && premiumAccessToken != _premiumAccessToken) }
if (premiumAccessToken != null &&
premiumAccessToken != _premiumAccessToken) {
_premiumAccessToken = premiumAccessToken; _premiumAccessToken = premiumAccessToken;
if (premiumLogin != null && premiumLogin != _premiumLogin) }
if (premiumLogin != null && premiumLogin != _premiumLogin) {
_premiumLogin = premiumLogin; _premiumLogin = premiumLogin;
if (lastAccountId != null && lastAccountId != _lastAccountId) }
if (lastAccountId != null && lastAccountId != _lastAccountId) {
_lastAccountId = lastAccountId; _lastAccountId = lastAccountId;
}
if (renamedSubjectsEnabled != null && if (renamedSubjectsEnabled != null &&
renamedSubjectsEnabled != _renamedSubjectsEnabled) renamedSubjectsEnabled != _renamedSubjectsEnabled) {
_renamedSubjectsEnabled = renamedSubjectsEnabled; _renamedSubjectsEnabled = renamedSubjectsEnabled;
}
if (renamedSubjectsItalics != null && if (renamedSubjectsItalics != null &&
renamedSubjectsItalics != _renamedSubjectsItalics) renamedSubjectsItalics != _renamedSubjectsItalics) {
_renamedSubjectsItalics = renamedSubjectsItalics; _renamedSubjectsItalics = renamedSubjectsItalics;
}
if (store) await _database?.store.storeSettings(this); if (store) await _database?.store.storeSettings(this);
notifyListeners(); notifyListeners();
} }

View File

@ -38,6 +38,7 @@ class DarkMobileAppColors implements ThemeAppColors {
final gradeTwo = const Color(0xFFAE3DF4); final gradeTwo = const Color(0xFFAE3DF4);
@override @override
final gradeOne = const Color(0xFFF43DAB); final gradeOne = const Color(0xFFF43DAB);
@override
final purple = const Color(0xffBF5AF2); final purple = const Color(0xffBF5AF2);
@override @override
final pink = const Color(0xffFF375F); final pink = const Color(0xffFF375F);

View File

@ -16,13 +16,15 @@ import 'package:filcnaplo_kreta_api/client/client.dart';
class NavigationScreen extends StatefulWidget { class NavigationScreen extends StatefulWidget {
const NavigationScreen({Key? key}) : super(key: key); const NavigationScreen({Key? key}) : super(key: key);
static NavigationScreenState? of(BuildContext context) => context.findAncestorStateOfType<NavigationScreenState>(); static NavigationScreenState? of(BuildContext context) =>
context.findAncestorStateOfType<NavigationScreenState>();
@override @override
State<NavigationScreen> createState() => NavigationScreenState(); State<NavigationScreen> createState() => NavigationScreenState();
} }
class NavigationScreenState extends State<NavigationScreen> with WidgetsBindingObserver { class NavigationScreenState extends State<NavigationScreen>
with WidgetsBindingObserver {
final _navigatorState = GlobalKey<NavigatorState>(); final _navigatorState = GlobalKey<NavigatorState>();
late NavigationRoute selected; late NavigationRoute selected;
late SettingsProvider settings; late SettingsProvider settings;
@ -40,7 +42,8 @@ class NavigationScreenState extends State<NavigationScreen> with WidgetsBindingO
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
// set client User-Agent // set client User-Agent
Provider.of<KretaClient>(context, listen: false).userAgent = settings.config.userAgent; Provider.of<KretaClient>(context, listen: false).userAgent =
settings.config.userAgent;
// Get news // Get news
newsProvider = Provider.of<NewsProvider>(context, listen: false); newsProvider = Provider.of<NewsProvider>(context, listen: false);
@ -54,7 +57,11 @@ class NavigationScreenState extends State<NavigationScreen> with WidgetsBindingO
await Window.initialize(); await Window.initialize();
} catch (_) {} } catch (_) {}
// Transparent sidebar // Transparent sidebar
await Window.setEffect(effect: WindowEffect.acrylic, color: Platform.isMacOS ? Colors.transparent : const Color.fromARGB(27, 27, 27, 27)); await Window.setEffect(
effect: WindowEffect.acrylic,
color: Platform.isMacOS
? Colors.transparent
: const Color.fromARGB(27, 27, 27, 27));
// todo: do for windows // todo: do for windows
if (Platform.isMacOS) { if (Platform.isMacOS) {
@ -75,8 +82,12 @@ class NavigationScreenState extends State<NavigationScreen> with WidgetsBindingO
@override @override
void didChangePlatformBrightness() { void didChangePlatformBrightness() {
if (settings.theme == ThemeMode.system) { if (settings.theme == ThemeMode.system) {
Brightness? brightness = WidgetsBinding.instance.window.platformBrightness; // ignore: deprecated_member_use
Provider.of<ThemeModeObserver>(context, listen: false).changeTheme(brightness == Brightness.light ? ThemeMode.light : ThemeMode.dark); Brightness? brightness =
// ignore: deprecated_member_use
WidgetsBinding.instance.window.platformBrightness;
Provider.of<ThemeModeObserver>(context, listen: false).changeTheme(
brightness == Brightness.light ? ThemeMode.light : ThemeMode.dark);
} }
super.didChangePlatformBrightness(); super.didChangePlatformBrightness();
} }
@ -103,8 +114,12 @@ class NavigationScreenState extends State<NavigationScreen> with WidgetsBindingO
if (_navigatorState.currentState != null) if (_navigatorState.currentState != null)
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor.withOpacity(.5), color:
border: Border(right: BorderSide(color: AppColors.of(context).shadow.withOpacity(.7), width: 1.0)), Theme.of(context).scaffoldBackgroundColor.withOpacity(.5),
border: Border(
right: BorderSide(
color: AppColors.of(context).shadow.withOpacity(.7),
width: 1.0)),
), ),
child: Padding( child: Padding(
padding: EdgeInsets.only(top: topInset), padding: EdgeInsets.only(top: topInset),
@ -125,7 +140,8 @@ class NavigationScreenState extends State<NavigationScreen> with WidgetsBindingO
child: Navigator( child: Navigator(
key: _navigatorState, key: _navigatorState,
initialRoute: selected.name, initialRoute: selected.name,
onGenerateRoute: (settings) => navigationRouteHandler(settings), onGenerateRoute: (settings) =>
navigationRouteHandler(settings),
), ),
), ),
), ),

View File

@ -97,7 +97,11 @@ class GradeProvider with ChangeNotifier {
.i18n; .i18n;
grade.value.shortName = _settings.goodStudent grade.value.shortName = _settings.goodStudent
? "Jeles".i18n ? "Jeles".i18n
: '${grade.json!["SzovegesErtekelesRovidNev"]}' != "null" && '${grade.json!["SzovegesErtekelesRovidNev"]}' != "-" && '${grade.json!["SzovegesErtekelesRovidNev"]}'.replaceAll(RegExp(r'[0123456789]+[%]?'), '') != "" : '${grade.json!["SzovegesErtekelesRovidNev"]}' != "null" &&
'${grade.json!["SzovegesErtekelesRovidNev"]}' != "-" &&
'${grade.json!["SzovegesErtekelesRovidNev"]}'
.replaceAll(RegExp(r'[0123456789]+[%]?'), '') !=
""
? '${grade.json!["SzovegesErtekelesRovidNev"]}'.i18n ? '${grade.json!["SzovegesErtekelesRovidNev"]}'.i18n
: grade.value.valueName; : grade.value.valueName;
} }
@ -118,14 +122,16 @@ class GradeProvider with ChangeNotifier {
if (grades.isNotEmpty || _grades.isNotEmpty) await store(grades); if (grades.isNotEmpty || _grades.isNotEmpty) await store(grades);
List? groupsJson = await _kreta.getAPI(KretaAPI.groups(iss)); List? groupsJson = await _kreta.getAPI(KretaAPI.groups(iss));
if (groupsJson == null || groupsJson.isEmpty) if (groupsJson == null || groupsJson.isEmpty) {
throw "Cannot fetch Groups for User ${user.id}"; throw "Cannot fetch Groups for User ${user.id}";
}
_groups = (groupsJson[0]["OktatasNevelesiFeladat"] ?? {})["Uid"] ?? ""; _groups = (groupsJson[0]["OktatasNevelesiFeladat"] ?? {})["Uid"] ?? "";
List? groupAvgJson = List? groupAvgJson =
await _kreta.getAPI(KretaAPI.groupAverages(iss, _groups)); await _kreta.getAPI(KretaAPI.groupAverages(iss, _groups));
if (groupAvgJson == null) if (groupAvgJson == null) {
throw "Cannot fetch Class Averages for User ${user.id}"; throw "Cannot fetch Class Averages for User ${user.id}";
}
final groupAvgs = final groupAvgs =
groupAvgJson.map((e) => GroupAverage.fromJson(e)).toList(); groupAvgJson.map((e) => GroupAverage.fromJson(e)).toList();
await storeGroupAvg(groupAvgs); await storeGroupAvg(groupAvgs);

View File

@ -37,10 +37,14 @@ class TimetableProvider with ChangeNotifier {
// for renamed subjects // for renamed subjects
Future<void> convertBySettings() async { Future<void> convertBySettings() async {
Map<String, String> renamedSubjects = Map<String, String> renamedSubjects =
(await _database.query.getSettings(_database)).renamedSubjectsEnabled ? await _database.userQuery.renamedSubjects(userId: _user.id!) : {}; (await _database.query.getSettings(_database)).renamedSubjectsEnabled
? await _database.userQuery.renamedSubjects(userId: _user.id!)
: {};
for (Lesson lesson in _lessons.values.expand((e) => e)) { for (Lesson lesson in _lessons.values.expand((e) => e)) {
lesson.subject.renamedTo = renamedSubjects.isNotEmpty ? renamedSubjects[lesson.subject.id] : null; lesson.subject.renamedTo = renamedSubjects.isNotEmpty
? renamedSubjects[lesson.subject.id]
: null;
} }
notifyListeners(); notifyListeners();
@ -54,7 +58,8 @@ class TimetableProvider with ChangeNotifier {
User? user = _user.user; User? user = _user.user;
if (user == null) throw "Cannot fetch Lessons for User null"; if (user == null) throw "Cannot fetch Lessons for User null";
String iss = user.instituteCode; String iss = user.instituteCode;
List? lessonsJson = await _kreta.getAPI(KretaAPI.timetable(iss, start: week.start, end: week.end)); List? lessonsJson = await _kreta
.getAPI(KretaAPI.timetable(iss, start: week.start, end: week.end));
if (lessonsJson == null) throw "Cannot fetch Lessons for User ${user.id}"; if (lessonsJson == null) throw "Cannot fetch Lessons for User ${user.id}";
List<Lesson> lessons = lessonsJson.map((e) => Lesson.fromJson(e)).toList(); List<Lesson> lessons = lessonsJson.map((e) => Lesson.fromJson(e)).toList();
@ -72,7 +77,7 @@ class TimetableProvider with ChangeNotifier {
if (user == null) throw "Cannot store Lessons for User null"; if (user == null) throw "Cannot store Lessons for User null";
String userId = user.id; String userId = user.id;
// TODO: clear indexes with weeks outside of the current school year // -TODO: clear indexes with weeks outside of the current school year
await _database.userStore.storeLessons(_lessons, userId: userId); await _database.userStore.storeLessons(_lessons, userId: userId);
} }

View File

@ -22,16 +22,21 @@ class MessageViewTile extends StatelessWidget {
UserProvider user = Provider.of<UserProvider>(context, listen: false); UserProvider user = Provider.of<UserProvider>(context, listen: false);
String recipientLabel = ""; String recipientLabel = "";
if (message.recipients.any((r) => r.name == user.student?.name)) recipientLabel = "me".i18n; if (message.recipients.any((r) => r.name == user.student?.name))
recipientLabel = "me".i18n;
if (recipientLabel != "" && message.recipients.length > 1) { if (recipientLabel != "" && message.recipients.length > 1) {
recipientLabel += " +"; recipientLabel += " +";
recipientLabel += message.recipients.where((r) => r.name != user.student?.name).length.toString(); recipientLabel += message.recipients
.where((r) => r.name != user.student?.name)
.length
.toString();
} }
if (recipientLabel == "") { if (recipientLabel == "") {
// note: convertint to set to remove duplicates // note: convertint to set to remove duplicates
recipientLabel += message.recipients.map((r) => r.name).toSet().join(", "); recipientLabel +=
message.recipients.map((r) => r.name).toSet().join(", ");
} }
List<Widget> attachments = []; List<Widget> attachments = [];
@ -75,9 +80,9 @@ class MessageViewTile extends StatelessWidget {
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 1, maxLines: 1,
), ),
trailing: Row( trailing: const Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: const [ children: [
// IconButton( // IconButton(
// onPressed: () {}, // onPressed: () {},
// icon: Icon(FeatherIcons.cornerUpLeft, color: AppColors.of(context).text), // icon: Icon(FeatherIcons.cornerUpLeft, color: AppColors.of(context).text),

View File

@ -55,7 +55,9 @@ class _LiveCardState extends State<LiveCard> {
case LiveCardState.morning: case LiveCardState.morning:
child = LiveCardWidget( child = LiveCardWidget(
key: const Key('livecard.morning'), key: const Key('livecard.morning'),
title: DateFormat("EEEE", I18n.of(context).locale.toString()).format(DateTime.now()).capital(), title: DateFormat("EEEE", I18n.of(context).locale.toString())
.format(DateTime.now())
.capital(),
icon: FeatherIcons.sun, icon: FeatherIcons.sun,
description: liveCard.nextLesson != null description: liveCard.nextLesson != null
? Text.rich( ? Text.rich(
@ -63,26 +65,40 @@ class _LiveCardState extends State<LiveCard> {
children: [ children: [
TextSpan(text: "first_lesson_1".i18n), TextSpan(text: "first_lesson_1".i18n),
TextSpan( TextSpan(
text: liveCard.nextLesson!.subject.renamedTo ?? liveCard.nextLesson!.subject.name.capital(), text: liveCard.nextLesson!.subject.renamedTo ??
liveCard.nextLesson!.subject.name.capital(),
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.secondary.withOpacity(.85), color: Theme.of(context)
fontStyle: liveCard.nextLesson!.subject.isRenamed && settingsProvider.renamedSubjectsItalics ? FontStyle.italic : null), .colorScheme
.secondary
.withOpacity(.85),
fontStyle: liveCard.nextLesson!.subject.isRenamed &&
settingsProvider.renamedSubjectsItalics
? FontStyle.italic
: null),
), ),
TextSpan(text: "first_lesson_2".i18n), TextSpan(text: "first_lesson_2".i18n),
TextSpan( TextSpan(
text: liveCard.nextLesson!.room.capital(), text: liveCard.nextLesson!.room.capital(),
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.secondary.withOpacity(.85), color: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.85),
), ),
), ),
TextSpan(text: "first_lesson_3".i18n), TextSpan(text: "first_lesson_3".i18n),
TextSpan( TextSpan(
text: DateFormat('H:mm').format(liveCard.nextLesson!.start), text: DateFormat('H:mm')
.format(liveCard.nextLesson!.start),
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.secondary.withOpacity(.85), color: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.85),
), ),
), ),
TextSpan(text: "first_lesson_4".i18n), TextSpan(text: "first_lesson_4".i18n),
@ -93,30 +109,48 @@ class _LiveCardState extends State<LiveCard> {
); );
break; break;
case LiveCardState.duringLesson: case LiveCardState.duringLesson:
final elapsedTime = DateTime.now().difference(liveCard.currentLesson!.start).inSeconds.toDouble() + bellDelay.inSeconds; final elapsedTime = DateTime.now()
final maxTime = liveCard.currentLesson!.end.difference(liveCard.currentLesson!.start).inSeconds.toDouble(); .difference(liveCard.currentLesson!.start)
.inSeconds
.toDouble() +
bellDelay.inSeconds;
final maxTime = liveCard.currentLesson!.end
.difference(liveCard.currentLesson!.start)
.inSeconds
.toDouble();
final showMinutes = maxTime - elapsedTime > 60; final showMinutes = maxTime - elapsedTime > 60;
child = LiveCardWidget( child = LiveCardWidget(
key: const Key('livecard.duringLesson'), key: const Key('livecard.duringLesson'),
leading: liveCard.currentLesson!.lessonIndex + (RegExp(r'\d').hasMatch(liveCard.currentLesson!.lessonIndex) ? "." : ""), leading: liveCard.currentLesson!.lessonIndex +
title: liveCard.currentLesson!.subject.renamedTo ?? liveCard.currentLesson!.subject.name.capital(), (RegExp(r'\d').hasMatch(liveCard.currentLesson!.lessonIndex)
? "."
: ""),
title: liveCard.currentLesson!.subject.renamedTo ??
liveCard.currentLesson!.subject.name.capital(),
titleItalic: liveCard.currentLesson!.subject.isRenamed, titleItalic: liveCard.currentLesson!.subject.isRenamed,
subtitle: liveCard.currentLesson!.room, subtitle: liveCard.currentLesson!.room,
icon: SubjectIcon.resolveVariant(subject: liveCard.currentLesson!.subject, context: context), icon: SubjectIcon.resolveVariant(
description: liveCard.currentLesson!.description != "" ? Text(liveCard.currentLesson!.description) : null, subject: liveCard.currentLesson!.subject, context: context),
nextSubject: liveCard.nextLesson?.subject.renamedTo ?? liveCard.nextLesson?.subject.name.capital(), description: liveCard.currentLesson!.description != ""
nextSubjectItalic: liveCard.nextLesson?.subject.isRenamed == true && settingsProvider.renamedSubjectsItalics ?? false, ? Text(liveCard.currentLesson!.description)
: null,
nextSubject: liveCard.nextLesson?.subject.renamedTo ??
liveCard.nextLesson?.subject.name.capital(),
nextSubjectItalic: liveCard.nextLesson?.subject.isRenamed == true &&
settingsProvider.renamedSubjectsItalics,
nextRoom: liveCard.nextLesson?.room, nextRoom: liveCard.nextLesson?.room,
progressMax: showMinutes ? maxTime / 60 : maxTime, progressMax: showMinutes ? maxTime / 60 : maxTime,
progressCurrent: showMinutes ? elapsedTime / 60 : elapsedTime, progressCurrent: showMinutes ? elapsedTime / 60 : elapsedTime,
progressAccuracy: showMinutes ? ProgressAccuracy.minutes : ProgressAccuracy.seconds, progressAccuracy:
showMinutes ? ProgressAccuracy.minutes : ProgressAccuracy.seconds,
onProgressTap: () { onProgressTap: () {
showDialog( showDialog(
barrierColor: Colors.black, barrierColor: Colors.black,
context: context, context: context,
builder: (context) => HeadsUpCountdown(maxTime: maxTime, elapsedTime: elapsedTime), builder: (context) =>
HeadsUpCountdown(maxTime: maxTime, elapsedTime: elapsedTime),
); );
}, },
); );
@ -131,8 +165,15 @@ class _LiveCardState extends State<LiveCard> {
final diff = liveCard.getFloorDifference(); final diff = liveCard.getFloorDifference();
final maxTime = liveCard.nextLesson!.start.difference(liveCard.prevLesson!.end).inSeconds.toDouble(); final maxTime = liveCard.nextLesson!.start
final elapsedTime = DateTime.now().difference(liveCard.prevLesson!.end).inSeconds.toDouble() + bellDelay.inSeconds.toDouble(); .difference(liveCard.prevLesson!.end)
.inSeconds
.toDouble();
final elapsedTime = DateTime.now()
.difference(liveCard.prevLesson!.end)
.inSeconds
.toDouble() +
bellDelay.inSeconds.toDouble();
final showMinutes = maxTime - elapsedTime > 60; final showMinutes = maxTime - elapsedTime > 60;
@ -141,14 +182,21 @@ class _LiveCardState extends State<LiveCard> {
title: "break".i18n, title: "break".i18n,
icon: iconFloorMap[diff], icon: iconFloorMap[diff],
description: liveCard.nextLesson!.room != liveCard.prevLesson!.room description: liveCard.nextLesson!.room != liveCard.prevLesson!.room
? Text("go $diff".i18n.fill([diff != "to room" ? (liveCard.nextLesson!.getFloor() ?? 0) : liveCard.nextLesson!.room])) ? Text("go $diff".i18n.fill([
diff != "to room"
? (liveCard.nextLesson!.getFloor() ?? 0)
: liveCard.nextLesson!.room
]))
: Text("stay".i18n), : Text("stay".i18n),
nextSubject: liveCard.nextLesson?.subject.renamedTo ?? liveCard.nextLesson?.subject.name.capital(), nextSubject: liveCard.nextLesson?.subject.renamedTo ??
nextSubjectItalic: liveCard.nextLesson?.subject.isRenamed == true && settingsProvider.renamedSubjectsItalics ?? false, liveCard.nextLesson?.subject.name.capital(),
nextSubjectItalic: liveCard.nextLesson?.subject.isRenamed == true &&
settingsProvider.renamedSubjectsItalics,
nextRoom: diff != "to room" ? liveCard.nextLesson?.room : null, nextRoom: diff != "to room" ? liveCard.nextLesson?.room : null,
progressMax: showMinutes ? maxTime / 60 : maxTime, progressMax: showMinutes ? maxTime / 60 : maxTime,
progressCurrent: showMinutes ? elapsedTime / 60 : elapsedTime, progressCurrent: showMinutes ? elapsedTime / 60 : elapsedTime,
progressAccuracy: showMinutes ? ProgressAccuracy.minutes : ProgressAccuracy.seconds, progressAccuracy:
showMinutes ? ProgressAccuracy.minutes : ProgressAccuracy.seconds,
onProgressTap: () { onProgressTap: () {
showDialog( showDialog(
barrierColor: Colors.black, barrierColor: Colors.black,
@ -164,14 +212,18 @@ class _LiveCardState extends State<LiveCard> {
case LiveCardState.afternoon: case LiveCardState.afternoon:
child = LiveCardWidget( child = LiveCardWidget(
key: const Key('livecard.afternoon'), key: const Key('livecard.afternoon'),
title: DateFormat("EEEE", I18n.of(context).locale.toString()).format(DateTime.now()).capital(), title: DateFormat("EEEE", I18n.of(context).locale.toString())
.format(DateTime.now())
.capital(),
icon: FeatherIcons.coffee, icon: FeatherIcons.coffee,
); );
break; break;
case LiveCardState.night: case LiveCardState.night:
child = LiveCardWidget( child = LiveCardWidget(
key: const Key('livecard.night'), key: const Key('livecard.night'),
title: DateFormat("EEEE", I18n.of(context).locale.toString()).format(DateTime.now()).capital(), title: DateFormat("EEEE", I18n.of(context).locale.toString())
.format(DateTime.now())
.capital(),
icon: FeatherIcons.moon, icon: FeatherIcons.moon,
); );
break; break;

View File

@ -12,14 +12,16 @@ class PremiumButton extends StatefulWidget {
State<PremiumButton> createState() => _PremiumButtonState(); State<PremiumButton> createState() => _PremiumButtonState();
} }
class _PremiumButtonState extends State<PremiumButton> with TickerProviderStateMixin { class _PremiumButtonState extends State<PremiumButton>
with TickerProviderStateMixin {
late final AnimationController _animation; late final AnimationController _animation;
bool _heldDown = false; bool _heldDown = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_animation = AnimationController(vsync: this, duration: const Duration(seconds: 3)); _animation =
AnimationController(vsync: this, duration: const Duration(seconds: 3));
_animation.repeat(); _animation.repeat();
} }
@ -38,7 +40,8 @@ class _PremiumButtonState extends State<PremiumButton> with TickerProviderStateM
transitionType: ContainerTransitionType.fadeThrough, transitionType: ContainerTransitionType.fadeThrough,
openElevation: 0, openElevation: 0,
closedElevation: 0, closedElevation: 0,
closedShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14.0)), closedShape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(14.0)),
openBuilder: (context, _) => const PremiumScreen(), openBuilder: (context, _) => const PremiumScreen(),
closedBuilder: (context, action) => GestureDetector( closedBuilder: (context, action) => GestureDetector(
onTapDown: (_) => setState(() => _heldDown = true), onTapDown: (_) => setState(() => _heldDown = true),
@ -57,16 +60,20 @@ class _PremiumButtonState extends State<PremiumButton> with TickerProviderStateM
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(14.0), borderRadius: BorderRadius.circular(14.0),
child: ImageFiltered( child: ImageFiltered(
imageFilter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), imageFilter:
ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: Container( child: Container(
height: 70, height: 70,
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: SweepGradient(colors: const [ gradient: SweepGradient(
colors: const [
Colors.blue, Colors.blue,
Colors.orange, Colors.orange,
Colors.purple, Colors.purple,
Colors.blue, Colors.blue,
], transform: GradientRotation(_animation.value * 6.283185)), ],
transform: GradientRotation(
_animation.value * 6.283185)),
), ),
), ),
), ),
@ -92,9 +99,9 @@ class _PremiumButtonState extends State<PremiumButton> with TickerProviderStateM
Color(0xff1EA18F), Color(0xff1EA18F),
]), ]),
), ),
child: Row( child: const Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: const [ children: [
Icon(FilcIcons.premium, color: Colors.white), Icon(FilcIcons.premium, color: Colors.white),
SizedBox(width: 12.0), SizedBox(width: 12.0),
Text( Text(

View File

@ -21,8 +21,9 @@ class PremiumScreen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final middleColor = final middleColor = Theme.of(context).brightness == Brightness.dark
Theme.of(context).brightness == Brightness.dark ? const Color.fromARGB(255, 20, 57, 46) : const Color.fromARGB(255, 10, 140, 123); ? const Color.fromARGB(255, 20, 57, 46)
: const Color.fromARGB(255, 10, 140, 123);
final future = FilcAPI.getSupporters(); final future = FilcAPI.getSupporters();
@ -78,7 +79,8 @@ class PremiumScreen extends StatelessWidget {
children: [ children: [
Expanded( Expanded(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0), padding:
const EdgeInsets.symmetric(horizontal: 24.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -87,16 +89,25 @@ class PremiumScreen extends StatelessWidget {
const SizedBox(height: 12.0), const SizedBox(height: 12.0),
const Text( const Text(
"Még több filc.", "Még több filc.",
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 25.0, color: Colors.white), style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 25.0,
color: Colors.white),
), ),
const Text( const Text(
"reFilc Premium.", "reFilc Premium.",
style: TextStyle(fontWeight: FontWeight.w800, fontSize: 35.0, color: Colors.white), style: TextStyle(
fontWeight: FontWeight.w800,
fontSize: 35.0,
color: Colors.white),
), ),
const SizedBox(height: 15.0), const SizedBox(height: 15.0),
Text( Text(
"Támogasd a filcet, és szerezz cserébe pár kényelmes jutalmat!", "Támogasd a filcet, és szerezz cserébe pár kényelmes jutalmat!",
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 20, color: Colors.white.withOpacity(.8)), style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20,
color: Colors.white.withOpacity(.8)),
), ),
const SizedBox(height: 25.0), const SizedBox(height: 25.0),
SupportersButton(supporters: future), SupportersButton(supporters: future),
@ -110,43 +121,61 @@ class PremiumScreen extends StatelessWidget {
), ),
), ),
SliverPadding( SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 24.0).add(const EdgeInsets.only(bottom: 100)), padding: const EdgeInsets.symmetric(horizontal: 24.0)
.add(const EdgeInsets.only(bottom: 100)),
sliver: SliverToBoxAdapter( sliver: SliverToBoxAdapter(
child: Column( child: Column(
children: [ children: [
PremiumPlanCard( PremiumPlanCard(
icon: const Icon(FilcIcons.kupak), icon: const Icon(FilcIcons.kupak),
title: Text("Kupak", style: TextStyle(foreground: GradientStyles.kupakPaint)), title: Text("Kupak",
style: TextStyle(
foreground: GradientStyles.kupakPaint)),
gradient: GradientStyles.kupak, gradient: GradientStyles.kupak,
price: 2, price: 2,
description: const Text("Szabd személyre a filcet és láss részletesebb statisztikákat."), description: const Text(
url: "https://github.com/sponsors/filc/sponsorships?tier_id=238453&preview=true", "Szabd személyre a filcet és láss részletesebb statisztikákat."),
active: ActiveSponsorCard.estimateLevel(context.watch<PremiumProvider>().scopes) == PremiumFeatureLevel.kupak, url:
"https://github.com/sponsors/filc/sponsorships?tier_id=238453&preview=true",
active: ActiveSponsorCard.estimateLevel(
context.watch<PremiumProvider>().scopes) ==
PremiumFeatureLevel.kupak,
), ),
const SizedBox(height: 8.0), const SizedBox(height: 8.0),
PremiumPlanCard( PremiumPlanCard(
icon: const Icon(FilcIcons.tinta), icon: const Icon(FilcIcons.tinta),
title: Text("Tinta", style: TextStyle(foreground: GradientStyles.tintaPaint)), title: Text("Tinta",
style: TextStyle(
foreground: GradientStyles.tintaPaint)),
gradient: GradientStyles.tinta, gradient: GradientStyles.tinta,
price: 5, price: 5,
description: const Text("Kényelmesebb órarend, asztali alkalmazás és célok kitűzése."), description: const Text(
url: "https://github.com/sponsors/filc/sponsorships?tier_id=238454&preview=true", "Kényelmesebb órarend, asztali alkalmazás és célok kitűzése."),
active: ActiveSponsorCard.estimateLevel(context.watch<PremiumProvider>().scopes) == PremiumFeatureLevel.tinta, url:
"https://github.com/sponsors/filc/sponsorships?tier_id=238454&preview=true",
active: ActiveSponsorCard.estimateLevel(
context.watch<PremiumProvider>().scopes) ==
PremiumFeatureLevel.tinta,
), ),
const SizedBox(height: 12.0), const SizedBox(height: 12.0),
PremiumGoalCard(progress: snapshot.data?.progress ?? 0, target: snapshot.data?.max ?? 1), PremiumGoalCard(
progress: snapshot.data?.progress ?? 0,
target: snapshot.data?.max ?? 1),
const SizedBox(height: 12.0), const SizedBox(height: 12.0),
const GithubConnectButton(), const GithubConnectButton(),
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 14.0).add(const EdgeInsets.only(top: 12.0)), padding: const EdgeInsets.symmetric(vertical: 14.0)
child: Row( .add(const EdgeInsets.only(top: 12.0)),
children: const [ child: const Row(
children: [
Icon(FilcIcons.kupak), Icon(FilcIcons.kupak),
SizedBox(width: 12.0), SizedBox(width: 12.0),
Expanded( Expanded(
child: Text( child: Text(
"Kupak jutalmak", "Kupak jutalmak",
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 20), style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20),
), ),
), ),
], ],
@ -154,40 +183,50 @@ class PremiumScreen extends StatelessWidget {
), ),
PremiumRewardCard( PremiumRewardCard(
imageKey: "premium_nickname_showcase", imageKey: "premium_nickname_showcase",
icon: SvgPicture.asset("assets/images/nickname_icon.svg", color: Theme.of(context).iconTheme.color), icon: SvgPicture.asset(
"assets/images/nickname_icon.svg",
color: Theme.of(context).iconTheme.color),
title: const Text("Profil személyre szabás"), title: const Text("Profil személyre szabás"),
description: const Text("Állíts be egy saját becenevet és egy profilképet (akár animáltat is!)"), description: const Text(
"Állíts be egy saját becenevet és egy profilképet (akár animáltat is!)"),
), ),
const SizedBox(height: 14.0), const SizedBox(height: 14.0),
PremiumRewardCard( PremiumRewardCard(
imageKey: "premium_theme_showcase", imageKey: "premium_theme_showcase",
icon: SvgPicture.asset("assets/images/theme_icon.svg", color: Theme.of(context).iconTheme.color), icon: SvgPicture.asset("assets/images/theme_icon.svg",
color: Theme.of(context).iconTheme.color),
title: const Text("Téma+"), title: const Text("Téma+"),
description: const Text("Válassz saját háttérszínt és kártyaszínt is, akár saját HEX-kóddal!"), description: const Text(
"Válassz saját háttérszínt és kártyaszínt is, akár saját HEX-kóddal!"),
), ),
const SizedBox(height: 14.0), const SizedBox(height: 14.0),
PremiumRewardCard( PremiumRewardCard(
imageKey: "premium_stats_showcase", imageKey: "premium_stats_showcase",
icon: SvgPicture.asset("assets/images/stats_icon.svg", color: Theme.of(context).iconTheme.color), icon: SvgPicture.asset("assets/images/stats_icon.svg",
color: Theme.of(context).iconTheme.color),
title: const Text("Részletes jegy statisztika"), title: const Text("Részletes jegy statisztika"),
description: const Text("Válassz heti, havi és háromhavi időtartam közül, és pontosan lásd, mennyi jegyed van."), description: const Text(
"Válassz heti, havi és háromhavi időtartam közül, és pontosan lásd, mennyi jegyed van."),
), ),
const SizedBox(height: 14.0), const SizedBox(height: 14.0),
const PremiumRewardCard( const PremiumRewardCard(
title: Text("Még pár dolog..."), title: Text("Még pár dolog..."),
description: description: Text(
Text("🔣\tVálassz ikon témát\n\tPrémium rang és csevegő a discord szerverünkön\n📬\tElsőbbségi segítségnyújtás"), "🔣\tVálassz ikon témát\n\tPrémium rang és csevegő a discord szerverünkön\n📬\tElsőbbségi segítségnyújtás"),
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 14.0).add(const EdgeInsets.only(top: 12.0)), padding: const EdgeInsets.symmetric(vertical: 14.0)
child: Row( .add(const EdgeInsets.only(top: 12.0)),
children: const [ child: const Row(
children: [
Icon(FilcIcons.tinta), Icon(FilcIcons.tinta),
SizedBox(width: 12.0), SizedBox(width: 12.0),
Expanded( Expanded(
child: Text( child: Text(
"Tinta jutalmak", "Tinta jutalmak",
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 20), style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20),
), ),
), ),
], ],
@ -195,48 +234,62 @@ class PremiumScreen extends StatelessWidget {
), ),
PremiumRewardCard( PremiumRewardCard(
imageKey: "premium_timetable_showcase", imageKey: "premium_timetable_showcase",
icon: SvgPicture.asset("assets/images/timetable_icon.svg", color: Theme.of(context).iconTheme.color), icon: SvgPicture.asset(
"assets/images/timetable_icon.svg",
color: Theme.of(context).iconTheme.color),
title: const Text("Heti órarend nézet"), title: const Text("Heti órarend nézet"),
description: description: const Text(
const Text("Egy órarend, ami a teljes képernyődet kihasználja, csak nem olyan idegesítő, mint az eKRÉTA féle."), "Egy órarend, ami a teljes képernyődet kihasználja, csak nem olyan idegesítő, mint az eKRÉTA féle."),
), ),
const SizedBox(height: 14.0), const SizedBox(height: 14.0),
PremiumRewardCard( PremiumRewardCard(
imageKey: "premium_widget_showcase", imageKey: "premium_widget_showcase",
icon: SvgPicture.asset("assets/images/widget_icon.svg", color: Theme.of(context).iconTheme.color), icon: SvgPicture.asset(
"assets/images/widget_icon.svg",
color: Theme.of(context).iconTheme.color),
title: const Text("Widget"), title: const Text("Widget"),
description: const Text("Mindig lásd, milyen órád lesz, a kezdőképernyőd kényelméből."), description: const Text(
"Mindig lásd, milyen órád lesz, a kezdőképernyőd kényelméből."),
), ),
const SizedBox(height: 14.0), const SizedBox(height: 14.0),
PremiumRewardCard( PremiumRewardCard(
soon: true, soon: true,
imageKey: "premium_goal_showcase", imageKey: "premium_goal_showcase",
icon: SvgPicture.asset("assets/images/goal_icon.svg", color: Theme.of(context).iconTheme.color), icon: SvgPicture.asset("assets/images/goal_icon.svg",
color: Theme.of(context).iconTheme.color),
title: const Text("Cél követés"), title: const Text("Cél követés"),
description: const Text("Add meg, mi a célod, és mi majd kiszámoljuk, hogyan juthatsz oda!"), description: const Text(
"Add meg, mi a célod, és mi majd kiszámoljuk, hogyan juthatsz oda!"),
), ),
const SizedBox(height: 14.0), const SizedBox(height: 14.0),
PremiumRewardCard( PremiumRewardCard(
soon: true, soon: true,
imageKey: "premium_desktop_showcase", imageKey: "premium_desktop_showcase",
icon: SvgPicture.asset("assets/images/desktop_icon.svg", color: Theme.of(context).iconTheme.color), icon: SvgPicture.asset(
"assets/images/desktop_icon.svg",
color: Theme.of(context).iconTheme.color),
title: const Text("Asztali verzió"), title: const Text("Asztali verzió"),
description: const Text("Érd el a reFilcet a gépeden is, és menekülj meg a csúnya felhasználói felületektől!"), description: const Text(
"Érd el a reFilcet a gépeden is, és menekülj meg a csúnya felhasználói felületektől!"),
), ),
const SizedBox(height: 14.0), const SizedBox(height: 14.0),
const PremiumRewardCard( const PremiumRewardCard(
title: Text("Még pár dolog..."), title: Text("Még pár dolog..."),
description: Text("🖋️\tMinden kupak jutalom\n\tKorai hozzáférés új verziókhoz"), description: Text(
"🖋️\tMinden kupak jutalom\n\tKorai hozzáférés új verziókhoz"),
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 14.0).add(const EdgeInsets.only(top: 12.0)), padding: const EdgeInsets.symmetric(vertical: 14.0)
child: Row( .add(const EdgeInsets.only(top: 12.0)),
children: const [ child: const Row(
children: [
SizedBox(width: 12.0), SizedBox(width: 12.0),
Expanded( Expanded(
child: Text( child: Text(
"Mire vársz még?", "Mire vársz még?",
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 20), style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20),
), ),
), ),
], ],
@ -244,20 +297,24 @@ class PremiumScreen extends StatelessWidget {
), ),
GithubCard( GithubCard(
onPressed: () { onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) { Navigator.of(context)
.push(MaterialPageRoute(builder: (context) {
return const PremiumActivationView(); return const PremiumActivationView();
})); }));
}, },
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 14.0).add(const EdgeInsets.only(top: 12.0)), padding: const EdgeInsets.symmetric(vertical: 14.0)
child: Row( .add(const EdgeInsets.only(top: 12.0)),
children: const [ child: const Row(
children: [
SizedBox(width: 12.0), SizedBox(width: 12.0),
Expanded( Expanded(
child: Text( child: Text(
"Gyakori kérdések", "Gyakori kérdések",
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 20), style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20),
), ),
), ),
], ],

View File

@ -95,6 +95,46 @@ class NavigationScreenState extends State<NavigationScreen>
} }
} }
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
// Configure BackgroundFetch.
int status = await BackgroundFetch.configure(
BackgroundFetchConfig(
minimumFetchInterval: 15,
stopOnTerminate: false,
enableHeadless: true,
requiresBatteryNotLow: false,
requiresCharging: false,
requiresStorageNotLow: false,
requiresDeviceIdle: false,
requiredNetworkType: NetworkType.ANY), (String taskId) async {
// <-- Event handler
// This is the fetch-event callback.
if (kDebugMode) {
print("[BackgroundFetch] Event received $taskId");
}
// IMPORTANT: You must signal completion of your task or the OS can punish your app
// for taking too long in the background.
BackgroundFetch.finish(taskId);
}, (String taskId) async {
// <-- Task timeout handler.
// This task has exceeded its allowed running-time. You must stop what you're doing and immediately .finish(taskId)
if (kDebugMode) {
print("[BackgroundFetch] TASK TIMEOUT taskId: $taskId");
}
BackgroundFetch.finish(taskId);
});
if (kDebugMode) {
print('[BackgroundFetch] configure success: $status');
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -138,7 +178,10 @@ class NavigationScreenState extends State<NavigationScreen>
@override @override
void didChangePlatformBrightness() { void didChangePlatformBrightness() {
if (settings.theme == ThemeMode.system) { if (settings.theme == ThemeMode.system) {
Brightness? brightness = WidgetsBinding.instance.window.platformBrightness; // ignore: deprecated_member_use
Brightness? brightness =
// ignore: deprecated_member_use
WidgetsBinding.instance.window.platformBrightness;
Provider.of<ThemeModeObserver>(context, listen: false).changeTheme( Provider.of<ThemeModeObserver>(context, listen: false).changeTheme(
brightness == Brightness.light ? ThemeMode.light : ThemeMode.dark); brightness == Brightness.light ? ThemeMode.light : ThemeMode.dark);
} }

View File

@ -484,8 +484,9 @@ class _BellDelaySettingState extends State<BellDelaySetting>
Duration sdiff = lesson.start.difference(now); Duration sdiff = lesson.start.difference(now);
Duration ediff = lesson.end.difference(now); Duration ediff = lesson.end.difference(now);
if (closest == null || sdiff.abs() < closest.abs()) if (closest == null || sdiff.abs() < closest.abs()) {
closest = sdiff; closest = sdiff;
}
if (ediff.abs() < closest.abs()) closest = ediff; if (ediff.abs() < closest.abs()) closest = ediff;
} }
if (closest != null) { if (closest != null) {

View File

@ -84,26 +84,28 @@ class _SettingsScreenState extends State<SettingsScreen>
String _firstName; String _firstName;
List<String> _nameParts = user.displayName?.split(" ") ?? ["?"]; List<String> _nameParts = account.displayName.split(" ");
if (!settings.presentationMode) { if (!settings.presentationMode) {
_firstName = _nameParts.length > 1 ? _nameParts[1] : _nameParts[0]; _firstName = _nameParts.length > 1 ? _nameParts[1] : _nameParts[0];
} else { } else {
_firstName = "János"; _firstName = "János";
} }
accountTiles.add(AccountTile( accountTiles.add(
AccountTile(
name: Text(!settings.presentationMode ? account.name : "János", name: Text(!settings.presentationMode ? account.name : "János",
style: const TextStyle(fontWeight: FontWeight.w500)), style: const TextStyle(fontWeight: FontWeight.w500)),
username: username: Text(
Text(!settings.presentationMode ? account.username : "01234567890"), !settings.presentationMode ? account.username : "01234567890"),
profileImage: ProfileImage( profileImage: ProfileImage(
name: _firstName, name: _firstName,
role: account.role,
profilePictureString: account.picture,
backgroundColor: Theme.of(context) backgroundColor: Theme.of(context)
.colorScheme .colorScheme
.primary, //!settings.presentationMode .primary, //!settings.presentationMode
//? ColorUtils.stringToColor(account.name) //? ColorUtils.stringToColor(account.name)
//: Theme.of(context).colorScheme.secondary, //: Theme.of(context).colorScheme.secondary,
role: account.role,
), ),
onTap: () { onTap: () {
user.setUser(account.id); user.setUser(account.id);
@ -111,7 +113,8 @@ class _SettingsScreenState extends State<SettingsScreen>
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
onTapMenu: () => _showBottomSheet(account), onTapMenu: () => _showBottomSheet(account),
)); ),
);
}); });
} }
@ -973,7 +976,9 @@ class _SettingsScreenState extends State<SettingsScreen>
child: Text("v${release.data!['version']}"), child: Text("v${release.data!['version']}"),
); );
} else { } else {
String envAppVer = const String.fromEnvironment("APPVER", defaultValue: "?"); String envAppVer = const String.fromEnvironment(
"APPVER",
defaultValue: "?");
return DefaultTextStyle( return DefaultTextStyle(
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme

View File

@ -5,6 +5,6 @@ class GradesBody extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column(); return const Column();
} }
} }

View File

@ -5,6 +5,6 @@ class PersonalityBody extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column(); return const Column();
} }
} }

View File

@ -24,7 +24,8 @@ class _ActivationDashboardState extends State<ActivationDashboard> {
setState(() { setState(() {
manualActivationLoading = true; manualActivationLoading = true;
}); });
final result = await context.read<PremiumProvider>().auth.finishAuth(data.text!); final result =
await context.read<PremiumProvider>().auth.finishAuth(data.text!);
setState(() { setState(() {
manualActivationLoading = false; manualActivationLoading = false;
}); });
@ -63,24 +64,27 @@ class _ActivationDashboardState extends State<ActivationDashboard> {
), ),
const SizedBox(height: 12.0), const SizedBox(height: 12.0),
Card( Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14.0)), shape: RoundedRectangleBorder(
child: Padding( borderRadius: BorderRadius.circular(14.0)),
padding: const EdgeInsets.all(20.0), child: const Padding(
padding: EdgeInsets.all(20.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
children: const [ children: [
Icon(FeatherIcons.alertTriangle, size: 20.0, color: Colors.orange), Icon(FeatherIcons.alertTriangle,
size: 20.0, color: Colors.orange),
SizedBox(width: 12.0), SizedBox(width: 12.0),
Text( Text(
"Figyelem!", "Figyelem!",
style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold), style: TextStyle(
fontSize: 18.0, fontWeight: FontWeight.bold),
), ),
], ],
), ),
const SizedBox(height: 6.0), SizedBox(height: 6.0),
const Text( Text(
"Csak akkor érzékeli a Filc a támogatói státuszod, ha nem állítod privátra!", "Csak akkor érzékeli a Filc a támogatói státuszod, ha nem állítod privátra!",
style: TextStyle(fontSize: 16.0), style: TextStyle(fontSize: 16.0),
), ),
@ -90,24 +94,27 @@ class _ActivationDashboardState extends State<ActivationDashboard> {
), ),
const SizedBox(height: 12.0), const SizedBox(height: 12.0),
Card( Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14.0)), shape: RoundedRectangleBorder(
child: Padding( borderRadius: BorderRadius.circular(14.0)),
padding: const EdgeInsets.all(20.0), child: const Padding(
padding: EdgeInsets.all(20.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
children: const [ children: [
Icon(FeatherIcons.alertTriangle, size: 20.0, color: Colors.orange), Icon(FeatherIcons.alertTriangle,
size: 20.0, color: Colors.orange),
SizedBox(width: 12.0), SizedBox(width: 12.0),
Text( Text(
"Figyelem!", "Figyelem!",
style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold), style: TextStyle(
fontSize: 18.0, fontWeight: FontWeight.bold),
), ),
], ],
), ),
const SizedBox(height: 6.0), SizedBox(height: 6.0),
const Text( Text(
"Ha friss támogató vagy, 5-10 percbe telhet az aktiválás. Kérlek gyere vissza később, és próbáld újra!", "Ha friss támogató vagy, 5-10 percbe telhet az aktiválás. Kérlek gyere vissza később, és próbáld újra!",
style: TextStyle(fontSize: 16.0), style: TextStyle(fontSize: 16.0),
), ),
@ -117,7 +124,8 @@ class _ActivationDashboardState extends State<ActivationDashboard> {
), ),
const SizedBox(height: 12.0), const SizedBox(height: 12.0),
Card( Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14.0)), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(14.0)),
child: Padding( child: Padding(
padding: const EdgeInsets.all(20.0), padding: const EdgeInsets.all(20.0),
child: Column( child: Column(
@ -125,15 +133,20 @@ class _ActivationDashboardState extends State<ActivationDashboard> {
children: [ children: [
const Text( const Text(
"Ha bejelentkezés után nem lép vissza az alkalmazásba automatikusan, aktiváld a támogatásod manuálisan", "Ha bejelentkezés után nem lép vissza az alkalmazásba automatikusan, aktiváld a támogatásod manuálisan",
style: TextStyle(fontSize: 15.0, fontWeight: FontWeight.w500), style:
TextStyle(fontSize: 15.0, fontWeight: FontWeight.w500),
), ),
const SizedBox(height: 6.0), const SizedBox(height: 6.0),
Center( Center(
child: TextButton.icon( child: TextButton.icon(
onPressed: onManualActivation, onPressed: onManualActivation,
style: ButtonStyle( style: ButtonStyle(
foregroundColor: MaterialStatePropertyAll(Theme.of(context).colorScheme.secondary), foregroundColor: MaterialStatePropertyAll(
overlayColor: MaterialStatePropertyAll(Theme.of(context).colorScheme.secondary.withOpacity(.1)), Theme.of(context).colorScheme.secondary),
overlayColor: MaterialStatePropertyAll(Theme.of(context)
.colorScheme
.secondary
.withOpacity(.1)),
), ),
icon: manualActivationLoading icon: manualActivationLoading
? const SizedBox( ? const SizedBox(
@ -164,8 +177,10 @@ class _ActivationDashboardState extends State<ActivationDashboard> {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
style: ButtonStyle( style: ButtonStyle(
foregroundColor: MaterialStatePropertyAll(AppColors.of(context).text), foregroundColor:
overlayColor: MaterialStatePropertyAll(AppColors.of(context).text.withOpacity(.1)), MaterialStatePropertyAll(AppColors.of(context).text),
overlayColor: MaterialStatePropertyAll(
AppColors.of(context).text.withOpacity(.1)),
), ),
icon: const Icon(FeatherIcons.arrowLeft, size: 20.0), icon: const Icon(FeatherIcons.arrowLeft, size: 20.0),
label: const Text( label: const Text(

View File

@ -22,7 +22,8 @@ import 'package:provider/provider.dart';
import 'modify_subject_names.i18n.dart'; import 'modify_subject_names.i18n.dart';
class MenuRenamedSubjects extends StatelessWidget { class MenuRenamedSubjects extends StatelessWidget {
const MenuRenamedSubjects({Key? key, required this.settings}) : super(key: key); const MenuRenamedSubjects({Key? key, required this.settings})
: super(key: key);
final SettingsProvider settings; final SettingsProvider settings;
@ -31,8 +32,10 @@ class MenuRenamedSubjects extends StatelessWidget {
return PanelButton( return PanelButton(
padding: const EdgeInsets.only(left: 14.0), padding: const EdgeInsets.only(left: 14.0),
onPressed: () { onPressed: () {
if (!Provider.of<PremiumProvider>(context, listen: false).hasScope(PremiumScopes.renameSubjects)) { if (!Provider.of<PremiumProvider>(context, listen: false)
PremiumLockedFeatureUpsell.show(context: context, feature: PremiumFeature.subjectrename); .hasScope(PremiumScopes.renameSubjects)) {
PremiumLockedFeatureUpsell.show(
context: context, feature: PremiumFeature.subjectrename);
return; return;
} }
@ -42,23 +45,32 @@ class MenuRenamedSubjects extends StatelessWidget {
}, },
title: Text( title: Text(
"rename_subjects".i18n, "rename_subjects".i18n,
style: TextStyle(color: AppColors.of(context).text.withOpacity(settings.renamedSubjectsEnabled ? 1.0 : .5)), style: TextStyle(
color: AppColors.of(context)
.text
.withOpacity(settings.renamedSubjectsEnabled ? 1.0 : .5)),
), ),
leading: settings.renamedSubjectsEnabled leading: settings.renamedSubjectsEnabled
? const Icon(FeatherIcons.penTool) ? const Icon(FeatherIcons.penTool)
: Icon(FeatherIcons.penTool, color: AppColors.of(context).text.withOpacity(.25)), : Icon(FeatherIcons.penTool,
color: AppColors.of(context).text.withOpacity(.25)),
trailingDivider: true, trailingDivider: true,
trailing: Switch( trailing: Switch(
onChanged: (v) async { onChanged: (v) async {
if (!Provider.of<PremiumProvider>(context, listen: false).hasScope(PremiumScopes.renameSubjects)) { if (!Provider.of<PremiumProvider>(context, listen: false)
PremiumLockedFeatureUpsell.show(context: context, feature: PremiumFeature.subjectrename); .hasScope(PremiumScopes.renameSubjects)) {
PremiumLockedFeatureUpsell.show(
context: context, feature: PremiumFeature.subjectrename);
return; return;
} }
settings.update(renamedSubjectsEnabled: v); settings.update(renamedSubjectsEnabled: v);
await Provider.of<GradeProvider>(context, listen: false).convertBySettings(); await Provider.of<GradeProvider>(context, listen: false)
await Provider.of<TimetableProvider>(context, listen: false).convertBySettings(); .convertBySettings();
await Provider.of<AbsenceProvider>(context, listen: false).convertBySettings(); await Provider.of<TimetableProvider>(context, listen: false)
.convertBySettings();
await Provider.of<AbsenceProvider>(context, listen: false)
.convertBySettings();
}, },
value: settings.renamedSubjectsEnabled, value: settings.renamedSubjectsEnabled,
activeColor: Theme.of(context).colorScheme.secondary, activeColor: Theme.of(context).colorScheme.secondary,
@ -87,7 +99,11 @@ class _ModifySubjectNamesState extends State<ModifySubjectNames> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
subjects = Provider.of<GradeProvider>(context, listen: false).grades.map((e) => e.subject).toSet().toList() subjects = Provider.of<GradeProvider>(context, listen: false)
.grades
.map((e) => e.subject)
.toSet()
.toList()
..sort((a, b) => a.name.compareTo(b.name)); ..sort((a, b) => a.name.compareTo(b.name));
user = Provider.of<UserProvider>(context, listen: false); user = Provider.of<UserProvider>(context, listen: false);
dbProvider = Provider.of<DatabaseProvider>(context, listen: false); dbProvider = Provider.of<DatabaseProvider>(context, listen: false);
@ -102,7 +118,8 @@ class _ModifySubjectNamesState extends State<ModifySubjectNames> {
context: context, context: context,
builder: (context) => StatefulBuilder(builder: (context, setS) { builder: (context) => StatefulBuilder(builder: (context, setS) {
return AlertDialog( return AlertDialog(
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(14.0))), shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(14.0))),
title: Text("rename_subject".i18n), title: Text("rename_subject".i18n),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -162,13 +179,18 @@ class _ModifySubjectNamesState extends State<ModifySubjectNames> {
border: Border.all(color: Colors.grey, width: 2), border: Border.all(color: Colors.grey, width: 2),
borderRadius: BorderRadius.circular(12.0), borderRadius: BorderRadius.circular(12.0),
), ),
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 8.0), padding: const EdgeInsets.symmetric(
vertical: 12.0, horizontal: 8.0),
child: Text( child: Text(
selectedSubjectId == null ? "select_subject".i18n : subjects.firstWhere((element) => element.id == selectedSubjectId).name, selectedSubjectId == null
style: Theme.of(context) ? "select_subject".i18n
.textTheme : subjects
.titleSmall! .firstWhere(
.copyWith(fontWeight: FontWeight.w700, color: AppColors.of(context).text.withOpacity(0.75)), (element) => element.id == selectedSubjectId)
.name,
style: Theme.of(context).textTheme.titleSmall!.copyWith(
fontWeight: FontWeight.w700,
color: AppColors.of(context).text.withOpacity(0.75)),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 2, maxLines: 2,
textAlign: TextAlign.center, textAlign: TextAlign.center,
@ -183,11 +205,13 @@ class _ModifySubjectNamesState extends State<ModifySubjectNames> {
controller: _subjectName, controller: _subjectName,
decoration: InputDecoration( decoration: InputDecoration(
border: OutlineInputBorder( border: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.grey, width: 1.5), borderSide:
const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0), borderRadius: BorderRadius.circular(12.0),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.grey, width: 1.5), borderSide:
const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0), borderRadius: BorderRadius.circular(12.0),
), ),
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0), contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
@ -227,10 +251,14 @@ class _ModifySubjectNamesState extends State<ModifySubjectNames> {
final renamedSubs = await fetchRenamedSubjects(); final renamedSubs = await fetchRenamedSubjects();
renamedSubs[selectedSubjectId!] = _subjectName.text; renamedSubs[selectedSubjectId!] = _subjectName.text;
await dbProvider.userStore.storeRenamedSubjects(renamedSubs, userId: user.id!); await dbProvider.userStore
await Provider.of<GradeProvider>(context, listen: false).convertBySettings(); .storeRenamedSubjects(renamedSubs, userId: user.id!);
await Provider.of<TimetableProvider>(context, listen: false).convertBySettings(); await Provider.of<GradeProvider>(context, listen: false)
await Provider.of<AbsenceProvider>(context, listen: false).convertBySettings(); .convertBySettings();
await Provider.of<TimetableProvider>(context, listen: false)
.convertBySettings();
await Provider.of<AbsenceProvider>(context, listen: false)
.convertBySettings();
} }
Navigator.of(context).pop(true); Navigator.of(context).pop(true);
setState(() {}); setState(() {});
@ -265,9 +293,17 @@ class _ModifySubjectNamesState extends State<ModifySubjectNames> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Panel( Panel(
child: PanelButton(title: Text("italics_toggle".i18n), trailing: Switch(value: settings.renamedSubjectsItalics, onChanged: (value) => settings.update(renamedSubjectsItalics: value),) child: PanelButton(
),), title: Text("italics_toggle".i18n),
SizedBox(height: 20,), trailing: Switch(
value: settings.renamedSubjectsItalics,
onChanged: (value) =>
settings.update(renamedSubjectsItalics: value),
)),
),
const SizedBox(
height: 20,
),
InkWell( InkWell(
onTap: showRenameDialog, onTap: showRenameDialog,
borderRadius: BorderRadius.circular(12.0), borderRadius: BorderRadius.circular(12.0),
@ -277,7 +313,8 @@ class _ModifySubjectNamesState extends State<ModifySubjectNames> {
border: Border.all(color: Colors.grey, width: 2), border: Border.all(color: Colors.grey, width: 2),
borderRadius: BorderRadius.circular(12.0), borderRadius: BorderRadius.circular(12.0),
), ),
padding: const EdgeInsets.symmetric(vertical: 18.0, horizontal: 12.0), padding: const EdgeInsets.symmetric(
vertical: 18.0, horizontal: 12.0),
child: Center( child: Center(
child: Text( child: Text(
"rename_new_subject".i18n, "rename_new_subject".i18n,
@ -296,14 +333,17 @@ class _ModifySubjectNamesState extends State<ModifySubjectNames> {
FutureBuilder<Map<String, String>>( FutureBuilder<Map<String, String>>(
future: fetchRenamedSubjects(), future: fetchRenamedSubjects(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData || snapshot.data!.isEmpty) return Container(); if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Container();
}
return Panel( return Panel(
title: Text("renamed_subjects".i18n), title: Text("renamed_subjects".i18n),
child: Column( child: Column(
children: snapshot.data!.keys.map( children: snapshot.data!.keys.map(
(key) { (key) {
Subject? subject = subjects.firstWhere((element) => key == element.id); Subject? subject = subjects
.firstWhere((element) => key == element.id);
String renameTo = snapshot.data![key]!; String renameTo = snapshot.data![key]!;
return RenamedSubjectItem( return RenamedSubjectItem(
subject: subject, subject: subject,
@ -317,9 +357,12 @@ class _ModifySubjectNamesState extends State<ModifySubjectNames> {
}, },
removeCallback: () { removeCallback: () {
setState(() { setState(() {
Map<String, String> subs = Map.from(snapshot.data!); Map<String, String> subs =
Map.from(snapshot.data!);
subs.remove(key); subs.remove(key);
dbProvider.userStore.storeRenamedSubjects(subs, userId: user.id!); dbProvider.userStore.storeRenamedSubjects(
subs,
userId: user.id!);
}); });
}, },
); );
@ -355,11 +398,14 @@ class RenamedSubjectItem extends StatelessWidget {
return ListTile( return ListTile(
minLeadingWidth: 32.0, minLeadingWidth: 32.0,
dense: true, dense: true,
contentPadding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 6.0), contentPadding:
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 6.0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)),
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
onTap: () {}, onTap: () {},
leading: Icon(SubjectIcon.resolveVariant(subject: subject, context: context), color: AppColors.of(context).text.withOpacity(.75)), leading: Icon(
SubjectIcon.resolveVariant(subject: subject, context: context),
color: AppColors.of(context).text.withOpacity(.75)),
title: InkWell( title: InkWell(
onTap: modifyCallback, onTap: modifyCallback,
child: Column( child: Column(
@ -367,7 +413,10 @@ class RenamedSubjectItem extends StatelessWidget {
children: [ children: [
Text( Text(
subject.name.capital(), subject.name.capital(),
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 14, color: AppColors.of(context).text.withOpacity(.75)), style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14,
color: AppColors.of(context).text.withOpacity(.75)),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
@ -382,7 +431,8 @@ class RenamedSubjectItem extends StatelessWidget {
), ),
trailing: InkWell( trailing: InkWell(
onTap: removeCallback, onTap: removeCallback,
child: Icon(FeatherIcons.trash, color: AppColors.of(context).red.withOpacity(.75)), child: Icon(FeatherIcons.trash,
color: AppColors.of(context).red.withOpacity(.75)),
), ),
); );
} }