Compare commits
32 Commits
4.1.0-beta
...
4.1.1-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d9f99a955 | ||
|
|
2c5939fab4 | ||
|
|
95ed503e53 | ||
|
|
51e2c63134 | ||
|
|
50bc03f403 | ||
|
|
f5bc16ba42 | ||
|
|
f4501ce251 | ||
|
|
3317472773 | ||
|
|
acdd47a49a | ||
|
|
fa8be89aaf | ||
|
|
5034af2fb4 | ||
|
|
87842de421 | ||
|
|
1f46a0509f | ||
|
|
8e9713e436 | ||
|
|
fe0a7d81ae | ||
|
|
f9e14349b7 | ||
|
|
a1f087758f | ||
|
|
4068abdb95 | ||
|
|
9314c613bc | ||
|
|
458e93e19f | ||
|
|
ba8d26d250 | ||
|
|
33e3495d9f | ||
|
|
f71e72e443 | ||
|
|
c615a33bd2 | ||
|
|
7ad0ea26e2 | ||
|
|
0ad663beb3 | ||
|
|
1366984c15 | ||
|
|
62d3895373 | ||
|
|
3579c4e821 | ||
|
|
5c39865d40 | ||
|
|
551b2849fe | ||
|
|
ce1c5eb0d8 |
@@ -1,39 +1,36 @@
|
||||
|
||||
# Hozzájárulási útmutató
|
||||
# Contribution guide
|
||||
Köszönjük, ha programozással segíted a munkánkat!
|
||||
A folytatáshoz szükséged lesz egy Linuxot vagy Windowst futtató számítógépre, minimális programozási tapasztalatra és egy kis angoltudásra.
|
||||
Segít, ha nem csak kicsit tudsz programozni, és ha ismered a Gitet és a GitHubot ;)
|
||||
A folytatáshoz szükséged lesz egy Linux-ot vagy Windows-t futtató számítógépre, minimális programozási tapasztalatra és egy kis angoltudásra.
|
||||
Segít, ha már gyakorlottabb vagy a programozásban, és ha ismered a [Git](https://git-scm.com/) és a [GitHub](https://github.com/) működését. ;)
|
||||
|
||||
## Miben segítsek?
|
||||
Kérünk, **olyan dologgal járulj hozzá** a reFilchez, ami valószínűleg **sok embernek hasznos lesz** majd. Szeretnénk egy minél teljeskörűbb iskolai asszisztenst létrehozni, de az iskolaspecifikus, vagy külön neked hasznos funkciók helye inkább legyen a saját forkod.
|
||||
Kérünk, **olyan dologgal járulj hozzá** a **reFilc**hez, ami valószínűleg **sok embernek hasznos lehet**. Szeretnénk egy minél teljeskörűbb iskolai asszisztenst létrehozni, de az iskolaspecifikus, vagy külön neked hasznos funkciók helye inkább legyen a saját Fork-od.
|
||||
|
||||
Fontos, hogy **mielőtt egy nagy volumenű projektbe belekezdesz, futtasd meg ötletedet a [Discord szerverünkön](https://dc.refilc.hu/),** ahol még azelőtt tudunk tanácsot adni, mielőtt sok-sok órát beleöltél volna egy esetleg felesleges dologba.
|
||||
Fontos, hogy **mielőtt egy nagyobb méretű projektbe belekezdenél, futtasd meg ötletedet a [Discord szerverünkön](https://dc.refilc.hu/)**, ahol még azelőtt tudunk tanácsot adni, hogy sok-sok órát beleöltél volna egy esetleg felesleges dologba.
|
||||
|
||||
A legjobban annak örülünk, ha az [Issues](https://github.com/refilc/naplo/issues) oldalról szemezgetsz, **ha lehet, a [help wanted taggel megjelöltekkel kezdd](https://github.com/refilc/naplo/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22),** vagy ha új vagy a Flutterhez, ajánljuk figyelmedbe [ezeket a viszonylag könnyen javítható hibákat](https://github.com/refilc/naplo/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) (ha épp van ilyen).
|
||||
A legjobban annak örülünk, ha az [Issues](https://github.com/refilc/naplo/issues) oldalról szemezgetsz. Ha még új vagy a Flutterben, ajánljuk figyelmedbe ezeket a [viszonylag könnyen javítható hibákat](https://github.com/refilc/naplo/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22), ha éppen van ilyen.
|
||||
|
||||
## Hogyan segítsek?
|
||||
Nem ígérhetünk itt sem programozás-, sem Git-kurzust, de a projektspecifikus dolgokat leírjuk, és segítünk a Flutter telepítésében.
|
||||
|
||||
Nem ígérhetünk itt sem programozás-, sem git-kurzust, de a projektspecifikus dolgokat leírjuk, és segítünk a Flutter feltelepítésében.
|
||||
A **reFilc** a Google által pár éve létrehozott **[Flutter](https://flutter.dev/)** keretrendszert használja, aminek nyelve a **[Dart](https://dart.dev/)**. Ha ismered a C#, Java, C++, vagy egyéb hasonló programnyelvek működését, **nem fog nagy gondot okozni a használata.** A felhasználói felület létrehozásában az is segíthet, ha foglalkoztál már korábban weboldalakkal vagy alkalmazásfejlesztéssel.
|
||||
Ha még nem használtad a Flutter-t, mindenképp böngészd át a [YouTube csatornájukat](https://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw).
|
||||
Kód vagy UI teszteléséhez Flutter telepítése nélkül is használhatod a [DartPad](https://dartpad.dev/)-et.
|
||||
|
||||
A reFilc a Google által pár éve létrehozott **[Fluttert](https://flutter.dev/)** használja, aminek nyelve a **[Dart](https://dart.dev/)**. Ha ismered a C#-ot, Javát, C++t, vagy egyéb hasonló nyelvet, **nem fog gondot okozni a használata.** A felhasználói felület létrehozásában az is segíthet, ha foglalkoztál már korábban weboldalakkal.
|
||||
Ha még nem használtál Fluttert, mindenképp böngészd át a [YouTube csatornájukat](https://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw).
|
||||
Könnyen tudsz kódot, vagy akár UI-t is tesztelni a [DartPad](https://dartpad.dev/) oldalon.
|
||||
#### [Segítség a Flutter telepítéséhez](https://docs.flutter.dev/get-started/install)
|
||||
**Használd a Flutter stable verzióját!** Írd be a terminálba: `flutter channel stable`
|
||||
|
||||
#### [Segítség a Flutter telepítéséhez és a forráskód futtatásához](https://docs.flutter.dev/get-started/install)
|
||||
Fontos: **Legyél a flutter beta verzióján!** Írd be: `flutter channel beta`
|
||||
Ha nem értessz a Git-hez vagy a GitHub-hoz, ajánljuk figyelmedbe [ezt a cikket](https://medium.com/envienta-magyarorsz%C3%A1g/git-%C3%A9s-github-gyorstalpal%C3%B3-f2d78a732deb), viszont arra kérünk, hogy a használatukat ne a **reFilc**en próbáld ki először. Hozz létre egy saját Repo-t és abban tesztelgess. Ha már nagyjából kitapasztaltad, várjuk hozzájárulásodat.
|
||||
|
||||
|
||||
|
||||
Ha nem értesz a Githez, ajánljuk figyelmedbe [ezt a cikket](https://medium.com/envienta-magyarorsz%C3%A1g/git-%C3%A9s-github-gyorstalpal%C3%B3-f2d78a732deb). Viszont arra kérünk, a Git használatát ne a reFilcen próbáld ki először, hozz létre előbb egy saját Repót, és abba tesztelgess. Ha már nagyjából kitapasztaltad, várjuk hozzájárulásodat.
|
||||
|
||||
Készíts egy forkot a saját fiókod alá.
|
||||
A reFilc legfrissebb, épp fejlesztés alatt álló verzióját a [master branch](https://github.com/refilc/naplo/tree/master)-en találod, kérjük ide commitolj, és ide célozd a forkodból a Pull Requested. Írd le benne, mit változtattál, és ha lehet, csatolj képernyőképet is.
|
||||
Minél gyakrabban készíts minél részletesebben elnevezett commitokat, hogy el tudjunk tájékozódni az általad beküldött kódon.
|
||||
Készíts egy Fork-ot a saját GitHub fiókod alá.
|
||||
A **reFilc** legfrissebb, **épp fejlesztés alatt álló verzióját a [master branch](https://github.com/refilc/naplo/tree/master)-en találod**. Kérjük ide Commit-olj és ide célozd a Fork-odból a Pull Request-edet. Írd le benne, hogy mit változtattál és ha lehet, csatolj képernyőképet is.
|
||||
Minél gyakrabban készíts minél részletesebben elnevezett Commit-okat, hogy mások is el tudjanak igazodni az általad beküldött kódban.
|
||||
|
||||
---
|
||||
|
||||
Az általad fejlesztett funkciók mellé a changelogban odakerül GitHub felhasználóneved.
|
||||
Ha jelentős és rendszeres hozzájáruló vagy, Discordon megkapod a `DEV` rangot.
|
||||
Az általad fejlesztett funkciók mellé a Changelog-ba odakerül a GitHub felhasználóneved.
|
||||
Ha jelentős és rendszeres hozzájáruló vagy, Discord-on megkaphatod a `DEV` rangot.
|
||||
|
||||
Ha bárhol elakadtál, keress minket Discordon.
|
||||
Jó fejlesztést kívánunk!
|
||||
Ha bárhol elakadtál vagy kérdésed van, keress bátran Discordon!
|
||||
**Jó fejlesztést kívánunk!**
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#### Nem hivatalos e-napló alkalmazás az eKRÉTA rendszerhez - tanulóktól, tanulóknak.
|
||||
|
||||
[](https://github.com/refilc/naplo/releases) [](http://dc.refilc.hu)
|
||||
[](https://github.com/refilc/naplo/releases) [](https://dc.refilc.hu)
|
||||
|
||||
## Setup
|
||||
|
||||
@@ -29,11 +29,13 @@ flutter run
|
||||
|
||||
### Contribution
|
||||
|
||||
**Nézd meg a [Contribution guide](CONTRIBUTING.md)-ot!**
|
||||
|
||||
Az összes (ugyan azon verzióhoz tartozó) contribution meg fog jelenni a release-nél. Kérjük, írd le a Discord nevedet a Description-be, hogy adhassunk rangot.
|
||||
|
||||
-------
|
||||
|
||||
# Kudo
|
||||
# Developers
|
||||
|
||||
**annon:** a Filc napló készítője (ez az app a Filcen alapul)
|
||||
|
||||
|
||||
BIN
filcnaplo/assets/images/card_border.png
Normal file
BIN
filcnaplo/assets/images/card_border.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
15
filcnaplo/ios/Flutter/Generated 3.xcconfig
Normal file
15
filcnaplo/ios/Flutter/Generated 3.xcconfig
Normal file
@@ -0,0 +1,15 @@
|
||||
// This is a generated file; do not edit or check into version control.
|
||||
FLUTTER_ROOT=/Users/kima/development/flutter
|
||||
FLUTTER_APPLICATION_PATH=/Users/kima/Documents/refilc/app/naplo/filcnaplo
|
||||
COCOAPODS_PARALLEL_CODE_SIGN=true
|
||||
FLUTTER_TARGET=/Users/kima/Documents/refilc/app/naplo/filcnaplo/lib/main.dart
|
||||
FLUTTER_BUILD_DIR=build
|
||||
FLUTTER_BUILD_NAME=4.1.0
|
||||
FLUTTER_BUILD_NUMBER=213
|
||||
EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386
|
||||
EXCLUDED_ARCHS[sdk=iphoneos*]=armv7
|
||||
DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==,RkxVVFRFUl9XRUJfQ0FOVkFTS0lUX1VSTD1odHRwczovL3d3dy5nc3RhdGljLmNvbS9mbHV0dGVyLWNhbnZhc2tpdC8yYTM0MDFjOWJiYjVhOWE5YWVjNzRkNGY3MzVkMThhOWRkM2ViZjJkLw==
|
||||
DART_OBFUSCATION=false
|
||||
TRACK_WIDGET_CREATION=true
|
||||
TREE_SHAKE_ICONS=false
|
||||
PACKAGE_CONFIG=/Users/kima/Documents/refilc/app/naplo/filcnaplo/.dart_tool/package_config.json
|
||||
14
filcnaplo/ios/Flutter/flutter_export_environment 2.sh
Executable file
14
filcnaplo/ios/Flutter/flutter_export_environment 2.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
# This is a generated file; do not edit or check into version control.
|
||||
export "FLUTTER_ROOT=/Users/kima/development/flutter"
|
||||
export "FLUTTER_APPLICATION_PATH=/Users/kima/Documents/refilc/app/naplo/filcnaplo"
|
||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||
export "FLUTTER_TARGET=/Users/kima/Documents/refilc/app/naplo/filcnaplo/lib/main.dart"
|
||||
export "FLUTTER_BUILD_DIR=build"
|
||||
export "FLUTTER_BUILD_NAME=4.1.0"
|
||||
export "FLUTTER_BUILD_NUMBER=213"
|
||||
export "DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==,RkxVVFRFUl9XRUJfQ0FOVkFTS0lUX1VSTD1odHRwczovL3d3dy5nc3RhdGljLmNvbS9mbHV0dGVyLWNhbnZhc2tpdC8yYTM0MDFjOWJiYjVhOWE5YWVjNzRkNGY3MzVkMThhOWRkM2ViZjJkLw=="
|
||||
export "DART_OBFUSCATION=false"
|
||||
export "TRACK_WIDGET_CREATION=true"
|
||||
export "TREE_SHAKE_ICONS=false"
|
||||
export "PACKAGE_CONFIG=/Users/kima/Documents/refilc/app/naplo/filcnaplo/.dart_tool/package_config.json"
|
||||
@@ -488,7 +488,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.6.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -526,7 +526,7 @@
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo.livecardpro;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo.livecardpro;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
@@ -567,7 +567,7 @@
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo.livecardpro;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo.livecardpro;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
@@ -607,7 +607,7 @@
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo.livecardpro;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo.livecardpro;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
@@ -746,7 +746,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.6.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
@@ -774,7 +774,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.6.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.refilcnaplo.livecard</string>
|
||||
|
||||
@@ -7,7 +7,5 @@
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.widgetkit-extension</string>
|
||||
</dict>
|
||||
<key>NSSupportsLiveActivities</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -49,10 +49,16 @@ Future loginApi({
|
||||
}) async {
|
||||
Provider.of<KretaClient>(context, listen: false).userAgent =
|
||||
Provider.of<SettingsProvider>(context, listen: false).config.userAgent;
|
||||
|
||||
|
||||
Map<String, String> headers = {
|
||||
"content-type": "application/x-www-form-urlencoded",
|
||||
};
|
||||
|
||||
String nonceStr = await Provider.of<KretaClient>(context, listen: false)
|
||||
.getAPI(KretaAPI.nonce, json: false);
|
||||
|
||||
Nonce nonce = getNonce(nonceStr, username, instituteCode);
|
||||
headers.addAll(nonce.header());
|
||||
|
||||
Map? res = await Provider.of<KretaClient>(context, listen: false)
|
||||
.postAPI(KretaAPI.login,
|
||||
|
||||
@@ -40,6 +40,8 @@ class LiveCardProvider extends ChangeNotifier {
|
||||
String? _latestActivityId;
|
||||
Map<String, String> _lastActivity = {};
|
||||
|
||||
bool _hasCheckedTimetable = false;
|
||||
|
||||
LiveCardProvider({
|
||||
required TimetableProvider timetable,
|
||||
required SettingsProvider settings,
|
||||
@@ -198,7 +200,8 @@ class LiveCardProvider extends ChangeNotifier {
|
||||
|
||||
List<Lesson> today = _today(_timetable);
|
||||
|
||||
if (today.isEmpty) {
|
||||
if (today.isEmpty && !_hasCheckedTimetable) {
|
||||
_hasCheckedTimetable = true;
|
||||
await _timetable.fetch(week: Week.current());
|
||||
today = _today(_timetable);
|
||||
}
|
||||
@@ -252,7 +255,10 @@ class LiveCardProvider extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
if (currentLesson != null) {
|
||||
if (now.isBefore(DateTime(now.year, DateTime.august, 31)) &&
|
||||
now.isAfter(DateTime(now.year, DateTime.june, 14))) {
|
||||
currentState = LiveCardState.summary;
|
||||
} else if (currentLesson != null) {
|
||||
currentState = LiveCardState.duringLesson;
|
||||
} else if (nextLesson != null && prevLesson != null) {
|
||||
currentState = LiveCardState.duringBreak;
|
||||
|
||||
21
filcnaplo/lib/models/personality.dart
Normal file
21
filcnaplo/lib/models/personality.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
class Personality {
|
||||
PersonalityType type;
|
||||
|
||||
Personality({
|
||||
this.type = PersonalityType.npc,
|
||||
});
|
||||
}
|
||||
|
||||
enum PersonalityType {
|
||||
geek,
|
||||
sick,
|
||||
late,
|
||||
quitter,
|
||||
healthy,
|
||||
acceptable,
|
||||
fallible,
|
||||
average,
|
||||
diligent,
|
||||
cheater,
|
||||
npc
|
||||
}
|
||||
@@ -194,7 +194,7 @@ class SettingsProvider extends ChangeNotifier {
|
||||
premiumLogin: map["premium_login"],
|
||||
lastAccountId: map["last_account_id"],
|
||||
renameSubjectsEnabled: map["renamed_subjects_enabled"] == 1,
|
||||
renameSubjectsItalics: map["renamed_subjects_italics"] == 0,
|
||||
renameSubjectsItalics: map["renamed_subjects_italics"] == 1,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.1.0+213
|
||||
version: 4.1.1+215
|
||||
|
||||
environment:
|
||||
sdk: ">=2.17.0 <3.0.0"
|
||||
@@ -65,6 +65,7 @@ dependencies:
|
||||
background_fetch: ^1.1.5
|
||||
flutter_local_notifications: ^14.1.0
|
||||
package_info_plus: ^4.0.2
|
||||
screenshot: ^2.1.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_lints: ^2.0.1
|
||||
|
||||
@@ -23,7 +23,6 @@ class Empty extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// make the face randomness a bit more constant (to avoid strokes)
|
||||
int index = Random(DateTime.now().minute).nextInt(faces.length);
|
||||
|
||||
return Center(
|
||||
@@ -32,9 +31,19 @@ class Empty extends StatelessWidget {
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
text: faces[index],
|
||||
style: TextStyle(fontSize: 32.0, fontWeight: FontWeight.w500, color: AppColors.of(context).text.withOpacity(.75)),
|
||||
style: TextStyle(
|
||||
fontSize: 32.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.of(context).text.withOpacity(.75)),
|
||||
children: subtitle != null
|
||||
? [TextSpan(text: "\n" + subtitle!, style: TextStyle(fontSize: 18.0, height: 2.0, color: AppColors.of(context).text.withOpacity(.5)))]
|
||||
? [
|
||||
TextSpan(
|
||||
text: "\n" + subtitle!,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
height: 2.0,
|
||||
color: AppColors.of(context).text.withOpacity(.5)))
|
||||
]
|
||||
: [],
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import 'package:dotted_border/dotted_border.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class EmptyCard extends StatefulWidget {
|
||||
const EmptyCard({
|
||||
Key? key,
|
||||
required this.text,
|
||||
}) : super(key: key);
|
||||
|
||||
final String text;
|
||||
|
||||
@override
|
||||
State<EmptyCard> createState() => _EmptyCardState();
|
||||
}
|
||||
|
||||
class _EmptyCardState extends State<EmptyCard> {
|
||||
bool hold = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onLongPressDown: (_) => setState(() => hold = true),
|
||||
onLongPressEnd: (_) => setState(() => hold = false),
|
||||
onLongPressCancel: () => setState(() => hold = false),
|
||||
child: AnimatedScale(
|
||||
scale: hold ? 1.018 : 1.0,
|
||||
curve: Curves.easeInOutBack,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: Container(
|
||||
height: 444,
|
||||
padding:
|
||||
const EdgeInsets.only(top: 12, bottom: 12, left: 12, right: 12),
|
||||
decoration: BoxDecoration(
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: DottedBorder(
|
||||
color: Colors.black.withOpacity(0.9),
|
||||
dashPattern: const [12, 12],
|
||||
padding:
|
||||
const EdgeInsets.only(top: 20, bottom: 20, left: 20, right: 20),
|
||||
child: Center(
|
||||
child: Text(
|
||||
widget.text,
|
||||
style: TextStyle(
|
||||
color: Colors.white.withOpacity(0.9),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,374 @@
|
||||
import 'package:dotted_border/dotted_border.dart';
|
||||
import 'package:filcnaplo/api/providers/user_provider.dart';
|
||||
import 'package:filcnaplo/helpers/average_helper.dart';
|
||||
import 'package:filcnaplo/models/settings.dart';
|
||||
import 'package:filcnaplo/models/personality.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/absence.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/grade.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/lesson.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/subject.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/week.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'personality_card.i18n.dart';
|
||||
|
||||
class PersonalityCard extends StatefulWidget {
|
||||
const PersonalityCard({
|
||||
Key? key,
|
||||
required this.user,
|
||||
}) : super(key: key);
|
||||
|
||||
final UserProvider user;
|
||||
|
||||
@override
|
||||
State<PersonalityCard> createState() => _PersonalityCardState();
|
||||
}
|
||||
|
||||
class _PersonalityCardState extends State<PersonalityCard> {
|
||||
late GradeProvider gradeProvider;
|
||||
late AbsenceProvider absenceProvider;
|
||||
late TimetableProvider timetableProvider;
|
||||
late SettingsProvider settings;
|
||||
|
||||
late List<int> subjectAvgsList = [];
|
||||
late Map<Subject, double> subjectAvgs = {};
|
||||
late double subjectAvg;
|
||||
late List<Grade> classWorkGrades;
|
||||
late Map<int, int> mostCommonGrade;
|
||||
late List<Absence> absences = [];
|
||||
final Map<Subject, Lesson> _lessonCount = {};
|
||||
late int totalDelays;
|
||||
late int unexcusedAbsences;
|
||||
|
||||
late PersonalityType finalPersonality;
|
||||
|
||||
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();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
gradeProvider = Provider.of<GradeProvider>(context, listen: false);
|
||||
absenceProvider = Provider.of<AbsenceProvider>(context, listen: false);
|
||||
timetableProvider = Provider.of<TimetableProvider>(context, listen: false);
|
||||
settings = Provider.of<SettingsProvider>(context, listen: false);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
for (final lesson in timetableProvider.getWeek(Week.current()) ?? []) {
|
||||
if (!lesson.isEmpty &&
|
||||
lesson.subject.id != '' &&
|
||||
lesson.lessonYearIndex != null) {
|
||||
_lessonCount.update(
|
||||
lesson.subject,
|
||||
(value) {
|
||||
if (lesson.lessonYearIndex! > value.lessonYearIndex!) {
|
||||
return lesson;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
ifAbsent: () => lesson,
|
||||
);
|
||||
}
|
||||
}
|
||||
setState(() {});
|
||||
});
|
||||
}
|
||||
|
||||
void getGrades() {
|
||||
List<Subject> subjects = gradeProvider.grades
|
||||
.map((e) => e.subject)
|
||||
.toSet()
|
||||
.toList()
|
||||
..sort((a, b) => a.name.compareTo(b.name));
|
||||
|
||||
for (Subject subject in subjects) {
|
||||
List<Grade> subjectGrades = getSubjectGrades(subject);
|
||||
|
||||
double avg = AverageHelper.averageEvals(subjectGrades);
|
||||
if (avg != 0) subjectAvgs[subject] = avg;
|
||||
|
||||
subjectAvgsList.add(avg.round());
|
||||
}
|
||||
|
||||
subjectAvg = subjectAvgs.isNotEmpty
|
||||
? subjectAvgs.values.fold(0.0, (double a, double b) => a + b) /
|
||||
subjectAvgs.length
|
||||
: 0.0;
|
||||
|
||||
classWorkGrades =
|
||||
gradeProvider.grades.where((a) => a.value.weight <= 75).toList();
|
||||
}
|
||||
|
||||
void getMostCommonGrade() {
|
||||
Map<int, int> counts = {};
|
||||
|
||||
subjectAvgsList.map((e) {
|
||||
if (counts.containsKey(e)) {
|
||||
counts.update(e, (value) => value++);
|
||||
} else {
|
||||
counts[e] = 1;
|
||||
}
|
||||
});
|
||||
|
||||
var maxValue = 0;
|
||||
var maxKey = 0;
|
||||
|
||||
counts.forEach((k, v) {
|
||||
if (v > maxValue) {
|
||||
maxValue = v;
|
||||
maxKey = k;
|
||||
}
|
||||
});
|
||||
|
||||
mostCommonGrade = {maxKey: maxValue};
|
||||
}
|
||||
|
||||
void getAbsences() {
|
||||
absences = absenceProvider.absences.where((a) => a.delay == 0).toList();
|
||||
|
||||
unexcusedAbsences = absences
|
||||
.where((a) => a.state == Justification.unexcused && a.delay == 0)
|
||||
.length;
|
||||
}
|
||||
|
||||
void getAndSortDelays() {
|
||||
Iterable<int> unexcusedDelays = absences
|
||||
.where((a) => a.state == Justification.unexcused && a.delay > 0)
|
||||
.map((e) => e.delay);
|
||||
totalDelays = unexcusedDelays.isNotEmpty
|
||||
? unexcusedDelays.reduce((a, b) => a + b)
|
||||
: 0;
|
||||
}
|
||||
|
||||
void doEverything() {
|
||||
getGrades();
|
||||
getMostCommonGrade();
|
||||
getAbsences();
|
||||
getAndSortDelays();
|
||||
}
|
||||
|
||||
void getPersonality() {
|
||||
if (settings.goodStudent) {
|
||||
finalPersonality = PersonalityType.cheater;
|
||||
} else if (subjectAvg > 4.7) {
|
||||
finalPersonality = PersonalityType.geek;
|
||||
} else if (mostCommonGrade.keys.toList()[0] == 1 &&
|
||||
mostCommonGrade.values.toList()[0] > 1) {
|
||||
finalPersonality = PersonalityType.fallible;
|
||||
} else if (absences.length < 10) {
|
||||
finalPersonality = PersonalityType.healthy;
|
||||
} else if (unexcusedAbsences >= 10) {
|
||||
finalPersonality = PersonalityType.quitter;
|
||||
} else if (totalDelays > 50) {
|
||||
finalPersonality = PersonalityType.late;
|
||||
} else if (absences.length >= 100) {
|
||||
finalPersonality = PersonalityType.sick;
|
||||
} else if (mostCommonGrade.keys.toList()[0] == 2) {
|
||||
finalPersonality = PersonalityType.acceptable;
|
||||
} else if (mostCommonGrade.keys.toList()[0] == 3) {
|
||||
finalPersonality = PersonalityType.average;
|
||||
} else if (classWorkGrades.length >= 5) {
|
||||
finalPersonality = PersonalityType.diligent;
|
||||
} else {
|
||||
finalPersonality = PersonalityType.npc;
|
||||
}
|
||||
}
|
||||
|
||||
Widget cardInnerBuilder() {
|
||||
Map<PersonalityType, Map<String, String>> personality = {
|
||||
PersonalityType.geek: {
|
||||
'emoji': '🤓',
|
||||
'title': 't_geek',
|
||||
'description': 'd_geek',
|
||||
'subtitle': 's_geek',
|
||||
'subvalue': subjectAvg.toStringAsFixed(2),
|
||||
},
|
||||
PersonalityType.sick: {
|
||||
'emoji': '🤒',
|
||||
'title': 't_sick',
|
||||
'description': 'd_sick',
|
||||
'subtitle': 's_sick',
|
||||
'subvalue': absences.length.toString(),
|
||||
},
|
||||
PersonalityType.late: {
|
||||
'emoji': '⌛',
|
||||
'title': 't_late',
|
||||
'description': 'd_late',
|
||||
'subtitle': 's_late',
|
||||
'subvalue': totalDelays.toString(),
|
||||
},
|
||||
PersonalityType.quitter: {
|
||||
'emoji': '❓',
|
||||
'title': 't_quitter',
|
||||
'description': 'd_quitter',
|
||||
'subtitle': 's_quitter',
|
||||
'subvalue': unexcusedAbsences.toString(),
|
||||
},
|
||||
PersonalityType.healthy: {
|
||||
'emoji': '😷',
|
||||
'title': 't_healthy',
|
||||
'description': 'd_healthy',
|
||||
'subtitle': 's_healthy',
|
||||
'subvalue': absences.length.toString(),
|
||||
},
|
||||
PersonalityType.acceptable: {
|
||||
'emoji': '🤏',
|
||||
'title': 't_acceptable',
|
||||
'description': 'd_acceptable',
|
||||
'subtitle': 's_acceptable',
|
||||
'subvalue': mostCommonGrade.values.toList()[0].toString(),
|
||||
},
|
||||
PersonalityType.fallible: {
|
||||
'emoji': '📉',
|
||||
'title': 't_fallible',
|
||||
'description': 'd_fallible',
|
||||
'subtitle': 's_fallible',
|
||||
'subvalue': mostCommonGrade.values.toList()[0].toString(),
|
||||
},
|
||||
PersonalityType.average: {
|
||||
'emoji': '👌',
|
||||
'title': 't_average',
|
||||
'description': 'd_average',
|
||||
'subtitle': 's_average',
|
||||
'subvalue': mostCommonGrade.values.toList()[0].toString(),
|
||||
},
|
||||
PersonalityType.diligent: {
|
||||
'emoji': '💫',
|
||||
'title': 't_diligent',
|
||||
'description': 'd_diligent',
|
||||
'subtitle': 's_diligent',
|
||||
'subvalue': classWorkGrades.length.toString(),
|
||||
},
|
||||
PersonalityType.cheater: {
|
||||
'emoji': '🧑💻',
|
||||
'title': 't_cheater',
|
||||
'description': 'd_cheater',
|
||||
'subtitle': 's_cheater',
|
||||
'subvalue': '0',
|
||||
},
|
||||
PersonalityType.npc: {
|
||||
'emoji': '⛰️',
|
||||
'title': 't_npc',
|
||||
'description': 'd_npc',
|
||||
'subtitle': 's_npc',
|
||||
'subvalue': '69420',
|
||||
}
|
||||
};
|
||||
|
||||
Map<PersonalityType, Widget> personalityWidgets = {};
|
||||
|
||||
for (var i in personality.keys) {
|
||||
Widget w = Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
personality[i]?['emoji'] ?? '❓',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 128.0,
|
||||
height: 1.2,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
(personality[i]?['title'] ?? 'unknown').i18n,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 38.0,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Text(
|
||||
(personality[i]?['description'] ?? 'unknown_personality').i18n,
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
height: 1.2,
|
||||
color: Colors.white.withOpacity(0.8),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
Text(
|
||||
(personality[i]?['subtitle'] ?? 'unknown').i18n,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 20.0,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
personality[i]?['subvalue'] ?? '0',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 69.0,
|
||||
height: 1.15,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
personalityWidgets.addAll({i: w});
|
||||
}
|
||||
|
||||
return personalityWidgets[finalPersonality] ?? Container();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
doEverything();
|
||||
getPersonality();
|
||||
|
||||
return GestureDetector(
|
||||
onLongPressDown: (_) => setState(() => hold = true),
|
||||
onLongPressEnd: (_) => setState(() => hold = false),
|
||||
onLongPressCancel: () => setState(() => hold = false),
|
||||
child: AnimatedScale(
|
||||
scale: hold ? 1.018 : 1.0,
|
||||
curve: Curves.easeInOutBack,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: Container(
|
||||
padding:
|
||||
const EdgeInsets.only(top: 12, bottom: 12, left: 12, right: 12),
|
||||
decoration: BoxDecoration(
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: DottedBorder(
|
||||
color: Colors.black.withOpacity(0.9),
|
||||
dashPattern: const [12, 12],
|
||||
padding:
|
||||
const EdgeInsets.only(top: 20, bottom: 20, left: 20, right: 20),
|
||||
child: cardInnerBuilder(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
import 'package:i18n_extension/i18n_extension.dart';
|
||||
|
||||
extension Localization on String {
|
||||
static final _t = Translations.byLocale("hu_hu") +
|
||||
{
|
||||
"en_en": {
|
||||
// main
|
||||
"unknown": "???",
|
||||
"unknown_personality": "Unknown personality...",
|
||||
// personalities
|
||||
"t_geek": "Know-It-All",
|
||||
"d_geek":
|
||||
"You learn a lot, but don't worry - Being a know-it-all is a blessing in disguise. You'll be successful in life.",
|
||||
"s_geek": "Year-end average",
|
||||
"t_sick": "Sick",
|
||||
"d_sick":
|
||||
"Get well soon, bro. Even if you lied about being sick to skip school.",
|
||||
"s_sick": "Absences",
|
||||
"t_late": "Late",
|
||||
"d_late":
|
||||
"The tram's wheel got punctured. The airplane was derailed. Your dog ate your shoe. We believe you.",
|
||||
"s_late": "Delays (minutes)",
|
||||
"t_quitter": "Skipper",
|
||||
"d_quitter": "Supplementary exam incoming.",
|
||||
"s_quitter": "Igazolatlan hiányzások",
|
||||
"t_healthy": "Healthy",
|
||||
"d_healthy":
|
||||
"As cool as a cucumber! You almost never missed a class.",
|
||||
"s_healthy": "Absences",
|
||||
"t_acceptable": "Acceptable",
|
||||
"d_acceptable":
|
||||
"Final exams are D. But who cares? It's still a grade. Not a good one, but it's definitely a grade.",
|
||||
"s_acceptable": "D's",
|
||||
"t_fallible": "Failed",
|
||||
"d_fallible": "Good luck next year.",
|
||||
"s_fallible": "F's",
|
||||
"t_average": "It's okay",
|
||||
"d_average": "Not good, not bad. The golden mean, if you will...",
|
||||
"s_average": "C's",
|
||||
"t_diligent": "Hard-worker",
|
||||
"d_diligent":
|
||||
"You noted everything, you made that presentation, and you lead the group project.",
|
||||
"s_diligent": "Class work A's",
|
||||
"t_cheater": "Cheater",
|
||||
"d_cheater":
|
||||
"You enabled the \"Good Student\" mode. Wow. You may have outsmarted me, but I have outsmarted your outsmarting.",
|
||||
"s_cheater": "Bitches",
|
||||
"t_npc": "NPC",
|
||||
"d_npc":
|
||||
"You're such a non-player character, we couldn't give you a personality.",
|
||||
"s_npc": "In-game playtime (hours)",
|
||||
},
|
||||
"hu_hu": {
|
||||
// main
|
||||
"unknown": "???",
|
||||
"unknown_personality": "Ismeretlen személyiség...",
|
||||
// personalities
|
||||
"t_geek": "Stréber",
|
||||
"d_geek":
|
||||
"Sokat tanulsz, de ezzel semmi baj! Ez egyben áldás és átok, de legalább az életben sikeres leszel.",
|
||||
"s_geek": "Év végi átlagod",
|
||||
"t_sick": "Beteges",
|
||||
"d_sick":
|
||||
"Jobbulást, tesó. Még akkor is, ha hazudtál arról, hogy beteg vagy, hogy ne kelljen suliba menned.",
|
||||
"s_sick": "Hiányzásaid",
|
||||
"t_late": "Késős",
|
||||
"d_late":
|
||||
"Kilyukadt a villamos kereke. Kisiklott a repülő. A kutyád megette a cipőd. Elhisszük.",
|
||||
"s_late": "Késések (perc)",
|
||||
"t_quitter": "Lógós",
|
||||
"d_quitter": "Osztályzóvizsga incoming.",
|
||||
"s_quitter": "Igazolatlan hiányzások",
|
||||
"t_healthy": "Makk",
|
||||
"d_healthy":
|
||||
"...egészséges vagy! Egész évben alig hiányoztál az iskolából.",
|
||||
"s_healthy": "Hiányzásaid",
|
||||
"t_acceptable": "Elmegy",
|
||||
"d_acceptable":
|
||||
"A kettes érettségi is érettségi. Nem egy jó érettségi, de biztos, hogy egy érettségi.",
|
||||
"s_acceptable": "Kettesek",
|
||||
"t_fallible": "Bukós",
|
||||
"d_fallible": "Jövőre több sikerrel jársz.",
|
||||
"s_fallible": "Karók",
|
||||
"t_average": "Közepes",
|
||||
"d_average": "Se jó, se rossz. Az arany középút, ha akarsz...",
|
||||
"s_average": "Hármasok",
|
||||
"t_diligent": "Szorgalmas",
|
||||
"d_diligent":
|
||||
"Leírtad a jegyzetet, megcsináltad a prezentációt, és te vezetted a projektmunkát.",
|
||||
"s_diligent": "Órai munka ötösök",
|
||||
"t_cheater": "Csaló",
|
||||
"d_cheater":
|
||||
"Bekapcsoltad a “Jó Tanuló” módot. Wow. Azt hitted, túl járhatsz az eszemen, de kijátszottam a kijátszásod.",
|
||||
"s_cheater": "Bitches",
|
||||
"t_npc": "NPC",
|
||||
"d_npc":
|
||||
"Egy akkora nagy non-player character vagy, hogy neked semmilyen személyiség nem jutott ezen kívül.",
|
||||
"s_npc": "In-game playtime (óra)",
|
||||
},
|
||||
"de_de": {
|
||||
// main
|
||||
"unknown": "???",
|
||||
"unknown_personality": "Unbekannte Persönlichkeit...",
|
||||
// personalities
|
||||
"t_geek": "Besserwisser",
|
||||
"d_geek":
|
||||
"Du lernst eine Menge, aber sorge dich nicht - ein Besserwisser zu sein wird sich letzten Endes doch als Segen erweisen. Du wirst erfolgreich sein im Leben.",
|
||||
"s_geek": "Durchschnittsschüler",
|
||||
"t_sick": "Krank",
|
||||
"d_sick":
|
||||
"Werd schnell wieder gesund, Brudi. Selbst wenn du gelogen hast, nur um Schule zu schwänzen zu können.",
|
||||
"s_sick": "Abwesenheiten",
|
||||
"t_late": "Verspätet",
|
||||
"d_late":
|
||||
"Die Straßenbahn hat eine Reifenpanne. Das Flugzeug ist entgleist. Dein Hund hat deinen Schuh gefressen. Klar, wir glauben dir.",
|
||||
"s_late": "Verspätung (Minuten)",
|
||||
"t_quitter": "Schulschwänzer",
|
||||
"d_quitter": "Ein zusätzlicher Test wird anstehen.",
|
||||
"s_quitter": "Unentschuldigte Abwesenheiten",
|
||||
"t_healthy": "Gesund",
|
||||
"d_healthy":
|
||||
"Du bist die Ruhe selbst! Du hast fast nie eine Unterrichtsstunde verpasst.",
|
||||
"s_healthy": "Abwesenheiten",
|
||||
"t_acceptable": "Akzeptabel",
|
||||
"d_acceptable":
|
||||
"Die Abschlussprüfungen waren gerade einmal eine 4. Aber wen juckt's? Es ist immer noch positiv. Nicht allzu gut, aber definitiv positiv.",
|
||||
"s_acceptable": "4er",
|
||||
"t_fallible": "Durchgefallen",
|
||||
"d_fallible": "Viel Glück im nächsten Jahr.",
|
||||
"s_fallible": "5er",
|
||||
"t_average": "Es ist in Ordnung",
|
||||
"d_average":
|
||||
"Nicht gut, nicht schlecht. Der goldene Durchschnitt, wenn du so willst...",
|
||||
"s_average": "3er",
|
||||
"t_diligent": "Ein Fleißiger",
|
||||
"d_diligent":
|
||||
"Du hast bei allem mitgeschrieben, du hast den Vortrag gehalten, und du hast die Gruppenarbeit geleitet.",
|
||||
"s_diligent": "1er Schüler",
|
||||
"t_cheater": "Geschummelt",
|
||||
"d_cheater":
|
||||
"Du hast den „Guter Schüler“ Modus aktiviert. Wow. Du magst mich zwar vielleicht überlistet haben, aber ich habe deine Überlistung überlistet.",
|
||||
"s_cheater": "Bitches",
|
||||
"t_npc": "COM",
|
||||
"d_npc":
|
||||
"Du bist einfach so sehr wie ein Computer, dass wir dir nicht einmal eine Persönlichkeit geben konnten.",
|
||||
"s_npc": "Spielzeit (Stunden)",
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -56,16 +56,43 @@ class _LiveCardState extends State<LiveCard> {
|
||||
case LiveCardState.summary:
|
||||
child = LiveCardWidget(
|
||||
key: const Key('livecard.summary'),
|
||||
title: '',
|
||||
title: 'Vége a tanévnek! 🥳',
|
||||
icon: FeatherIcons.arrowRight,
|
||||
description: const Text(''),
|
||||
onTap: () => Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) => const SummaryScreen(
|
||||
currentPage: 'grades',
|
||||
),
|
||||
description: Text(
|
||||
'Irány az összefoglaláshoz',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 18.0,
|
||||
color: Theme.of(context).textTheme.bodyMedium?.color,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
// showSlidingBottomSheet(
|
||||
// context,
|
||||
// useRootNavigator: true,
|
||||
// builder: (context) => SlidingSheetDialog(
|
||||
// color: Colors.black.withOpacity(0.99),
|
||||
// duration: const Duration(milliseconds: 400),
|
||||
// scrollSpec: const ScrollSpec.bouncingScroll(),
|
||||
// snapSpec: const SnapSpec(
|
||||
// snap: true,
|
||||
// snappings: [1.0],
|
||||
// initialSnap: 1.0,
|
||||
// positioning: SnapPositioning.relativeToAvailableSpace,
|
||||
// ),
|
||||
// minHeight: MediaQuery.of(context).size.height,
|
||||
// cornerRadius: 16,
|
||||
// cornerRadiusOnFullscreen: 0,
|
||||
// builder: (context, state) => const Material(
|
||||
// color: Colors.black,
|
||||
// child: SummaryScreen(
|
||||
// currentPage: 'start',
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
SummaryScreen.show(context: context, currentPage: 'start');
|
||||
},
|
||||
);
|
||||
break;
|
||||
case LiveCardState.morning:
|
||||
|
||||
@@ -81,22 +81,35 @@ class _LiveCardWidgetState extends State<LiveCardWidget> {
|
||||
child: widget.isEvent
|
||||
? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
widget.title ?? 'Esemény',
|
||||
style: TextStyle(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 24.0,
|
||||
color:
|
||||
Theme.of(context).textTheme.bodyMedium?.color,
|
||||
fontStyle:
|
||||
widget.titleItalic ? FontStyle.italic : null,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
widget.description ??
|
||||
const Text('Nincs leírás megadva.'),
|
||||
Text(
|
||||
'Nincs leírás megadva.',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 18.0,
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.color,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 15,
|
||||
child: Container(
|
||||
|
||||
227
filcnaplo_mobile_ui/lib/screens/summary/pages/allsum_page.dart
Normal file
227
filcnaplo_mobile_ui/lib/screens/summary/pages/allsum_page.dart
Normal file
@@ -0,0 +1,227 @@
|
||||
import 'package:filcnaplo/api/providers/user_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/absence.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/grade.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/subject.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/homework_provider.dart';
|
||||
import 'package:filcnaplo_mobile_ui/screens/summary/summary_screen.i18n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class AllSumBody extends StatefulWidget {
|
||||
const AllSumBody({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_AllSumBodyState createState() => _AllSumBodyState();
|
||||
}
|
||||
|
||||
class _AllSumBodyState extends State<AllSumBody> {
|
||||
late UserProvider user;
|
||||
late GradeProvider gradeProvider;
|
||||
late HomeworkProvider homeworkProvider;
|
||||
late AbsenceProvider absenceProvider;
|
||||
//late TimetableProvider timetableProvider;
|
||||
|
||||
late Map<String, Map<String, dynamic>> things = {};
|
||||
late List<Widget> firstSixTiles = [];
|
||||
late List<Widget> lastSixTiles = [];
|
||||
|
||||
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();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
gradeProvider = Provider.of<GradeProvider>(context, listen: false);
|
||||
homeworkProvider = Provider.of<HomeworkProvider>(context, listen: false);
|
||||
absenceProvider = Provider.of<AbsenceProvider>(context, listen: false);
|
||||
//timetableProvider = Provider.of<TimetableProvider>(context, listen: false);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
setState(() {
|
||||
animation = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void getGrades() {
|
||||
var allGrades = gradeProvider.grades;
|
||||
var testsGrades = gradeProvider.grades.where((a) => a.value.weight == 100);
|
||||
var closingTestsGrades =
|
||||
gradeProvider.grades.where((a) => a.value.weight >= 200);
|
||||
|
||||
things.addAll({
|
||||
'tests': {'name': 'test'.i18n, 'value': testsGrades.length},
|
||||
'closingTests': {
|
||||
'name': 'closingtest'.i18n,
|
||||
'value': closingTestsGrades.length
|
||||
},
|
||||
'grades': {'name': 'grade'.i18n, 'value': allGrades.length}
|
||||
});
|
||||
}
|
||||
|
||||
void getHomework() {
|
||||
var allHomework = homeworkProvider.homework;
|
||||
|
||||
things.addAll({
|
||||
'homework': {'name': 'hw'.i18n, 'value': allHomework.length}
|
||||
});
|
||||
}
|
||||
|
||||
void getSubjects() {
|
||||
var allSubjects = gradeProvider.grades
|
||||
.map((e) => e.subject)
|
||||
.toSet()
|
||||
.toList()
|
||||
..sort((a, b) => a.name.compareTo(b.name));
|
||||
//var totalLessons;
|
||||
var totalLessons = 0;
|
||||
|
||||
things.addAll({
|
||||
'subjects': {'name': 'subject'.i18n, 'value': allSubjects.length},
|
||||
'lessons': {'name': 'lesson'.i18n, 'value': totalLessons}
|
||||
});
|
||||
}
|
||||
|
||||
void getAbsences() {
|
||||
var allAbsences = absenceProvider.absences.where((a) => a.delay == 0);
|
||||
var excusedAbsences = absenceProvider.absences
|
||||
.where((a) => a.state == Justification.excused && a.delay == 0);
|
||||
var unexcusedAbsences = absenceProvider.absences.where((a) =>
|
||||
(a.state == Justification.unexcused ||
|
||||
a.state == Justification.pending) &&
|
||||
a.delay == 0);
|
||||
|
||||
things.addAll({
|
||||
'absences': {'name': 'absence_sum'.i18n, 'value': allAbsences.length},
|
||||
'excusedAbsences': {
|
||||
'name': 'excused'.i18n,
|
||||
'value': excusedAbsences.length
|
||||
},
|
||||
'unexcusedAbsences': {
|
||||
'name': 'unexcused'.i18n,
|
||||
'value': unexcusedAbsences.length
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void getDelays() {
|
||||
var allDelays = absenceProvider.absences.where((a) => a.delay > 0);
|
||||
var totalDelayTime = (allDelays.map((a) {
|
||||
return a.delay;
|
||||
}).toList())
|
||||
.reduce((a, b) => a + b);
|
||||
var unexcusedDelays = absenceProvider.absences
|
||||
.where((a) => a.state == Justification.unexcused && a.delay > 0);
|
||||
|
||||
things.addAll({
|
||||
'delays': {'name': 'delay_sum'.i18n, 'value': allDelays.length},
|
||||
'totalDelay': {'name': 'min'.i18n, 'value': totalDelayTime},
|
||||
'unexcusedDelays': {
|
||||
'name': 'unexcused'.i18n,
|
||||
'value': unexcusedDelays.length
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void getEverything() {
|
||||
getGrades();
|
||||
getHomework();
|
||||
getSubjects();
|
||||
getAbsences();
|
||||
getDelays();
|
||||
}
|
||||
|
||||
void generateTiles() {
|
||||
for (var i in things.values) {
|
||||
Widget w = Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
i.values.toList()[1].toString(),
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w800,
|
||||
fontSize: 36.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
i.values.toList()[0],
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 18.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
// TODO: az orakat es a hazikat szarul keri le, de majd meg lesz csinalva
|
||||
if (firstSixTiles.length < 6) {
|
||||
firstSixTiles.add(w);
|
||||
} else if (lastSixTiles.length < 6) {
|
||||
lastSixTiles.add(w);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
getEverything();
|
||||
generateTiles();
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 45,
|
||||
),
|
||||
AnimatedContainer(
|
||||
curve: Curves.easeInOut,
|
||||
duration: const Duration(milliseconds: 420),
|
||||
transform: Matrix4.translationValues(
|
||||
animation ? 0 : MediaQuery.of(context).size.width, 0, 0),
|
||||
height: 250,
|
||||
child: GridView.count(
|
||||
crossAxisCount: 3,
|
||||
mainAxisSpacing: 0,
|
||||
crossAxisSpacing: 5,
|
||||
children: firstSixTiles,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 30,
|
||||
),
|
||||
AnimatedContainer(
|
||||
curve: Curves.easeInOut,
|
||||
duration: const Duration(milliseconds: 420),
|
||||
transform: Matrix4.translationValues(
|
||||
animation ? 0 : -MediaQuery.of(context).size.width, 0, 0),
|
||||
height: 250,
|
||||
child: GridView.count(
|
||||
crossAxisCount: 3,
|
||||
mainAxisSpacing: 0,
|
||||
crossAxisSpacing: 5,
|
||||
children: lastSixTiles,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,362 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:math';
|
||||
|
||||
class GradesBody extends StatelessWidget {
|
||||
import 'package:filcnaplo/api/providers/user_provider.dart';
|
||||
import 'package:filcnaplo/helpers/average_helper.dart';
|
||||
import 'package:filcnaplo/models/settings.dart';
|
||||
import 'package:filcnaplo/ui/widgets/grade/grade_tile.dart';
|
||||
import 'package:filcnaplo/utils/format.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/screens/summary/summary_screen.i18n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:i18n_extension/i18n_widget.dart';
|
||||
|
||||
List<String> faces = [
|
||||
"(·.·)",
|
||||
"(≥o≤)",
|
||||
"(·_·)",
|
||||
"(˚Δ˚)b",
|
||||
"(^-^*)",
|
||||
"(='X'=)",
|
||||
"(>_<)",
|
||||
"(;-;)",
|
||||
"\\(^Д^)/",
|
||||
"\\(o_o)/",
|
||||
];
|
||||
|
||||
class GradesBody extends StatefulWidget {
|
||||
const GradesBody({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_GradesBodyState createState() => _GradesBodyState();
|
||||
}
|
||||
|
||||
class _GradesBodyState extends State<GradesBody> {
|
||||
late UserProvider user;
|
||||
late GradeProvider gradeProvider;
|
||||
late SettingsProvider settings;
|
||||
|
||||
late double subjectAvg;
|
||||
late double endYearAvg;
|
||||
late String endYearAvgText;
|
||||
|
||||
List<Widget> subjectTiles5 = [];
|
||||
List<Widget> subjectTiles3 = [];
|
||||
List<Widget> subjectTiles1 = [];
|
||||
|
||||
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();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
gradeProvider = Provider.of<GradeProvider>(context, listen: false);
|
||||
settings = Provider.of<SettingsProvider>(context, listen: false);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
setState(() {
|
||||
animation = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void generateTiles({required int filter}) {
|
||||
List<Subject> subjects = gradeProvider.grades
|
||||
.map((e) => e.subject)
|
||||
.toSet()
|
||||
.toList()
|
||||
..sort((a, b) => a.name.compareTo(b.name));
|
||||
List<Widget> tiles = [];
|
||||
|
||||
Map<Subject, double> subjectAvgs = {};
|
||||
|
||||
var count = 1;
|
||||
|
||||
for (Subject subject in subjects) {
|
||||
List<Grade> subjectGrades = getSubjectGrades(subject);
|
||||
|
||||
double avg = AverageHelper.averageEvals(subjectGrades);
|
||||
if (avg != 0) subjectAvgs[subject] = avg;
|
||||
|
||||
Widget widget = AnimatedContainer(
|
||||
curve: Curves.easeInOut,
|
||||
duration: Duration(milliseconds: 300 + (count * 120)),
|
||||
transform: Matrix4.translationValues(
|
||||
animation ? 0 : MediaQuery.of(context).size.width, 0, 0),
|
||||
child: Row(
|
||||
children: [
|
||||
GradeValueWidget(
|
||||
GradeValue(avg.round(), '', '', 100),
|
||||
fill: true,
|
||||
size: 28.0,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
subject.renamedTo ?? subject.name.capital(),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20.0,
|
||||
color: Colors.white.withOpacity(0.98),
|
||||
fontStyle: settings.renamedSubjectsItalics && subject.isRenamed
|
||||
? FontStyle.italic
|
||||
: null,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
if (avg.round() == filter) {
|
||||
tiles.add(widget);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (tiles.isEmpty) {
|
||||
int index = Random(DateTime.now().minute).nextInt(faces.length);
|
||||
Widget faceWidget = Center(
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
text: faces[index],
|
||||
style: const TextStyle(
|
||||
fontSize: 32.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "\n${'no_grades'.i18n}",
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
height: 2.0,
|
||||
color: Colors.white.withOpacity(0.5)),
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
tiles.insert(0, faceWidget);
|
||||
}
|
||||
|
||||
subjectAvg = subjectAvgs.isNotEmpty
|
||||
? subjectAvgs.values.fold(0.0, (double a, double b) => a + b) /
|
||||
subjectAvgs.length
|
||||
: 0.0;
|
||||
|
||||
List<Grade> endYearGrades = gradeProvider.grades
|
||||
.where((grade) => grade.type == GradeType.endYear)
|
||||
.toList();
|
||||
endYearAvg = AverageHelper.averageEvals(endYearGrades, finalAvg: true);
|
||||
endYearAvgText = endYearAvg.toStringAsFixed(1);
|
||||
if (I18n.of(context).locale.languageCode != "en") {
|
||||
endYearAvgText = endYearAvgText.replaceAll(".", ",");
|
||||
}
|
||||
|
||||
if (filter == 5) {
|
||||
subjectTiles5 = List.castFrom(tiles);
|
||||
if (subjectTiles5.length > 4) {
|
||||
subjectTiles5.length = 4;
|
||||
}
|
||||
} else if (filter == 3) {
|
||||
subjectTiles3 = List.castFrom(tiles);
|
||||
if (subjectTiles3.length > 3) {
|
||||
subjectTiles3.length = 3;
|
||||
}
|
||||
} else if (filter == 1) {
|
||||
subjectTiles1 = List.castFrom(tiles);
|
||||
if (subjectTiles1.length > 2) {
|
||||
subjectTiles1.length = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getGrades() {
|
||||
generateTiles(filter: 5);
|
||||
generateTiles(filter: 3);
|
||||
generateTiles(filter: 1);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Column();
|
||||
user = Provider.of<UserProvider>(context);
|
||||
settings = Provider.of<SettingsProvider>(context);
|
||||
|
||||
getGrades();
|
||||
|
||||
return Expanded(
|
||||
child: ListView(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: ((100 * subjectTiles5.length) /
|
||||
(subjectTiles5[0].runtimeType == AnimatedContainer
|
||||
? 1.95
|
||||
: 1.2))
|
||||
.toDouble(),
|
||||
child: ListView.builder(
|
||||
padding: const EdgeInsets.only(left: 5),
|
||||
physics: const BouncingScrollPhysics(),
|
||||
itemCount: max(subjectTiles5.length, 1),
|
||||
itemBuilder: (context, index) {
|
||||
if (subjectTiles5.isNotEmpty) {
|
||||
EdgeInsetsGeometry panelPadding =
|
||||
const EdgeInsets.symmetric(horizontal: 24.0);
|
||||
|
||||
if (subjectTiles5[index].runtimeType == AnimatedContainer) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: subjectTiles5[index]);
|
||||
} else {
|
||||
return Padding(
|
||||
padding: panelPadding, child: subjectTiles5[index]);
|
||||
}
|
||||
} else {
|
||||
return Container();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12.0),
|
||||
Text(
|
||||
'tryagain'.i18n,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 22.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12.0),
|
||||
SizedBox(
|
||||
height: ((100 * subjectTiles3.length) /
|
||||
(subjectTiles3[0].runtimeType == AnimatedContainer
|
||||
? 1.95
|
||||
: 1.2))
|
||||
.toDouble(),
|
||||
child: ListView.builder(
|
||||
padding: const EdgeInsets.only(left: 5),
|
||||
physics: const BouncingScrollPhysics(),
|
||||
itemCount: max(subjectTiles3.length, 1),
|
||||
itemBuilder: (context, index) {
|
||||
if (subjectTiles3.isNotEmpty) {
|
||||
EdgeInsetsGeometry panelPadding =
|
||||
const EdgeInsets.symmetric(horizontal: 24.0);
|
||||
|
||||
if (subjectTiles3[index].runtimeType == AnimatedContainer) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: subjectTiles3[index]);
|
||||
} else {
|
||||
return Padding(
|
||||
padding: panelPadding, child: subjectTiles3[index]);
|
||||
}
|
||||
} else {
|
||||
return Container();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12.0),
|
||||
Text(
|
||||
'oops'.i18n,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 22.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12.0),
|
||||
SizedBox(
|
||||
height: ((100 * subjectTiles1.length) /
|
||||
(subjectTiles1[0].runtimeType == AnimatedContainer
|
||||
? 1.95
|
||||
: 1.2))
|
||||
.toDouble(),
|
||||
child: ListView.builder(
|
||||
padding: const EdgeInsets.only(left: 5),
|
||||
physics: const BouncingScrollPhysics(),
|
||||
itemCount: max(subjectTiles1.length, 1),
|
||||
itemBuilder: (context, index) {
|
||||
if (subjectTiles1.isNotEmpty) {
|
||||
EdgeInsetsGeometry panelPadding =
|
||||
const EdgeInsets.symmetric(horizontal: 24.0);
|
||||
|
||||
if (subjectTiles1[index].runtimeType == AnimatedContainer) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: subjectTiles1[index]);
|
||||
} else {
|
||||
return Padding(
|
||||
padding: panelPadding, child: subjectTiles1[index]);
|
||||
}
|
||||
} else {
|
||||
return Container();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30.0),
|
||||
Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'endyear_avg'.i18n,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 22.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 10.0),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0, vertical: 4.0),
|
||||
decoration: BoxDecoration(
|
||||
color: gradeColor(context: context, value: endYearAvg)
|
||||
.withOpacity(.2),
|
||||
border: Border.all(
|
||||
color: (gradeColor(context: context, value: endYearAvg))
|
||||
.withOpacity(0.0),
|
||||
width: 2.0,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(45.0),
|
||||
),
|
||||
child: AutoSizeText.rich(
|
||||
TextSpan(
|
||||
text: endYearAvgText,
|
||||
),
|
||||
maxLines: 1,
|
||||
minFontSize: 5,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: gradeColor(context: context, value: endYearAvg),
|
||||
fontWeight: FontWeight.w800,
|
||||
fontSize: 32.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
319
filcnaplo_mobile_ui/lib/screens/summary/pages/lessons_page.dart
Normal file
319
filcnaplo_mobile_ui/lib/screens/summary/pages/lessons_page.dart
Normal file
@@ -0,0 +1,319 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:filcnaplo/api/providers/user_provider.dart';
|
||||
import 'package:filcnaplo/helpers/subject.dart';
|
||||
import 'package:filcnaplo/models/settings.dart';
|
||||
import 'package:filcnaplo/utils/format.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/absence.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/lesson.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/subject.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/week.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart';
|
||||
import 'package:filcnaplo_mobile_ui/screens/summary/summary_screen.i18n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
List<String> faces = [
|
||||
"(·.·)",
|
||||
"(≥o≤)",
|
||||
"(·_·)",
|
||||
"(˚Δ˚)b",
|
||||
"(^-^*)",
|
||||
"(='X'=)",
|
||||
"(>_<)",
|
||||
"(;-;)",
|
||||
"\\(^Д^)/",
|
||||
"\\(o_o)/",
|
||||
];
|
||||
|
||||
class SubjectAbsence {
|
||||
Subject subject;
|
||||
List<Absence> absences;
|
||||
double percentage;
|
||||
|
||||
SubjectAbsence(
|
||||
{required this.subject, this.absences = const [], this.percentage = 0.0});
|
||||
}
|
||||
|
||||
class LessonsBody extends StatefulWidget {
|
||||
const LessonsBody({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_LessonsBodyState createState() => _LessonsBodyState();
|
||||
}
|
||||
|
||||
class _LessonsBodyState extends State<LessonsBody> {
|
||||
late UserProvider user;
|
||||
late AbsenceProvider absenceProvider;
|
||||
late SettingsProvider settingsProvider;
|
||||
late TimetableProvider timetableProvider;
|
||||
|
||||
late List<SubjectAbsence> absences = [];
|
||||
late List<Widget> lessons = [];
|
||||
late List<Absence> delays = [];
|
||||
final Map<Subject, Lesson> _lessonCount = {};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
absenceProvider = Provider.of<AbsenceProvider>(context, listen: false);
|
||||
settingsProvider = Provider.of<SettingsProvider>(context, listen: false);
|
||||
timetableProvider = Provider.of<TimetableProvider>(context, listen: false);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
for (final lesson in timetableProvider.getWeek(Week.current()) ?? []) {
|
||||
if (!lesson.isEmpty &&
|
||||
lesson.subject.id != '' &&
|
||||
lesson.lessonYearIndex != null) {
|
||||
_lessonCount.update(
|
||||
lesson.subject,
|
||||
(value) {
|
||||
if (lesson.lessonYearIndex! > value.lessonYearIndex!) {
|
||||
return lesson;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
ifAbsent: () => lesson,
|
||||
);
|
||||
}
|
||||
}
|
||||
setState(() {});
|
||||
});
|
||||
}
|
||||
|
||||
void buildSubjectAbsences() {
|
||||
Map<Subject, SubjectAbsence> _absences = {};
|
||||
|
||||
for (final absence in absenceProvider.absences) {
|
||||
if (absence.delay != 0) continue;
|
||||
|
||||
if (!_absences.containsKey(absence.subject)) {
|
||||
_absences[absence.subject] =
|
||||
SubjectAbsence(subject: absence.subject, absences: [absence]);
|
||||
} else {
|
||||
_absences[absence.subject]?.absences.add(absence);
|
||||
}
|
||||
}
|
||||
|
||||
_absences.forEach((subject, absence) {
|
||||
final absentLessonsOfSubject = absenceProvider.absences
|
||||
.where((e) => e.subject == subject && e.delay == 0)
|
||||
.length;
|
||||
final totalLessonsOfSubject = _lessonCount[subject]?.lessonYearIndex ?? 0;
|
||||
|
||||
double absentLessonsOfSubjectPercentage;
|
||||
|
||||
if (absentLessonsOfSubject <= totalLessonsOfSubject) {
|
||||
absentLessonsOfSubjectPercentage =
|
||||
absentLessonsOfSubject / totalLessonsOfSubject * 100;
|
||||
} else {
|
||||
absentLessonsOfSubjectPercentage = -1;
|
||||
}
|
||||
|
||||
_absences[subject]?.percentage =
|
||||
absentLessonsOfSubjectPercentage.clamp(-1, 100.0);
|
||||
});
|
||||
|
||||
absences = _absences.values.toList();
|
||||
absences.sort((a, b) => -a.percentage.compareTo(b.percentage));
|
||||
}
|
||||
|
||||
void getAndSortDelays() {
|
||||
delays = absenceProvider.absences;
|
||||
delays.sort((a, b) => -a.delay.compareTo(b.delay));
|
||||
}
|
||||
|
||||
void generateTiles() {
|
||||
Widget leastAbsent = Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
SubjectIcon.resolveVariant(
|
||||
subject: absences.last.subject, context: context),
|
||||
color: Colors.white,
|
||||
size: 64,
|
||||
),
|
||||
Text(
|
||||
absences.last.subject.renamedTo ??
|
||||
absences.last.subject.name.capital(),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w800,
|
||||
fontSize: 36.0,
|
||||
fontStyle: absences.last.subject.isRenamed &&
|
||||
settingsProvider.renamedSubjectsItalics
|
||||
? FontStyle.italic
|
||||
: null,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'absence'.i18n.fill([absences.last.absences.length]),
|
||||
style: const TextStyle(
|
||||
fontSize: 18.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
if (absences.last.absences.isNotEmpty) {
|
||||
lessons.add(leastAbsent);
|
||||
} else {
|
||||
lessons.add(buildFaceWidget());
|
||||
}
|
||||
|
||||
Widget mostAbsent = Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
SubjectIcon.resolveVariant(
|
||||
subject: absences.first.subject, context: context),
|
||||
color: Colors.white,
|
||||
size: 64,
|
||||
),
|
||||
Text(
|
||||
absences.first.subject.renamedTo ??
|
||||
absences.first.subject.name.capital(),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w800,
|
||||
fontSize: 36.0,
|
||||
fontStyle: absences.first.subject.isRenamed &&
|
||||
settingsProvider.renamedSubjectsItalics
|
||||
? FontStyle.italic
|
||||
: null,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'absence'.i18n.fill([absences.first.absences.length]),
|
||||
style: const TextStyle(
|
||||
fontSize: 18.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
if (absences.first.absences.isNotEmpty) {
|
||||
lessons.add(mostAbsent);
|
||||
} else {
|
||||
lessons.add(buildFaceWidget());
|
||||
}
|
||||
|
||||
Widget mostDelays = Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
SubjectIcon.resolveVariant(
|
||||
subject: delays.first.subject, context: context),
|
||||
color: Colors.white,
|
||||
size: 64,
|
||||
),
|
||||
Text(
|
||||
delays.first.subject.renamedTo ??
|
||||
delays.first.subject.name.capital(),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w800,
|
||||
fontSize: 36.0,
|
||||
fontStyle: delays.first.subject.isRenamed &&
|
||||
settingsProvider.renamedSubjectsItalics
|
||||
? FontStyle.italic
|
||||
: null,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'delay'.i18n.fill([delays.first.delay]),
|
||||
style: const TextStyle(
|
||||
fontSize: 18.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
if (delays.first.delay != 0) {
|
||||
lessons.add(mostDelays);
|
||||
} else {
|
||||
lessons.add(buildFaceWidget());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
buildSubjectAbsences();
|
||||
getAndSortDelays();
|
||||
generateTiles();
|
||||
|
||||
return Expanded(
|
||||
child: ListView(
|
||||
children: [
|
||||
lessons[0],
|
||||
const SizedBox(height: 18.0),
|
||||
Text(
|
||||
'dontfelt'.i18n,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 22.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18.0),
|
||||
lessons[1],
|
||||
const SizedBox(height: 18.0),
|
||||
Text(
|
||||
'youlate'.i18n,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 22.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18.0),
|
||||
lessons[2],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildFaceWidget() {
|
||||
int index = Random(DateTime.now().minute).nextInt(faces.length);
|
||||
return Center(
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
text: faces[index],
|
||||
style: const TextStyle(
|
||||
fontSize: 32.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "\n${'no_lesson'.i18n}",
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
height: 2.0,
|
||||
color: Colors.white.withOpacity(0.5)),
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,128 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:io';
|
||||
|
||||
class PersonalityBody extends StatelessWidget {
|
||||
import 'package:filcnaplo/api/providers/user_provider.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/personality_card/empty_card.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/personality_card/personality_card.dart';
|
||||
import 'package:filcnaplo_mobile_ui/screens/summary/summary_screen.i18n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:screenshot/screenshot.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
||||
|
||||
class PersonalityBody extends StatefulWidget {
|
||||
const PersonalityBody({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_PersonalityBodyState createState() => _PersonalityBodyState();
|
||||
}
|
||||
|
||||
class _PersonalityBodyState extends State<PersonalityBody> {
|
||||
late UserProvider user;
|
||||
|
||||
bool isRevealed = false;
|
||||
|
||||
ScreenshotController screenshotController = ScreenshotController();
|
||||
|
||||
sharePersonality() async {
|
||||
await screenshotController.capture().then((image) async {
|
||||
if (image != null) {
|
||||
final directory = await getApplicationDocumentsDirectory();
|
||||
if (await File('${directory.path}/refilc_personality.png').exists()) {
|
||||
await File('${directory.path}/refilc_personality.png').delete();
|
||||
}
|
||||
final imagePath =
|
||||
await File('${directory.path}/refilc_personality.png').create();
|
||||
await imagePath.writeAsBytes(image);
|
||||
|
||||
await Share.shareXFiles([XFile(imagePath.path)]);
|
||||
}
|
||||
}).catchError((err) {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
savePersonality() async {
|
||||
await screenshotController.capture().then((image) async {
|
||||
if (image != null) {
|
||||
await ImageGallerySaver.saveImage(image, name: 'refilc_personality');
|
||||
}
|
||||
}).catchError((err) {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Column();
|
||||
user = Provider.of<UserProvider>(context);
|
||||
|
||||
return Expanded(
|
||||
child: ListView(
|
||||
children: [
|
||||
const SizedBox(height: 30),
|
||||
AnimatedCrossFade(
|
||||
duration: const Duration(milliseconds: 1000),
|
||||
sizeCurve: Curves.easeInToLinear,
|
||||
firstChild: Screenshot(
|
||||
controller: screenshotController,
|
||||
child: PersonalityCard(user: user),
|
||||
),
|
||||
secondChild: GestureDetector(
|
||||
onTap: () => setState(() {
|
||||
isRevealed = true;
|
||||
}),
|
||||
child: EmptyCard(text: 'click_reveal'.i18n),
|
||||
),
|
||||
crossFadeState: isRevealed
|
||||
? CrossFadeState.showFirst
|
||||
: CrossFadeState.showSecond,
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
if (isRevealed)
|
||||
Center(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
await sharePersonality();
|
||||
},
|
||||
icon: const Icon(
|
||||
FeatherIcons.share,
|
||||
color: Colors.white,
|
||||
size: 30,
|
||||
),
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateProperty.all(
|
||||
Colors.white.withOpacity(0.2)),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
await savePersonality();
|
||||
},
|
||||
icon: const Icon(
|
||||
FeatherIcons.bookmark,
|
||||
color: Colors.white,
|
||||
size: 30,
|
||||
),
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateProperty.all(
|
||||
Colors.white.withOpacity(0.2)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 60),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
import 'package:filcnaplo/api/providers/user_provider.dart';
|
||||
import 'package:filcnaplo/models/settings.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
|
||||
import 'package:filcnaplo_mobile_ui/screens/summary/summary_screen.dart';
|
||||
import 'package:filcnaplo_mobile_ui/screens/summary/summary_screen.i18n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wtf_sliding_sheet/wtf_sliding_sheet.dart';
|
||||
|
||||
class StartBody extends StatefulWidget {
|
||||
const StartBody({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_StartBodyState createState() => _StartBodyState();
|
||||
}
|
||||
|
||||
class _StartBodyState extends State<StartBody> {
|
||||
late UserProvider user;
|
||||
late GradeProvider gradeProvider;
|
||||
late SettingsProvider settings;
|
||||
|
||||
late String firstName;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
gradeProvider = Provider.of<GradeProvider>(context, listen: false);
|
||||
settings = Provider.of<SettingsProvider>(context, listen: false);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const SizedBox(height: 40.0),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
showSlidingBottomSheet(
|
||||
context,
|
||||
useRootNavigator: true,
|
||||
builder: (context) => SlidingSheetDialog(
|
||||
color: Colors.black.withOpacity(0.99),
|
||||
duration: const Duration(milliseconds: 400),
|
||||
scrollSpec: const ScrollSpec.bouncingScroll(),
|
||||
snapSpec: const SnapSpec(
|
||||
snap: true,
|
||||
snappings: [1.0],
|
||||
initialSnap: 1.0,
|
||||
positioning: SnapPositioning.relativeToAvailableSpace,
|
||||
),
|
||||
minHeight: MediaQuery.of(context).size.height,
|
||||
cornerRadius: 16,
|
||||
cornerRadiusOnFullscreen: 0,
|
||||
builder: (context, state) => const Material(
|
||||
color: Colors.black,
|
||||
child: SummaryScreen(
|
||||
currentPage: 'grades',
|
||||
isBottomSheet: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
FeatherIcons.arrowRight,
|
||||
size: 145,
|
||||
color: Colors.white,
|
||||
grade: 0.001,
|
||||
weight: 0.001,
|
||||
),
|
||||
Text(
|
||||
'start'.i18n,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 16.0,
|
||||
color: Colors.white.withOpacity(0.7),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 169.69),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,48 @@
|
||||
import 'package:confetti/confetti.dart';
|
||||
import 'package:filcnaplo/api/providers/user_provider.dart';
|
||||
import 'package:filcnaplo/models/settings.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wtf_sliding_sheet/wtf_sliding_sheet.dart';
|
||||
import 'summary_screen.i18n.dart';
|
||||
|
||||
import 'pages/allsum_page.dart';
|
||||
import 'pages/start_page.dart';
|
||||
import 'pages/grades_page.dart';
|
||||
import 'pages/lessons_page.dart';
|
||||
import 'pages/personality_page.dart';
|
||||
|
||||
class SummaryScreen extends StatefulWidget {
|
||||
final String currentPage;
|
||||
final bool isBottomSheet;
|
||||
|
||||
const SummaryScreen({Key? key, this.currentPage = 'personality'})
|
||||
: super(key: key);
|
||||
const SummaryScreen({
|
||||
Key? key,
|
||||
this.currentPage = 'personality',
|
||||
this.isBottomSheet = false,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_SummaryScreenState createState() => _SummaryScreenState();
|
||||
|
||||
static show(
|
||||
{required BuildContext context,
|
||||
String currentPage = 'personality'}) =>
|
||||
Navigator.of(context, rootNavigator: true).push(CupertinoPageRoute(
|
||||
builder: (context) => SummaryScreen(currentPage: currentPage)));
|
||||
}
|
||||
|
||||
class _SummaryScreenState extends State<SummaryScreen> {
|
||||
class _SummaryScreenState extends State<SummaryScreen>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late UserProvider user;
|
||||
late SettingsProvider settings;
|
||||
|
||||
ConfettiController? _confettiController;
|
||||
|
||||
late String firstName;
|
||||
|
||||
final LinearGradient _backgroundGradient = const LinearGradient(
|
||||
colors: [
|
||||
Color(0xff1d56ac),
|
||||
@@ -22,34 +53,170 @@ class _SummaryScreenState extends State<SummaryScreen> {
|
||||
stops: [-1.0, 1.0],
|
||||
);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_confettiController?.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
user = Provider.of<UserProvider>(context);
|
||||
settings = Provider.of<SettingsProvider>(context);
|
||||
|
||||
List<String> nameParts = user.displayName?.split(" ") ?? ["?"];
|
||||
if (!settings.presentationMode) {
|
||||
firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0];
|
||||
} else {
|
||||
firstName = "János";
|
||||
}
|
||||
|
||||
return widget.isBottomSheet
|
||||
? buildContainer()
|
||||
: Scaffold(
|
||||
body: buildContainer(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildContainer() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(gradient: _backgroundGradient),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(gradient: _backgroundGradient),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(gradient: _backgroundGradient),
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: MediaQuery.of(context).size.height,
|
||||
child: SafeArea(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 24.0,
|
||||
right: 24.0,
|
||||
top: 26.0 + MediaQuery.of(context).padding.top,
|
||||
bottom: 52.0,
|
||||
),
|
||||
child: widget.currentPage == 'grades'
|
||||
? const GradesBody()
|
||||
: widget.currentPage == 'lessons'
|
||||
? const GradesBody()
|
||||
: widget.currentPage == 'allsum'
|
||||
? const GradesBody()
|
||||
: const GradesBody(),
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: MediaQuery.of(context).size.height,
|
||||
child: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 24.0,
|
||||
right: 24.0,
|
||||
top: 15.0,
|
||||
bottom: 40.0,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: widget.currentPage == 'start'
|
||||
? CrossAxisAlignment.center
|
||||
: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: widget.currentPage == 'start'
|
||||
? MainAxisAlignment.spaceBetween
|
||||
: MainAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'greeting'.i18n.fill([firstName]),
|
||||
textAlign: TextAlign.left,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 26.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
widget.currentPage == 'start'
|
||||
? 'title_start'.i18n
|
||||
: widget.currentPage == 'grades'
|
||||
? 'title_grades'.i18n
|
||||
: widget.currentPage == 'lessons'
|
||||
? 'title_lessons'.i18n
|
||||
: widget.currentPage == 'personality'
|
||||
? 'title_personality'.i18n
|
||||
: '',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: false,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 22.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
widget.currentPage != 'start'
|
||||
? IconButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
if (widget.currentPage == 'grades') {
|
||||
openNewPage(page: 'lessons');
|
||||
} else if (widget.currentPage == 'lessons') {
|
||||
openNewPage(page: 'allsum');
|
||||
} else if (widget.currentPage == 'allsum') {
|
||||
openNewPage(page: 'personality');
|
||||
} else {
|
||||
Navigator.of(context).maybePop();
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
widget.currentPage == 'personality'
|
||||
? FeatherIcons.x
|
||||
: FeatherIcons.arrowRight,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: Container()
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12.0),
|
||||
widget.currentPage == 'start'
|
||||
? const StartBody()
|
||||
: widget.currentPage == 'grades'
|
||||
? const GradesBody()
|
||||
: widget.currentPage == 'lessons'
|
||||
? const LessonsBody()
|
||||
: widget.currentPage == 'allsum'
|
||||
? const AllSumBody()
|
||||
: const PersonalityBody(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void openNewPage({String page = 'personality'}) {
|
||||
showSlidingBottomSheet(
|
||||
context,
|
||||
useRootNavigator: true,
|
||||
builder: (context) => SlidingSheetDialog(
|
||||
color: Colors.black.withOpacity(0.99),
|
||||
duration: const Duration(milliseconds: 400),
|
||||
scrollSpec: const ScrollSpec.bouncingScroll(),
|
||||
snapSpec: const SnapSpec(
|
||||
snap: true,
|
||||
snappings: [1.0],
|
||||
initialSnap: 1.0,
|
||||
positioning: SnapPositioning.relativeToAvailableSpace,
|
||||
),
|
||||
minHeight: MediaQuery.of(context).size.height,
|
||||
cornerRadius: 16,
|
||||
cornerRadiusOnFullscreen: 0,
|
||||
builder: (context, state) => Material(
|
||||
color: Colors.black,
|
||||
child: SummaryScreen(
|
||||
currentPage: page,
|
||||
isBottomSheet: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
//SummaryScreen.show(context: context, currentPage: page);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,111 @@ import 'package:i18n_extension/i18n_extension.dart';
|
||||
extension SettingsLocalization on String {
|
||||
static final _t = Translations.byLocale("hu_hu") +
|
||||
{
|
||||
"en_en": {},
|
||||
"hu_hu": {},
|
||||
"de_de": {},
|
||||
"en_en": {
|
||||
// main thingies
|
||||
"no_grades": "No grades found",
|
||||
"no_lesson": "No lessons found",
|
||||
"greeting": "You had a good year, %s!",
|
||||
"title_start": "So let's summarize...",
|
||||
"title_grades": "Let's look at your marks... 📖",
|
||||
"title_lessons": "Your favorite lesson 💓",
|
||||
"title_personality": "Your personality is...",
|
||||
// start page
|
||||
"start": "Start",
|
||||
// grades page
|
||||
"tryagain": "He puts the master to the test! 🔃",
|
||||
"oops": "Ouch... 🥴",
|
||||
"endyear_avg": "Year-end average",
|
||||
// lessons page
|
||||
"absence": "%s absence(s)",
|
||||
"delay": "A total of %s minute(s) late",
|
||||
"dontfelt": "You didn't like it...",
|
||||
"youlate": "You're late!",
|
||||
// allsum page
|
||||
"test": "test(s)",
|
||||
"closingtest": "module test(s)",
|
||||
"grade": "grades",
|
||||
"hw": "homework",
|
||||
"subject": "subjects",
|
||||
"lesson": "lessons",
|
||||
"absence_sum": "absence(s)",
|
||||
"excused": "excused",
|
||||
"unexcused": "unexcused",
|
||||
"delay_sum": "delay(s)",
|
||||
"min": "minute(s)",
|
||||
// personality page
|
||||
"click_reveal": "Click to reveal...",
|
||||
},
|
||||
"hu_hu": {
|
||||
// main thingies
|
||||
"no_grades": "Nincsenek jegyek",
|
||||
"no_lesson": "Nincsenek tanórák",
|
||||
"greeting": "Jó éved volt, %s!",
|
||||
"title_start": "Összegezzünk hát...",
|
||||
"title_grades": "Nézzük a jegyeidet... 📖",
|
||||
"title_lessons": "A kedvenc órád 💓",
|
||||
"title_personality": "A te személyiséged...",
|
||||
// start page
|
||||
"start": "Kezdés",
|
||||
// grades page
|
||||
"tryagain": "Próba teszi a mestert! 🔃",
|
||||
"oops": "Ajjaj... 🥴",
|
||||
"endyear_avg": "Év végi átlagod",
|
||||
// lessons page
|
||||
"absence": "%s hiányzás",
|
||||
"delay": "Összesen %s perc késés",
|
||||
"dontfelt": "Nem volt kedved hozzá...",
|
||||
"youlate": "Késtél!",
|
||||
// allsum page
|
||||
"test": "dolgozat",
|
||||
"closingtest": "témazáró",
|
||||
"grade": "jegy",
|
||||
"hw": "házi",
|
||||
"subject": "tantárgy",
|
||||
"lesson": "óra",
|
||||
"absence_sum": "hiányzás",
|
||||
"excused": "igazolt",
|
||||
"unexcused": "igazolatlan",
|
||||
"delay_sum": "késés",
|
||||
"min": "perc",
|
||||
// personality page
|
||||
"click_reveal": "Kattints a felfedéshez...",
|
||||
},
|
||||
"de_de": {
|
||||
// main thingies
|
||||
"no_grades": "Keine Grade gefunden",
|
||||
"no_lesson": "Keine Lektionen gefunden",
|
||||
"greeting": "Du hattest ein gutes Jahr, %s!",
|
||||
"title_start": "Fassen wir also zusammen...",
|
||||
"title_grades": "Schauen wir uns eure Tickets an... 📖",
|
||||
"title_lessons": "Deine Lieblingsuhr 💓",
|
||||
"title_personality": "Deine Persönlichkeit...",
|
||||
// start page
|
||||
"start": "Anfang",
|
||||
// grades page
|
||||
"tryagain": "Er stellt den Meister auf die Probe! 🔃",
|
||||
"oops": "Autsch... 🥴",
|
||||
"endyear_avg": "Ihr Jahresenddurchschnitt",
|
||||
// lessons page
|
||||
"absence": "%s Abwesenheit(en)",
|
||||
"delay": "Insgesamt %s Minute(n) zu spät",
|
||||
"dontfelt": "Es hat dir nicht gefallen...",
|
||||
"youlate": "Du bist spät!",
|
||||
// allsum page
|
||||
"test": "These(n)",
|
||||
"closingtest": "Modultest",
|
||||
"grade": "Grad",
|
||||
"hw": "Hausaufgaben",
|
||||
"subject": "Themen",
|
||||
"lesson": "Lektionen",
|
||||
"absence_sum": "Abwesenheit(en)",
|
||||
"excused": "bescheinigte",
|
||||
"unexcused": "unentschuldigte",
|
||||
"delay_sum": "Verzögerung(en)",
|
||||
"min": "Minute(n)",
|
||||
// personality page
|
||||
"click_reveal": "Klicken Sie hier, um es anzuzeigen...",
|
||||
},
|
||||
};
|
||||
|
||||
String get i18n => localize(this, _t);
|
||||
|
||||
@@ -40,6 +40,9 @@ dependencies:
|
||||
background_fetch: ^1.1.5
|
||||
wtf_sliding_sheet: ^1.0.0
|
||||
package_info_plus: ^4.0.2
|
||||
dotted_border: ^2.0.0+3
|
||||
screenshot: ^2.1.0
|
||||
image_gallery_saver: ^2.0.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_lints: ^1.0.0
|
||||
|
||||
@@ -293,13 +293,10 @@ class _ModifySubjectNamesState extends State<ModifySubjectNames> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Panel(
|
||||
child: PanelButton(
|
||||
child: SwitchListTile(
|
||||
title: Text("italics_toggle".i18n),
|
||||
trailing: Switch(
|
||||
value: settings.renamedSubjectsItalics,
|
||||
onChanged: (value) =>
|
||||
settings.update(renamedSubjectsItalics: value),
|
||||
)),
|
||||
onChanged: (value) => settings.update(renamedSubjectsItalics: value),
|
||||
value: settings.renamedSubjectsItalics,),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
|
||||
Reference in New Issue
Block a user