Compare commits

..

70 Commits
4.3.0 ... 4.4.0

Author SHA1 Message Date
Márton Kiss
82db2e2091 Merge pull request #75 from refilc/dev
added gitignore
2023-10-15 20:57:27 +02:00
Kima
774f63aa89 added gitignore 2023-10-15 20:57:00 +02:00
Márton Kiss
8375e1877a Merge pull request #74 from refilc/dev
changed build number to final
2023-10-15 20:34:10 +02:00
Kima
b00fab090c changed build number to final 2023-10-15 20:33:31 +02:00
Márton Kiss
382961971d Merge pull request #73 from refilc/dev
Dev
2023-10-15 20:29:14 +02:00
Kima
04c5c819f8 remove trailing from app icon option 2023-10-15 19:59:00 +02:00
Kima
6249015bef Revert "Some localization changes"
This reverts commit be4737f9db.
2023-10-15 19:54:17 +02:00
Kima
2fade7117b Merge branch 'dev' of github.com:refilc/naplo into dev 2023-10-15 19:48:23 +02:00
Kima
49c396e746 fixed error reporting 2023-10-15 19:48:20 +02:00
Pearoo
be4737f9db Some localization changes 2023-10-15 18:43:29 +02:00
Kima
d27c059b23 fixed height glitch on grades page 2023-10-15 17:20:08 +02:00
Kima
21a5771211 temp removed icon color tab 2023-10-15 16:35:50 +02:00
Kima
501d83c229 Merge branch 'dev' of github.com:refilc/naplo into dev 2023-10-15 16:08:26 +02:00
Kima
6651bbf14a fixed typo 2023-10-15 16:08:23 +02:00
Pearoo
ddf1944883 Fix typo in failure_warning 2023-10-15 16:03:02 +02:00
Kima
bf0eeb83e4 changed "default" to "dynamic" at welcome message 2023-10-15 15:15:13 +02:00
Kima
d41c39849b changed build number 2023-10-15 15:14:07 +02:00
Kima
25294dd4a7 added "soon alert" widget 2023-10-15 15:03:09 +02:00
Kima
d0f347c80d added app icon change option to settings 2023-10-15 15:02:59 +02:00
Kima
44464e1946 moved "secret settings" after account list 2023-10-15 14:41:31 +02:00
Kima
5a371d7200 added "send message" button to messages screen 2023-10-15 14:36:43 +02:00
Kima
27fefb4c27 fixed homework provider finally 2023-10-15 14:29:25 +02:00
Kima
efe58eeea9 added clear goal button to goal planning 2023-10-15 13:46:58 +02:00
Kima
8e629ef596 added textfield clear to enterid in theme menu 2023-10-15 13:18:25 +02:00
Kima
d188cefc07 fixed theme share with new options 2023-10-15 13:15:55 +02:00
Kima
c5b6f92b0e commented subject provider 2023-10-15 12:55:14 +02:00
Kima
2d5cbe8799 changed old subject type to gradesubject 2023-10-15 12:14:06 +02:00
Pearoo
c7c3b421f4 Added subjects API endpoint
Also added JSON structure in comments
No implementation yet, will be used in the future
Kudos @sleddev
2023-10-15 11:42:35 +02:00
Kima
adfa653062 changed version string 2023-10-12 21:48:16 +02:00
Kima
86f7cf3b2e fixed subject icon things 2023-10-12 21:10:14 +02:00
Kima
1cc885e4b7 fixed exam subject rename thing 2023-10-12 21:06:53 +02:00
Kima
a4207b8348 fixed livecard italic font bug 2023-10-12 20:58:23 +02:00
Kima
3e600f69f0 fix shadow thing on timetable 2023-10-12 20:54:07 +02:00
Kima
205d90523c added check everywhere to shadow effect 2023-10-12 20:38:32 +02:00
Kima
906de6dd45 changed shadow effect toggle icon to moon 2023-10-12 20:10:04 +02:00
Kima
3ff0927834 added toggle for shadow effect to settings screen 2023-10-12 20:08:23 +02:00
Kima
14e5614adc done icon color changer in settings 2023-10-12 19:51:41 +02:00
Kima
6ed89b2a1e added missing translation 2023-10-12 19:26:41 +02:00
Kima
5272ac5a01 added icon color changer everywhere 2023-10-12 19:24:40 +02:00
Kima
46e6120af3 added things to db and theme share 2023-10-12 19:14:40 +02:00
Kima
600bf7d763 removed import dsklfjnu 2023-10-12 19:10:54 +02:00
Kima
10750f898f added shadow effect and icon color option to sp 2023-10-12 19:10:32 +02:00
Pearoo
1d5ebe7bbd Fix cancelled vs. delayed card
Fixes https://discord.com/channels/1111649116020285532/1154687576758829097
Implements 9845a35 from `cancelled-bugfix` branch
Deletes `cancelled-bugfix` branch
2023-10-10 07:01:57 +02:00
Pearoo
2aa8db8f42 Merge pull request #70 from refilc/dev
Implement 6388932
2023-10-10 06:47:55 +02:00
Pearoo
f95d4582be Implement 6388932 2023-10-09 07:37:40 +02:00
Pearoo
63889325cf Add good student disclaimer german localisation
Fixes https://discord.com/channels/1111649116020285532/1160698590033870848
2023-10-09 07:26:29 +02:00
Márton Kiss
acbffd6d72 Merge pull request #69 from refilc/dev
69-es szamu pr haha 😏
2023-10-08 17:00:13 +02:00
Kima
b19da9cb66 finally fixed kreten error shit sdfadfsdfhsdfgh 2023-10-08 16:55:06 +02:00
Kima
fd80aec51f added upgrade-pub.sh to upgrade pub packages 2023-10-08 16:24:59 +02:00
Kima
5776622276 settings account tiles now showing nickname 2023-10-08 12:44:45 +02:00
Kima
69ea3e1a7f update version string 2023-10-08 12:03:08 +02:00
Kima
3d451f6f91 fixed the fix lol 2023-10-08 11:52:39 +02:00
Kima
387e2e46db fixed i18n error spam on home screen (welcome msg) 2023-10-08 11:51:09 +02:00
Kima
a7f1681902 someone commented birthday greeting, fuck yourself 2023-10-08 11:48:09 +02:00
Kima
4b127bdf56 fixed homewrok not showing up 2023-10-08 11:46:00 +02:00
Kima
dbb6125ab5 fixed live card not showing on android 2023-10-08 11:42:27 +02:00
Kima
b6d4ac6168 maybe fixed error shit 2023-10-08 11:33:09 +02:00
Kima
9d20d08838 fixed goal planner done popup 2023-10-07 19:41:33 +02:00
Kima
f39ac80770 fixed app bricking with welcome message thing 2023-10-05 21:54:57 +02:00
Kima
41991b3b66 change log message bc livecard is shit but idk why 2023-10-05 21:30:24 +02:00
ReinerRego
53ec3e567a Merge pull request #68 from TMarccci/dev
Xcode 15, iOS 17 - Bug Fix+Others
2023-10-05 00:07:41 +02:00
Tihanyi Marcell
176608bfc5 Xcode 15, iOS 17 - Bug Fix+Others 2023-10-04 23:25:00 +02:00
ReinerRego
92b4094550 started fixing desktop ui 2023-10-04 14:10:17 +02:00
Márton Kiss
45c6fccb89 Merge pull request #66 from TMarccci/master
Added a few subjects to helper
2023-09-28 21:37:56 +02:00
Tihanyi Marcell
014329d7fe Added a few subjects to helper 2023-09-28 21:28:30 +02:00
Márton Kiss
dca01d0ed0 Merge pull request #65 from sleddev/dev
timetable italics + instituteCode search + theme preview background color
2023-09-28 21:17:50 +02:00
SledDev
493adaa5f2 fixed background color in theme preview 2023-09-28 20:15:09 +02:00
SledDev
8451983163 find schools by instituteCode 2023-09-28 19:41:43 +02:00
SledDev
2b7e143812 fixed fullscreen timetable italics 2023-09-28 19:12:56 +02:00
Pearoo
9845a35c6e Fix english absence error + comment bugreports 2023-09-28 18:17:24 +02:00
97 changed files with 1435 additions and 1127 deletions

77
.gitignore vendored
View File

@@ -1,52 +1,37 @@
# See https://www.dartlang.org/guides/libraries/private-files
.gitignore
filcnaplo/.flutter-plugins
filcnaplo/.flutter-plugins-dependencies
filcnaplo/pubspec.lock
filcnaplo/.dart_tool/
filcnaplo/android/
filcnaplo/ios/
filcnaplo/windows/
filcnaplo/linux/
filcnaplo/macos/
filcnaplo/build/
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
filcnaplo_desktop_ui/.flutter-plugins
filcnaplo_desktop_ui/.flutter-plugins-dependencies
filcnaplo_desktop_ui/pubspec.lock
filcnaplo_desktop_ui/.dart_tool/
# Directory created by dartdoc
# If you don't generate documentation locally you can remove this line.
doc/api/
filcnaplo_kreta_api/.flutter-plugins
filcnaplo_kreta_api/.flutter-plugins-dependencies
filcnaplo_kreta_api/pubspec.lock
filcnaplo_kreta_api/.dart_tool/
# 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
filcnaplo_mobile_ui/.flutter-plugins
filcnaplo_mobile_ui/.flutter-plugins-dependencies
filcnaplo_mobile_ui/pubspec.lock
filcnaplo_mobile_ui/.dart_tool/
*.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
filcnaplo_premium/.flutter-plugins
filcnaplo_premium/.flutter-plugins-dependencies
filcnaplo_premium/pubspec.lock
filcnaplo_premium/.dart_tool/
filcnaplo_premium/android/
.flutter-plugins*
filcnaplo/ios/Flutter/flutter_export_environment 4.sh
filcnaplo/ios/Flutter/Generated 4.xcconfig
.vscode
.github
.idea
.gitmodules

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

@@ -136,7 +136,7 @@
android:layout_below="@id/iv_1"
android:layout_marginHorizontal="15dp"
android:fontFamily="@font/montserrat_medium"
android:text="A widget használatához, bejelentkezés szükséges."
android:text="A widget használatához bejelentkezés szükséges."
android:textColor="@color/black"
android:paddingTop="10dp"
android:textSize="17sp"

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

@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '11.0'
platform :ios, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
@@ -39,5 +39,8 @@ end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET'
end
end
end

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

@@ -51,7 +51,7 @@ class LiveCardProvider extends ChangeNotifier {
_liveActivitiesPlugin.areActivitiesEnabled().then((value) {
// Console log
if (kDebugMode) {
print("Live card enabled: $value");
print("iOS LiveActivity enabled: $value");
}
if (value) {
@@ -62,13 +62,13 @@ class LiveCardProvider extends ChangeNotifier {
});
}
});
_timer = Timer.periodic(const Duration(seconds: 1), (timer) => update());
_delay = settings.bellDelayEnabled
? Duration(seconds: settings.bellDelay)
: Duration.zero;
update();
}
_timer = Timer.periodic(const Duration(seconds: 1), (timer) => update());
_delay = settings.bellDelayEnabled
? Duration(seconds: settings.bellDelay)
: Duration.zero;
update();
}
@override
@@ -196,7 +196,7 @@ class LiveCardProvider extends ChangeNotifier {
}
} catch (e) {
if (kDebugMode) {
print('ERROR: Unable to create or update iOS LiveCard!');
print('ERROR: Unable to create or update iOS LiveActivity!');
}
}
}

View File

@@ -79,11 +79,12 @@ class StatusProvider extends ChangeNotifier {
}
}
if (_stack.contains(Status.network)) return;
if (res.body == "invalid_grant" ||
if (res.body == 'invalid_grant' ||
res.body.replaceAll(' ', '') == '' ||
res.statusCode == 400) {
if (!_stack.contains(Status.apiError)) {
if (!_stack.contains(Status.apiError) &&
!_stack.contains(Status.network)) {
if (res.statusCode == 401) return;
_stack.insert(0, Status.apiError);
notifyListeners();
}

View File

@@ -131,6 +131,7 @@ class App extends StatelessWidget {
create: (context) => HomeworkProvider(
context: context,
database: database,
user: user,
),
),
ChangeNotifierProvider<MessageProvider>(

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

@@ -195,7 +195,7 @@ class NotificationsHelper {
if (userProvider.getUsers().length == 1) {
await flutterLocalNotificationsPlugin.show(
absence.id.hashCode,
"title_absence".i18n,
"title_absence".i18n, // https://discord.com/channels/1111649116020285532/1153273625206591528
"body_absence".i18n.fill(
[
DateFormat("yyyy-MM-dd").format(absence.date),
@@ -210,7 +210,7 @@ class NotificationsHelper {
} else {
await flutterLocalNotificationsPlugin.show(
absence.id.hashCode,
"title_absence".i18n,
"title_absence".i18n, // https://discord.com/channels/1111649116020285532/1153273625206591528
"body_absence_multiuser".i18n.fill(
[
userProvider.displayName!,

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,82 +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");
} else if (RegExp("asztali alkalmazasok").hasMatch(name)) {
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();
@@ -113,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)) {
@@ -131,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.0+226
version: 4.4.0+233
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);
@@ -144,8 +144,8 @@ class _GradesPageState extends State<GradesPage> {
Expanded(
child: StatisticsTile(
outline: true,
title: AutoSizeText(
"classavg".i18n,
title: AutoSizeText( // https://discord.com/channels/1111649116020285532/1153397476578050130
"classavg".i18n,
textAlign: TextAlign.center,
maxLines: 2,
wrapWords: false,

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

@@ -0,0 +1,122 @@
import 'package:filcnaplo_mobile_ui/screens/login/login_input.dart';
import 'package:filcnaplo_mobile_ui/screens/login/school_input/school_input_overlay.dart';
import 'package:filcnaplo_desktop_ui/screens/login/school_input/school_input_tile.dart';
import 'package:filcnaplo_mobile_ui/screens/login/school_input/school_search.dart';
import 'package:flutter/material.dart';
import 'package:filcnaplo_kreta_api/models/school.dart';
class SchoolInput extends StatefulWidget {
const SchoolInput({Key? key, required this.controller, required this.scroll})
: super(key: key);
final SchoolInputController controller;
final ScrollController scroll;
@override
_SchoolInputState createState() => _SchoolInputState();
}
class _SchoolInputState extends State<SchoolInput> {
final _focusNode = FocusNode();
final _layerLink = LayerLink();
late SchoolInputOverlay overlay;
@override
void initState() {
super.initState();
widget.controller.update = (fn) {
if (mounted) setState(fn);
};
overlay = SchoolInputOverlay(layerLink: _layerLink);
// Show school list when focused
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
WidgetsBinding.instance
.addPostFrameCallback((_) => overlay.createOverlayEntry(context));
Future.delayed(const Duration(milliseconds: 100)).then((value) {
if (mounted && widget.scroll.hasClients) {
widget.scroll.animateTo(widget.scroll.offset + 500,
duration: const Duration(milliseconds: 500),
curve: Curves.ease);
}
});
} else {
overlay.entry?.remove();
}
});
// LoginInput TextField listener
widget.controller.textController.addListener(() {
String text = widget.controller.textController.text;
if (text.isEmpty) {
overlay.children = null;
return;
}
List<School> results =
searchSchools(widget.controller.schools ?? [], text);
setState(() {
overlay.children = results
.map((School e) => SchoolInputTile(
school: e,
onTap: () => _selectSchool(e),
))
.toList();
});
Overlay.of(context).setState(() {});
});
}
void _selectSchool(School school) {
FocusScope.of(context).requestFocus(FocusNode());
setState(() {
widget.controller.selectedSchool = school;
widget.controller.textController.text = school.name;
});
}
@override
Widget build(BuildContext context) {
return CompositedTransformTarget(
link: _layerLink,
child: widget.controller.schools == null
? Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 10.0),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.15),
borderRadius: BorderRadius.circular(12.0),
),
child: const Center(
child: SizedBox(
height: 28.0,
width: 28.0,
child: CircularProgressIndicator(
color: Colors.white,
),
),
),
)
: LoginInput(
style: LoginInputStyle.school,
focusNode: _focusNode,
onClear: () {
widget.controller.selectedSchool = null;
FocusScope.of(context).requestFocus(_focusNode);
},
controller: widget.controller.textController,
),
);
}
}
class SchoolInputController {
final textController = TextEditingController();
School? selectedSchool;
List<School>? schools;
late void Function(void Function()) update;
}

View File

@@ -0,0 +1,65 @@
import 'package:filcnaplo_kreta_api/models/school.dart';
import 'package:flutter/material.dart';
class SchoolInputTile extends StatelessWidget {
const SchoolInputTile({Key? key, required this.school, this.onTap})
: super(key: key);
final School school;
final Function()? onTap;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: GestureDetector(
onPanDown: (e) {
onTap!();
},
child: InkWell(
onTapDown: (e) {},
borderRadius: BorderRadius.circular(6.0),
child: Padding(
padding: const EdgeInsets.all(6.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// School name
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
school.name,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontWeight: FontWeight.w600),
),
),
Row(
children: [
// School id
Expanded(
child: Text(
school.instituteCode,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
// School city
Expanded(
child: Text(
school.city,
textAlign: TextAlign.right,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
],
),
),
),
),
);
}
}

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;
@@ -24,10 +24,12 @@ class HomeworkProvider with ChangeNotifier {
List<Homework> initialHomework = const [],
required BuildContext context,
required DatabaseProvider database,
required UserProvider user,
}) {
_homework = List.castFrom(initialHomework);
_context = context;
_database = database;
_user = user;
if (_homework.isEmpty) restore();
}
@@ -78,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)
}
@@ -93,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);
}
});
@@ -110,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

@@ -127,7 +127,7 @@ class AbsenceView extends StatelessWidget {
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
onPressed: () {
onPressed: () { // https://discord.com/channels/1111649116020285532/1149964760130002945
Navigator.of(context).pop();
if (outsideContext != null) {

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 != ""
? "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(
@@ -40,7 +40,7 @@ class AbsenceSubjectView extends StatelessWidget {
TimetablePage.jump(context, lesson: lesson);
} else {
ScaffoldMessenger.of(context).showSnackBar(CustomSnackBar(
content: Text("Cannot find lesson".i18n,
content: Text("lesson_not_found".i18n,
style: const TextStyle(color: Colors.white)),
backgroundColor: AppColors.of(context).red,
context: context,

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

@@ -17,6 +17,7 @@ extension ScreensLocalization on String {
"Subjects": "Subjects",
"attention": "Attention!",
"attention_body": "Percentage calculations are only an approximation so they may not be accurate.",
"lesson_not_found": "Cannot find lesson",
},
"hu_hu": {
"Absences": "Hiányzások",
@@ -32,6 +33,7 @@ extension ScreensLocalization on String {
"Subjects": "Tantárgyak",
"attention": "Figyelem!",
"attention_body": "A százalékos számítások csak közelítések, ezért előfordulhat, hogy nem pontosak.",
"lesson_not_found": "Nem található óra",
},
"de_de": {
"Absences": "Fehlen",
@@ -47,6 +49,7 @@ extension ScreensLocalization on String {
"Subjects": "Fächer",
"attention": "Achtung!",
"attention_body": "Prozentberechnungen sind nur eine Annäherung und können daher ungenau sein.",
"lesson_not_found": "Lektion kann nicht gefunden werden",
},
};

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

@@ -102,6 +102,8 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
firstName = "János";
}
bool customWelcome = false;
if (now.isBefore(DateTime(now.year, DateTime.august, 31)) &&
now.isAfter(DateTime(now.year, DateTime.june, 14))) {
greeting = "goodrest";
@@ -112,16 +114,16 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
Future.delayed(const Duration(seconds: 1))
.then((value) => mounted ? _confettiController?.play() : null);
}
// } else if (now.month == user.student?.birth.month &&
// now.day == user.student?.birth.day) {
// greeting = "happybirthday";
} else if (now.month == user.student?.birth.month &&
now.day == user.student?.birth.day) {
greeting = "happybirthday";
// if (NavigationScreen.of(context)?.init("confetti") ?? false) {
// _confettiController =
// ConfettiController(duration: const Duration(seconds: 3));
// Future.delayed(const Duration(seconds: 1))
// .then((value) => mounted ? _confettiController?.play() : null);
// }
if (NavigationScreen.of(context)?.init("confetti") ?? false) {
_confettiController =
ConfettiController(duration: const Duration(seconds: 3));
Future.delayed(const Duration(seconds: 1))
.then((value) => mounted ? _confettiController?.play() : null);
}
} else if (now.isAfter(DateTime(now.year, DateTime.may, 28)) &&
now.isBefore(DateTime(now.year, DateTime.may, 30))) {
greeting = "refilcopen";
@@ -144,6 +146,8 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
settings.welcomeMessage,
[firstName],
);
customWelcome = true;
} else if (now.hour >= 18) {
greeting = "goodevening";
} else if (now.hour >= 10) {
@@ -153,6 +157,8 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
} else {
greeting = "goodevening";
}
greeting = customWelcome ? greeting : greeting.i18n.fill([firstName]);
}
@override
@@ -191,7 +197,7 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
title: Padding(
padding: const EdgeInsets.only(left: 24.0),
child: Text(
greeting.i18n.fill([firstName]),
greeting,
overflow: TextOverflow.fade,
style: TextStyle(
fontWeight: FontWeight.bold,

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

@@ -17,6 +17,8 @@ List<School> searchSchools(List<School> all, String pattern) {
});
if (contains == pattern.split(" ").length) results.add(item);
if (item.instituteCode.toLowerCase().specialChars().contains(pattern)) results.add(item);
}
results.sort((a, b) => a.name.compareTo(b.name));

View File

@@ -51,6 +51,9 @@ class SubjectIconGallery extends StatelessWidget {
SubjectIconItem("Magatartás"),
SubjectIconItem("Angol nyelv"),
SubjectIconItem("Linux"),
SubjectIconItem("Adatbázis"),
SubjectIconItem("Asztali alkalmazások"),
SubjectIconItem("Projekt"),
],
),
);

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';
@@ -87,7 +88,9 @@ class _SettingsScreenState extends State<SettingsScreen>
String _firstName;
List<String> _nameParts = account.displayName.split(" ");
List<String> _nameParts =
(account.nickname != '' ? account.nickname : account.displayName)
.split(" ");
if (!settings.presentationMode) {
_firstName = _nameParts.length > 1 ? _nameParts[1] : _nameParts[0];
} else {
@@ -96,7 +99,10 @@ class _SettingsScreenState extends State<SettingsScreen>
accountTiles.add(
AccountTile(
name: Text(!settings.presentationMode ? account.name : "János",
name: Text(
!settings.presentationMode
? (account.nickname != '' ? account.nickname : account.name)
: "János",
style: const TextStyle(fontWeight: FontWeight.w500)),
username: Text(
!settings.presentationMode ? account.username : "01234567890"),
@@ -275,7 +281,7 @@ class _SettingsScreenState extends State<SettingsScreen>
child: Panel(
child: Column(
children: [
// Account list
// account list
...accountTiles,
if (accountTiles.isNotEmpty)
@@ -291,7 +297,7 @@ class _SettingsScreenState extends State<SettingsScreen>
),
),
// Account settings
// account settings
PanelButton(
onPressed: () {
Navigator.of(context)
@@ -334,7 +340,7 @@ class _SettingsScreenState extends State<SettingsScreen>
),
),
// Updates
// updates
if (updateProvider.available)
Padding(
padding: const EdgeInsets.symmetric(
@@ -372,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(
@@ -584,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),
@@ -679,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: () {
@@ -698,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),
@@ -746,7 +787,7 @@ class _SettingsScreenState extends State<SettingsScreen>
),
),
// Extras
// extra settings
Padding(
padding:
const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0),
@@ -793,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),
@@ -949,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": "Same in English.",
"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,
@@ -22,9 +22,9 @@ class GoalProvider extends ChangeNotifier {
Future<void> fetchDone({required GradeProvider gradeProvider}) async {
var goalAvgs = await _db.userQuery.subjectGoalAverages(userId: _user.id!);
var beforeAvgs = 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;
}
}
@@ -330,6 +337,7 @@ class _PremiumCustomAccentColorSettingState
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
gradient: LinearGradient(
// https://discord.com/channels/1111649116020285532/1153619667848548452
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
stops: const [
@@ -337,7 +345,8 @@ class _PremiumCustomAccentColorSettingState
0.75
],
colors: [
Theme.of(context).colorScheme.background,
settings.customBackgroundColor ??
Theme.of(context).colorScheme.background,
isBackgroundDifferent
? HSVColor.fromColor(Theme.of(context)
.colorScheme
@@ -703,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) {
@@ -753,6 +769,12 @@ class _PremiumCustomAccentColorSettingState
CustomColorMode.accent;
});
break;
case 5:
setState(() {
colorMode =
CustomColorMode.icon;
});
break;
}
},
controller: _colorsTabController,
@@ -780,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);
@@ -805,6 +833,10 @@ class _PremiumCustomAccentColorSettingState
AppColors.of(context)
.highlight,
store: true);
settings.update(
customIconColor:
const Color(0x00000000),
store: true);
} else {
updateCustomColor(c, true);
}
@@ -823,6 +855,11 @@ class _PremiumCustomAccentColorSettingState
settings.update(
gradeColors: colors);
// changing shadow effect
settings.update(
shadowEffect:
theme.shadowEffect);
// changing theme
setState(() {
updateCustomColor(
@@ -832,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",
},
};

View File

@@ -126,8 +126,14 @@ class _WelcomeMessageEditorState extends State<WelcomeMessageEditor> {
// }
var finalText = _welcomeMsg.text
.trim()
.replaceAll('%s', '')
.replaceFirst('%name%', '%s');
.replaceFirst('%name%', '\$s')
.replaceFirst('%user%', '\$s')
.replaceFirst('%username%', '\$s')
.replaceFirst('%me%', '\$s')
.replaceFirst('%profile%', '\$s')
.replaceAll('%', '')
.replaceFirst('\$s', '%s');
// .replaceAll('\$s', 's');
widget.settingsProvider
.update(welcomeMessage: finalText, store: true);

View File

@@ -1,4 +1,5 @@
import 'package:filcnaplo/helpers/subject.dart';
import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/theme/colors/colors.dart';
import 'package:filcnaplo_kreta_api/controllers/timetable_controller.dart';
import 'package:filcnaplo_mobile_ui/common/empty.dart';
@@ -9,6 +10,7 @@ import 'package:filcnaplo/utils/format.dart';
import 'dart:math' as math;
import 'package:intl/intl.dart';
import 'package:i18n_extension/i18n_widget.dart';
import 'package:provider/provider.dart';
class PremiumFSTimetable extends StatefulWidget {
const PremiumFSTimetable({Key? key, required this.controller})
@@ -21,6 +23,8 @@ class PremiumFSTimetable extends StatefulWidget {
}
class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
late SettingsProvider settings;
@override
void initState() {
super.initState();
@@ -37,6 +41,8 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
@override
Widget build(BuildContext context) {
settings = Provider.of<SettingsProvider>(context);
if (widget.controller.days == null || widget.controller.days!.isEmpty) {
return const Center(child: Empty());
}
@@ -174,7 +180,7 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
style: TextStyle(
fontStyle: lessons[lessonIndex]
.subject
.isRenamed
.isRenamed && settings.renamedSubjectsItalics
? FontStyle.italic
: null,
),

7
upgrade-pub.sh Normal file
View File

@@ -0,0 +1,7 @@
cd filcnaplo && flutter pub upgrade && cd ..
cd filcnaplo_kreta_api && flutter pub upgrade && cd ..
cd filcnaplo_mobile_ui && flutter pub upgrade && cd ..
cd filcnaplo_desktop_ui && flutter pub upgrade && cd ..
cd filcnaplo_premium && flutter pub upgrade && cd ..
echo Upgraded pub.