Merge pull request #73 from refilc/dev

Dev
This commit is contained in:
Márton Kiss 2023-10-15 20:29:14 +02:00 committed by GitHub
commit 382961971d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
81 changed files with 1133 additions and 1101 deletions

52
.gitignore vendored
View File

@ -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

3
.idea/.gitignore generated vendored
View File

@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

40
.vscode/launch.json vendored
View File

@ -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"
}
]
}

47
filcnaplo/.gitignore vendored
View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -190,12 +190,22 @@ class FilcAPI {
static Future<void> 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;

View File

@ -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,

View File

@ -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<SettingsProvider>(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<SettingsProvider>(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ó";

View File

@ -67,6 +67,8 @@ class SettingsProvider extends ChangeNotifier {
Color _customAccentColor;
Color _customBackgroundColor;
Color _customHighlightColor;
Color _customIconColor;
bool _shadowEffect;
List<String> _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<String> 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<String>(),
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<String> 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<String>? 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;
}

View File

@ -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,
);
}

View File

@ -5,17 +5,21 @@ enum SubjectLessonCountUpdateState { ready, updating }
class SubjectLessonCount {
DateTime lastUpdated;
Map<Subject, int> subjects;
Map<GradeSubject, int> 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,
),
),

View File

@ -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<SettingsProvider>(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,

View File

@ -34,8 +34,7 @@ class GradeTile extends StatelessWidget {
GradeCalculatorProvider calculatorProvider =
Provider.of<GradeCalculatorProvider>(context, listen: false);
SettingsProvider settingsProvider =
Provider.of<SettingsProvider>(context);
SettingsProvider settingsProvider = Provider.of<SettingsProvider>(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<SettingsProvider>(context, listen: false)
.shadowEffect)
BoxShadow(
color: color,
blurRadius: 62.0,

View File

@ -1 +0,0 @@
flutter/ephemeral

View File

@ -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 "$<$<NOT:$<CONFIG:Debug>>:-O3>")
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>: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()

View File

@ -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}
)

View File

@ -1,7 +0,0 @@
# Flutter-related
**/Flutter/ephemeral/
**/Pods/
# Xcode-related
**/dgph
**/xcuserdata/

View File

@ -1,2 +0,0 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"

View File

@ -1,2 +0,0 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"

View File

@ -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"

View File

@ -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/

View File

@ -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

View File

@ -31,7 +31,7 @@ import 'absences_page.i18n.dart';
enum AbsenceFilter { absences, delays, misses }
class SubjectAbsence {
Subject subject;
GradeSubject subject;
List<Absence> absences;
double percentage;
@ -56,7 +56,7 @@ class _AbsencesPageState extends State<AbsencesPage>
late String firstName;
late TabController _tabController;
late List<SubjectAbsence> absences = [];
final Map<Subject, Lesson> _lessonCount = {};
final Map<GradeSubject, Lesson> _lessonCount = {};
@override
void initState() {
@ -87,7 +87,7 @@ class _AbsencesPageState extends State<AbsencesPage>
}
void buildSubjectAbsences() {
Map<Subject, SubjectAbsence> _absences = {};
Map<GradeSubject, SubjectAbsence> _absences = {};
for (final absence in absenceProvider.absences) {
if (absence.delay != 0) continue;

View File

@ -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<GradeSubjectView> {
bool gradeCalcMode = false;
List<Grade> getSubjectGrades(Subject subject) => !gradeCalcMode
List<Grade> getSubjectGrades(GradeSubject subject) => !gradeCalcMode
? gradeProvider.grades.where((e) => e.subject == subject).toList()
: calculatorProvider.grades.where((e) => e.subject == subject).toList();

View File

@ -41,7 +41,7 @@ class _GradesPageState extends State<GradesPage> {
int avgDropValue = 0;
List<Grade> getSubjectGrades(Subject subject, {int days = 0}) => gradeProvider
List<Grade> getSubjectGrades(GradeSubject subject, {int days = 0}) => gradeProvider
.grades
.where((e) =>
e.subject == subject &&
@ -51,14 +51,14 @@ class _GradesPageState extends State<GradesPage> {
.toList();
void generateTiles() {
List<Subject> subjects = gradeProvider.grades
List<GradeSubject> subjects = gradeProvider.grades
.map((e) => e.subject)
.toSet()
.toList()
..sort((a, b) => a.name.compareTo(b.name));
List<Widget> tiles = [];
Map<Subject, double> subjectAvgs = {};
Map<GradeSubject, double> subjectAvgs = {};
tiles.addAll(subjects.map((subject) {
List<Grade> subjectGrades = getSubjectGrades(subject);

View File

@ -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": {

View File

@ -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

View File

@ -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 {

View File

@ -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,

View File

@ -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

View File

@ -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,

View File

@ -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,
);
}

View File

@ -12,7 +12,7 @@ class Homework {
bool homeworkEnabled;
Teacher teacher;
String content;
Subject subject;
GradeSubject subject;
String group;
List<HomeworkAttachment> 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"] ?? ""
: "",

View File

@ -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

View File

@ -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;
}

View File

@ -27,19 +27,49 @@ class ExamProvider with ChangeNotifier {
// Load exams from the database
if (userId != null) {
var dbExams = await Provider.of<DatabaseProvider>(_context, listen: false).userQuery.getExams(userId: userId);
var dbExams = await Provider.of<DatabaseProvider>(_context, listen: false)
.userQuery
.getExams(userId: userId);
_exams = dbExams;
notifyListeners();
await convertBySettings();
}
}
// for renamed subjects
Future<void> convertBySettings() async {
final _database = Provider.of<DatabaseProvider>(_context, listen: false);
Map<String, String> renamedSubjects =
(await _database.query.getSettings(_database)).renamedSubjectsEnabled
? await _database.userQuery.renamedSubjects(
userId:
Provider.of<UserProvider>(_context, listen: false).user!.id)
: {};
Map<String, String> renamedTeachers =
(await _database.query.getSettings(_database)).renamedTeachersEnabled
? await _database.userQuery.renamedTeachers(
userId:
Provider.of<UserProvider>(_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<void> fetch() async {
User? user = Provider.of<UserProvider>(_context, listen: false).user;
if (user == null) throw "Cannot fetch Exams for User null";
String iss = user.instituteCode;
List? examsJson = await Provider.of<KretaClient>(_context, listen: false).getAPI(KretaAPI.exams(iss));
List? examsJson = await Provider.of<KretaClient>(_context, listen: false)
.getAPI(KretaAPI.exams(iss));
if (examsJson == null) throw "Cannot fetch Exams for User ${user.id}";
List<Exam> 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<DatabaseProvider>(_context, listen: false).userStore.storeExams(exams, userId: userId);
await Provider.of<DatabaseProvider>(_context, listen: false)
.userStore
.storeExams(exams, userId: userId);
_exams = exams;
notifyListeners();
await convertBySettings();
}
}

View File

@ -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<KretaClient>(_context, listen: false)
Iterable hwjson = await Provider.of<KretaClient>(_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>(), (Map hw) async {
Map? e = await Provider.of<KretaClient>(_context, listen: false)
.getAPI(KretaAPI.homework(iss, id: hw["Uid"]));
Map<String, String> renamedSubjects = _settings.renamedSubjectsEnabled
? await _database.userQuery.renamedSubjects(userId: _user.user!.id)
: {};
// Map<String, String> 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

View File

@ -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<Grade> _grades;
// late DateTime _lastSeen;
// late String _groups;
// List<GroupAverage> _groupAvg = [];
// late final SettingsProvider _settings;
// late final UserProvider _user;
// late final DatabaseProvider _database;
// late final KretaClient _kreta;
// // Public
// List<Grade> get grades => _grades;
// DateTime get lastSeenDate =>
// _settings.gradeOpeningFun ? _lastSeen : DateTime(3000);
// String get groups => _groups;
// List<GroupAverage> get groupAverages => _groupAvg;
// SubjectProvider({
// List<Grade> 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<void> seenAll() async {
// String? userId = _user.id;
// if (userId != null) {
// final userStore = _database.userStore;
// userStore.storeLastSeenGrade(DateTime.now(), userId: userId);
// _lastSeen = DateTime.now();
// }
// }
// Future<void> 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<void> convertBySettings() async {
// Map<String, String> renamedSubjects = _settings.renamedSubjectsEnabled
// ? await _database.userQuery.renamedSubjects(userId: _user.user!.id)
// : {};
// Map<String, String> 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<void> 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<Grade> 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<void> store(List<Grade> 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<void> storeGroupAvg(List<GroupAverage> 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();
// }
// }

View File

@ -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

View File

@ -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<SettingsProvider>(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<SettingsProvider>(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<SettingsProvider>(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<SettingsProvider>(context, listen: false)
.shadowEffect)
BoxShadow(
offset: const Offset(0, 21),
blurRadius: 23.0,
color: Theme.of(context).shadowColor,
)
],
),
);

View File

@ -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<EmptyCard> {
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<SettingsProvider>(context, listen: false)
.shadowEffect)
BoxShadow(
color: Colors.black.withOpacity(0.08),
offset: const Offset(0, 5),
blurRadius: 20,
spreadRadius: 10,
),
],
),
child: DottedBorder(

View File

@ -35,12 +35,12 @@ class _PersonalityCardState extends State<PersonalityCard> {
late SettingsProvider settings;
late List<int> subjectAvgsList = [];
late Map<Subject, double> subjectAvgs = {};
late Map<GradeSubject, double> subjectAvgs = {};
late double subjectAvg;
late List<Grade> classWorkGrades;
late Map<int, int> mostCommonGrade;
late List<Absence> absences = [];
final Map<Subject, Lesson> _lessonCount = {};
final Map<GradeSubject, Lesson> _lessonCount = {};
late int totalDelays;
late int unexcusedAbsences;
@ -48,14 +48,15 @@ class _PersonalityCardState extends State<PersonalityCard> {
bool hold = false;
List<Grade> 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<Grade> 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<PersonalityCard> {
}
void getGrades() {
List<Subject> subjects = gradeProvider.grades
List<GradeSubject> 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<Grade> subjectGrades = getSubjectGrades(subject);
double avg = AverageHelper.averageEvals(subjectGrades);

View File

@ -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())
],
);
}
}

View File

@ -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<Object> params) => localizeFill(this, params);
String plural(int value) => localizePlural(value, this, _t);
String version(Object modifier) => localizeVersion(modifier, this, _t);
}

View File

@ -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(

View File

@ -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),

View File

@ -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),

View File

@ -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,

View File

@ -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(

View File

@ -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(

View File

@ -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),

View File

@ -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<SettingsProvider>(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,
),
),
),

View File

@ -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<Absence> absences;
static void show(Subject subject, List<Absence> absences,
static void show(GradeSubject subject, List<Absence> absences,
{required BuildContext context}) {
Navigator.of(context, rootNavigator: true)
.push<Absence>(CupertinoPageRoute(

View File

@ -33,7 +33,7 @@ import 'absences_page.i18n.dart';
enum AbsenceFilter { absences, delays, misses }
class SubjectAbsence {
Subject subject;
GradeSubject subject;
List<Absence> absences;
double percentage;
@ -58,7 +58,7 @@ class _AbsencesPageState extends State<AbsencesPage>
late String firstName;
late TabController _tabController;
late List<SubjectAbsence> absences = [];
final Map<Subject, Lesson> _lessonCount = {};
final Map<GradeSubject, Lesson> _lessonCount = {};
@override
void initState() {
@ -90,7 +90,7 @@ class _AbsencesPageState extends State<AbsencesPage>
}
void buildSubjectAbsences() {
Map<Subject, SubjectAbsence> _absences = {};
Map<GradeSubject, SubjectAbsence> _absences = {};
for (final absence in absenceProvider.absences) {
if (absence.delay != 0) continue;
@ -285,8 +285,9 @@ class _AbsencesPageState extends State<AbsencesPage>
content: Text("attention_body".i18n),
actions: [
ActionButton(
label: "Ok",
onTap: () => Navigator.of(context).pop())
label: "Ok",
onTap: () => Navigator.of(context).pop(),
),
],
),
);

View File

@ -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();

View File

@ -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<Subject, double> subjectAvgs;
final Map<GradeSubject, double> subjectAvgs;
@override
Widget build(BuildContext context) {

View File

@ -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<GradeSubjectView> {
String plan = '';
List<Grade> getSubjectGrades(Subject subject) => !gradeCalcMode
List<Grade> getSubjectGrades(GradeSubject subject) => !gradeCalcMode
? gradeProvider.grades.where((e) => e.subject == subject).toList()
: calculatorProvider.grades.where((e) => e.subject == subject).toList();

View File

@ -48,24 +48,25 @@ class _GradesPageState extends State<GradesPage> {
int avgDropValue = 0;
List<Grade> 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<Grade> 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<Subject> subjects = gradeProvider.grades
List<GradeSubject> subjects = gradeProvider.grades
.map((e) => e.subject)
.toSet()
.toList()
..sort((a, b) => a.name.compareTo(b.name));
List<Widget> tiles = [];
Map<Subject, double> subjectAvgs = {};
Map<GradeSubject, double> subjectAvgs = {};
tiles.addAll(subjects.map((subject) {
List<Grade> subjectGrades = getSubjectGrades(subject);
@ -154,7 +155,7 @@ class _GradesPageState extends State<GradesPage> {
title: AutoSizeText(
"subjectavg".i18n,
textAlign: TextAlign.center,
maxLines: 2,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
value: subjectAvg,
@ -167,7 +168,7 @@ class _GradesPageState extends State<GradesPage> {
title: AutoSizeText(
"classavg".i18n,
textAlign: TextAlign.center,
maxLines: 2,
maxLines: 1,
wrapWords: false,
overflow: TextOverflow.ellipsis,
),

View File

@ -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": {

View File

@ -172,7 +172,8 @@ class _LiveCardState extends State<LiveCard> {
: ""),
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),

View File

@ -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<LiveCardWidget> {
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<SettingsProvider>(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<LiveCardWidget> {
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:

View File

@ -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<MessagesPage>
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),

View File

@ -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<SettingsScreen>
),
),
// Updates
// updates
if (updateProvider.available)
Padding(
padding: const EdgeInsets.symmetric(
@ -377,122 +378,7 @@ class _SettingsScreenState extends State<SettingsScreen>
// 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<SettingsScreen>
),
),
// 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<SettingsScreen>
),
),
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<SettingsScreen>
),
),
),
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<SettingsScreen>
),
),
// Extras
// extra settings
Padding(
padding:
const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0),
@ -798,12 +834,23 @@ class _SettingsScreenState extends State<SettingsScreen>
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<SettingsScreen>
),
),
),
// version info
SafeArea(
top: false,
child: Center(

View File

@ -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",
},
};

View File

@ -30,7 +30,7 @@ class _AllSumBodyState extends State<AllSumBody> {
int avgDropValue = 0;
bool animation = false;
List<Grade> getSubjectGrades(Subject subject, {int days = 0}) => gradeProvider
List<Grade> getSubjectGrades(GradeSubject subject, {int days = 0}) => gradeProvider
.grades
.where((e) =>
e.subject == subject &&

View File

@ -50,14 +50,15 @@ class _GradesBodyState extends State<GradesBody> {
int avgDropValue = 0;
bool animation = false;
List<Grade> 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<Grade> 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<GradesBody> {
}
void generateTiles({required int filter}) {
List<Subject> subjects = gradeProvider.grades
List<GradeSubject> subjects = gradeProvider.grades
.map((e) => e.subject)
.toSet()
.toList()
..sort((a, b) => a.name.compareTo(b.name));
List<Widget> tiles = [];
Map<Subject, double> subjectAvgs = {};
Map<GradeSubject, double> subjectAvgs = {};
var count = 1;
for (Subject subject in subjects) {
for (GradeSubject subject in subjects) {
List<Grade> subjectGrades = getSubjectGrades(subject);
double avg = AverageHelper.averageEvals(subjectGrades);

View File

@ -28,7 +28,7 @@ List<String> faces = [
];
class SubjectAbsence {
Subject subject;
GradeSubject subject;
List<Absence> absences;
double percentage;
@ -52,7 +52,7 @@ class _LessonsBodyState extends State<LessonsBody> {
late List<SubjectAbsence> absences = [];
late List<Widget> lessons = [];
late List<Absence> delays = [];
final Map<Subject, Lesson> _lessonCount = {};
final Map<GradeSubject, Lesson> _lessonCount = {};
@override
void initState() {
@ -85,7 +85,7 @@ class _LessonsBodyState extends State<LessonsBody> {
}
void buildSubjectAbsences() {
Map<Subject, SubjectAbsence> _absences = {};
Map<GradeSubject, SubjectAbsence> _absences = {};
for (final absence in absenceProvider.absences) {
if (absence.delay != 0) continue;

View File

@ -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

View File

@ -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<Subject> subjects = gradeProvider.grades
List<GradeSubject> subjects = gradeProvider.grades
.map((e) => e.subject)
.toSet()
.toList()
@ -45,7 +45,7 @@ class GoalProvider extends ChangeNotifier {
_doneSubject = null;
}
Future<void> clearGoal(Subject subject) async {
Future<void> clearGoal(GradeSubject subject) async {
final goalPlans = await _db.userQuery.subjectGoalPlans(userId: _user.id!);
final goalAvgs = await _db.userQuery.subjectGoalAverages(userId: _user.id!);
final goalBeforeGrades =

View File

@ -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);

View File

@ -262,6 +262,7 @@ class _FilcColorPickerState extends State<FilcColorPicker> {
if (theme != null) {
widget.onThemeIdProvided(theme);
idController.clear();
} else {
ScaffoldMessenger.of(context).showSnackBar(
CustomSnackBar(

View File

@ -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<T?> show<T>(
Subject subject, {
GradeSubject subject, {
required BuildContext context,
}) async {
UserProvider user = Provider.of<UserProvider>(context, listen: false);

View File

@ -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),

View File

@ -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<GoalPlannerScreen> {
bool gradeCalcMode = false;
List<Grade> getSubjectGrades(Subject subject) => !gradeCalcMode
List<Grade> getSubjectGrades(GradeSubject subject) => !gradeCalcMode
? gradeProvider.grades.where((e) => e.subject == subject).toList()
: calculatorProvider.grades.where((e) => e.subject == subject).toList();

View File

@ -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<GoalStateScreen> {
setState(() {});
}
List<Grade> getSubjectGrades(Subject subject) =>
List<Grade> getSubjectGrades(GradeSubject subject) =>
gradeProvider.grades.where((e) => (e.subject == subject)).toList();
List<Grade> getAfterGoalGrades(Subject subject) => gradeProvider.grades
List<Grade> getAfterGoalGrades(GradeSubject subject) => gradeProvider.grades
.where((e) => (e.subject == subject && e.date.isAfter(goalPinDate)))
.toList();
@ -199,11 +201,39 @@ class _GoalStateScreenState extends State<GoalStateScreen> {
),
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<GoalProvider>(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),

View File

@ -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.",
},
};

View File

@ -91,7 +91,7 @@ class _ModifySubjectNamesState extends State<ModifySubjectNames> {
final _subjectName = TextEditingController();
String? selectedSubjectId;
late List<Subject> subjects;
late List<GradeSubject> subjects;
late UserProvider user;
late DatabaseProvider dbProvider;
late SettingsProvider settings;
@ -294,9 +294,11 @@ class _ModifySubjectNamesState extends State<ModifySubjectNames> {
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<ModifySubjectNames> {
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;

View File

@ -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);

View File

@ -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",
},
};