diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 36ba336..0000000 --- a/.gitignore +++ /dev/null @@ -1,52 +0,0 @@ -# See https://www.dartlang.org/guides/libraries/private-files - -.gitignore - -termek.txt -.DS_Store -filc3.properties -local.properties -# Files and directories created by pub -.dart_tool/ -.packages -build/ -# If you're building an application, you may want to check-in your pubspec.lock -pubspec.lock - -# Directory created by dartdoc -# If you don't generate documentation locally you can remove this line. -doc/api/ - -# Avoid committing generated Javascript files: -*.dart.js -*.info.json # Produced by the --dump-info flag. -*.js # When generated by dart2js. Don't specify *.js if your - # project includes source files written in JavaScript. -*.js_ -*.js.deps -*.js.map - -*.txt -filcnaplo/macos/Flutter/GeneratedPluginRegistrant.swift -filcnaplo/windows/flutter/ephemeral/.plugin_symlinks/connectivity_plus -filcnaplo/windows/flutter/ephemeral/.plugin_symlinks/dynamic_color -filcnaplo/windows/flutter/ephemeral/.plugin_symlinks/flutter_acrylic -filcnaplo/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows -filcnaplo/windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows -filcnaplo/windows/flutter/ephemeral/.plugin_symlinks/share_plus_windows -filcnaplo/windows/flutter/ephemeral/.plugin_symlinks/url_launcher_windows -filcnaplo/windows/flutter/ephemeral/generated_config.cmake -filcnaplo/windows/flutter/generated_plugin_registrant.cc -filcnaplo/windows/flutter/generated_plugin_registrant.h -filcnaplo/windows/flutter/generated_plugins.cmake -filcnaplo/linux/flutter/generated_plugin_registrant.cc -filcnaplo/linux/flutter/generated_plugin_registrant.h -filcnaplo/linux/flutter/generated_plugins.cmake -filcnaplo/macos/Flutter/* -filcnaplo/ios/Podfile.lock -.vscode/ -key.properties - -.flutter-plugins* -filcnaplo/ios/Flutter/flutter_export_environment 4.sh -filcnaplo/ios/Flutter/Generated 4.xcconfig diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 3c003e4..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "filcnaplo", - "cwd": "filcnaplo", - "request": "launch", - "type": "dart", - "toolArgs": [ - "--dart-define=APPVER=$(cat pubspec.yaml | grep version: | cut -d' ' -f2 | cut -d+ -f1)" - ] - }, - // { - // "name": "filcnaplo release", - // "cwd": "filcnaplo release", - // "request": "launch", - // "type": "dart", - // "program": "lib/main.dart", - // "toolArgs": [ - // "--dart-define=APPVER=$(cat pubspec.yaml | grep version: | cut -d' ' -f2 | cut -d+ -f1)" - // ] - // }, - { - "name": "Flutter", - "program": "lib/main.dart", - "cwd": "filcnaplo", - "request": "launch", - "type": "dart", - "flutterMode": "debug" - }, - { - "name": "Flutter (release)", - "program": "lib/main.dart", - "cwd": "filcnaplo", - "request": "launch", - "type": "dart", - "flutterMode": "release" - } - ] -} \ No newline at end of file diff --git a/filcnaplo/.gitignore b/filcnaplo/.gitignore deleted file mode 100644 index 7900af4..0000000 --- a/filcnaplo/.gitignore +++ /dev/null @@ -1,47 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Web related -lib/generated_plugin_registrant.dart - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release -key.properties diff --git a/filcnaplo/android/.gitignore b/filcnaplo/android/.gitignore deleted file mode 100644 index a2ea94a..0000000 --- a/filcnaplo/android/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties -.project \ No newline at end of file diff --git a/filcnaplo/assets/fonts/Montserrat/OFL.txt b/filcnaplo/assets/fonts/Montserrat/OFL.txt deleted file mode 100644 index 7881887..0000000 --- a/filcnaplo/assets/fonts/Montserrat/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2011 The Montserrat Project Authors (https://github.com/JulietaUla/Montserrat) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/filcnaplo/ios/.gitignore b/filcnaplo/ios/.gitignore deleted file mode 100644 index 8adea5a..0000000 --- a/filcnaplo/ios/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/filcnaplo/lib/api/client.dart b/filcnaplo/lib/api/client.dart index 9921580..459c3b8 100644 --- a/filcnaplo/lib/api/client.dart +++ b/filcnaplo/lib/api/client.dart @@ -190,12 +190,22 @@ class FilcAPI { static Future sendReport(ErrorReport report) async { try { - http.Response res = await http.post(Uri.parse(reportApi), body: { + Map body = { "os": report.os, "version": report.version, "error": report.error, "stack_trace": report.stack, - }); + }; + + var client = http.Client(); + + http.Response res = await client.post( + Uri.parse(reportApi), + body: body, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + ); if (res.statusCode != 200) { throw "HTTP ${res.statusCode}: ${res.body}"; @@ -213,6 +223,8 @@ class FilcAPI { theme.json['background_color'] = theme.backgroundColor.value.toString(); theme.json['panels_color'] = theme.panelsColor.value.toString(); theme.json['accent_color'] = theme.accentColor.value.toString(); + theme.json['icon_color'] = theme.iconColor.value.toString(); + theme.json['shadow_effect'] = theme.shadowEffect.toString(); // set linked grade colors theme.json['grade_colors_id'] = theme.gradeColors.id; diff --git a/filcnaplo/lib/database/init.dart b/filcnaplo/lib/database/init.dart index 274dbce..47ce105 100644 --- a/filcnaplo/lib/database/init.dart +++ b/filcnaplo/lib/database/init.dart @@ -15,7 +15,8 @@ const settingsDB = DatabaseStruct("settings", { "accent_color": int, "news": int, "seen_news": String, "developer_mode": int, "update_channel": int, "config": String, "custom_accent_color": int, - "custom_background_color": int, "custom_highlight_color": int, // general + "custom_background_color": int, "custom_highlight_color": int, + "custom_icon_color": int, "shadow_effect": 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, diff --git a/filcnaplo/lib/helpers/subject.dart b/filcnaplo/lib/helpers/subject.dart index 3cdb746..e571975 100644 --- a/filcnaplo/lib/helpers/subject.dart +++ b/filcnaplo/lib/helpers/subject.dart @@ -22,7 +22,8 @@ class SubjectIconData { }); } -SubjectIconVariants createIcon({required IconData material, required IconData cupertino}) { +SubjectIconVariants createIcon( + {required IconData material, required IconData cupertino}) { return { IconPack.material: material, IconPack.cupertino: cupertino, @@ -30,88 +31,224 @@ SubjectIconVariants createIcon({required IconData material, required IconData cu } class SubjectIcon { - static String resolveName({Subject? subject, String? subjectName}) => _resolve(subject: subject, subjectName: subjectName).name; - static IconData resolveVariant({Subject? subject, String? subjectName, required BuildContext context}) => - _resolve(subject: subject, subjectName: subjectName).data[Provider.of(context, listen: false).iconPack]!; + static String resolveName({GradeSubject? subject, String? subjectName}) => + _resolve(subject: subject, subjectName: subjectName).name; + static IconData resolveVariant( + {GradeSubject? subject, + String? subjectName, + required BuildContext context}) => + _resolve(subject: subject, subjectName: subjectName).data[ + Provider.of(context, listen: false).iconPack]!; - static SubjectIconData _resolve({Subject? subject, String? subjectName}) { + static SubjectIconData _resolve( + {GradeSubject? subject, String? subjectName}) { assert(!(subject == null && subjectName == null)); - String name = (subject?.name ?? subjectName ?? "").toLowerCase().specialChars().trim(); - String category = subject?.category.description.toLowerCase().specialChars() ?? ""; + String name = (subject?.name ?? subjectName ?? "") + .toLowerCase() + .specialChars() + .trim(); + String category = + subject?.category.description.toLowerCase().specialChars() ?? ""; // todo: check for categories if (RegExp("mate(k|matika)").hasMatch(name) || category == "matematika") { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.function, material: Icons.calculate_outlined), name: "function"); - } else if (RegExp("magyar nyelv|nyelvtan").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.textformat_alt, material: Icons.spellcheck_outlined), name: "textformat.alt"); - } else if (RegExp("irodalom").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.book, material: Icons.menu_book_outlined), name: "book"); - } else if (RegExp("tor(i|tenelem)").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.compass, material: Icons.hourglass_empty_outlined), name: "safari"); - } else if (RegExp("foldrajz").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.map, material: Icons.public_outlined), name: "map"); - } else if (RegExp("rajz|muvtori|muveszet|vizualis").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.paintbrush, material: Icons.palette_outlined), name: "paintbrush"); - } else if (RegExp("fizika").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.lightbulb, material: Icons.emoji_objects_outlined), name: "lightbulb"); - } else if (RegExp("^enek|zene|szolfezs|zongora|korus").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.music_note, material: Icons.music_note_outlined), name: "music.note"); - } else if (RegExp("^tes(i|tneveles)|sport").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.sportscourt, material: Icons.sports_soccer_outlined), name: "sportscourt"); - } else if (RegExp("kemia").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.lab_flask, material: Icons.science_outlined), name: "testtube.2"); - } else if (RegExp("biologia").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.paw, material: Icons.pets_outlined), name: "pawprint"); - } else if (RegExp("kornyezet|termeszet ?(tudomany|ismeret)|hon( es nep)?ismeret").hasMatch(name)) { return SubjectIconData( - data: createIcon(cupertino: CupertinoIcons.arrow_3_trianglepath, material: Icons.eco_outlined), name: "arrow.3.trianglepath"); + data: createIcon( + cupertino: CupertinoIcons.function, + material: Icons.calculate_outlined), + name: "function"); + } else if (RegExp("magyar nyelv|nyelvtan").hasMatch(name)) { + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.textformat_alt, + material: Icons.spellcheck_outlined), + name: "textformat.alt"); + } else if (RegExp("irodalom").hasMatch(name)) { + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.book, + material: Icons.menu_book_outlined), + name: "book"); + } else if (RegExp("tor(i|tenelem)").hasMatch(name)) { + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.compass, + material: Icons.hourglass_empty_outlined), + name: "safari"); + } else if (RegExp("foldrajz").hasMatch(name)) { + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.map, material: Icons.public_outlined), + name: "map"); + } else if (RegExp("rajz|muvtori|muveszet|vizualis").hasMatch(name)) { + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.paintbrush, + material: Icons.palette_outlined), + name: "paintbrush"); + } else if (RegExp("fizika").hasMatch(name)) { + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.lightbulb, + material: Icons.emoji_objects_outlined), + name: "lightbulb"); + } else if (RegExp("^enek|zene|szolfezs|zongora|korus").hasMatch(name)) { + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.music_note, + material: Icons.music_note_outlined), + name: "music.note"); + } else if (RegExp("^tes(i|tneveles)|sport").hasMatch(name)) { + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.sportscourt, + material: Icons.sports_soccer_outlined), + name: "sportscourt"); + } else if (RegExp("kemia").hasMatch(name)) { + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.lab_flask, + material: Icons.science_outlined), + name: "testtube.2"); + } else if (RegExp("biologia").hasMatch(name)) { + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.paw, material: Icons.pets_outlined), + name: "pawprint"); + } else if (RegExp( + "kornyezet|termeszet ?(tudomany|ismeret)|hon( es nep)?ismeret") + .hasMatch(name)) { + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.arrow_3_trianglepath, + material: Icons.eco_outlined), + name: "arrow.3.trianglepath"); } else if (RegExp("(hit|erkolcs)tan|vallas|etika").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.heart, material: Icons.favorite_border_outlined), name: "heart"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.heart, + material: Icons.favorite_border_outlined), + name: "heart"); } else if (RegExp("penzugy").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.money_dollar, material: Icons.savings_outlined), name: "dollarsign"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.money_dollar, + material: Icons.savings_outlined), + name: "dollarsign"); } else if (RegExp("informatika|szoftver|iroda|digitalis").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.device_laptop, material: Icons.computer_outlined), name: "laptopcomputer"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.device_laptop, + material: Icons.computer_outlined), + name: "laptopcomputer"); } else if (RegExp("prog").hasMatch(name)) { return SubjectIconData( - data: createIcon(cupertino: CupertinoIcons.chevron_left_slash_chevron_right, material: Icons.code_outlined), + data: createIcon( + cupertino: CupertinoIcons.chevron_left_slash_chevron_right, + material: Icons.code_outlined), name: "chevron.left.forwardslash.chevron.right"); } else if (RegExp("halozat").hasMatch(name)) { return SubjectIconData( - data: createIcon(cupertino: CupertinoIcons.antenna_radiowaves_left_right, material: Icons.wifi_tethering_outlined), + data: createIcon( + cupertino: CupertinoIcons.antenna_radiowaves_left_right, + material: Icons.wifi_tethering_outlined), name: "antenna.radiowaves.left.and.right"); } else if (RegExp("szinhaz").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.hifispeaker, material: Icons.theater_comedy_outlined), name: "hifispeaker"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.hifispeaker, + material: Icons.theater_comedy_outlined), + name: "hifispeaker"); } else if (RegExp("film|media").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.film, material: Icons.theaters_outlined), name: "film"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.film, + material: Icons.theaters_outlined), + name: "film"); } else if (RegExp("elektro(tech)?nika").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.bolt, material: Icons.electrical_services_outlined), name: "bolt"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.bolt, + material: Icons.electrical_services_outlined), + name: "bolt"); } else if (RegExp("gepesz|mernok|ipar").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.wrench, material: Icons.precision_manufacturing_outlined), name: "wrench"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.wrench, + material: Icons.precision_manufacturing_outlined), + name: "wrench"); } else if (RegExp("technika").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.hammer, material: Icons.build_outlined), name: "hammer"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.hammer, material: Icons.build_outlined), + name: "hammer"); } else if (RegExp("tanc").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.music_mic, material: Icons.speaker_outlined), name: "music.mic"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.music_mic, + material: Icons.speaker_outlined), + name: "music.mic"); } else if (RegExp("filozofia").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.bubble_left, material: Icons.psychology_outlined), name: "bubble.left"); - } else if (RegExp("osztaly(fonoki|kozosseg)").hasMatch(name) || name == "ofo") { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.group, material: Icons.groups_outlined), name: "person.3"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.bubble_left, + material: Icons.psychology_outlined), + name: "bubble.left"); + } else if (RegExp("osztaly(fonoki|kozosseg)").hasMatch(name) || + name == "ofo") { + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.group, material: Icons.groups_outlined), + name: "person.3"); } else if (RegExp("gazdasag").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.chart_pie, material: Icons.account_balance_outlined), name: "chart.pie"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.chart_pie, + material: Icons.account_balance_outlined), + name: "chart.pie"); } else if (RegExp("szorgalom").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.checkmark_seal, material: Icons.verified_outlined), name: "checkmark.seal"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.checkmark_seal, + material: Icons.verified_outlined), + name: "checkmark.seal"); } else if (RegExp("magatartas").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.smiley, material: Icons.emoji_people_outlined), name: "face.smiling"); - } else if (RegExp("angol|nemet|francia|olasz|orosz|spanyol|latin|kinai|nyelv").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.globe, material: Icons.translate_outlined), name: "globe"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.smiley, + material: Icons.emoji_people_outlined), + name: "face.smiling"); + } else if (RegExp( + "angol|nemet|francia|olasz|orosz|spanyol|latin|kinai|nyelv") + .hasMatch(name)) { + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.globe, + material: Icons.translate_outlined), + name: "globe"); } else if (RegExp("linux").hasMatch(name)) { - return SubjectIconData(data: createIcon(material: FilcIcons.linux, cupertino: FilcIcons.linux)); + return SubjectIconData( + data: createIcon( + material: FilcIcons.linux, cupertino: FilcIcons.linux)); } else if (RegExp("adatbazis").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.table_badge_more, material: Icons.table_chart), name: "table.badge.more"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.table_badge_more, + material: Icons.table_chart), + name: "table.badge.more"); } else if (RegExp("asztali alkalmazasok").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.macwindow, material: Icons.desktop_windows_outlined), name: "macwindow"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.macwindow, + material: Icons.desktop_windows_outlined), + name: "macwindow"); } else if (RegExp("projekt").hasMatch(name)) { - return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.person_3_fill, material: Icons.groups_3), name: "person.3.fill"); + return SubjectIconData( + data: createIcon( + cupertino: CupertinoIcons.person_3_fill, + material: Icons.groups_3), + name: "person.3.fill"); } return SubjectIconData(); @@ -119,10 +256,13 @@ class SubjectIcon { } class ShortSubject { - static String resolve({Subject? subject, String? subjectName}) { + static String resolve({GradeSubject? subject, String? subjectName}) { assert(!(subject == null && subjectName == null)); - String name = (subject?.name ?? subjectName ?? "").toLowerCase().specialChars().trim(); + String name = (subject?.name ?? subjectName ?? "") + .toLowerCase() + .specialChars() + .trim(); // String category = subject?.category.description.toLowerCase().specialChars() ?? ""; if (RegExp("magyar irodalom").hasMatch(name)) { @@ -137,7 +277,9 @@ class ShortSubject { return "Tesi"; } else if (RegExp("tortenelem").hasMatch(name)) { return "Töri"; - } else if (RegExp("(angol|nemet|francia|olasz|orosz|spanyol|latin|kinai) nyelv").hasMatch(name)) { + } else if (RegExp( + "(angol|nemet|francia|olasz|orosz|spanyol|latin|kinai) nyelv") + .hasMatch(name)) { return (subject?.name ?? subjectName ?? "?").replaceAll(" nyelv", ""); } else if (RegExp("informatika").hasMatch(name)) { return "Infó"; diff --git a/filcnaplo/lib/models/settings.dart b/filcnaplo/lib/models/settings.dart index 05989b6..9bbb2df 100644 --- a/filcnaplo/lib/models/settings.dart +++ b/filcnaplo/lib/models/settings.dart @@ -67,6 +67,8 @@ class SettingsProvider extends ChangeNotifier { Color _customAccentColor; Color _customBackgroundColor; Color _customHighlightColor; + Color _customIconColor; + bool _shadowEffect; List _premiumScopes; String _premiumAccessToken; String _premiumLogin; @@ -112,6 +114,8 @@ class SettingsProvider extends ChangeNotifier { required Color customAccentColor, required Color customBackgroundColor, required Color customHighlightColor, + required Color customIconColor, + required bool shadowEffect, required List premiumScopes, required String premiumAccessToken, required String premiumLogin, @@ -155,6 +159,8 @@ class SettingsProvider extends ChangeNotifier { _customAccentColor = customAccentColor, _customBackgroundColor = customBackgroundColor, _customHighlightColor = customHighlightColor, + _customIconColor = customIconColor, + _shadowEffect = shadowEffect, _premiumScopes = premiumScopes, _premiumAccessToken = premiumAccessToken, _premiumLogin = premiumLogin, @@ -217,6 +223,8 @@ class SettingsProvider extends ChangeNotifier { customAccentColor: Color(map["custom_accent_color"]), customBackgroundColor: Color(map["custom_background_color"]), customHighlightColor: Color(map["custom_highlight_color"]), + customIconColor: Color(map["custom_icon_color"]), + shadowEffect: map["shadow_effect"] == 1, premiumScopes: jsonDecode(map["premium_scopes"]).cast(), premiumAccessToken: map["premium_token"], premiumLogin: map["premium_login"], @@ -267,6 +275,8 @@ class SettingsProvider extends ChangeNotifier { "custom_accent_color": _customAccentColor.value, "custom_background_color": _customBackgroundColor.value, "custom_highlight_color": _customHighlightColor.value, + "custom_icon_color": _customIconColor.value, + "shadow_effect": _shadowEffect ? 1 : 0, "premium_scopes": jsonEncode(_premiumScopes), "premium_token": _premiumAccessToken, "premium_login": _premiumLogin, @@ -321,6 +331,8 @@ class SettingsProvider extends ChangeNotifier { customAccentColor: const Color(0xff3D7BF4), customBackgroundColor: const Color(0xff000000), customHighlightColor: const Color(0xff222222), + customIconColor: const Color(0x00000000), + shadowEffect: true, premiumScopes: [PremiumScopes.all], premiumAccessToken: "igen", premiumLogin: "igen", @@ -370,6 +382,8 @@ class SettingsProvider extends ChangeNotifier { : _customAccentColor; Color? get customBackgroundColor => _customBackgroundColor; Color? get customHighlightColor => _customHighlightColor; + Color? get customIconColor => _customIconColor; + bool get shadowEffect => _shadowEffect; List get premiumScopes => _premiumScopes; String get premiumAccessToken => _premiumAccessToken; String get premiumLogin => _premiumLogin; @@ -415,6 +429,8 @@ class SettingsProvider extends ChangeNotifier { Color? customAccentColor, Color? customBackgroundColor, Color? customHighlightColor, + Color? customIconColor, + bool? shadowEffect, List? premiumScopes, String? premiumAccessToken, String? premiumLogin, @@ -511,6 +527,12 @@ class SettingsProvider extends ChangeNotifier { customHighlightColor != _customHighlightColor) { _customHighlightColor = customHighlightColor; } + if (customIconColor != null && customIconColor != _customIconColor) { + _customIconColor = customIconColor; + } + if (shadowEffect != null && shadowEffect != _shadowEffect) { + _shadowEffect = shadowEffect; + } if (premiumScopes != null && premiumScopes != _premiumScopes) { _premiumScopes = premiumScopes; } diff --git a/filcnaplo/lib/models/shared_theme.dart b/filcnaplo/lib/models/shared_theme.dart index e983729..6ab6e24 100644 --- a/filcnaplo/lib/models/shared_theme.dart +++ b/filcnaplo/lib/models/shared_theme.dart @@ -8,6 +8,8 @@ class SharedTheme { Color backgroundColor; Color panelsColor; Color accentColor; + Color iconColor; + bool shadowEffect; SharedGradeColors gradeColors; SharedTheme({ @@ -18,6 +20,8 @@ class SharedTheme { required this.backgroundColor, required this.panelsColor, required this.accentColor, + required this.iconColor, + required this.shadowEffect, required this.gradeColors, }); @@ -30,6 +34,8 @@ class SharedTheme { backgroundColor: Color(json['background_color']), panelsColor: Color(json['panels_color']), accentColor: Color(json['accent_color']), + iconColor: Color(json['icon_color']), + shadowEffect: json['shadow_effect'] ?? true, gradeColors: gradeColors, ); } diff --git a/filcnaplo/lib/models/subject_lesson_count.dart b/filcnaplo/lib/models/subject_lesson_count.dart index 8a8adde..70d733e 100644 --- a/filcnaplo/lib/models/subject_lesson_count.dart +++ b/filcnaplo/lib/models/subject_lesson_count.dart @@ -5,17 +5,21 @@ enum SubjectLessonCountUpdateState { ready, updating } class SubjectLessonCount { DateTime lastUpdated; - Map subjects; + Map subjects; SubjectLessonCountUpdateState state; - SubjectLessonCount({required this.lastUpdated, required this.subjects, this.state = SubjectLessonCountUpdateState.ready}); + SubjectLessonCount( + {required this.lastUpdated, + required this.subjects, + this.state = SubjectLessonCountUpdateState.ready}); factory SubjectLessonCount.fromMap(Map json) { return SubjectLessonCount( - lastUpdated: DateTime.fromMillisecondsSinceEpoch(json["last_updated"] ?? 0), + lastUpdated: + DateTime.fromMillisecondsSinceEpoch(json["last_updated"] ?? 0), subjects: ((json["subjects"] as Map?) ?? {}).map( (key, value) => MapEntry( - Subject(id: key, name: "", category: Category.fromJson({})), + GradeSubject(id: key, name: "", category: Category.fromJson({})), value, ), ), diff --git a/filcnaplo/lib/ui/filter/widgets.dart b/filcnaplo/lib/ui/filter/widgets.dart index 4986c34..79bf730 100644 --- a/filcnaplo/lib/ui/filter/widgets.dart +++ b/filcnaplo/lib/ui/filter/widgets.dart @@ -214,19 +214,21 @@ Widget filterItemBuilder( child: DecoratedBox( decoration: BoxDecoration( boxShadow: [ - BoxShadow( - offset: const Offset(0, 21), - blurRadius: 23.0, - color: Theme.of(context).shadowColor.withOpacity( - Theme.of(context).shadowColor.opacity * - CurvedAnimation( - parent: CurvedAnimation( - parent: animation, - curve: Curves.easeInOutCubic), - curve: const Interval(2 / 3, 1.0), - ).value, - ), - ), + if (Provider.of(context, listen: false) + .shadowEffect) + BoxShadow( + offset: const Offset(0, 21), + blurRadius: 23.0, + color: Theme.of(context).shadowColor.withOpacity( + Theme.of(context).shadowColor.opacity * + CurvedAnimation( + parent: CurvedAnimation( + parent: animation, + curve: Curves.easeInOutCubic), + curve: const Interval(2 / 3, 1.0), + ).value, + ), + ), ], ), child: child, diff --git a/filcnaplo/lib/ui/widgets/grade/grade_tile.dart b/filcnaplo/lib/ui/widgets/grade/grade_tile.dart index 50e0d3a..a2778e5 100644 --- a/filcnaplo/lib/ui/widgets/grade/grade_tile.dart +++ b/filcnaplo/lib/ui/widgets/grade/grade_tile.dart @@ -34,8 +34,7 @@ class GradeTile extends StatelessWidget { GradeCalculatorProvider calculatorProvider = Provider.of(context, listen: false); - SettingsProvider settingsProvider = - Provider.of(context); + SettingsProvider settingsProvider = Provider.of(context); // Test order: // description // mode @@ -50,7 +49,8 @@ class GradeTile extends StatelessWidget { } } else { title = subjectName; - isTitleItalic = grade.subject.isRenamed && settingsProvider.renamedSubjectsItalics; + isTitleItalic = + grade.subject.isRenamed && settingsProvider.renamedSubjectsItalics; } // Test order: @@ -62,7 +62,9 @@ class GradeTile extends StatelessWidget { ? modeDescription : "" : subjectName; - isSubtitleItalic = isSubjectView ? false : grade.subject.isRenamed && settingsProvider.renamedSubjectsItalics; + isSubtitleItalic = isSubjectView + ? false + : grade.subject.isRenamed && settingsProvider.renamedSubjectsItalics; } else { subtitle = grade.value.valueName.split("(")[0]; } @@ -127,9 +129,7 @@ class GradeTile extends StatelessWidget { overflow: TextOverflow.ellipsis, style: TextStyle( fontWeight: FontWeight.w600, - fontStyle: isTitleItalic - ? FontStyle.italic - : null), + fontStyle: isTitleItalic ? FontStyle.italic : null), ), subtitle: subtitle != "" ? censored @@ -149,7 +149,10 @@ class GradeTile extends StatelessWidget { subtitle, maxLines: 1, overflow: TextOverflow.ellipsis, - style: TextStyle(fontWeight: FontWeight.w500, fontStyle: isSubtitleItalic ? FontStyle.italic : null), + style: TextStyle( + fontWeight: FontWeight.w500, + fontStyle: + isSubtitleItalic ? FontStyle.italic : null), ) : null, trailing: isSubjectView @@ -210,8 +213,8 @@ class GradeValueWidget extends StatelessWidget { GradeValue value = this.value; bool isSubjectView = SubjectGradesContainer.of(context) != null; - Color color = - this.color ?? gradeColor(context: context, value: value.value, nocolor: nocolor); + Color color = this.color ?? + gradeColor(context: context, value: value.value, nocolor: nocolor); Widget valueText; final percentage = value.percentage; @@ -283,7 +286,9 @@ class GradeValueWidget extends StatelessWidget { color: color.withOpacity(contrast ? 1.0 : .25), shape: BoxShape.circle, boxShadow: [ - if (shadow) + if (shadow && + Provider.of(context, listen: false) + .shadowEffect) BoxShadow( color: color, blurRadius: 62.0, diff --git a/filcnaplo/linux/.gitignore b/filcnaplo/linux/.gitignore deleted file mode 100644 index c7ea17f..0000000 --- a/filcnaplo/linux/.gitignore +++ /dev/null @@ -1 +0,0 @@ -flutter/ephemeral diff --git a/filcnaplo/linux/CMakeLists.txt b/filcnaplo/linux/CMakeLists.txt deleted file mode 100644 index 900368d..0000000 --- a/filcnaplo/linux/CMakeLists.txt +++ /dev/null @@ -1,116 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -project(runner LANGUAGES CXX) - -set(BINARY_NAME "filcnaplo") -set(APPLICATION_ID "hu.filc.filcnaplo") - -cmake_policy(SET CMP0063 NEW) - -set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - -# Root filesystem for cross-building. -if(FLUTTER_TARGET_PLATFORM_SYSROOT) - set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endif() - -# Configure build options. -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") -endif() - -# Compilation settings that should be applied to most targets. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_14) - target_compile_options(${TARGET} PRIVATE -Wall -Werror) - target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") - target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") -endfunction() - -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") - -# Flutter library and tool build rules. -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) - -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Application build -add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) -apply_standard_settings(${BINARY_NAME}) -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) -add_dependencies(${BINARY_NAME} flutter_assemble) -# Only the install-generated bundle's copy of the executable will launch -# correctly, since the resources must in the right relative locations. To avoid -# people trying to run the unbundled copy, put it in a subdirectory instead of -# the default top-level location. -set_target_properties(${BINARY_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" -) - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# By default, "installing" just makes a relocatable bundle in the build -# directory. -set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -# Start with a clean build bundle directory every time. -install(CODE " - file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") - " COMPONENT Runtime) - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -if(PLUGIN_BUNDLED_LIBRARIES) - install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") - install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() diff --git a/filcnaplo/linux/flutter/CMakeLists.txt b/filcnaplo/linux/flutter/CMakeLists.txt deleted file mode 100644 index 7a0003d..0000000 --- a/filcnaplo/linux/flutter/CMakeLists.txt +++ /dev/null @@ -1,87 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. - -# Serves the same purpose as list(TRANSFORM ... PREPEND ...), -# which isn't available in 3.10. -function(list_prepend LIST_NAME PREFIX) - set(NEW_LIST "") - foreach(element ${${LIST_NAME}}) - list(APPEND NEW_LIST "${PREFIX}${element}") - endforeach(element) - set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) -endfunction() - -# === Flutter Library === -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) -pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) - -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "fl_basic_message_channel.h" - "fl_binary_codec.h" - "fl_binary_messenger.h" - "fl_dart_project.h" - "fl_engine.h" - "fl_json_message_codec.h" - "fl_json_method_codec.h" - "fl_message_codec.h" - "fl_method_call.h" - "fl_method_channel.h" - "fl_method_codec.h" - "fl_method_response.h" - "fl_plugin_registrar.h" - "fl_plugin_registry.h" - "fl_standard_message_codec.h" - "fl_standard_method_codec.h" - "fl_string_codec.h" - "fl_value.h" - "fl_view.h" - "flutter_linux.h" -) -list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") -target_link_libraries(flutter INTERFACE - PkgConfig::GTK - PkgConfig::GLIB - PkgConfig::GIO -) -add_dependencies(flutter flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CMAKE_CURRENT_BINARY_DIR}/_phony_ - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" - ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} -) diff --git a/filcnaplo/macos/.gitignore b/filcnaplo/macos/.gitignore deleted file mode 100644 index d4e0569..0000000 --- a/filcnaplo/macos/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/dgph -**/xcuserdata/ diff --git a/filcnaplo/macos/Flutter/Flutter-Debug.xcconfig b/filcnaplo/macos/Flutter/Flutter-Debug.xcconfig deleted file mode 100644 index 63eaa61..0000000 --- a/filcnaplo/macos/Flutter/Flutter-Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/filcnaplo/macos/Flutter/Flutter-Release.xcconfig b/filcnaplo/macos/Flutter/Flutter-Release.xcconfig deleted file mode 100644 index 88d14e0..0000000 --- a/filcnaplo/macos/Flutter/Flutter-Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/filcnaplo/pubspec.yaml b/filcnaplo/pubspec.yaml index 844ef02..5d8a82b 100644 --- a/filcnaplo/pubspec.yaml +++ b/filcnaplo/pubspec.yaml @@ -3,7 +3,7 @@ description: "Nem hivatalos e-napló alkalmazás az e-Kréta rendszerhez" homepage: https://refilc.hu publish_to: "none" -version: 4.3.1+230 +version: 4.4.0+232 environment: sdk: ">=2.17.0 <3.0.0" diff --git a/filcnaplo/windows/.gitignore b/filcnaplo/windows/.gitignore deleted file mode 100644 index d492d0d..0000000 --- a/filcnaplo/windows/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -flutter/ephemeral/ - -# Visual Studio user-specific files. -*.suo -*.user -*.userosscache -*.sln.docstates - -# Visual Studio build-related files. -x64/ -x86/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ diff --git a/filcnaplo_desktop_ui/.gitignore b/filcnaplo_desktop_ui/.gitignore deleted file mode 100644 index 516bea4..0000000 --- a/filcnaplo_desktop_ui/.gitignore +++ /dev/null @@ -1,47 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Web related -lib/generated_plugin_registrant.dart - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release -pubspec.lock diff --git a/filcnaplo_desktop_ui/lib/pages/absences/absences_page.dart b/filcnaplo_desktop_ui/lib/pages/absences/absences_page.dart index f9270b5..5f25081 100644 --- a/filcnaplo_desktop_ui/lib/pages/absences/absences_page.dart +++ b/filcnaplo_desktop_ui/lib/pages/absences/absences_page.dart @@ -31,7 +31,7 @@ import 'absences_page.i18n.dart'; enum AbsenceFilter { absences, delays, misses } class SubjectAbsence { - Subject subject; + GradeSubject subject; List absences; double percentage; @@ -56,7 +56,7 @@ class _AbsencesPageState extends State late String firstName; late TabController _tabController; late List absences = []; - final Map _lessonCount = {}; + final Map _lessonCount = {}; @override void initState() { @@ -87,7 +87,7 @@ class _AbsencesPageState extends State } void buildSubjectAbsences() { - Map _absences = {}; + Map _absences = {}; for (final absence in absenceProvider.absences) { if (absence.delay != 0) continue; diff --git a/filcnaplo_desktop_ui/lib/pages/grades/grade_subject_view.dart b/filcnaplo_desktop_ui/lib/pages/grades/grade_subject_view.dart index 95571f1..1b30577 100644 --- a/filcnaplo_desktop_ui/lib/pages/grades/grade_subject_view.dart +++ b/filcnaplo_desktop_ui/lib/pages/grades/grade_subject_view.dart @@ -32,7 +32,7 @@ class GradeSubjectView extends StatefulWidget { const GradeSubjectView(this.subject, {Key? key, this.groupAverage = 0.0}) : super(key: key); - final Subject subject; + final GradeSubject subject; final double groupAverage; void push(BuildContext context, {bool root = false}) { @@ -62,7 +62,7 @@ class _GradeSubjectViewState extends State { bool gradeCalcMode = false; - List getSubjectGrades(Subject subject) => !gradeCalcMode + List getSubjectGrades(GradeSubject subject) => !gradeCalcMode ? gradeProvider.grades.where((e) => e.subject == subject).toList() : calculatorProvider.grades.where((e) => e.subject == subject).toList(); diff --git a/filcnaplo_desktop_ui/lib/pages/grades/grades_page.dart b/filcnaplo_desktop_ui/lib/pages/grades/grades_page.dart index 0a2099b..06bbcd5 100644 --- a/filcnaplo_desktop_ui/lib/pages/grades/grades_page.dart +++ b/filcnaplo_desktop_ui/lib/pages/grades/grades_page.dart @@ -41,7 +41,7 @@ class _GradesPageState extends State { int avgDropValue = 0; - List getSubjectGrades(Subject subject, {int days = 0}) => gradeProvider + List getSubjectGrades(GradeSubject subject, {int days = 0}) => gradeProvider .grades .where((e) => e.subject == subject && @@ -51,14 +51,14 @@ class _GradesPageState extends State { .toList(); void generateTiles() { - List subjects = gradeProvider.grades + List subjects = gradeProvider.grades .map((e) => e.subject) .toSet() .toList() ..sort((a, b) => a.name.compareTo(b.name)); List tiles = []; - Map subjectAvgs = {}; + Map subjectAvgs = {}; tiles.addAll(subjects.map((subject) { List subjectGrades = getSubjectGrades(subject); diff --git a/filcnaplo_desktop_ui/lib/pages/grades/grades_page.i18n.dart b/filcnaplo_desktop_ui/lib/pages/grades/grades_page.i18n.dart index 11d7fbb..56db6ff 100644 --- a/filcnaplo_desktop_ui/lib/pages/grades/grades_page.i18n.dart +++ b/filcnaplo_desktop_ui/lib/pages/grades/grades_page.i18n.dart @@ -16,7 +16,7 @@ extension Localization on String { "7_days_average": "Weekly Average", "subjectavg": "Subject Average", "classavg": "Class Average", - "fail_warning": "Faliure warning", + "fail_warning": "Failure warning", "fail_warning_description": "You are failing %d subject(s)", }, "hu_hu": { diff --git a/filcnaplo_kreta_api/.gitignore b/filcnaplo_kreta_api/.gitignore deleted file mode 100644 index 516bea4..0000000 --- a/filcnaplo_kreta_api/.gitignore +++ /dev/null @@ -1,47 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Web related -lib/generated_plugin_registrant.dart - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release -pubspec.lock diff --git a/filcnaplo_kreta_api/lib/client/api.dart b/filcnaplo_kreta_api/lib/client/api.dart index 4c2f775..708da1d 100644 --- a/filcnaplo_kreta_api/lib/client/api.dart +++ b/filcnaplo_kreta_api/lib/client/api.dart @@ -54,6 +54,30 @@ class KretaAPI { String iss, String uid, String type) => BaseKreta.kreta(iss) + KretaApiEndpoints.downloadHomeworkAttachments(uid, type); + static String subjects(String iss, String uid) => + BaseKreta.kreta(iss) + + KretaApiEndpoints.subjects + + "?oktatasiNevelesiFeladatUid=" + uid; + // Structure: + // { + // "Uid": 000, + // "Tantargy": { + // "Uid": 000, + // "Nev": "Irodalom", + // "Kategoria": { + // "Uid": "000,magyar_nyelv_es_irodalom", + // "Nev": "magyar_nyelv_es_irodalom", + // "Leiras": "Magyar nyelv és irodalom" + // }, + // "SortIndex": 0, + // }, + // "Atlag": null, // float + // "AtlagAlakulasaIdoFuggvenyeben": Array[], // no idea what this is + // "SulyozottOsztalyzatOsszege": null, // int | float + // "SulyozottOsztalyzatSzama": null, // int | float + // "SortIndex": 0 + // } + // refer to https://discord.com/channels/1111649116020285532/1111798771513303102/1148368925969612920 // ADMIN API static const sendMessage = @@ -105,6 +129,7 @@ class KretaApiEndpoints { static const capabilities = "/ellenorzo/V3/Sajat/Intezmenyek"; static String downloadHomeworkAttachments(String uid, String type) => "/ellenorzo/V3/Sajat/Csatolmany/$uid"; + static const subjects = "/ellenorzo/V3/Sajat/Ertekelesek/Atlagok/TantargyiAtlagok"; } class KretaAdminEndpoints { diff --git a/filcnaplo_kreta_api/lib/models/absence.dart b/filcnaplo_kreta_api/lib/models/absence.dart index 9997351..23d4db3 100644 --- a/filcnaplo_kreta_api/lib/models/absence.dart +++ b/filcnaplo_kreta_api/lib/models/absence.dart @@ -13,7 +13,7 @@ class Absence { Category? justification; Category? type; Category? mode; - Subject subject; + GradeSubject subject; DateTime lessonStart; DateTime lessonEnd; int? lessonIndex; @@ -83,7 +83,7 @@ class Absence { : null, type: json["Tipus"] != null ? Category.fromJson(json["Tipus"]) : null, mode: json["Mod"] != null ? Category.fromJson(json["Mod"]) : null, - subject: Subject.fromJson(json["Tantargy"] ?? {}), + subject: GradeSubject.fromJson(json["Tantargy"] ?? {}), lessonStart: lessonStart, lessonEnd: lessonEnd, lessonIndex: lessonIndex, diff --git a/filcnaplo_kreta_api/lib/models/exam.dart b/filcnaplo_kreta_api/lib/models/exam.dart index 5f7689b..94055fa 100644 --- a/filcnaplo_kreta_api/lib/models/exam.dart +++ b/filcnaplo_kreta_api/lib/models/exam.dart @@ -1,3 +1,5 @@ +import 'package:filcnaplo_kreta_api/models/subject.dart'; + import 'category.dart'; import 'teacher.dart'; @@ -6,8 +8,9 @@ class Exam { DateTime date; DateTime writeDate; Category? mode; - int? subjectIndex; - String subjectName; + // int? subjectIndex; + // String subjectName; + GradeSubject subject; Teacher teacher; String description; String group; @@ -18,8 +21,9 @@ class Exam { required this.date, required this.writeDate, this.mode, - this.subjectIndex, - required this.subjectName, + // this.subjectIndex, + // required this.subjectName, + required this.subject, required this.teacher, required this.description, required this.group, @@ -36,8 +40,9 @@ class Exam { ? DateTime.parse(json["Datum"]).toLocal() : DateTime(0), mode: json["Modja"] != null ? Category.fromJson(json["Modja"]) : null, - subjectIndex: json["OrarendiOraOraszama"], - subjectName: json["TantargyNeve"] ?? "", + // subjectIndex: json["OrarendiOraOraszama"], + // subjectName: json["TantargyNeve"] ?? "", + subject: GradeSubject.fromJson(json["Tantargy"] ?? {}), teacher: Teacher.fromString((json["RogzitoTanarNeve"] ?? "").trim()), description: (json["Temaja"] ?? "").trim(), group: json["OsztalyCsoport"] != null diff --git a/filcnaplo_kreta_api/lib/models/grade.dart b/filcnaplo_kreta_api/lib/models/grade.dart index 80c7db7..35d6709 100644 --- a/filcnaplo_kreta_api/lib/models/grade.dart +++ b/filcnaplo_kreta_api/lib/models/grade.dart @@ -12,7 +12,7 @@ class Grade { String description; GradeType type; String groupId; - Subject subject; + GradeSubject subject; Category? gradeType; Category mode; DateTime writeDate; @@ -57,7 +57,7 @@ class Grade { ? Category.getGradeType(json["Tipus"]["Nev"]) : GradeType.unknown, groupId: (json["OsztalyCsoport"] ?? {})["Uid"] ?? "", - subject: Subject.fromJson(json["Tantargy"] ?? {}), + subject: GradeSubject.fromJson(json["Tantargy"] ?? {}), gradeType: json["ErtekFajta"] != null ? Category.fromJson(json["ErtekFajta"]) : null, diff --git a/filcnaplo_kreta_api/lib/models/group_average.dart b/filcnaplo_kreta_api/lib/models/group_average.dart index e95f730..7441966 100644 --- a/filcnaplo_kreta_api/lib/models/group_average.dart +++ b/filcnaplo_kreta_api/lib/models/group_average.dart @@ -3,7 +3,7 @@ import 'package:filcnaplo_kreta_api/models/subject.dart'; class GroupAverage { String uid; double average; - Subject subject; + GradeSubject subject; Map json; GroupAverage({required this.uid, required this.average, required this.subject, this.json = const {}}); @@ -12,7 +12,7 @@ class GroupAverage { return GroupAverage( uid: json["Uid"] ?? "", average: json["OsztalyCsoportAtlag"] ?? 0, - subject: Subject.fromJson(json["Tantargy"] ?? {}), + subject: GradeSubject.fromJson(json["Tantargy"] ?? {}), json: json, ); } diff --git a/filcnaplo_kreta_api/lib/models/homework.dart b/filcnaplo_kreta_api/lib/models/homework.dart index bd4ab39..88102ec 100644 --- a/filcnaplo_kreta_api/lib/models/homework.dart +++ b/filcnaplo_kreta_api/lib/models/homework.dart @@ -12,7 +12,7 @@ class Homework { bool homeworkEnabled; Teacher teacher; String content; - Subject subject; + GradeSubject subject; String group; List attachments; String id; @@ -48,7 +48,7 @@ class Homework { homeworkEnabled: json["IsTanuloHaziFeladatEnabled"] ?? false, teacher: Teacher.fromString((json["RogzitoTanarNeve"] ?? "").trim()), content: (json["Szoveg"] ?? "").trim(), - subject: Subject.fromJson(json["Tantargy"] ?? {}), + subject: GradeSubject.fromJson(json["Tantargy"] ?? {}), group: json["OsztalyCsoport"] != null ? json["OsztalyCsoport"]["Uid"] ?? "" : "", diff --git a/filcnaplo_kreta_api/lib/models/lesson.dart b/filcnaplo_kreta_api/lib/models/lesson.dart index afa7d7c..7cd0008 100644 --- a/filcnaplo_kreta_api/lib/models/lesson.dart +++ b/filcnaplo_kreta_api/lib/models/lesson.dart @@ -6,7 +6,7 @@ class Lesson { Map? json; Category? status; DateTime date; - Subject subject; + GradeSubject subject; String lessonIndex; int? lessonYearIndex; Teacher? substituteTeacher; @@ -68,7 +68,7 @@ class Lesson { date: json["Datum"] != null ? DateTime.parse(json["Datum"]).toLocal() : DateTime(0), - subject: Subject.fromJson(json["Tantargy"] ?? {}), + subject: GradeSubject.fromJson(json["Tantargy"] ?? {}), lessonIndex: json["Oraszam"] != null ? json["Oraszam"].toString() : "+", lessonYearIndex: json["OraEvesSorszama"], substituteTeacher: json["HelyettesTanarNeve"] != null diff --git a/filcnaplo_kreta_api/lib/models/subject.dart b/filcnaplo_kreta_api/lib/models/subject.dart index ec36d32..1ebd8ec 100644 --- a/filcnaplo_kreta_api/lib/models/subject.dart +++ b/filcnaplo_kreta_api/lib/models/subject.dart @@ -1,6 +1,6 @@ import 'category.dart'; -class Subject { +class GradeSubject { String id; Category category; String name; @@ -8,11 +8,16 @@ class Subject { bool get isRenamed => renamedTo != null; - Subject({required this.id, required this.category, required this.name, this.renamedTo}); + GradeSubject({ + required this.id, + required this.category, + required this.name, + this.renamedTo, + }); - factory Subject.fromJson(Map json) { + factory GradeSubject.fromJson(Map json) { final id = json["Uid"] ?? ""; - return Subject( + return GradeSubject( id: id, category: Category.fromJson(json["Kategoria"] ?? {}), name: (json["Nev"] ?? "").trim(), @@ -21,7 +26,7 @@ class Subject { @override bool operator ==(other) { - if (other is! Subject) return false; + if (other is! GradeSubject) return false; return id == other.id; } diff --git a/filcnaplo_kreta_api/lib/providers/exam_provider.dart b/filcnaplo_kreta_api/lib/providers/exam_provider.dart index 6f69f47..8f0c1e5 100644 --- a/filcnaplo_kreta_api/lib/providers/exam_provider.dart +++ b/filcnaplo_kreta_api/lib/providers/exam_provider.dart @@ -27,19 +27,49 @@ class ExamProvider with ChangeNotifier { // Load exams from the database if (userId != null) { - var dbExams = await Provider.of(_context, listen: false).userQuery.getExams(userId: userId); + var dbExams = await Provider.of(_context, listen: false) + .userQuery + .getExams(userId: userId); _exams = dbExams; notifyListeners(); + await convertBySettings(); } } + // for renamed subjects + Future convertBySettings() async { + final _database = Provider.of(_context, listen: false); + Map renamedSubjects = + (await _database.query.getSettings(_database)).renamedSubjectsEnabled + ? await _database.userQuery.renamedSubjects( + userId: + Provider.of(_context, listen: false).user!.id) + : {}; + Map renamedTeachers = + (await _database.query.getSettings(_database)).renamedTeachersEnabled + ? await _database.userQuery.renamedTeachers( + userId: + Provider.of(_context, listen: false).user!.id) + : {}; + + for (Exam exam in _exams) { + exam.subject.renamedTo = + renamedSubjects.isNotEmpty ? renamedSubjects[exam.subject.id] : null; + exam.teacher.renamedTo = + renamedTeachers.isNotEmpty ? renamedTeachers[exam.teacher.id] : null; + } + + notifyListeners(); + } + // Fetches Exams from the Kreta API then stores them in the database Future fetch() async { User? user = Provider.of(_context, listen: false).user; if (user == null) throw "Cannot fetch Exams for User null"; String iss = user.instituteCode; - List? examsJson = await Provider.of(_context, listen: false).getAPI(KretaAPI.exams(iss)); + List? examsJson = await Provider.of(_context, listen: false) + .getAPI(KretaAPI.exams(iss)); if (examsJson == null) throw "Cannot fetch Exams for User ${user.id}"; List exams = examsJson.map((e) => Exam.fromJson(e)).toList(); @@ -52,8 +82,11 @@ class ExamProvider with ChangeNotifier { if (user == null) throw "Cannot store Exams for User null"; String userId = user.id; - await Provider.of(_context, listen: false).userStore.storeExams(exams, userId: userId); + await Provider.of(_context, listen: false) + .userStore + .storeExams(exams, userId: userId); _exams = exams; notifyListeners(); + await convertBySettings(); } } diff --git a/filcnaplo_kreta_api/lib/providers/homework_provider.dart b/filcnaplo_kreta_api/lib/providers/homework_provider.dart index 9d4eeb8..34b12a0 100644 --- a/filcnaplo_kreta_api/lib/providers/homework_provider.dart +++ b/filcnaplo_kreta_api/lib/providers/homework_provider.dart @@ -1,6 +1,6 @@ import 'package:filcnaplo/api/providers/user_provider.dart'; import 'package:filcnaplo/api/providers/database_provider.dart'; -import 'package:filcnaplo/models/settings.dart'; +// import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo/models/user.dart'; import 'package:filcnaplo_kreta_api/client/api.dart'; import 'package:filcnaplo_kreta_api/client/client.dart'; @@ -11,7 +11,7 @@ import 'package:provider/provider.dart'; class HomeworkProvider with ChangeNotifier { // Private - late final SettingsProvider _settings; + // late final SettingsProvider _settings; late final UserProvider _user; late final DatabaseProvider _database; @@ -80,9 +80,11 @@ class HomeworkProvider with ChangeNotifier { List? homeworkJson = []; try { - homeworkJson = await Provider.of(_context, listen: false) + Iterable hwjson = await Provider.of(_context, listen: false) .getAPI(KretaAPI.homework(iss, start: from)); + homeworkJson = List.from(hwjson.map((model) => model)); } catch (e) { + if (kDebugMode) print(e); // error fetcing homework (unknown error) } @@ -95,15 +97,15 @@ class HomeworkProvider with ChangeNotifier { await Future.forEach(homeworkJson.cast(), (Map hw) async { Map? e = await Provider.of(_context, listen: false) .getAPI(KretaAPI.homework(iss, id: hw["Uid"])); - Map renamedSubjects = _settings.renamedSubjectsEnabled - ? await _database.userQuery.renamedSubjects(userId: _user.user!.id) - : {}; + // Map renamedSubjects = _settings.renamedSubjectsEnabled + // ? await _database.userQuery.renamedSubjects(userId: _user.user!.id) + // : {}; if (e != null) { - Homework hw = Homework.fromJson(e); - hw.subject.renamedTo = - renamedSubjects.isNotEmpty ? renamedSubjects[hw.subject.id] : null; - homework.add(hw); + Homework hmwrk = Homework.fromJson(e); + // hw.subject.renamedTo = + // renamedSubjects.isNotEmpty ? renamedSubjects[hw.subject.id] : null; + homework.add(hmwrk); } }); @@ -112,6 +114,7 @@ class HomeworkProvider with ChangeNotifier { if (db) await store(homework); _homework = homework; notifyListeners(); + await convertBySettings(); } // Stores Homework in the database diff --git a/filcnaplo_kreta_api/lib/providers/subject_provider.dart b/filcnaplo_kreta_api/lib/providers/subject_provider.dart new file mode 100644 index 0000000..8401e3a --- /dev/null +++ b/filcnaplo_kreta_api/lib/providers/subject_provider.dart @@ -0,0 +1,165 @@ +// import 'package:filcnaplo/api/providers/user_provider.dart'; +// import 'package:filcnaplo/api/providers/database_provider.dart'; +// import 'package:filcnaplo/models/settings.dart'; +// import 'package:filcnaplo/models/user.dart'; +// import 'package:filcnaplo_kreta_api/client/api.dart'; +// import 'package:filcnaplo_kreta_api/client/client.dart'; +// import 'package:filcnaplo_kreta_api/models/grade.dart'; +// import 'package:filcnaplo_kreta_api/models/group_average.dart'; +// import 'package:filcnaplo_kreta_api/providers/grade_provider.i18n.dart'; +// import 'package:flutter/material.dart'; + +// class SubjectProvider with ChangeNotifier { +// // Private +// late List _grades; +// late DateTime _lastSeen; +// late String _groups; +// List _groupAvg = []; +// late final SettingsProvider _settings; +// late final UserProvider _user; +// late final DatabaseProvider _database; +// late final KretaClient _kreta; + +// // Public +// List get grades => _grades; +// DateTime get lastSeenDate => +// _settings.gradeOpeningFun ? _lastSeen : DateTime(3000); +// String get groups => _groups; +// List get groupAverages => _groupAvg; + +// SubjectProvider({ +// List initialGrades = const [], +// required SettingsProvider settings, +// required UserProvider user, +// required DatabaseProvider database, +// required KretaClient kreta, +// }) { +// _settings = settings; +// _user = user; +// _database = database; +// _kreta = kreta; + +// _grades = List.castFrom(initialGrades); +// _lastSeen = DateTime.now(); + +// if (_grades.isEmpty) restore(); +// } + +// Future seenAll() async { +// String? userId = _user.id; +// if (userId != null) { +// final userStore = _database.userStore; +// userStore.storeLastSeenGrade(DateTime.now(), userId: userId); +// _lastSeen = DateTime.now(); +// } +// } + +// Future restore() async { +// String? userId = _user.id; + +// // Load grades from the database +// if (userId != null) { +// final userQuery = _database.userQuery; + +// _grades = await userQuery.getGrades(userId: userId); +// await convertBySettings(); +// _groupAvg = await userQuery.getGroupAverages(userId: userId); +// notifyListeners(); +// DateTime lastSeenDB = await userQuery.lastSeenGrade(userId: userId); +// if (lastSeenDB.millisecondsSinceEpoch == 0 || +// lastSeenDB.year == 0 || +// !_settings.gradeOpeningFun) { +// _lastSeen = DateTime.now(); +// await seenAll(); +// } else { +// _lastSeen = lastSeenDB; +// } +// notifyListeners(); +// } +// } + +// // good student mode, renamed subjects +// Future convertBySettings() async { +// Map renamedSubjects = _settings.renamedSubjectsEnabled +// ? await _database.userQuery.renamedSubjects(userId: _user.user!.id) +// : {}; +// Map renamedTeachers = _settings.renamedTeachersEnabled +// ? await _database.userQuery.renamedTeachers(userId: _user.user!.id) +// : {}; + +// for (Grade grade in _grades) { +// grade.subject.renamedTo = +// renamedSubjects.isNotEmpty ? renamedSubjects[grade.subject.id] : null; +// grade.teacher.renamedTo = +// renamedTeachers.isNotEmpty ? renamedTeachers[grade.teacher.id] : null; + +// grade.value.value = +// _settings.goodStudent ? 5 : grade.json!["SzamErtek"] ?? 0; +// grade.value.valueName = _settings.goodStudent +// ? "Jeles".i18n +// : '${grade.json!["SzovegesErtek"]}' +// .replaceAll(RegExp(r'[(]+[12345]?[)]'), '') +// .i18n; +// grade.value.shortName = _settings.goodStudent +// ? "Jeles".i18n +// : '${grade.json!["SzovegesErtekelesRovidNev"]}' != "null" && +// '${grade.json!["SzovegesErtekelesRovidNev"]}' != "-" && +// '${grade.json!["SzovegesErtekelesRovidNev"]}' +// .replaceAll(RegExp(r'[0123456789]+[%]?'), '') != +// "" +// ? '${grade.json!["SzovegesErtekelesRovidNev"]}'.i18n +// : grade.value.valueName; +// } + +// notifyListeners(); +// } + +// // fetch subjects from kreten then store them +// Future fetch() async { +// User? user = _user.user; +// if (user == null) throw "Cannot fetch Subjects for User null"; +// String iss = user.instituteCode; + +// List? gradesJson = await _kreta.getAPI(KretaAPI.subjects(iss, "")); +// if (gradesJson == null) throw "Cannot fetch Subjects for User ${user.id}"; +// List grades = gradesJson.map((e) => Grade.fromJson(e)).toList(); + +// if (grades.isNotEmpty || _grades.isNotEmpty) await store(grades); + +// List? groupsJson = await _kreta.getAPI(KretaAPI.groups(iss)); +// if (groupsJson == null || groupsJson.isEmpty) { +// throw "Cannot fetch Groups for User ${user.id}"; +// } +// _groups = (groupsJson[0]["OktatasNevelesiFeladat"] ?? {})["Uid"] ?? ""; + +// List? groupAvgJson = +// await _kreta.getAPI(KretaAPI.groupAverages(iss, _groups)); +// if (groupAvgJson == null) { +// throw "Cannot fetch Class Averages for User ${user.id}"; +// } +// final groupAvgs = +// groupAvgJson.map((e) => GroupAverage.fromJson(e)).toList(); +// await storeGroupAvg(groupAvgs); +// } + +// // store subjects in db +// Future store(List grades) async { +// User? user = _user.user; +// if (user == null) throw "Cannot store Grades for User null"; +// String userId = user.id; + +// await _database.userStore.storeGrades(grades, userId: userId); +// _grades = grades; +// await convertBySettings(); +// } + +// Future storeGroupAvg(List groupAvgs) async { +// _groupAvg = groupAvgs; + +// User? user = _user.user; +// if (user == null) throw "Cannot store Grades for User null"; +// String userId = user.id; +// await _database.userStore.storeGroupAverages(groupAvgs, userId: userId); +// notifyListeners(); +// } +// } diff --git a/filcnaplo_mobile_ui/.gitignore b/filcnaplo_mobile_ui/.gitignore deleted file mode 100644 index 516bea4..0000000 --- a/filcnaplo_mobile_ui/.gitignore +++ /dev/null @@ -1,47 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Web related -lib/generated_plugin_registrant.dart - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release -pubspec.lock diff --git a/filcnaplo_mobile_ui/lib/common/panel/panel.dart b/filcnaplo_mobile_ui/lib/common/panel/panel.dart index cc82c53..0e2f351 100755 --- a/filcnaplo_mobile_ui/lib/common/panel/panel.dart +++ b/filcnaplo_mobile_ui/lib/common/panel/panel.dart @@ -1,8 +1,12 @@ +import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo/theme/colors/colors.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class Panel extends StatelessWidget { - const Panel({Key? key, this.child, this.title, this.padding, this.hasShadow = true}) : super(key: key); + const Panel( + {Key? key, this.child, this.title, this.padding, this.hasShadow = true}) + : super(key: key); final Widget? child; final Widget? title; @@ -25,7 +29,9 @@ class Panel extends StatelessWidget { borderRadius: BorderRadius.circular(16.0), color: Theme.of(context).colorScheme.background, boxShadow: [ - if (hasShadow) + if (hasShadow && + Provider.of(context, listen: false) + .shadowEffect) BoxShadow( offset: const Offset(0, 21), blurRadius: 23.0, @@ -51,7 +57,9 @@ class PanelTitle extends StatelessWidget { return Padding( padding: const EdgeInsets.only(left: 14.0, bottom: 8.0), child: DefaultTextStyle( - style: Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.w600, color: AppColors.of(context).text.withOpacity(0.65)), + style: Theme.of(context).textTheme.titleMedium!.copyWith( + fontWeight: FontWeight.w600, + color: AppColors.of(context).text.withOpacity(0.65)), child: title, ), ); @@ -69,14 +77,17 @@ class PanelHeader extends StatelessWidget { width: double.infinity, padding: padding, decoration: BoxDecoration( - borderRadius: const BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0)), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0)), color: Theme.of(context).colorScheme.background, boxShadow: [ - BoxShadow( - offset: const Offset(0, 21), - blurRadius: 23.0, - color: Theme.of(context).shadowColor, - ) + if (Provider.of(context, listen: false) + .shadowEffect) + BoxShadow( + offset: const Offset(0, 21), + blurRadius: 23.0, + color: Theme.of(context).shadowColor, + ) ], ), ); @@ -96,11 +107,13 @@ class PanelBody extends StatelessWidget { decoration: BoxDecoration( color: Theme.of(context).colorScheme.background, boxShadow: [ - BoxShadow( - offset: const Offset(0, 21), - blurRadius: 23.0, - color: Theme.of(context).shadowColor, - ) + if (Provider.of(context, listen: false) + .shadowEffect) + BoxShadow( + offset: const Offset(0, 21), + blurRadius: 23.0, + color: Theme.of(context).shadowColor, + ) ], ), padding: padding, @@ -120,14 +133,18 @@ class PanelFooter extends StatelessWidget { width: double.infinity, padding: padding, decoration: BoxDecoration( - borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(16.0), bottomRight: Radius.circular(16.0)), + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(16.0), + bottomRight: Radius.circular(16.0)), color: Theme.of(context).colorScheme.background, boxShadow: [ - BoxShadow( - offset: const Offset(0, 21), - blurRadius: 23.0, - color: Theme.of(context).shadowColor, - ) + if (Provider.of(context, listen: false) + .shadowEffect) + BoxShadow( + offset: const Offset(0, 21), + blurRadius: 23.0, + color: Theme.of(context).shadowColor, + ) ], ), ); diff --git a/filcnaplo_mobile_ui/lib/common/personality_card/empty_card.dart b/filcnaplo_mobile_ui/lib/common/personality_card/empty_card.dart index 9df12a8..fec8b1a 100644 --- a/filcnaplo_mobile_ui/lib/common/personality_card/empty_card.dart +++ b/filcnaplo_mobile_ui/lib/common/personality_card/empty_card.dart @@ -1,5 +1,7 @@ import 'package:dotted_border/dotted_border.dart'; +import 'package:filcnaplo/models/settings.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class EmptyCard extends StatefulWidget { const EmptyCard({ @@ -39,12 +41,14 @@ class _EmptyCardState extends State { color: const Color(0x280008FF), borderRadius: const BorderRadius.all(Radius.circular(5)), boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.08), - offset: const Offset(0, 5), - blurRadius: 20, - spreadRadius: 10, - ), + if (Provider.of(context, listen: false) + .shadowEffect) + BoxShadow( + color: Colors.black.withOpacity(0.08), + offset: const Offset(0, 5), + blurRadius: 20, + spreadRadius: 10, + ), ], ), child: DottedBorder( diff --git a/filcnaplo_mobile_ui/lib/common/personality_card/personality_card.dart b/filcnaplo_mobile_ui/lib/common/personality_card/personality_card.dart index a6dec8e..b442c38 100644 --- a/filcnaplo_mobile_ui/lib/common/personality_card/personality_card.dart +++ b/filcnaplo_mobile_ui/lib/common/personality_card/personality_card.dart @@ -35,12 +35,12 @@ class _PersonalityCardState extends State { late SettingsProvider settings; late List subjectAvgsList = []; - late Map subjectAvgs = {}; + late Map subjectAvgs = {}; late double subjectAvg; late List classWorkGrades; late Map mostCommonGrade; late List absences = []; - final Map _lessonCount = {}; + final Map _lessonCount = {}; late int totalDelays; late int unexcusedAbsences; @@ -48,14 +48,15 @@ class _PersonalityCardState extends State { bool hold = false; - List getSubjectGrades(Subject subject, {int days = 0}) => gradeProvider - .grades - .where((e) => - e.subject == subject && - e.type == GradeType.midYear && - (days == 0 || - e.date.isBefore(DateTime.now().subtract(Duration(days: days))))) - .toList(); + List getSubjectGrades(GradeSubject subject, {int days = 0}) => + gradeProvider.grades + .where((e) => + e.subject == subject && + e.type == GradeType.midYear && + (days == 0 || + e.date + .isBefore(DateTime.now().subtract(Duration(days: days))))) + .toList(); @override void initState() { @@ -89,13 +90,13 @@ class _PersonalityCardState extends State { } void getGrades() { - List subjects = gradeProvider.grades + List subjects = gradeProvider.grades .map((e) => e.subject) .toSet() .toList() ..sort((a, b) => a.name.compareTo(b.name)); - for (Subject subject in subjects) { + for (GradeSubject subject in subjects) { List subjectGrades = getSubjectGrades(subject); double avg = AverageHelper.averageEvals(subjectGrades); diff --git a/filcnaplo_mobile_ui/lib/common/soon_alert/soon_alert.dart b/filcnaplo_mobile_ui/lib/common/soon_alert/soon_alert.dart new file mode 100644 index 0000000..4fdba24 --- /dev/null +++ b/filcnaplo_mobile_ui/lib/common/soon_alert/soon_alert.dart @@ -0,0 +1,22 @@ +import 'package:filcnaplo_mobile_ui/common/action_button.dart'; +import 'package:filcnaplo_mobile_ui/common/soon_alert/soon_alert.i18n.dart'; +import 'package:flutter/material.dart'; + +class SoonAlert extends StatelessWidget { + const SoonAlert({Key? key}) : super(key: key); + + static show({required BuildContext context}) => + showDialog(context: context, builder: (context) => const SoonAlert()); + + @override + Widget build(BuildContext context) { + return AlertDialog( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)), + title: Text('soon'.i18n), + content: Text('soon_body'.i18n), + actions: [ + ActionButton(label: "Ok", onTap: () => Navigator.of(context).pop()) + ], + ); + } +} diff --git a/filcnaplo_mobile_ui/lib/common/soon_alert/soon_alert.i18n.dart b/filcnaplo_mobile_ui/lib/common/soon_alert/soon_alert.i18n.dart new file mode 100644 index 0000000..f5066c9 --- /dev/null +++ b/filcnaplo_mobile_ui/lib/common/soon_alert/soon_alert.i18n.dart @@ -0,0 +1,24 @@ +import 'package:i18n_extension/i18n_extension.dart'; + +extension Localization on String { + static final _t = Translations.byLocale("hu_hu") + + { + "en_en": { + "soon": "Soon...", + "soon_body": "This feature is currently not available yet!", + }, + "hu_hu": { + "soon": "Hamarosan...", + "soon_body": "Ez a funkció jelenleg még nem elérhető!", + }, + "de_de": { + "soon": "Bald...", + "soon_body": "Diese Funktion ist derzeit noch nicht verfügbar!", + }, + }; + + String get i18n => localize(this, _t); + String fill(List params) => localizeFill(this, params); + String plural(int value) => localizePlural(value, this, _t); + String version(Object modifier) => localizeVersion(modifier, this, _t); +} diff --git a/filcnaplo_mobile_ui/lib/common/widgets/absence/absence_subject_tile.dart b/filcnaplo_mobile_ui/lib/common/widgets/absence/absence_subject_tile.dart index c8fc05d..adf5e5f 100755 --- a/filcnaplo_mobile_ui/lib/common/widgets/absence/absence_subject_tile.dart +++ b/filcnaplo_mobile_ui/lib/common/widgets/absence/absence_subject_tile.dart @@ -8,10 +8,16 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class AbsenceSubjectTile extends StatelessWidget { - const AbsenceSubjectTile(this.subject, {Key? key, this.percentage = 0.0, this.excused = 0, this.unexcused = 0, this.pending = 0, this.onTap}) + const AbsenceSubjectTile(this.subject, + {Key? key, + this.percentage = 0.0, + this.excused = 0, + this.unexcused = 0, + this.pending = 0, + this.onTap}) : super(key: key); - final Subject subject; + final GradeSubject subject; final void Function()? onTap; final double percentage; @@ -31,12 +37,20 @@ class AbsenceSubjectTile extends StatelessWidget { shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)), visualDensity: VisualDensity.compact, onTap: onTap, - leading: Icon(SubjectIcon.resolveVariant(subject: subject, context: context), size: 32.0), + leading: Icon( + SubjectIcon.resolveVariant(subject: subject, context: context), + size: 32.0), title: Text( subject.renamedTo ?? subject.name.capital(), maxLines: 2, overflow: TextOverflow.ellipsis, - style: TextStyle(fontWeight: FontWeight.w600, fontSize: 15.0, fontStyle: subject.isRenamed && settingsProvider.renamedSubjectsItalics ? FontStyle.italic : null), + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 15.0, + fontStyle: + subject.isRenamed && settingsProvider.renamedSubjectsItalics + ? FontStyle.italic + : null), ), subtitle: AbsenceDisplay(excused, unexcused, pending), trailing: Row( @@ -47,7 +61,10 @@ class AbsenceSubjectTile extends StatelessWidget { Stack( alignment: Alignment.centerRight, children: [ - const Opacity(child: Text("100%", style: TextStyle(fontFamily: "monospace")), opacity: 0), + const Opacity( + child: Text("100%", + style: TextStyle(fontFamily: "monospace")), + opacity: 0), Text( percentage.round().toString() + "%", style: TextStyle( diff --git a/filcnaplo_mobile_ui/lib/common/widgets/exam/exam_tile.dart b/filcnaplo_mobile_ui/lib/common/widgets/exam/exam_tile.dart index b72983b..151ad39 100755 --- a/filcnaplo_mobile_ui/lib/common/widgets/exam/exam_tile.dart +++ b/filcnaplo_mobile_ui/lib/common/widgets/exam/exam_tile.dart @@ -6,7 +6,8 @@ import 'package:filcnaplo/utils/format.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart'; class ExamTile extends StatelessWidget { - const ExamTile(this.exam, {Key? key, this.onTap, this.padding}) : super(key: key); + const ExamTile(this.exam, {Key? key, this.onTap, this.padding}) + : super(key: key); final Exam exam; final void Function()? onTap; @@ -22,26 +23,32 @@ class ExamTile extends StatelessWidget { visualDensity: VisualDensity.compact, contentPadding: const EdgeInsets.only(left: 8.0, right: 12.0), onTap: onTap, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14.0)), + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(14.0)), leading: SizedBox( width: 44, height: 44, child: Padding( padding: const EdgeInsets.only(top: 2.0), child: Icon( - SubjectIcon.resolveVariant(subjectName: exam.subjectName, context: context), + SubjectIcon.resolveVariant( + subject: exam.subject, context: context), size: 28.0, color: AppColors.of(context).text.withOpacity(.75), ), )), title: Text( - exam.description != "" ? exam.description : (exam.mode?.description ?? "Számonkérés"), + exam.description != "" + ? exam.description + : (exam.mode?.description ?? "Számonkérés"), maxLines: 2, overflow: TextOverflow.ellipsis, style: const TextStyle(fontWeight: FontWeight.w600), ), subtitle: Text( - exam.subjectName.capital(), + exam.subject.isRenamed + ? exam.subject.renamedTo! + : exam.subject.name.capital(), maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(fontWeight: FontWeight.w500), diff --git a/filcnaplo_mobile_ui/lib/common/widgets/exam/exam_view.dart b/filcnaplo_mobile_ui/lib/common/widgets/exam/exam_view.dart index 4061baa..632fb2f 100755 --- a/filcnaplo_mobile_ui/lib/common/widgets/exam/exam_view.dart +++ b/filcnaplo_mobile_ui/lib/common/widgets/exam/exam_view.dart @@ -29,13 +29,15 @@ class ExamView extends StatelessWidget { padding: const EdgeInsets.only(left: 6.0), child: Icon( SubjectIcon.resolveVariant( - subjectName: exam.subjectName, context: context), + subject: exam.subject, context: context), size: 36.0, color: AppColors.of(context).text.withOpacity(.75), ), ), title: Text( - exam.subjectName.capital(), + exam.subject.isRenamed + ? exam.subject.renamedTo! + : exam.subject.name.capital(), maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(fontWeight: FontWeight.w600), diff --git a/filcnaplo_mobile_ui/lib/common/widgets/grade/grade_subject_tile.dart b/filcnaplo_mobile_ui/lib/common/widgets/grade/grade_subject_tile.dart index 35e6509..00e87d0 100755 --- a/filcnaplo_mobile_ui/lib/common/widgets/grade/grade_subject_tile.dart +++ b/filcnaplo_mobile_ui/lib/common/widgets/grade/grade_subject_tile.dart @@ -16,7 +16,7 @@ class GradeSubjectTile extends StatelessWidget { this.averageBefore = 0.0}) : super(key: key); - final Subject subject; + final GradeSubject subject; final void Function()? onTap; final double average; final double groupAverage; @@ -56,7 +56,10 @@ class GradeSubjectTile extends StatelessWidget { fontWeight: FontWeight.w600, fontSize: 14.0, color: textColor, - fontStyle: settingsProvider.renamedSubjectsItalics && subject.isRenamed ? FontStyle.italic : null), + fontStyle: + settingsProvider.renamedSubjectsItalics && subject.isRenamed + ? FontStyle.italic + : null), ), trailing: Row( mainAxisSize: MainAxisSize.min, diff --git a/filcnaplo_mobile_ui/lib/common/widgets/homework/homework_tile.dart b/filcnaplo_mobile_ui/lib/common/widgets/homework/homework_tile.dart index 2013519..6b1ad2e 100755 --- a/filcnaplo_mobile_ui/lib/common/widgets/homework/homework_tile.dart +++ b/filcnaplo_mobile_ui/lib/common/widgets/homework/homework_tile.dart @@ -46,7 +46,7 @@ class HomeworkTile extends StatelessWidget { padding: const EdgeInsets.only(top: 2.0), child: Icon( SubjectIcon.resolveVariant( - subjectName: homework.subject.name, context: context), + subject: homework.subject, context: context), size: 28.0, color: AppColors.of(context).text.withOpacity(.75), ), @@ -69,7 +69,12 @@ class HomeworkTile extends StatelessWidget { homework.subject.renamedTo ?? homework.subject.name.capital(), maxLines: 2, overflow: TextOverflow.ellipsis, - style: TextStyle(fontWeight: FontWeight.w600, fontStyle: homework.subject.isRenamed && settingsProvider.renamedSubjectsItalics ? FontStyle.italic : null), + style: TextStyle( + fontWeight: FontWeight.w600, + fontStyle: homework.subject.isRenamed && + settingsProvider.renamedSubjectsItalics + ? FontStyle.italic + : null), ), subtitle: censored ? Wrap( diff --git a/filcnaplo_mobile_ui/lib/common/widgets/homework/homework_view.dart b/filcnaplo_mobile_ui/lib/common/widgets/homework/homework_view.dart index 8e26d92..a473cff 100755 --- a/filcnaplo_mobile_ui/lib/common/widgets/homework/homework_view.dart +++ b/filcnaplo_mobile_ui/lib/common/widgets/homework/homework_view.dart @@ -44,7 +44,7 @@ class HomeworkView extends StatelessWidget { ListTile( leading: Icon( SubjectIcon.resolveVariant( - subjectName: homework.subject.name, context: context), + subject: homework.subject, context: context), size: 36.0, ), title: Text( diff --git a/filcnaplo_mobile_ui/lib/common/widgets/lesson/changed_lesson_tile.dart b/filcnaplo_mobile_ui/lib/common/widgets/lesson/changed_lesson_tile.dart index 7125d2b..4b2b485 100755 --- a/filcnaplo_mobile_ui/lib/common/widgets/lesson/changed_lesson_tile.dart +++ b/filcnaplo_mobile_ui/lib/common/widgets/lesson/changed_lesson_tile.dart @@ -57,9 +57,9 @@ class ChangedLessonTile extends StatelessWidget { ), ), title: Text( - lesson.substituteTeacher?.name != "" || lesson.substituteTeacher?.name != null - ? "substituted".i18n - : "cancelled".i18n, + lesson.status?.name == "Elmaradt" && lesson.substituteTeacher?.name != "" + ? "cancelled".i18n + : "substituted".i18n, maxLines: 2, overflow: TextOverflow.ellipsis, style: const TextStyle(fontWeight: FontWeight.w600), diff --git a/filcnaplo_mobile_ui/lib/common/widgets/statistics_tile.dart b/filcnaplo_mobile_ui/lib/common/widgets/statistics_tile.dart index 268a254..9d01db3 100755 --- a/filcnaplo_mobile_ui/lib/common/widgets/statistics_tile.dart +++ b/filcnaplo_mobile_ui/lib/common/widgets/statistics_tile.dart @@ -1,7 +1,9 @@ import 'package:auto_size_text/auto_size_text.dart'; +import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo/ui/widgets/grade/grade_tile.dart'; import 'package:flutter/material.dart'; import 'package:i18n_extension/i18n_widget.dart'; +import 'package:provider/provider.dart'; class StatisticsTile extends StatelessWidget { const StatisticsTile({ @@ -31,7 +33,9 @@ class StatisticsTile extends StatelessWidget { } else { valueText = value.toStringAsFixed(0); } - if (I18n.of(context).locale.languageCode != "en") valueText = valueText.replaceAll(".", ","); + if (I18n.of(context).locale.languageCode != "en") { + valueText = valueText.replaceAll(".", ","); + } if (value.isNaN) { valueText = "?"; @@ -44,11 +48,13 @@ class StatisticsTile extends StatelessWidget { borderRadius: BorderRadius.circular(12.0), color: Theme.of(context).colorScheme.background, boxShadow: [ - BoxShadow( - offset: const Offset(0, 21), - blurRadius: 23.0, - color: Theme.of(context).shadowColor, - ) + if (Provider.of(context, listen: false) + .shadowEffect) + BoxShadow( + offset: const Offset(0, 21), + blurRadius: 23.0, + color: Theme.of(context).shadowColor, + ) ], ), constraints: const BoxConstraints( @@ -68,13 +74,19 @@ class StatisticsTile extends StatelessWidget { if (title != null) const SizedBox(height: 4.0), Container( margin: const EdgeInsets.only(top: 4.0), - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0), + padding: + const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0), decoration: BoxDecoration( - color: fill ? (color ?? gradeColor(context: context, value: value)).withOpacity(.2) : null, + color: fill + ? (color ?? gradeColor(context: context, value: value)) + .withOpacity(.2) + : null, border: outline || fill ? Border.all( - color: (color ?? gradeColor(context: context, value: value)).withOpacity(outline ? 1.0 : 0.0), - width: fill ? 2.0 : 5.0, + color: + (color ?? gradeColor(context: context, value: value)) + .withOpacity(outline ? 1.0 : 0.0), + width: fill ? 5.0 : 5.0, ) : null, borderRadius: BorderRadius.circular(45.0), @@ -96,7 +108,7 @@ class StatisticsTile extends StatelessWidget { style: TextStyle( color: color ?? gradeColor(context: context, value: value), fontWeight: FontWeight.w800, - fontSize: 32.0, + fontSize: 28.0, ), ), ), diff --git a/filcnaplo_mobile_ui/lib/pages/absences/absence_subject_view.dart b/filcnaplo_mobile_ui/lib/pages/absences/absence_subject_view.dart index dc184e7..c0a0a95 100755 --- a/filcnaplo_mobile_ui/lib/pages/absences/absence_subject_view.dart +++ b/filcnaplo_mobile_ui/lib/pages/absences/absence_subject_view.dart @@ -22,10 +22,10 @@ class AbsenceSubjectView extends StatelessWidget { const AbsenceSubjectView(this.subject, {Key? key, this.absences = const []}) : super(key: key); - final Subject subject; + final GradeSubject subject; final List absences; - static void show(Subject subject, List absences, + static void show(GradeSubject subject, List absences, {required BuildContext context}) { Navigator.of(context, rootNavigator: true) .push(CupertinoPageRoute( diff --git a/filcnaplo_mobile_ui/lib/pages/absences/absences_page.dart b/filcnaplo_mobile_ui/lib/pages/absences/absences_page.dart index dc2218d..43e6518 100755 --- a/filcnaplo_mobile_ui/lib/pages/absences/absences_page.dart +++ b/filcnaplo_mobile_ui/lib/pages/absences/absences_page.dart @@ -33,7 +33,7 @@ import 'absences_page.i18n.dart'; enum AbsenceFilter { absences, delays, misses } class SubjectAbsence { - Subject subject; + GradeSubject subject; List absences; double percentage; @@ -58,7 +58,7 @@ class _AbsencesPageState extends State late String firstName; late TabController _tabController; late List absences = []; - final Map _lessonCount = {}; + final Map _lessonCount = {}; @override void initState() { @@ -90,7 +90,7 @@ class _AbsencesPageState extends State } void buildSubjectAbsences() { - Map _absences = {}; + Map _absences = {}; for (final absence in absenceProvider.absences) { if (absence.delay != 0) continue; @@ -285,8 +285,9 @@ class _AbsencesPageState extends State content: Text("attention_body".i18n), actions: [ ActionButton( - label: "Ok", - onTap: () => Navigator.of(context).pop()) + label: "Ok", + onTap: () => Navigator.of(context).pop(), + ), ], ), ); diff --git a/filcnaplo_mobile_ui/lib/pages/grades/calculator/grade_calculator.dart b/filcnaplo_mobile_ui/lib/pages/grades/calculator/grade_calculator.dart index 384afa5..5e531b5 100755 --- a/filcnaplo_mobile_ui/lib/pages/grades/calculator/grade_calculator.dart +++ b/filcnaplo_mobile_ui/lib/pages/grades/calculator/grade_calculator.dart @@ -16,7 +16,7 @@ import 'grade_calculator.i18n.dart'; class GradeCalculator extends StatefulWidget { const GradeCalculator(this.subject, {Key? key}) : super(key: key); - final Subject subject; + final GradeSubject subject; @override _GradeCalculatorState createState() => _GradeCalculatorState(); diff --git a/filcnaplo_mobile_ui/lib/pages/grades/fail_warning.dart b/filcnaplo_mobile_ui/lib/pages/grades/fail_warning.dart index 9e893fe..14b55cf 100755 --- a/filcnaplo_mobile_ui/lib/pages/grades/fail_warning.dart +++ b/filcnaplo_mobile_ui/lib/pages/grades/fail_warning.dart @@ -7,7 +7,7 @@ import 'grades_page.i18n.dart'; class FailWarning extends StatelessWidget { const FailWarning({Key? key, required this.subjectAvgs}) : super(key: key); - final Map subjectAvgs; + final Map subjectAvgs; @override Widget build(BuildContext context) { diff --git a/filcnaplo_mobile_ui/lib/pages/grades/grade_subject_view.dart b/filcnaplo_mobile_ui/lib/pages/grades/grade_subject_view.dart index 21949b2..efc4cf4 100755 --- a/filcnaplo_mobile_ui/lib/pages/grades/grade_subject_view.dart +++ b/filcnaplo_mobile_ui/lib/pages/grades/grade_subject_view.dart @@ -42,7 +42,7 @@ class GradeSubjectView extends StatefulWidget { const GradeSubjectView(this.subject, {Key? key, this.groupAverage = 0.0}) : super(key: key); - final Subject subject; + final GradeSubject subject; final double groupAverage; void push(BuildContext context, {bool root = false}) { @@ -77,7 +77,7 @@ class _GradeSubjectViewState extends State { String plan = ''; - List getSubjectGrades(Subject subject) => !gradeCalcMode + List getSubjectGrades(GradeSubject subject) => !gradeCalcMode ? gradeProvider.grades.where((e) => e.subject == subject).toList() : calculatorProvider.grades.where((e) => e.subject == subject).toList(); diff --git a/filcnaplo_mobile_ui/lib/pages/grades/grades_page.dart b/filcnaplo_mobile_ui/lib/pages/grades/grades_page.dart index 8f0f6ca..48bd153 100755 --- a/filcnaplo_mobile_ui/lib/pages/grades/grades_page.dart +++ b/filcnaplo_mobile_ui/lib/pages/grades/grades_page.dart @@ -48,24 +48,25 @@ class _GradesPageState extends State { int avgDropValue = 0; - List getSubjectGrades(Subject subject, {int days = 0}) => gradeProvider - .grades - .where((e) => - e.subject == subject && - e.type == GradeType.midYear && - (days == 0 || - e.date.isBefore(DateTime.now().subtract(Duration(days: days))))) - .toList(); + List getSubjectGrades(GradeSubject subject, {int days = 0}) => + gradeProvider.grades + .where((e) => + e.subject == subject && + e.type == GradeType.midYear && + (days == 0 || + e.date + .isBefore(DateTime.now().subtract(Duration(days: days))))) + .toList(); void generateTiles() { - List subjects = gradeProvider.grades + List subjects = gradeProvider.grades .map((e) => e.subject) .toSet() .toList() ..sort((a, b) => a.name.compareTo(b.name)); List tiles = []; - Map subjectAvgs = {}; + Map subjectAvgs = {}; tiles.addAll(subjects.map((subject) { List subjectGrades = getSubjectGrades(subject); @@ -154,7 +155,7 @@ class _GradesPageState extends State { title: AutoSizeText( "subjectavg".i18n, textAlign: TextAlign.center, - maxLines: 2, + maxLines: 1, overflow: TextOverflow.ellipsis, ), value: subjectAvg, @@ -167,7 +168,7 @@ class _GradesPageState extends State { title: AutoSizeText( "classavg".i18n, textAlign: TextAlign.center, - maxLines: 2, + maxLines: 1, wrapWords: false, overflow: TextOverflow.ellipsis, ), diff --git a/filcnaplo_mobile_ui/lib/pages/grades/grades_page.i18n.dart b/filcnaplo_mobile_ui/lib/pages/grades/grades_page.i18n.dart index 11d7fbb..56db6ff 100755 --- a/filcnaplo_mobile_ui/lib/pages/grades/grades_page.i18n.dart +++ b/filcnaplo_mobile_ui/lib/pages/grades/grades_page.i18n.dart @@ -16,7 +16,7 @@ extension Localization on String { "7_days_average": "Weekly Average", "subjectavg": "Subject Average", "classavg": "Class Average", - "fail_warning": "Faliure warning", + "fail_warning": "Failure warning", "fail_warning_description": "You are failing %d subject(s)", }, "hu_hu": { diff --git a/filcnaplo_mobile_ui/lib/pages/home/live_card/live_card.dart b/filcnaplo_mobile_ui/lib/pages/home/live_card/live_card.dart index 94840aa..2973c4c 100755 --- a/filcnaplo_mobile_ui/lib/pages/home/live_card/live_card.dart +++ b/filcnaplo_mobile_ui/lib/pages/home/live_card/live_card.dart @@ -172,7 +172,8 @@ class _LiveCardState extends State { : ""), title: liveCard.currentLesson!.subject.renamedTo ?? liveCard.currentLesson!.subject.name.capital(), - titleItalic: liveCard.currentLesson!.subject.isRenamed, + titleItalic: liveCard.currentLesson!.subject.isRenamed && + settingsProvider.renamedSubjectsEnabled, subtitle: liveCard.currentLesson!.room, icon: SubjectIcon.resolveVariant( subject: liveCard.currentLesson!.subject, context: context), diff --git a/filcnaplo_mobile_ui/lib/pages/home/live_card/live_card_widget.dart b/filcnaplo_mobile_ui/lib/pages/home/live_card/live_card_widget.dart index 658fcaa..2498a22 100755 --- a/filcnaplo_mobile_ui/lib/pages/home/live_card/live_card_widget.dart +++ b/filcnaplo_mobile_ui/lib/pages/home/live_card/live_card_widget.dart @@ -1,7 +1,9 @@ +import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo/theme/colors/colors.dart'; import 'package:filcnaplo_mobile_ui/common/progress_bar.dart'; import 'package:flutter/material.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart'; +import 'package:provider/provider.dart'; import 'live_card.i18n.dart'; enum ProgressAccuracy { minutes, seconds } @@ -67,11 +69,13 @@ class _LiveCardWidgetState extends State { color: Theme.of(context).colorScheme.background, borderRadius: BorderRadius.circular(16.0), boxShadow: [ - BoxShadow( - offset: const Offset(0, 21), - blurRadius: 23.0, - color: Theme.of(context).shadowColor, - ) + if (Provider.of(context, listen: false) + .shadowEffect) + BoxShadow( + offset: const Offset(0, 21), + blurRadius: 23.0, + color: Theme.of(context).shadowColor, + ) ], ), child: Container( @@ -180,12 +184,12 @@ class _LiveCardWidgetState extends State { WidgetSpan( child: Container( margin: const EdgeInsets - .only( + .only( left: 6.0, bottom: 3.0), padding: const EdgeInsets - .symmetric( + .symmetric( horizontal: 4.0, vertical: 2.0), decoration: diff --git a/filcnaplo_mobile_ui/lib/pages/messages/messages_page.dart b/filcnaplo_mobile_ui/lib/pages/messages/messages_page.dart index c064bef..1a8334b 100755 --- a/filcnaplo_mobile_ui/lib/pages/messages/messages_page.dart +++ b/filcnaplo_mobile_ui/lib/pages/messages/messages_page.dart @@ -11,8 +11,10 @@ import 'package:filcnaplo_mobile_ui/common/filter_bar.dart'; import 'package:filcnaplo_mobile_ui/common/profile_image/profile_button.dart'; import 'package:filcnaplo_mobile_ui/common/profile_image/profile_image.dart'; import 'package:filcnaplo/ui/filter/sort.dart'; +import 'package:filcnaplo_mobile_ui/common/soon_alert/soon_alert.dart'; import 'package:filcnaplo_mobile_ui/common/widgets/message/message_viewable.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:provider/provider.dart'; import 'messages_page.i18n.dart'; @@ -61,6 +63,33 @@ class _MessagesPageState extends State centerTitle: false, surfaceTintColor: Theme.of(context).scaffoldBackgroundColor, actions: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, vertical: 5.0), + child: IconButton( + splashRadius: 24.0, + onPressed: () { + // Navigator.of(context, rootNavigator: true) + // .push(PageRouteBuilder( + // pageBuilder: (context, animation, secondaryAnimation) => + // PremiumFSTimetable( + // controller: controller, + // ), + // )) + // .then((_) { + // SystemChrome.setPreferredOrientations( + // [DeviceOrientation.portraitUp]); + // setSystemChrome(context); + // }); + SoonAlert.show(context: context); + }, + icon: Icon( + FeatherIcons.send, + color: AppColors.of(context).text, + ), + ), + ), + // Profile Icon Padding( padding: const EdgeInsets.only(right: 24.0), diff --git a/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.dart b/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.dart index 6e72b30..dd341b1 100755 --- a/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.dart +++ b/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.dart @@ -20,6 +20,7 @@ import 'package:filcnaplo_mobile_ui/common/bottom_sheet_menu/bottom_sheet_menu_i import 'package:filcnaplo_mobile_ui/common/panel/panel.dart'; import 'package:filcnaplo_mobile_ui/common/panel/panel_button.dart'; import 'package:filcnaplo_mobile_ui/common/profile_image/profile_image.dart'; +import 'package:filcnaplo_mobile_ui/common/soon_alert/soon_alert.dart'; import 'package:filcnaplo_mobile_ui/common/system_chrome.dart'; import 'package:filcnaplo_mobile_ui/common/widgets/update/updates_view.dart'; import 'package:filcnaplo_mobile_ui/screens/news/news_screen.dart'; @@ -339,7 +340,7 @@ class _SettingsScreenState extends State ), ), - // Updates + // updates if (updateProvider.available) Padding( padding: const EdgeInsets.symmetric( @@ -377,122 +378,7 @@ class _SettingsScreenState extends State // child: ActiveSponsorCard(), // ), - // General Settings - Padding( - padding: - const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), - child: Panel( - title: Text("general".i18n), - child: Column( - children: [ - PanelButton( - onPressed: () { - SettingsHelper.language(context); - setState(() {}); - }, - title: Text("language".i18n), - leading: const Icon(FeatherIcons.globe), - trailing: Text( - languageText, - style: const TextStyle(fontSize: 14.0), - ), - ), - PanelButton( - onPressed: () { - SettingsHelper.startPage(context); - setState(() {}); - }, - title: Text("startpage".i18n), - leading: const Icon(FeatherIcons.play), - trailing: Text( - startPageTitle.capital(), - style: const TextStyle(fontSize: 14.0), - ), - ), - PanelButton( - onPressed: () { - SettingsHelper.rounding(context); - setState(() {}); - }, - title: Text("rounding".i18n), - leading: const Icon(FeatherIcons.gitCommit), - trailing: Text( - (settings.rounding / 10).toStringAsFixed(1), - style: const TextStyle(fontSize: 14.0), - ), - ), - PanelButton( - onPressed: () { - SettingsHelper.vibrate(context); - setState(() {}); - }, - title: Text("vibrate".i18n), - leading: const Icon(FeatherIcons.radio), - trailing: Text( - vibrateTitle, - style: const TextStyle(fontSize: 14.0), - ), - ), - PanelButton( - padding: const EdgeInsets.only(left: 14.0), - onPressed: () { - SettingsHelper.bellDelay(context); - setState(() {}); - }, - title: Text( - "bell_delay".i18n, - style: TextStyle( - color: AppColors.of(context).text.withOpacity( - settings.bellDelayEnabled ? 1.0 : .5)), - ), - leading: settings.bellDelayEnabled - ? const Icon(FeatherIcons.bell) - : Icon(FeatherIcons.bellOff, - color: - AppColors.of(context).text.withOpacity(.25)), - trailingDivider: true, - trailing: Switch( - onChanged: (v) => settings.update(bellDelayEnabled: v), - value: settings.bellDelayEnabled, - activeColor: Theme.of(context).colorScheme.secondary, - ), - ), - Material( - type: MaterialType.transparency, - child: MenuNotifications(settings: settings)), - WelcomeMessagePanelButton(settings, user), - ], - ), - ), - ), - - if (kDebugMode) - Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0, horizontal: 24.0), - child: Panel( - title: const Text("Debug"), - child: Column( - children: [ - PanelButton( - title: const Text("Subject Icon Gallery"), - leading: - const Icon(CupertinoIcons.rectangle_3_offgrid_fill), - trailing: const Icon(Icons.arrow_forward), - onPressed: () { - Navigator.of(context, rootNavigator: true).push( - CupertinoPageRoute( - builder: (context) => - const SubjectIconGallery()), - ); - }, - ) - ], - ), - ), - ), - - // Secret Settings + // secret settings if (__ss) Padding( padding: const EdgeInsets.symmetric( @@ -589,7 +475,123 @@ class _SettingsScreenState extends State ), ), - // Theme Settings + // general things + Padding( + padding: + const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), + child: Panel( + title: Text("general".i18n), + child: Column( + children: [ + PanelButton( + onPressed: () { + SettingsHelper.language(context); + setState(() {}); + }, + title: Text("language".i18n), + leading: const Icon(FeatherIcons.globe), + trailing: Text( + languageText, + style: const TextStyle(fontSize: 14.0), + ), + ), + PanelButton( + onPressed: () { + SettingsHelper.startPage(context); + setState(() {}); + }, + title: Text("startpage".i18n), + leading: const Icon(FeatherIcons.play), + trailing: Text( + startPageTitle.capital(), + style: const TextStyle(fontSize: 14.0), + ), + ), + PanelButton( + onPressed: () { + SettingsHelper.rounding(context); + setState(() {}); + }, + title: Text("rounding".i18n), + leading: const Icon(FeatherIcons.gitCommit), + trailing: Text( + (settings.rounding / 10).toStringAsFixed(1), + style: const TextStyle(fontSize: 14.0), + ), + ), + PanelButton( + onPressed: () { + SettingsHelper.vibrate(context); + setState(() {}); + }, + title: Text("vibrate".i18n), + leading: const Icon(FeatherIcons.radio), + trailing: Text( + vibrateTitle, + style: const TextStyle(fontSize: 14.0), + ), + ), + PanelButton( + padding: const EdgeInsets.only(left: 14.0), + onPressed: () { + SettingsHelper.bellDelay(context); + setState(() {}); + }, + title: Text( + "bell_delay".i18n, + style: TextStyle( + color: AppColors.of(context).text.withOpacity( + settings.bellDelayEnabled ? 1.0 : .5)), + ), + leading: settings.bellDelayEnabled + ? const Icon(FeatherIcons.bell) + : Icon(FeatherIcons.bellOff, + color: + AppColors.of(context).text.withOpacity(.25)), + trailingDivider: true, + trailing: Switch( + onChanged: (v) => settings.update(bellDelayEnabled: v), + value: settings.bellDelayEnabled, + activeColor: Theme.of(context).colorScheme.secondary, + ), + ), + Material( + type: MaterialType.transparency, + child: MenuNotifications(settings: settings)), + WelcomeMessagePanelButton(settings, user), + ], + ), + ), + ), + + // icon gallery (debug mode) + if (kDebugMode) + Padding( + padding: const EdgeInsets.symmetric( + vertical: 12.0, horizontal: 24.0), + child: Panel( + title: const Text("Debug"), + child: Column( + children: [ + PanelButton( + title: const Text("Subject Icon Gallery"), + leading: + const Icon(CupertinoIcons.rectangle_3_offgrid_fill), + trailing: const Icon(Icons.arrow_forward), + onPressed: () { + Navigator.of(context, rootNavigator: true).push( + CupertinoPageRoute( + builder: (context) => + const SubjectIconGallery()), + ); + }, + ) + ], + ), + ), + ), + + // appearance things Padding( padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), @@ -684,8 +686,8 @@ class _SettingsScreenState extends State ), ), const PremiumIconPackSelector(), - // If iOS, show the iOS specific settings + // if ios show live activity color option if (defaultTargetPlatform == TargetPlatform.iOS) PanelButton( onPressed: () { @@ -703,12 +705,46 @@ class _SettingsScreenState extends State ), ), ), + + Material( + type: MaterialType.transparency, + child: SwitchListTile( + contentPadding: const EdgeInsets.only(left: 14.0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12.0)), + title: Row( + children: [ + Icon( + FeatherIcons.moon, + color: settings.shadowEffect + ? Theme.of(context).colorScheme.secondary + : AppColors.of(context).text.withOpacity(.25), + ), + const SizedBox(width: 14.0), + Expanded( + child: Text( + "shadow_effect".i18n, + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16.0, + color: AppColors.of(context).text.withOpacity( + settings.shadowEffect ? 1.0 : .5), + ), + ), + ), + ], + ), + onChanged: (v) => settings.update(shadowEffect: v), + value: settings.shadowEffect, + activeColor: Theme.of(context).colorScheme.secondary, + ), + ), ], ), ), ), - // Notifications + // popup alerts Padding( padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), @@ -751,7 +787,7 @@ class _SettingsScreenState extends State ), ), - // Extras + // extra settings Padding( padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), @@ -798,12 +834,23 @@ class _SettingsScreenState extends State MenuRenamedTeachers( settings: settings, ), + PanelButton( + onPressed: () { + SoonAlert.show(context: context); + }, + title: Text('app_icon'.i18n), + leading: const Icon(FeatherIcons.edit), + // trailing: Text( + // 'default'.i18n, + // style: const TextStyle(fontSize: 14.0), + // ), + ), ], ), ), ), - // About + // about sweetie Padding( padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), @@ -954,6 +1001,8 @@ class _SettingsScreenState extends State ), ), ), + + // version info SafeArea( top: false, child: Center( diff --git a/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.i18n.dart b/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.i18n.dart index cf8e7a9..b584b6d 100755 --- a/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.i18n.dart +++ b/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.i18n.dart @@ -74,8 +74,10 @@ extension SettingsLocalization on String { "devmode": "Developer Mode", "copy_jwt": "Copy JWT", "welcome_msg": "Welcome Message", - "default": "Default", + "default": "Dynamic", "edit_welcome_msg": "Edit welcome message", + "shadow_effect": "Shadow Effect", + "app_icon": "App Icon", }, "hu_hu": { "personal_details": "Személyes információk", @@ -148,8 +150,10 @@ extension SettingsLocalization on String { "devmode": "Fejlesztői mód", "copy_jwt": "JWT másolása", "welcome_msg": "Üdvözlő üzenet", - "default": "Alapértelmezett", + "default": "Dinamikus", "edit_welcome_msg": "Üdvözlő üzenet szerkesztése", + "shadow_effect": "Árnyékhatás", + "app_icon": "Alkalmazásikon", }, "de_de": { "personal_details": "Persönliche Angaben", @@ -198,7 +202,8 @@ extension SettingsLocalization on String { "graph_class_avg": "Klassendurchschnitt in der Grafik", "goodstudent": "Guter Student Modus", "attention": "Achtung!", - "goodstudent_disclaimer": "reFilc kann nicht für die Nutzung dieser Funktion haftbar gemacht werden.\n\n(Wenn deine Mutter dich verprügelt, weil du ihr falsche Noten gezeigt hast, kannst du dir nur die Schuld dafür geben)", + "goodstudent_disclaimer": + "reFilc kann nicht für die Nutzung dieser Funktion haftbar gemacht werden.\n\n(Wenn deine Mutter dich verprügelt, weil du ihr falsche Noten gezeigt hast, kannst du dir nur die Schuld dafür geben)", "understand": "Ich verstehe", "secret": "Geheime Einstellungen", "bell_delay": "Klingelverzögerung", @@ -221,8 +226,10 @@ extension SettingsLocalization on String { "devmode": "Entwicklermodus", "copy_jwt": "JWT kopieren", "welcome_msg": "Willkommensnachricht", - "default": "Standard", + "default": "Dynamisch", "edit_welcome_msg": "Begrüßungsnachricht bearbeiten", + "shadow_effect": "Schatteneffekt", + "app_icon": "App-Symbol", }, }; diff --git a/filcnaplo_mobile_ui/lib/screens/summary/pages/allsum_page.dart b/filcnaplo_mobile_ui/lib/screens/summary/pages/allsum_page.dart index b14a215..01900ff 100644 --- a/filcnaplo_mobile_ui/lib/screens/summary/pages/allsum_page.dart +++ b/filcnaplo_mobile_ui/lib/screens/summary/pages/allsum_page.dart @@ -30,7 +30,7 @@ class _AllSumBodyState extends State { int avgDropValue = 0; bool animation = false; - List getSubjectGrades(Subject subject, {int days = 0}) => gradeProvider + List getSubjectGrades(GradeSubject subject, {int days = 0}) => gradeProvider .grades .where((e) => e.subject == subject && diff --git a/filcnaplo_mobile_ui/lib/screens/summary/pages/grades_page.dart b/filcnaplo_mobile_ui/lib/screens/summary/pages/grades_page.dart index 5b75cbb..d56e3e4 100644 --- a/filcnaplo_mobile_ui/lib/screens/summary/pages/grades_page.dart +++ b/filcnaplo_mobile_ui/lib/screens/summary/pages/grades_page.dart @@ -50,14 +50,15 @@ class _GradesBodyState extends State { int avgDropValue = 0; bool animation = false; - List getSubjectGrades(Subject subject, {int days = 0}) => gradeProvider - .grades - .where((e) => - e.subject == subject && - e.type == GradeType.midYear && - (days == 0 || - e.date.isBefore(DateTime.now().subtract(Duration(days: days))))) - .toList(); + List getSubjectGrades(GradeSubject subject, {int days = 0}) => + gradeProvider.grades + .where((e) => + e.subject == subject && + e.type == GradeType.midYear && + (days == 0 || + e.date + .isBefore(DateTime.now().subtract(Duration(days: days))))) + .toList(); @override void initState() { @@ -74,18 +75,18 @@ class _GradesBodyState extends State { } void generateTiles({required int filter}) { - List subjects = gradeProvider.grades + List subjects = gradeProvider.grades .map((e) => e.subject) .toSet() .toList() ..sort((a, b) => a.name.compareTo(b.name)); List tiles = []; - Map subjectAvgs = {}; + Map subjectAvgs = {}; var count = 1; - for (Subject subject in subjects) { + for (GradeSubject subject in subjects) { List subjectGrades = getSubjectGrades(subject); double avg = AverageHelper.averageEvals(subjectGrades); diff --git a/filcnaplo_mobile_ui/lib/screens/summary/pages/lessons_page.dart b/filcnaplo_mobile_ui/lib/screens/summary/pages/lessons_page.dart index cd7c248..a90a02b 100644 --- a/filcnaplo_mobile_ui/lib/screens/summary/pages/lessons_page.dart +++ b/filcnaplo_mobile_ui/lib/screens/summary/pages/lessons_page.dart @@ -28,7 +28,7 @@ List faces = [ ]; class SubjectAbsence { - Subject subject; + GradeSubject subject; List absences; double percentage; @@ -52,7 +52,7 @@ class _LessonsBodyState extends State { late List absences = []; late List lessons = []; late List delays = []; - final Map _lessonCount = {}; + final Map _lessonCount = {}; @override void initState() { @@ -85,7 +85,7 @@ class _LessonsBodyState extends State { } void buildSubjectAbsences() { - Map _absences = {}; + Map _absences = {}; for (final absence in absenceProvider.absences) { if (absence.delay != 0) continue; diff --git a/filcnaplo_premium/.gitignore b/filcnaplo_premium/.gitignore deleted file mode 100644 index 5de5aa0..0000000 --- a/filcnaplo_premium/.gitignore +++ /dev/null @@ -1,48 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Web related -lib/generated_plugin_registrant.dart - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release -pubspec.lock -android/local.properties diff --git a/filcnaplo_premium/lib/providers/goal_provider.dart b/filcnaplo_premium/lib/providers/goal_provider.dart index 18f3244..1529903 100644 --- a/filcnaplo_premium/lib/providers/goal_provider.dart +++ b/filcnaplo_premium/lib/providers/goal_provider.dart @@ -9,10 +9,10 @@ class GoalProvider extends ChangeNotifier { final UserProvider _user; late bool _done = false; - late Subject? _doneSubject; + late GradeSubject? _doneSubject; bool get hasDoneGoals => _done; - Subject? get doneSubject => _doneSubject; + GradeSubject? get doneSubject => _doneSubject; GoalProvider({ required DatabaseProvider database, @@ -24,7 +24,7 @@ class GoalProvider extends ChangeNotifier { var goalAvgs = await _db.userQuery.subjectGoalAverages(userId: _user.id!); var beforeAvgs = await _db.userQuery.subjectGoalBefores(userId: _user.id!); - List subjects = gradeProvider.grades + List subjects = gradeProvider.grades .map((e) => e.subject) .toSet() .toList() @@ -45,7 +45,7 @@ class GoalProvider extends ChangeNotifier { _doneSubject = null; } - Future clearGoal(Subject subject) async { + Future clearGoal(GradeSubject subject) async { final goalPlans = await _db.userQuery.subjectGoalPlans(userId: _user.id!); final goalAvgs = await _db.userQuery.subjectGoalAverages(userId: _user.id!); final goalBeforeGrades = diff --git a/filcnaplo_premium/lib/providers/share_provider.dart b/filcnaplo_premium/lib/providers/share_provider.dart index 54a52bf..eaf9e2b 100644 --- a/filcnaplo_premium/lib/providers/share_provider.dart +++ b/filcnaplo_premium/lib/providers/share_provider.dart @@ -40,6 +40,11 @@ class ShareProvider extends ChangeNotifier { SettingsProvider.defaultSettings().customAccentColor) ?.value ?? const Color(0xFF3D7BF4).value, + 'icon_color': (settings.customIconColor ?? + SettingsProvider.defaultSettings().customIconColor) + ?.value ?? + const Color(0x00000000).value, + 'shadow_effect': settings.shadowEffect, }; SharedTheme theme = SharedTheme.fromJson(themeJson, gradeColors); diff --git a/filcnaplo_premium/lib/ui/mobile/flutter_colorpicker/colorpicker.dart b/filcnaplo_premium/lib/ui/mobile/flutter_colorpicker/colorpicker.dart index d10c6ca..9653e32 100644 --- a/filcnaplo_premium/lib/ui/mobile/flutter_colorpicker/colorpicker.dart +++ b/filcnaplo_premium/lib/ui/mobile/flutter_colorpicker/colorpicker.dart @@ -262,6 +262,7 @@ class _FilcColorPickerState extends State { if (theme != null) { widget.onThemeIdProvided(theme); + idController.clear(); } else { ScaffoldMessenger.of(context).showSnackBar( CustomSnackBar( diff --git a/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_complete_modal.dart b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_complete_modal.dart index 0b2d9c1..cce1654 100644 --- a/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_complete_modal.dart +++ b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_complete_modal.dart @@ -20,7 +20,7 @@ class GoalCompleteModal extends StatelessWidget { final UserProvider user; final DatabaseProvider database; - final Subject subject; + final GradeSubject subject; final double goalAverage; final double beforeAverage; @@ -218,7 +218,7 @@ class GoalCompleteModal extends StatelessWidget { } static Future show( - Subject subject, { + GradeSubject subject, { required BuildContext context, }) async { UserProvider user = Provider.of(context, listen: false); diff --git a/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_planner.dart b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_planner.dart index 22878a9..31e445b 100644 --- a/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_planner.dart +++ b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_planner.dart @@ -64,7 +64,7 @@ class GoalPlanner { form: '', groupId: '', type: GradeType.midYear, - subject: Subject.fromJson({}), + subject: GradeSubject.fromJson({}), mode: Category.fromJson({}), seenDate: DateTime(0), writeDate: DateTime(0), diff --git a/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_planner_screen.dart b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_planner_screen.dart index eef91b3..258a0f1 100644 --- a/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_planner_screen.dart +++ b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_planner_screen.dart @@ -25,7 +25,7 @@ enum PlanResult { } class GoalPlannerScreen extends StatefulWidget { - final Subject subject; + final GradeSubject subject; const GoalPlannerScreen({Key? key, required this.subject}) : super(key: key); @@ -42,7 +42,7 @@ class _GoalPlannerScreenState extends State { bool gradeCalcMode = false; - List getSubjectGrades(Subject subject) => !gradeCalcMode + List getSubjectGrades(GradeSubject subject) => !gradeCalcMode ? gradeProvider.grades.where((e) => e.subject == subject).toList() : calculatorProvider.grades.where((e) => e.subject == subject).toList(); diff --git a/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.dart b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.dart index 0141fac..ba577c8 100644 --- a/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.dart +++ b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.dart @@ -6,10 +6,12 @@ import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo_kreta_api/models/grade.dart'; import 'package:filcnaplo_kreta_api/models/subject.dart'; import 'package:filcnaplo_kreta_api/providers/grade_provider.dart'; +import 'package:filcnaplo_mobile_ui/common/action_button.dart'; import 'package:filcnaplo_mobile_ui/common/average_display.dart'; import 'package:filcnaplo_mobile_ui/common/panel/panel.dart'; import 'package:filcnaplo_mobile_ui/common/progress_bar.dart'; import 'package:filcnaplo_mobile_ui/common/round_border_icon.dart'; +import 'package:filcnaplo_premium/providers/goal_provider.dart'; import 'package:filcnaplo_premium/ui/mobile/goal_planner/goal_planner.dart'; import 'package:filcnaplo_premium/ui/mobile/goal_planner/goal_state_screen.i18n.dart'; import 'package:filcnaplo_premium/ui/mobile/goal_planner/route_option.dart'; @@ -22,7 +24,7 @@ import 'goal_planner_screen.dart'; import 'graph.dart'; class GoalStateScreen extends StatefulWidget { - final Subject subject; + final GradeSubject subject; const GoalStateScreen({Key? key, required this.subject}) : super(key: key); @@ -77,10 +79,10 @@ class _GoalStateScreenState extends State { setState(() {}); } - List getSubjectGrades(Subject subject) => + List getSubjectGrades(GradeSubject subject) => gradeProvider.grades.where((e) => (e.subject == subject)).toList(); - List getAfterGoalGrades(Subject subject) => gradeProvider.grades + List getAfterGoalGrades(GradeSubject subject) => gradeProvider.grades .where((e) => (e.subject == subject && e.date.isAfter(goalPinDate))) .toList(); @@ -199,11 +201,39 @@ class _GoalStateScreenState extends State { ), child: Column( children: [ - const Row( + Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ - BackButton(), + const BackButton(), + IconButton( + onPressed: () { + showDialog( + context: context, + builder: (context) => AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12.0)), + title: Text("attention".i18n), + content: Text("attention_body".i18n), + actions: [ + ActionButton( + label: "delete".i18n, + onTap: () async { + // clear the goal + await Provider.of(context, + listen: false) + .clearGoal(widget.subject); + // close the modal and the goal page + Navigator.of(context).pop(); + Navigator.of(context).pop(); + }, + ), + ], + ), + ); + }, + icon: const Icon(FeatherIcons.x), + ), ], ), const SizedBox(height: 22.0), diff --git a/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.i18n.dart b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.i18n.dart index 6999dc8..19c56ed 100644 --- a/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.i18n.dart +++ b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.i18n.dart @@ -22,6 +22,11 @@ extension Localization on String { "improved_by": "and improved your grade by %s", "detailed_stats": "See my detailed stats", "later": "Yay! I'll see my stats later.", + // sure delete modal + "delete": "Delete", + "attention": "Attention!", + "attention_body": + "Your goal and progress will be lost forever and cannot be restored.", }, "hu_hu": { // base page @@ -42,6 +47,11 @@ extension Localization on String { "improved_by": "%s-os javulást értél el!", "detailed_stats": "Részletes statisztikám", "later": "Hurrá! Megnézem máskor.", + // sure delete modal + "delete": "Törlés", + "attention": "Figyelem!", + "attention_body": + "A kitűzött célod és haladásod örökre elveszik és nem lesz visszaállítható.", }, "de_de": { // base page @@ -62,6 +72,11 @@ extension Localization on String { "improved_by": "Sie haben %s Verbesserung erreicht!", "detailed_stats": "Detaillierte Statistiken", "later": "Hurra! Ich schaue später nach.", + // sure delete modal + "delete": "Löschen", + "attention": "Achtung!", + "attention_body": + "Ihr Ziel und Ihr Fortschritt gehen für immer verloren und können nicht wiederhergestellt werden.", }, }; diff --git a/filcnaplo_premium/lib/ui/mobile/settings/modify_subject_names.dart b/filcnaplo_premium/lib/ui/mobile/settings/modify_subject_names.dart index 37daf97..d20f7cd 100644 --- a/filcnaplo_premium/lib/ui/mobile/settings/modify_subject_names.dart +++ b/filcnaplo_premium/lib/ui/mobile/settings/modify_subject_names.dart @@ -91,7 +91,7 @@ class _ModifySubjectNamesState extends State { final _subjectName = TextEditingController(); String? selectedSubjectId; - late List subjects; + late List subjects; late UserProvider user; late DatabaseProvider dbProvider; late SettingsProvider settings; @@ -294,9 +294,11 @@ class _ModifySubjectNamesState extends State { children: [ Panel( child: SwitchListTile( - title: Text("italics_toggle".i18n), - onChanged: (value) => settings.update(renamedSubjectsItalics: value), - value: settings.renamedSubjectsItalics,), + title: Text("italics_toggle".i18n), + onChanged: (value) => + settings.update(renamedSubjectsItalics: value), + value: settings.renamedSubjectsItalics, + ), ), const SizedBox( height: 20, @@ -339,7 +341,7 @@ class _ModifySubjectNamesState extends State { child: Column( children: snapshot.data!.keys.map( (key) { - Subject? subject = subjects + GradeSubject? subject = subjects .firstWhere((element) => key == element.id); String renameTo = snapshot.data![key]!; return RenamedSubjectItem( @@ -385,7 +387,7 @@ class RenamedSubjectItem extends StatelessWidget { required this.removeCallback, }) : super(key: key); - final Subject subject; + final GradeSubject subject; final String renamedTo; final void Function() modifyCallback; final void Function() removeCallback; diff --git a/filcnaplo_premium/lib/ui/mobile/settings/theme.dart b/filcnaplo_premium/lib/ui/mobile/settings/theme.dart index c9ffb30..763acf2 100644 --- a/filcnaplo_premium/lib/ui/mobile/settings/theme.dart +++ b/filcnaplo_premium/lib/ui/mobile/settings/theme.dart @@ -39,6 +39,7 @@ enum CustomColorMode { accent, background, highlight, + icon, enterId, } @@ -146,6 +147,8 @@ class _PremiumCustomAccentColorSettingState return settings.customHighlightColor; case CustomColorMode.accent: return settings.customAccentColor; + case CustomColorMode.icon: + return settings.customIconColor; case CustomColorMode.enterId: // do nothing here lol break; @@ -153,7 +156,7 @@ class _PremiumCustomAccentColorSettingState } void updateCustomColor(dynamic v, bool store, - {Color? accent, Color? background, Color? panels}) { + {Color? accent, Color? background, Color? panels, Color? icon}) { if (colorMode != CustomColorMode.theme) { settings.update(accentColor: AccentColor.custom, store: store); } @@ -186,10 +189,14 @@ class _PremiumCustomAccentColorSettingState case CustomColorMode.accent: settings.update(customAccentColor: v, store: store); break; + case CustomColorMode.icon: + settings.update(customIconColor: v, store: store); + break; case CustomColorMode.enterId: settings.update(customBackgroundColor: background, store: store); settings.update(customHighlightColor: panels, store: store); settings.update(customAccentColor: accent, store: store); + settings.update(customIconColor: icon, store: store); break; } } @@ -329,7 +336,8 @@ class _PremiumCustomAccentColorSettingState width: double.infinity, decoration: BoxDecoration( borderRadius: BorderRadius.circular(24), - gradient: LinearGradient( // https://discord.com/channels/1111649116020285532/1153619667848548452 + gradient: LinearGradient( + // https://discord.com/channels/1111649116020285532/1153619667848548452 begin: Alignment.topCenter, end: Alignment.bottomCenter, stops: const [ @@ -337,8 +345,8 @@ class _PremiumCustomAccentColorSettingState 0.75 ], colors: [ - settings.customBackgroundColor - ?? Theme.of(context).colorScheme.background, + settings.customBackgroundColor ?? + Theme.of(context).colorScheme.background, isBackgroundDifferent ? HSVColor.fromColor(Theme.of(context) .colorScheme @@ -704,6 +712,13 @@ class _PremiumCustomAccentColorSettingState tab: Tab( text: "colorpicker_accent" .i18n)), + // ColorTab( + // unlocked: hasAccess, + // color: settings.customIconColor ?? + // unknownColor, + // tab: Tab( + // text: + // "colorpicker_icon".i18n)), ], onTap: (index) { if (!hasAccess) { @@ -754,6 +769,12 @@ class _PremiumCustomAccentColorSettingState CustomColorMode.accent; }); break; + case 5: + setState(() { + colorMode = + CustomColorMode.icon; + }); + break; } }, controller: _colorsTabController, @@ -781,9 +802,15 @@ class _PremiumCustomAccentColorSettingState .accentColor] ?? AppColors.of(context) .text) // idk what else - : settings - .customHighlightColor ?? - unknownColor, + : colorMode == + CustomColorMode + .highlight + ? settings + .customHighlightColor ?? + unknownColor + : settings + .customIconColor ?? + unknownColor, onColorChanged: (c) { setState(() { updateCustomColor(c, false); @@ -806,6 +833,10 @@ class _PremiumCustomAccentColorSettingState AppColors.of(context) .highlight, store: true); + settings.update( + customIconColor: + const Color(0x00000000), + store: true); } else { updateCustomColor(c, true); } @@ -824,6 +855,11 @@ class _PremiumCustomAccentColorSettingState settings.update( gradeColors: colors); + // changing shadow effect + settings.update( + shadowEffect: + theme.shadowEffect); + // changing theme setState(() { updateCustomColor( @@ -833,6 +869,7 @@ class _PremiumCustomAccentColorSettingState background: theme.backgroundColor, panels: theme.panelsColor, + icon: theme.iconColor, ); }); setTheme(settings.theme, true); diff --git a/filcnaplo_premium/lib/ui/mobile/settings/theme.i18n.dart b/filcnaplo_premium/lib/ui/mobile/settings/theme.i18n.dart index f578ff3..ec20f96 100644 --- a/filcnaplo_premium/lib/ui/mobile/settings/theme.i18n.dart +++ b/filcnaplo_premium/lib/ui/mobile/settings/theme.i18n.dart @@ -9,6 +9,7 @@ extension SettingsLocalization on String { "colorpicker_background": "Background", "colorpicker_panels": "Panels", "colorpicker_accent": "Accent", + "colorpicker_icon": "Icon", "need_sub": "You need Kupak subscription to use modify this.", "advanced": "Advanced", "enter_id": "Enter ID", @@ -18,6 +19,7 @@ extension SettingsLocalization on String { "share_disclaimer": "By sharing the theme, you agree that the nickname you set and all settings of the theme will be shared publicly.", "understand": "I understand", + "share_subj_theme": "Share Theme", }, "hu_hu": { "theme_prev": "Előnézet", @@ -25,6 +27,7 @@ extension SettingsLocalization on String { "colorpicker_background": "Háttér", "colorpicker_panels": "Panelek", "colorpicker_accent": "Színtónus", + "colorpicker_icon": "Ikon", "need_sub": "A módosításhoz Kupak szintű támogatás szükséges.", "advanced": "Haladó", "enter_id": "ID megadása", @@ -34,6 +37,7 @@ extension SettingsLocalization on String { "share_disclaimer": "A téma megosztásával elfogadod, hogy az általad beállított becenév és a téma minden beállítása nyilvánosan megosztásra kerüljön.", "understand": "Értem", + "share_subj_theme": "Téma Megosztás", }, "de_de": { "theme_prev": "Vorschau", @@ -41,6 +45,7 @@ extension SettingsLocalization on String { "colorpicker_background": "Hintergrund", "colorpicker_panels": "Tafeln", "colorpicker_accent": "Akzent", + "colorpicker_icon": "Ikone", "need_sub": "Sie benötigen ein Kupak-Abonnement, um diese Funktion zu ändern.", "advanced": "Fortschrittlich", @@ -51,6 +56,7 @@ extension SettingsLocalization on String { "share_disclaimer": "Durch das Teilen des Themes erklären Sie sich damit einverstanden, dass der von Ihnen festgelegte Spitzname und alle Einstellungen des Themes öffentlich geteilt werden.", "understand": "Ich verstehe", + "share_subj_theme": "Thema Teilen", }, };