Compare commits

..

36 Commits
4.0.1 ... 4.0.3

Author SHA1 Message Date
Kima
8dbf605450 added black accent color 2023-06-08 21:28:28 +02:00
Kima
2f418a7c1a updated version string 2023-06-08 21:19:46 +02:00
Kima
5f0c82f54c added grade value translations 2023-06-08 21:18:20 +02:00
Kima
4e659308e5 fixed subject rename at homeworks 2023-06-08 20:38:10 +02:00
Kima
50e24bde17 added disable fading to all filter/tab bars 2023-06-08 20:07:17 +02:00
Márton Kiss
31f7c6a465 Merge pull request #6 from Monke14/bug-fixes
some fixes - by Monke14
2023-06-08 20:01:22 +02:00
Márton Kiss
e734579249 Merge branch 'master' into bug-fixes 2023-06-08 19:59:57 +02:00
Márton Kiss
2cff46d628 Merge pull request #5 from TMarccci/master
fixed lot of things - by TMarccci
2023-06-08 19:56:35 +02:00
Kima
87f3f93177 started creating end-year summary and stb 2023-06-08 19:53:50 +02:00
hihihaha
30733caa4a remove home screen tabbar fade 2023-06-08 16:18:39 +02:00
hihihaha
4e30a550e1 fix chart overflow 2023-06-08 16:18:08 +02:00
hihihaha
cb687d6b10 add themed icon 2023-06-08 16:17:56 +02:00
hihihaha
6c6d3a7cd8 fix english translations 2023-06-08 16:17:46 +02:00
Tihanyi Marcell
da06e400e1 Login add " ", Comment rename 2023-06-08 13:47:40 +02:00
Tihanyi Marcell
87b8cbb60f HotFix 2023-06-08 12:59:09 +02:00
Tihanyi Marcell
8bac300585 goalPlanner remove 2023-06-08 12:54:46 +02:00
Tihanyi Marcell
da7d2b9333 Fixed: Settings UI, Live Act, Class Avg 2023-06-08 12:44:47 +02:00
Kima
e1f84caf19 changed refilc bday strings 2023-06-07 21:27:56 +02:00
Kima
274da2b766 ok 2023-06-07 21:21:35 +02:00
Kima
35aba35801 Merge branch 'master' of github.com:refilc/naplo 2023-06-07 20:50:48 +02:00
Kima
964e002c46 added og filc color to accents 2023-06-07 20:50:45 +02:00
Márton Kiss
d3318e10ab fixed download counter in readme 2023-06-07 20:22:41 +02:00
Kima
4c43369d59 updated version string 2023-06-07 19:22:55 +02:00
Kima
176243b881 started uwu mode 2023-06-06 21:46:10 +02:00
Kima
ed02a340d0 ok 2023-06-06 21:11:52 +02:00
Kima
2877f4fc5c oke mostmar tenyleg fix 😭 vagy pedig mas baja 2023-06-06 21:03:30 +02:00
Kima
fceb3bf31a fixed settings screen version check 2023-06-06 20:58:33 +02:00
Kima
9883d081ff added back button to full-screen timetable 2023-06-06 20:27:37 +02:00
Kima
db5a9fb197 fixed translate bugs and subject name things 2023-06-06 19:18:56 +02:00
Kima
93438ce3df Merge branch 'master' of github.com:refilc/naplo 2023-06-05 21:21:48 +02:00
Kima
95bca64fb8 fixed quick actions colors 2023-06-05 21:21:45 +02:00
Pearoo
7821e10869 Update README.md 2023-06-01 10:58:53 +00:00
Pearoo
cede3c3129 Merge branch 'master' of https://github.com/refilc/naplo 2023-05-31 00:00:25 +02:00
Pearoo
528ee862b9 Update README.md - Squircle ikon 2023-05-30 21:28:25 +00:00
Pearoo
518932c260 Merge branch 'master' of https://github.com/refilc/naplo 2023-05-29 22:10:16 +02:00
Pearoo
281b9cf6c4 Update .gitignore 2023-05-29 13:31:03 +02:00
64 changed files with 742 additions and 238 deletions

25
.gitignore vendored
View File

@@ -25,3 +25,28 @@ doc/api/
*.js.map
*.txt
filcnaplo/linux/flutter/generated_plugin_registrant.cc
filcnaplo/linux/flutter/generated_plugin_registrant.h
filcnaplo/linux/flutter/generated_plugins.cmake
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/GeneratedPluginRegistrant.swift
filcnaplo/linux/flutter/generated_plugin_registrant.cc
filcnaplo/linux/flutter/generated_plugin_registrant.h
filcnaplo/linux/flutter/generated_plugins.cmake
filcnaplo/macos/Flutter/GeneratedPluginRegistrant.swift
.vscode/

2
.vscode/launch.json vendored
View File

@@ -27,7 +27,7 @@
"cwd": "filcnaplo",
"request": "launch",
"type": "dart",
"flutterMode": "release"
"flutterMode": "debug"
}
]
}

View File

@@ -1,11 +1,11 @@
<p align=center>
<img src="https://media.discordapp.net/attachments/1111727410677825596/1111790518964326510/reFilc_Logo2.png?width=671&height=671" width=150>
<img src="https://media.discordapp.net/attachments/1111727410677825596/1113217167513624646/reFilc_Logo_Squircle.png?width=671&height=671" width=150>
<h1 align=center><b>reFilc</b></h1>
</p>
#### Nem hivatalos e-napló alkalmazás az eKRÉTA rendszerhez - tanulóktól, tanulóknak.
[![Downloads](https://img.shields.io/github/downloads-pre/refilc/naplo/latest/total?color=%23&label=Downloads&logo=github&sort=semver)](https://github.com/refilc/naplo/releases) &nbsp; [![discord](https://img.shields.io/discord/1111649116020285532?label=Discord)](http://dc.refilc.hu)
[![Downloads](https://img.shields.io/github/downloads-pre/refilc/naplo/total?color=%23&label=Downloads&logo=github&sort=semver)](https://github.com/refilc/naplo/releases) &nbsp; [![discord](https://img.shields.io/discord/1111649116020285532?label=Discord)](http://dc.refilc.hu)
## Setup
@@ -37,6 +37,6 @@ Az összes (ugyan azon verzióhoz tartozó) contribution meg fog jelenni a relea
**annon:** a Filc napló készítője (ez az app a Filcen alapul)
**kima, chromium, peighter, mog, WolfY:** a fejlesztői csapat
**kima, mog, WolfY:** fejlesztők
**Regő, Pearoo:** weboldal design és community management

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome" />
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 916 B

After

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 735 KiB

View File

@@ -3,6 +3,8 @@
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array/>
<array>
<string>group.refilcnaplo.livecard</string>
</array>
</dict>
</plist>

View File

@@ -1,13 +1,14 @@
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "reFilc_Logo.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 KiB

View File

@@ -13,7 +13,7 @@ class LessonData {
var nextRoom: String
init?() {
let sharedDefault = UserDefaults(suiteName: "group.filcnaplo.livecard")!
let sharedDefault = UserDefaults(suiteName: "group.refilc.livecard")!
self.icon = sharedDefault.string(forKey: "icon")!
self.index = sharedDefault.string(forKey: "index")!

View File

@@ -3,6 +3,8 @@
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array/>
<array>
<string>group.refilcnaplo.livecard</string>
</array>
</dict>
</plist>

View File

@@ -68,8 +68,6 @@ struct LockScreenLiveActivityView: View {
.monospacedDigit()
.padding(.trailing, CGFloat(24))
}
.activitySystemActionForegroundColor(.teal)
.activityBackgroundTint(.teal)
}
}

View File

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

View File

@@ -13,7 +13,14 @@ import 'package:flutter/foundation.dart';
import 'package:live_activities/live_activities.dart';
import 'package:filcnaplo_mobile_ui/pages/home/live_card/live_card.i18n.dart';
enum LiveCardState { empty, duringLesson, duringBreak, morning, afternoon, night }
enum LiveCardState {
empty,
duringLesson,
duringBreak,
morning,
afternoon,
night
}
class LiveCardProvider extends ChangeNotifier {
Lesson? currentLesson;
@@ -37,19 +44,22 @@ class LiveCardProvider extends ChangeNotifier {
required SettingsProvider settings,
}) : _timetable = timetable,
_settings = settings {
_liveActivitiesPlugin.init(appGroupId: "group.filcnaplo.livecard");
_liveActivitiesPlugin.init(appGroupId: "group.refilc.livecard");
_liveActivitiesPlugin.getAllActivitiesIds().then((value) {
_latestActivityId = value.isNotEmpty ? value.first : null;
});
_timer = Timer.periodic(const Duration(seconds: 1), (timer) => update());
_delay = settings.bellDelayEnabled ? Duration(seconds: settings.bellDelay) : Duration.zero;
_delay = settings.bellDelayEnabled
? Duration(seconds: settings.bellDelay)
: Duration.zero;
update();
}
@override
void dispose() {
_timer.cancel();
if (_latestActivityId != null && Platform.isIOS) _liveActivitiesPlugin.endActivity(_latestActivityId!);
if (_latestActivityId != null && Platform.isIOS)
_liveActivitiesPlugin.endActivity(_latestActivityId!);
super.dispose();
}
@@ -78,14 +88,25 @@ class LiveCardProvider extends ChangeNotifier {
switch (currentState) {
case LiveCardState.duringLesson:
return {
"icon": currentLesson != null ? SubjectIcon.resolveName(subject: currentLesson?.subject) : "book",
"index": currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "",
"title": currentLesson != null ? ShortSubject.resolve(subject: currentLesson?.subject).capital() : "",
"icon": currentLesson != null
? SubjectIcon.resolveName(subject: currentLesson?.subject)
: "book",
"index":
currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "",
"title": currentLesson != null
? ShortSubject.resolve(subject: currentLesson?.subject).capital()
: "",
"subtitle": currentLesson?.room.replaceAll("_", " ") ?? "",
"description": currentLesson?.description ?? "",
"startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(),
"endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(),
"nextSubject": nextLesson != null ? ShortSubject.resolve(subject: nextLesson?.subject).capital() : "",
"startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds)
.toString(),
"endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds)
.toString(),
"nextSubject": nextLesson != null
? ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "",
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
};
case LiveCardState.duringBreak:
@@ -101,10 +122,19 @@ class LiveCardProvider extends ChangeNotifier {
return {
"icon": iconFloorMap[diff] ?? "cup.and.saucer",
"title": "Szünet",
"description": "go $diff".i18n.fill([diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room]),
"startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(),
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(),
"nextSubject": (nextLesson != null ? ShortSubject.resolve(subject: nextLesson?.subject) : "").capital(),
"description": "go $diff".i18n.fill([
diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room
]),
"startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds)
.toString(),
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds)
.toString(),
"nextSubject": (nextLesson != null
? ShortSubject.resolve(subject: nextLesson?.subject)
: "")
.capital(),
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
"index": "",
"subtitle": "",
@@ -119,15 +149,25 @@ class LiveCardProvider extends ChangeNotifier {
final cmap = toMap();
if (!mapEquals(cmap, _lastActivity)) {
_lastActivity = cmap;
if (_lastActivity.isNotEmpty) {
if (_latestActivityId == null) {
_liveActivitiesPlugin.createActivity(_lastActivity).then((value) => _latestActivityId = value);
try {
if (_lastActivity.isNotEmpty) {
if (_latestActivityId == null) {
_liveActivitiesPlugin
.createActivity(_lastActivity)
.then((value) => _latestActivityId = value);
} else {
_liveActivitiesPlugin.updateActivity(
_latestActivityId!, _lastActivity);
}
} else {
_liveActivitiesPlugin.updateActivity(_latestActivityId!, _lastActivity);
if (_latestActivityId != null) {
_liveActivitiesPlugin.endActivity(_latestActivityId!);
}
}
} catch (e) {
if (kDebugMode) {
print('ERROR: Unable to create or update iOS LiveCard!');
}
} else {
if (_latestActivityId != null) _liveActivitiesPlugin.endActivity(_latestActivityId!);
}
}
}
@@ -139,19 +179,28 @@ class LiveCardProvider extends ChangeNotifier {
today = _today(_timetable);
}
_delay = _settings.bellDelayEnabled ? Duration(seconds: _settings.bellDelay) : Duration.zero;
_delay = _settings.bellDelayEnabled
? Duration(seconds: _settings.bellDelay)
: Duration.zero;
final now = _now().add(_delay);
// Filter cancelled lessons #20
// Filter label lessons #128
today = today.where((lesson) => lesson.status?.name != "Elmaradt" && lesson.subject.id != '' && !lesson.isEmpty).toList();
today = today
.where((lesson) =>
lesson.status?.name != "Elmaradt" &&
lesson.subject.id != '' &&
!lesson.isEmpty)
.toList();
if (today.isNotEmpty) {
// sort
today.sort((a, b) => a.start.compareTo(b.start));
final _lesson = today.firstWhere((l) => l.start.isBefore(now) && l.end.isAfter(now), orElse: () => Lesson.fromJson({}));
final _lesson = today.firstWhere(
(l) => l.start.isBefore(now) && l.end.isAfter(now),
orElse: () => Lesson.fromJson({}));
if (_lesson.start.year != 0) {
currentLesson = _lesson;
@@ -159,7 +208,8 @@ class LiveCardProvider extends ChangeNotifier {
currentLesson = null;
}
final _next = today.firstWhere((l) => l.start.isAfter(now), orElse: () => Lesson.fromJson({}));
final _next = today.firstWhere((l) => l.start.isAfter(now),
orElse: () => Lesson.fromJson({}));
nextLessons = today.where((l) => l.start.isAfter(now)).toList();
if (_next.start.year != 0) {
@@ -168,7 +218,8 @@ class LiveCardProvider extends ChangeNotifier {
nextLesson = null;
}
final _prev = today.lastWhere((l) => l.end.isBefore(now), orElse: () => Lesson.fromJson({}));
final _prev = today.lastWhere((l) => l.end.isBefore(now),
orElse: () => Lesson.fromJson({}));
if (_prev.start.year != 0) {
prevLesson = _prev;
@@ -198,7 +249,10 @@ class LiveCardProvider extends ChangeNotifier {
Duration get delay => _delay;
bool _sameDate(DateTime a, DateTime b) => (a.year == b.year && a.month == b.month && a.day == b.day);
bool _sameDate(DateTime a, DateTime b) =>
(a.year == b.year && a.month == b.month && a.day == b.day);
List<Lesson> _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? []).where((l) => _sameDate(l.date, _now())).toList();
List<Lesson> _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? [])
.where((l) => _sameDate(l.date, _now()))
.toList();
}

View File

@@ -11,6 +11,7 @@ import 'package:filcnaplo/models/config.dart';
import 'package:filcnaplo/theme/observer.dart';
import 'package:filcnaplo/theme/theme.dart';
import 'package:filcnaplo_kreta_api/client/client.dart';
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
@@ -22,13 +23,18 @@ import 'package:provider/provider.dart';
import 'package:filcnaplo_mobile_ui/common/system_chrome.dart' as mobile;
import 'package:filcnaplo_mobile_ui/screens/login/login_route.dart' as mobile;
import 'package:filcnaplo_mobile_ui/screens/login/login_screen.dart' as mobile;
import 'package:filcnaplo_mobile_ui/screens/navigation/navigation_screen.dart' as mobile;
import 'package:filcnaplo_mobile_ui/screens/settings/settings_route.dart' as mobile;
import 'package:filcnaplo_mobile_ui/screens/settings/settings_screen.dart' as mobile;
import 'package:filcnaplo_mobile_ui/screens/navigation/navigation_screen.dart'
as mobile;
import 'package:filcnaplo_mobile_ui/screens/settings/settings_route.dart'
as mobile;
import 'package:filcnaplo_mobile_ui/screens/settings/settings_screen.dart'
as mobile;
// Desktop UI
import 'package:filcnaplo_desktop_ui/screens/navigation/navigation_screen.dart' as desktop;
import 'package:filcnaplo_desktop_ui/screens/login/login_screen.dart' as desktop;
import 'package:filcnaplo_desktop_ui/screens/navigation/navigation_screen.dart'
as desktop;
import 'package:filcnaplo_desktop_ui/screens/login/login_screen.dart'
as desktop;
import 'package:filcnaplo_desktop_ui/screens/login/login_route.dart' as desktop;
// Providers
@@ -36,7 +42,6 @@ import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
import 'package:filcnaplo_kreta_api/providers/event_provider.dart';
import 'package:filcnaplo_kreta_api/providers/exam_provider.dart';
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
import 'package:filcnaplo_kreta_api/providers/homework_provider.dart';
import 'package:filcnaplo_kreta_api/providers/message_provider.dart';
import 'package:filcnaplo_kreta_api/providers/note_provider.dart';
@@ -52,7 +57,12 @@ class App extends StatelessWidget {
final UserProvider user;
final DatabaseProvider database;
const App({Key? key, required this.database, required this.settings, required this.user}) : super(key: key);
const App(
{Key? key,
required this.database,
required this.settings,
required this.user})
: super(key: key);
@override
Widget build(BuildContext context) {
@@ -65,7 +75,8 @@ class App extends StatelessWidget {
final status = StatusProvider();
final kreta = KretaClient(user: user, settings: settings, status: status);
final timetable = TimetableProvider(user: user, database: database, kreta: kreta);
final timetable =
TimetableProvider(user: user, database: database, kreta: kreta);
final premium = PremiumProvider(settings: settings);
WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -83,23 +94,44 @@ class App extends StatelessWidget {
ChangeNotifierProvider<StatusProvider>(create: (_) => status),
Provider<KretaClient>(create: (_) => kreta),
Provider<DatabaseProvider>(create: (context) => database),
ChangeNotifierProvider<ThemeModeObserver>(create: (context) => ThemeModeObserver(initialTheme: settings.theme)),
ChangeNotifierProvider<NewsProvider>(create: (context) => NewsProvider(context: context)),
ChangeNotifierProvider<UpdateProvider>(create: (context) => UpdateProvider(context: context)),
ChangeNotifierProvider<ThemeModeObserver>(
create: (context) =>
ThemeModeObserver(initialTheme: settings.theme)),
ChangeNotifierProvider<NewsProvider>(
create: (context) => NewsProvider(context: context)),
ChangeNotifierProvider<UpdateProvider>(
create: (context) => UpdateProvider(context: context)),
// User data providers
ChangeNotifierProvider<GradeProvider>(create: (_) => GradeProvider(settings: settings, user: user, database: database, kreta: kreta)),
ChangeNotifierProvider<GradeProvider>(
create: (_) => GradeProvider(
settings: settings,
user: user,
database: database,
kreta: kreta)),
ChangeNotifierProvider<TimetableProvider>(create: (_) => timetable),
ChangeNotifierProvider<ExamProvider>(create: (context) => ExamProvider(context: context)),
ChangeNotifierProvider<HomeworkProvider>(create: (context) => HomeworkProvider(context: context)),
ChangeNotifierProvider<MessageProvider>(create: (context) => MessageProvider(context: context)),
ChangeNotifierProvider<NoteProvider>(create: (context) => NoteProvider(context: context)),
ChangeNotifierProvider<EventProvider>(create: (context) => EventProvider(context: context)),
ChangeNotifierProvider<AbsenceProvider>(create: (context) => AbsenceProvider(context: context)),
ChangeNotifierProvider<ExamProvider>(
create: (context) => ExamProvider(context: context)),
ChangeNotifierProvider<HomeworkProvider>(
create: (context) => HomeworkProvider(context: context)),
ChangeNotifierProvider<MessageProvider>(
create: (context) => MessageProvider(context: context)),
ChangeNotifierProvider<NoteProvider>(
create: (context) => NoteProvider(context: context)),
ChangeNotifierProvider<EventProvider>(
create: (context) => EventProvider(context: context)),
ChangeNotifierProvider<AbsenceProvider>(
create: (context) => AbsenceProvider(context: context)),
ChangeNotifierProvider<GradeCalculatorProvider>(
create: (_) => GradeCalculatorProvider(settings: settings, user: user, database: database, kreta: kreta)),
ChangeNotifierProvider<LiveCardProvider>(create: (context) => LiveCardProvider(timetable: timetable, settings: settings))
create: (_) => GradeCalculatorProvider(
settings: settings,
user: user,
database: database,
kreta: kreta)),
ChangeNotifierProvider<LiveCardProvider>(
create: (context) =>
LiveCardProvider(timetable: timetable, settings: settings))
],
child: Consumer<ThemeModeObserver>(
builder: (context, themeMode, child) {
@@ -110,12 +142,15 @@ class App extends StatelessWidget {
return MaterialApp(
builder: (context, child) {
// Limit font size scaling to 1.0
double textScaleFactor = min(MediaQuery.of(context).textScaleFactor, 1.0);
double textScaleFactor =
min(MediaQuery.of(context).textScaleFactor, 1.0);
return I18n(
initialLocale: Locale(settings.language, settings.language.toUpperCase()),
initialLocale: Locale(
settings.language, settings.language.toUpperCase()),
child: MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor),
data: MediaQuery.of(context)
.copyWith(textScaleFactor: textScaleFactor),
child: child ?? Container(),
),
);
@@ -148,7 +183,8 @@ class App extends StatelessWidget {
return locale;
},
onGenerateRoute: (settings) => rootNavigator(settings),
initialRoute: user.getUsers().isNotEmpty ? "navigation" : "login",
initialRoute:
user.getUsers().isNotEmpty ? "navigation" : "login",
);
},
);
@@ -162,7 +198,8 @@ class App extends StatelessWidget {
if (Platform.isAndroid || Platform.isIOS) {
switch (route.name) {
case "login_back":
return CupertinoPageRoute(builder: (context) => const mobile.LoginScreen(back: true));
return CupertinoPageRoute(
builder: (context) => const mobile.LoginScreen(back: true));
case "login":
return _rootRoute(const mobile.LoginScreen());
case "navigation":
@@ -175,7 +212,8 @@ class App extends StatelessWidget {
} else if (Platform.isWindows || Platform.isMacOS || Platform.isLinux) {
switch (route.name) {
case "login_back":
return CupertinoPageRoute(builder: (context) => const desktop.LoginScreen(back: true));
return CupertinoPageRoute(
builder: (context) => const desktop.LoginScreen(back: true));
case "login":
return _rootRoute(const desktop.LoginScreen());
case "navigation":

View File

@@ -10,6 +10,8 @@ enum AccentColor {
red,
pink,
purple,
none,
ogfilc,
adaptive,
custom
}
@@ -24,6 +26,8 @@ Map<AccentColor, Color> accentColorMap = {
AccentColor.red: Colors.red.shade300,
AccentColor.pink: Colors.pink.shade300,
AccentColor.purple: Colors.purple.shade300,
//AccentColor.none: Colors.black,
AccentColor.ogfilc: const Color(0xff20AC9B),
AccentColor.adaptive: const Color(0xFF3D7BF4),
AccentColor.custom: const Color(0xFF3D7BF4),
};

View File

@@ -15,7 +15,8 @@ import 'package:provider/provider.dart';
import 'lesson_tile.i18n.dart';
class LessonTile extends StatelessWidget {
const LessonTile(this.lesson, {Key? key, this.onTap, this.swapDesc = false}) : super(key: key);
const LessonTile(this.lesson, {Key? key, this.onTap, this.swapDesc = false})
: super(key: key);
final Lesson lesson;
final bool swapDesc;
@@ -34,7 +35,9 @@ class LessonTile extends StatelessWidget {
if (RegExp(r'\d').hasMatch(lesson.lessonIndex)) lessonIndexTrailing = ".";
var now = DateTime.now();
if (lesson.start.isBefore(now) && lesson.end.isAfter(now) && lesson.status?.name != "Elmaradt") {
if (lesson.start.isBefore(now) &&
lesson.end.isAfter(now) &&
lesson.status?.name != "Elmaradt") {
fillLeading = true;
}
@@ -62,7 +65,8 @@ class LessonTile extends StatelessWidget {
if (lesson.homeworkId != "") {
Homework homework = Provider.of<HomeworkProvider>(context, listen: false)
.homework
.firstWhere((h) => h.id == lesson.homeworkId, orElse: () => Homework.fromJson({}));
.firstWhere((h) => h.id == lesson.homeworkId,
orElse: () => Homework.fromJson({}));
if (homework.id != "") {
subtiles.add(LessonSubtile(
@@ -74,11 +78,16 @@ class LessonTile extends StatelessWidget {
}
if (lesson.exam != "") {
Exam exam = Provider.of<ExamProvider>(context, listen: false).exams.firstWhere((t) => t.id == lesson.exam, orElse: () => Exam.fromJson({}));
Exam exam = Provider.of<ExamProvider>(context, listen: false)
.exams
.firstWhere((t) => t.id == lesson.exam,
orElse: () => Exam.fromJson({}));
if (exam.id != "") {
subtiles.add(LessonSubtile(
type: LessonSubtileType.exam,
title: exam.description != "" ? exam.description : exam.mode?.description ?? "exam".i18n,
title: exam.description != ""
? exam.description
: exam.mode?.description ?? "exam".i18n,
onPressed: () => ExamView.show(exam, context: context),
));
}
@@ -87,7 +96,10 @@ class LessonTile extends StatelessWidget {
String description = '';
String room = '';
final cleanDesc = lesson.description.specialChars().toLowerCase().replaceAll(lesson.subject.name.specialChars().toLowerCase(), '');
final cleanDesc = lesson.description
.specialChars()
.toLowerCase()
.replaceAll(lesson.subject.name.specialChars().toLowerCase(), '');
if (!swapDesc) {
if (cleanDesc != "") {
@@ -131,16 +143,23 @@ class LessonTile extends StatelessWidget {
// onLongPress: kDebugMode ? () => log(jsonEncode(lesson.json)) : null,
visualDensity: VisualDensity.compact,
contentPadding: const EdgeInsets.symmetric(horizontal: 4.0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0)),
title: Text(
!lesson.isEmpty ? lesson.subject.renamedTo ?? lesson.subject.name.capital() : "empty".i18n,
!lesson.isEmpty
? lesson.subject.renamedTo ??
lesson.subject.name.capital()
: "empty".i18n,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 15.5,
color: AppColors.of(context).text.withOpacity(!lesson.isEmpty ? 1.0 : 0.5),
fontStyle: lesson.subject.isRenamed ? FontStyle.italic : null),
color: AppColors.of(context)
.text
.withOpacity(!lesson.isEmpty ? 1.0 : 0.5),
fontStyle:
lesson.subject.isRenamed ? FontStyle.italic : null),
),
subtitle: description != ""
? Text(
@@ -175,12 +194,20 @@ class LessonTile extends StatelessWidget {
offset: const Offset(-12.0, -2.0),
child: Container(
decoration: BoxDecoration(
color: fillLeading ? Theme.of(context).colorScheme.secondary.withOpacity(.3) : const Color(0x00000000),
color: fillLeading
? Theme.of(context)
.colorScheme
.secondary
.withOpacity(.3)
: const Color(0x00000000),
borderRadius: BorderRadius.circular(12.0),
boxShadow: [
if (fillLeading)
BoxShadow(
color: Theme.of(context).colorScheme.secondary.withOpacity(.25),
color: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.25),
blurRadius: 6.0,
)
],
@@ -210,7 +237,9 @@ class LessonTile extends StatelessWidget {
maxLines: 2,
style: TextStyle(
fontWeight: FontWeight.w500,
color: AppColors.of(context).text.withOpacity(.75),
color: AppColors.of(context)
.text
.withOpacity(.75),
),
),
),
@@ -225,7 +254,9 @@ class LessonTile extends StatelessWidget {
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.w500,
color: AppColors.of(context).text.withOpacity(.9),
color: AppColors.of(context)
.text
.withOpacity(.9),
),
),
],
@@ -249,7 +280,9 @@ class LessonTile extends StatelessWidget {
enum LessonSubtileType { homework, exam, absence }
class LessonSubtile extends StatelessWidget {
const LessonSubtile({Key? key, this.onPressed, required this.title, required this.type}) : super(key: key);
const LessonSubtile(
{Key? key, this.onPressed, required this.title, required this.type})
: super(key: key);
final Function()? onPressed;
final String title;
@@ -285,7 +318,8 @@ class LessonSubtile extends StatelessWidget {
Center(
child: SizedBox(
width: 30.0,
child: Icon(icon, color: iconColor.withOpacity(.75), size: 20.0),
child:
Icon(icon, color: iconColor.withOpacity(.75), size: 20.0),
),
),
Expanded(
@@ -295,7 +329,9 @@ class LessonSubtile extends StatelessWidget {
title.escapeHtml(),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontWeight: FontWeight.w500, color: AppColors.of(context).text.withOpacity(.65)),
style: TextStyle(
fontWeight: FontWeight.w500,
color: AppColors.of(context).text.withOpacity(.65)),
),
),
),

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.0.1+205
version: 4.0.3+210
environment:
sdk: ">=2.17.0 <3.0.0"
@@ -148,12 +148,12 @@ flutter:
style: italic
flutter_launcher_icons:
image_path: assets/icons/ic_launcher.png
image_path: assets/icons/ic_android.png
android: true
adaptive_icon_background: "#3D7BF4"
adaptive_icon_foreground: assets/icons/ic_launcher_foreground.png
ios: true
remove_alpha_ios: true
adaptive_icon_foreground: assets/icons/ic_android.png
ios: false
remove_alpha_ios: false
flutter_native_splash:
color: "#3D7BF4"

View File

@@ -169,7 +169,7 @@ class KretaClient {
Map? loginRes = await postAPI(KretaAPI.login,
headers: headers,
body: User.loginBody(
username: loginUser.username,
username: loginUser.username.replaceAll(' ', '') + ' ',
password: loginUser.password,
instituteCode: loginUser.instituteCode,
));

View File

@@ -1,5 +1,7 @@
import 'package:filcnaplo_kreta_api/client/api.dart';
import 'subject.dart';
class Homework {
Map? json;
DateTime date;
@@ -9,7 +11,7 @@ class Homework {
bool homeworkEnabled;
String teacher;
String content;
String subjectName;
Subject subject;
String group;
List<HomeworkAttachment> attachments;
String id;
@@ -22,7 +24,7 @@ class Homework {
required this.homeworkEnabled,
required this.teacher,
required this.content,
required this.subjectName,
required this.subject,
required this.group,
required this.attachments,
required this.id,
@@ -32,16 +34,27 @@ class Homework {
factory Homework.fromJson(Map json) {
return Homework(
id: json["Uid"] ?? "",
date: json["RogzitesIdopontja"] != null ? DateTime.parse(json["RogzitesIdopontja"]).toLocal() : DateTime(0),
lessonDate: json["FeladasDatuma"] != null ? DateTime.parse(json["FeladasDatuma"]).toLocal() : DateTime(0),
deadline: json["HataridoDatuma"] != null ? DateTime.parse(json["HataridoDatuma"]).toLocal() : DateTime(0),
date: json["RogzitesIdopontja"] != null
? DateTime.parse(json["RogzitesIdopontja"]).toLocal()
: DateTime(0),
lessonDate: json["FeladasDatuma"] != null
? DateTime.parse(json["FeladasDatuma"]).toLocal()
: DateTime(0),
deadline: json["HataridoDatuma"] != null
? DateTime.parse(json["HataridoDatuma"]).toLocal()
: DateTime(0),
byTeacher: json["IsTanarRogzitette"] ?? true,
homeworkEnabled: json["IsTanuloHaziFeladatEnabled"] ?? false,
teacher: (json["RogzitoTanarNeve"] ?? "").trim(),
content: (json["Szoveg"] ?? "").trim(),
subjectName: json["TantargyNeve"] ?? "",
group: json["OsztalyCsoport"] != null ? json["OsztalyCsoport"]["Uid"] ?? "" : "",
attachments: ((json["Csatolmanyok"] ?? []) as List).cast<Map>().map((Map json) => HomeworkAttachment.fromJson(json)).toList(),
subject: Subject.fromJson(json["Tantargy"] ?? {}),
group: json["OsztalyCsoport"] != null
? json["OsztalyCsoport"]["Uid"] ?? ""
: "",
attachments: ((json["Csatolmanyok"] ?? []) as List)
.cast<Map>()
.map((Map json) => HomeworkAttachment.fromJson(json))
.toList(),
json: json,
);
}
@@ -53,7 +66,8 @@ class HomeworkAttachment {
String name;
String type;
HomeworkAttachment({required this.id, this.name = "", this.type = "", this.json});
HomeworkAttachment(
{required this.id, this.name = "", this.type = "", this.json});
factory HomeworkAttachment.fromJson(Map json) {
return HomeworkAttachment(
@@ -64,6 +78,8 @@ class HomeworkAttachment {
);
}
String downloadUrl(String iss) => KretaAPI.downloadHomeworkAttachments(iss, id, type);
bool get isImage => name.endsWith(".jpg") || name.endsWith(".jpeg") || name.endsWith(".png");
String downloadUrl(String iss) =>
KretaAPI.downloadHomeworkAttachments(iss, id, type);
bool get isImage =>
name.endsWith(".jpg") || name.endsWith(".jpeg") || name.endsWith(".png");
}

View File

@@ -6,6 +6,7 @@ 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 GradeProvider with ChangeNotifier {
@@ -21,7 +22,8 @@ class GradeProvider with ChangeNotifier {
// Public
List<Grade> get grades => _grades;
DateTime get lastSeenDate => _settings.gradeOpeningFun ? _lastSeen : DateTime(3000);
DateTime get lastSeenDate =>
_settings.gradeOpeningFun ? _lastSeen : DateTime(3000);
String get groups => _groups;
List<GroupAverage> get groupAverages => _groupAvg;
@@ -65,7 +67,9 @@ class GradeProvider with ChangeNotifier {
_groupAvg = await userQuery.getGroupAverages(userId: userId);
notifyListeners();
DateTime lastSeenDB = await userQuery.lastSeenGrade(userId: userId);
if (lastSeenDB.millisecondsSinceEpoch == 0 || lastSeenDB.year == 0 || !_settings.gradeOpeningFun) {
if (lastSeenDB.millisecondsSinceEpoch == 0 ||
lastSeenDB.year == 0 ||
!_settings.gradeOpeningFun) {
_lastSeen = DateTime.now();
await seenAll();
} else {
@@ -77,13 +81,24 @@ class GradeProvider with ChangeNotifier {
// 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> renamedSubjects = _settings.renamedSubjectsEnabled
? await _database.userQuery.renamedSubjects(userId: _user.user!.id)
: {};
for (Grade grade in _grades) {
grade.subject.renamedTo = renamedSubjects.isNotEmpty ? renamedSubjects[grade.subject.id] : null;
grade.value.value = _settings.goodStudent ? 5 : grade.json!["SzamErtek"] ?? 0;
grade.value.valueName = _settings.goodStudent ? "Példás" : grade.json!["SzovegesErtek"] ?? "";
grade.value.shortName = _settings.goodStudent ? "Példás" : grade.json!["SzovegesErtekelesRovidNev"] ?? "";
grade.subject.renamedTo =
renamedSubjects.isNotEmpty ? renamedSubjects[grade.subject.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"]}'.i18n;
}
notifyListeners();
@@ -102,12 +117,16 @@ class GradeProvider with ChangeNotifier {
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}";
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();
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);
}

View File

@@ -0,0 +1,33 @@
import 'package:i18n_extension/i18n_extension.dart';
extension Localization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {
"Elégtelen": "Fail",
"Elégséges": "Warning but passing",
"Közepes": "Passed",
"": "Good",
"Jeles": "Excellent"
},
"hu_hu": {
"Elégtelen": "Elégtelen",
"Elégséges": "Elégséges",
"Közepes": "Közepes",
"": "",
"Jeles": "Jeles"
},
"de_de": {
"Elégtelen": "Ungenügend",
"Elégséges": "Mangelhaft",
"Közepes": "Ausreichend",
"": "Befriedigend",
"Jeles": "Gut"
},
};
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

@@ -1,5 +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/user.dart';
import 'package:filcnaplo_kreta_api/client/api.dart';
import 'package:filcnaplo_kreta_api/client/client.dart';
@@ -8,6 +9,12 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class HomeworkProvider with ChangeNotifier {
// Private
late final SettingsProvider _settings;
late final UserProvider _user;
late final DatabaseProvider _database;
// Public
late List<Homework> _homework;
late BuildContext _context;
List<Homework> get homework => _homework;
@@ -27,27 +34,56 @@ class HomeworkProvider with ChangeNotifier {
// Load homework from the database
if (userId != null) {
var dbHomework = await Provider.of<DatabaseProvider>(_context, listen: false).userQuery.getHomework(userId: userId);
var dbHomework =
await Provider.of<DatabaseProvider>(_context, listen: false)
.userQuery
.getHomework(userId: userId);
_homework = dbHomework;
notifyListeners();
await convertBySettings();
}
}
Future<void> convertBySettings() async {
Map<String, String> renamedSubjects =
(await _database.query.getSettings(_database)).renamedSubjectsEnabled
? await _database.userQuery.renamedSubjects(userId: _user.id!)
: {};
for (Homework homework in _homework) {
homework.subject.renamedTo = renamedSubjects.isNotEmpty
? renamedSubjects[homework.subject.id]
: null;
}
notifyListeners();
}
// Fetches Homework from the Kreta API then stores them in the database
Future<void> fetch({DateTime? from, bool db = true}) async {
User? user = Provider.of<UserProvider>(_context, listen: false).user;
if (user == null) throw "Cannot fetch Homework for User null";
String iss = user.instituteCode;
List? homeworkJson = await Provider.of<KretaClient>(_context, listen: false).getAPI(KretaAPI.homework(iss, start: from));
List? homeworkJson = await Provider.of<KretaClient>(_context, listen: false)
.getAPI(KretaAPI.homework(iss, start: from));
if (homeworkJson == null) throw "Cannot fetch Homework for User ${user.id}";
List<Homework> homework = [];
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"]));
if (e != null) homework.add(Homework.fromJson(e));
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)
: {};
if (e != null) {
Homework hw = Homework.fromJson(e);
hw.subject.renamedTo =
renamedSubjects.isNotEmpty ? renamedSubjects[hw.subject.id] : null;
homework.add(hw);
}
});
if (homework.isEmpty && _homework.isEmpty) return;
if (db) await store(homework);
@@ -60,6 +96,8 @@ class HomeworkProvider with ChangeNotifier {
User? user = Provider.of<UserProvider>(_context, listen: false).user;
if (user == null) throw "Cannot store Homework for User null";
String userId = user.id;
await Provider.of<DatabaseProvider>(_context, listen: false).userStore.storeHomework(homework, userId: userId);
await Provider.of<DatabaseProvider>(_context, listen: false)
.userStore
.storeHomework(homework, userId: userId);
}
}

View File

@@ -6,7 +6,9 @@ import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
class HomeworkTile extends StatelessWidget {
const HomeworkTile(this.homework, {Key? key, this.onTap, this.padding, this.censored = false}) : super(key: key);
const HomeworkTile(this.homework,
{Key? key, this.onTap, this.padding, this.censored = false})
: super(key: key);
final Homework homework;
final void Function()? onTap;
@@ -24,7 +26,8 @@ class HomeworkTile extends StatelessWidget {
visualDensity: VisualDensity.compact,
contentPadding: const EdgeInsets.only(left: 8.0, right: 12.0),
onTap: onTap,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)),
leading: SizedBox(
width: 44,
height: 44,
@@ -38,7 +41,8 @@ class HomeworkTile extends StatelessWidget {
: Padding(
padding: const EdgeInsets.only(top: 2.0),
child: Icon(
SubjectIcon.resolveVariant(subjectName: homework.subjectName, context: context),
SubjectIcon.resolveVariant(
subjectName: homework.subject.name, context: context),
size: 28.0,
color: AppColors.of(context).text.withOpacity(.75),
),
@@ -58,7 +62,7 @@ class HomeworkTile extends StatelessWidget {
],
)
: Text(
homework.subjectName.capital(),
homework.subject.renamedTo ?? homework.subject.name.capital(),
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontWeight: FontWeight.w600),

View File

@@ -40,11 +40,12 @@ class HomeworkView extends StatelessWidget {
// Header
ListTile(
leading: Icon(
SubjectIcon.resolveVariant(subjectName: homework.subjectName, context: context),
SubjectIcon.resolveVariant(
subjectName: homework.subject.name, context: context),
size: 36.0,
),
title: Text(
homework.subjectName.capital(),
homework.subject.renamedTo ?? homework.subject.name.capital(),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontWeight: FontWeight.w600),
@@ -62,9 +63,13 @@ class HomeworkView extends StatelessWidget {
),
// Details
if (homework.deadline.year != 0) Detail(title: "deadline".i18n, description: homework.deadline.format(context)),
if (homework.deadline.year != 0)
Detail(
title: "deadline".i18n,
description: homework.deadline.format(context)),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18.0, vertical: 6.0),
padding:
const EdgeInsets.symmetric(horizontal: 18.0, vertical: 6.0),
child: SelectableLinkify(
text: homework.content.escapeHtml(),
options: const LinkifyOptions(looseUrl: true, removeWww: true),

View File

@@ -182,11 +182,15 @@ class _AbsencesPageState extends State<AbsencesPage>
fontWeight: FontWeight.bold),
),
),
bottom: FilterBar(items: [
Tab(text: "Absences".i18n),
Tab(text: "Delays".i18n),
Tab(text: "Misses".i18n),
], controller: _tabController, disableFading: true),
bottom: FilterBar(
items: [
Tab(text: "Absences".i18n),
Tab(text: "Delays".i18n),
Tab(text: "Misses".i18n),
],
controller: _tabController,
disableFading: true,
),
),
],
body: TabBarView(

View File

@@ -20,9 +20,6 @@ import 'package:filcnaplo_mobile_ui/pages/grades/calculator/grade_calculator_pro
import 'package:filcnaplo_mobile_ui/pages/grades/grades_count.dart';
import 'package:filcnaplo_mobile_ui/pages/grades/graph.dart';
import 'package:filcnaplo_mobile_ui/pages/grades/subject_grades_container.dart';
import 'package:filcnaplo_premium/models/premium_scopes.dart';
import 'package:filcnaplo_premium/providers/premium_provider.dart';
import 'package:filcnaplo_premium/ui/mobile/premium/upsell.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
@@ -75,8 +72,9 @@ class _GradeSubjectViewState extends State<GradeSubjectView> {
final gradeDates = subjectGrades.map((e) => e.date.millisecondsSinceEpoch);
final maxGradeDate = gradeDates.fold(0, max);
final minGradeDate = gradeDates.fold(0, min);
if (maxGradeDate - minGradeDate < const Duration(days: 5).inMilliseconds)
if (maxGradeDate - minGradeDate < const Duration(days: 5).inMilliseconds) {
return false; // naplo/#78
}
return subjectGrades.where((e) => e.type == GradeType.midYear).length > 1;
}
@@ -214,25 +212,25 @@ class _GradeSubjectViewState extends State<GradeSubjectView> {
gradeCalc(context);
},
),
FloatingActionButton.small(
child: const Icon(FeatherIcons.flag, size: 20.0),
backgroundColor: Theme.of(context).colorScheme.secondary,
onPressed: () {
if (!Provider.of<PremiumProvider>(context, listen: false)
.hasScope(PremiumScopes.goalPlanner)) {
PremiumLockedFeatureUpsell.show(
context: context, feature: PremiumFeature.goalplanner);
return;
}
// FloatingActionButton.small(
// child: const Icon(FeatherIcons.flag, size: 20.0),
// backgroundColor: Theme.of(context).colorScheme.secondary,
// onPressed: () {
// if (!Provider.of<PremiumProvider>(context, listen: false)
// .hasScope(PremiumScopes.goalPlanner)) {
// PremiumLockedFeatureUpsell.show(
// context: context, feature: PremiumFeature.goalplanner);
// return;
// }
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Hamarosan...")));
// ScaffoldMessenger.of(context).showSnackBar(
// const SnackBar(content: Text("Hamarosan...")));
//Navigator.of(context).push(CupertinoPageRoute(
//builder: (context) => PremiumGoalplannerNewGoalScreen(
// subject: widget.subject)));
},
),
// Navigator.of(context).push(CupertinoPageRoute(
// builder: (context) => PremiumGoalplannerNewGoalScreen(
// subject: widget.subject)));
// },
// ),
],
),
),

View File

@@ -270,6 +270,7 @@ class _GradeGraphState extends State<GradeGraph> {
tData.sort((a, b) => a.writeDate.compareTo(b.writeDate));
return tData.first.writeDate.add(const Duration(days: 120)).isBefore(tData.last.writeDate) ? 2.0 : 1.0;
}(),
checkToShowTitle: (double minValue, double maxValue, SideTitles sideTitles, double appliedInterval, double value) { if (value == maxValue || value == minValue) return false; return true; },
),
leftTitles: SideTitles(
showTitles: true,

View File

@@ -249,6 +249,7 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
Tab(text: "Absences".i18n),
],
controller: _tabController,
disableFading: true,
onTap: (i) async {
int selectedPage =
_pageController.page!.round();

View File

@@ -11,7 +11,7 @@ extension Localization on String {
"happybirthday": "🎂 Happy birthday, %s!",
"merryxmas": "🎄 Merry Christmas, %s!",
"happynewyear": "🎉 Happy New Year, %s!",
"refilcopen": "🎈 Welcome in reFilc, %s!",
"refilcopen": "🎈 reFilc is 1 year old, %s!",
"empty": "Nothing to see here.",
"All": "All",
"Grades": "Grades",
@@ -30,7 +30,7 @@ extension Localization on String {
"happybirthday": "🎂 Boldog születésnapot, %s!",
"merryxmas": "🎄 Boldog Karácsonyt, %s!",
"happynewyear": "🎉 Boldog új évet, %s!",
"refilcopen": "🎈 Üdv a reFilc-ben, %s!",
"refilcopen": "🎈 1 éves a reFilc, %s!",
"empty": "Nincs itt semmi látnivaló.",
"All": "Összes",
"Grades": "Jegyek",
@@ -49,7 +49,7 @@ extension Localization on String {
"happybirthday": "🎂 Alles Gute zum Geburtstag, %s!",
"merryxmas": "🎄 Frohe Weihnachten, %s!",
"happynewyear": "🎉 Frohes neues Jahr, %s!",
"refilcopen": "🎈 Willkommen bei reFilc, %s!",
"refilcopen": "🎈 reFilc ist 1 Jahr alt, %s!",
"empty": "Hier gibt es nichts zu sehen.",
"All": "Alles",
"Grades": "Noten",

View File

@@ -90,12 +90,16 @@ class _MessagesPageState extends State<MessagesPage>
fontWeight: FontWeight.bold),
),
),
bottom: FilterBar(items: [
Tab(text: "Inbox".i18n),
Tab(text: "Sent".i18n),
Tab(text: "Trash".i18n),
Tab(text: "Draft".i18n),
], controller: tabController),
bottom: FilterBar(
items: [
Tab(text: "Inbox".i18n),
Tab(text: "Sent".i18n),
Tab(text: "Trash".i18n),
Tab(text: "Draft".i18n),
],
controller: tabController,
disableFading: true,
),
),
],
body: TabBarView(

View File

@@ -2,7 +2,8 @@ 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);
const SchoolInputTile({Key? key, required this.school, this.onTap})
: super(key: key);
final School school;
final Function()? onTap;

View File

@@ -173,8 +173,7 @@ class NavigationScreenState extends State<NavigationScreen>
@override
void didChangePlatformBrightness() {
if (settings.theme == ThemeMode.system) {
Brightness? brightness =
WidgetsBinding.instance.window.platformBrightness;
Brightness? brightness = MediaQuery.of(context).platformBrightness;
Provider.of<ThemeModeObserver>(context, listen: false).changeTheme(
brightness == Brightness.light ? ThemeMode.light : ThemeMode.dark);
}

View File

@@ -6,6 +6,7 @@ import 'package:filcnaplo_mobile_ui/common/panel/panel.dart';
import 'package:filcnaplo_mobile_ui/screens/news/news_tile.dart';
import 'package:filcnaplo/models/news.dart';
import 'package:filcnaplo_mobile_ui/screens/news/news_view.dart';
import 'package:filcnaplo_mobile_ui/screens/settings/settings_screen.i18n.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:filcnaplo/api/providers/news_provider.dart';
@@ -24,24 +25,28 @@ class NewsScreen extends StatelessWidget {
appBar: AppBar(
surfaceTintColor: Theme.of(context).scaffoldBackgroundColor,
leading: BackButton(color: AppColors.of(context).text),
title: Text("News", style: TextStyle(color: AppColors.of(context).text)),
title: Text("news".i18n,
style: TextStyle(color: AppColors.of(context).text)),
),
body: SafeArea(
child: RefreshIndicator(
onRefresh: () => newsProvider.fetch(),
child: ListView.builder(
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
itemCount: max(news.length, 1),
itemBuilder: (context, index) {
if (news.isNotEmpty) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0),
padding: const EdgeInsets.symmetric(
horizontal: 24.0, vertical: 12.0),
child: Panel(
child: Material(
type: MaterialType.transparency,
child: NewsTile(
news[index],
onTap: () => NewsView.show(news[index], context: context, force: true),
onTap: () => NewsView.show(news[index],
context: context, force: true),
),
),
),

View File

@@ -30,7 +30,11 @@ import 'package:filcnaplo/utils/format.dart';
import 'package:filcnaplo_premium/ui/mobile/settings/theme.dart';
class SettingsHelper {
static const Map<String, String> langMap = {"en": "🇬🇧 English", "hu": "🇭🇺 Magyar", "de": "🇩🇪 Deutsch"};
static const Map<String, String> langMap = {
"en": "🇬🇧 English",
"hu": "🇭🇺 Magyar",
"de": "🇩🇪 Deutsch"
};
static const Map<Pages, String> pageTitle = {
Pages.home: "home",
@@ -47,9 +51,11 @@ class SettingsHelper {
VibrationStrength.strong: "vstrong",
};
static Map<Pages, String> localizedPageTitles() => pageTitle.map((key, value) => MapEntry(key, ScreensLocalization(value).i18n));
static Map<Pages, String> localizedPageTitles() => pageTitle
.map((key, value) => MapEntry(key, ScreensLocalization(value).i18n));
static Map<VibrationStrength, String> localizedVibrationTitles() =>
vibrationTitle.map((key, value) => MapEntry(key, SettingsLocalization(value).i18n));
vibrationTitle
.map((key, value) => MapEntry(key, SettingsLocalization(value).i18n));
static void language(BuildContext context) {
showBottomSheetMenu(
@@ -58,7 +64,8 @@ class SettingsHelper {
String lang = langMap.keys.toList()[index];
return BottomSheetMenuItem(
onPressed: () {
Provider.of<SettingsProvider>(context, listen: false).update(language: lang);
Provider.of<SettingsProvider>(context, listen: false)
.update(language: lang);
I18n.of(context).locale = Locale(lang, lang.toUpperCase());
Navigator.of(context).maybePop();
if (Platform.isAndroid || Platform.isIOS) {
@@ -81,6 +88,19 @@ class SettingsHelper {
);
}
static void uwuMode(BuildContext context, value) {
final settings = Provider.of<SettingsProvider>(context, listen: false);
if (value) {
I18n.of(context).locale = const Locale('uw', 'UW');
} else {
I18n.of(context).locale =
Locale(settings.language, settings.language.toUpperCase());
}
if (Platform.isAndroid || Platform.isIOS) {
setupQuickActions();
}
}
static void iconPack(BuildContext context) {
final settings = Provider.of<SettingsProvider>(context, listen: false);
showBottomSheetMenu(
@@ -122,16 +142,20 @@ class SettingsHelper {
items: List.generate(Pages.values.length, (index) {
return BottomSheetMenuItem(
onPressed: () {
Provider.of<SettingsProvider>(context, listen: false).update(startPage: Pages.values[index]);
Provider.of<SettingsProvider>(context, listen: false)
.update(startPage: Pages.values[index]);
Navigator.of(context).maybePop();
},
title: Row(
children: [
Icon(pageIcons[Pages.values[index]], size: 20.0, color: Theme.of(context).colorScheme.secondary),
Icon(pageIcons[Pages.values[index]],
size: 20.0, color: Theme.of(context).colorScheme.secondary),
const SizedBox(width: 16.0),
Text(localizedPageTitles()[Pages.values[index]] ?? ""),
const Spacer(),
if (Pages.values[index] == Provider.of<SettingsProvider>(context, listen: false).startPage)
if (Pages.values[index] ==
Provider.of<SettingsProvider>(context, listen: false)
.startPage)
Icon(
Icons.check_circle,
color: Theme.of(context).colorScheme.secondary,
@@ -165,7 +189,8 @@ class SettingsHelper {
children: [
Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Icon(FeatherIcons.smartphone, size: 20.0, color: Theme.of(context).colorScheme.secondary),
child: Icon(FeatherIcons.smartphone,
size: 20.0, color: Theme.of(context).colorScheme.secondary),
),
Text(SettingsLocalization("system").i18n),
const Spacer(),
@@ -183,7 +208,8 @@ class SettingsHelper {
children: [
Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Icon(FeatherIcons.sun, size: 20.0, color: Theme.of(context).colorScheme.secondary),
child: Icon(FeatherIcons.sun,
size: 20.0, color: Theme.of(context).colorScheme.secondary),
),
Text(SettingsLocalization("light").i18n),
const Spacer(),
@@ -201,7 +227,8 @@ class SettingsHelper {
children: [
Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Icon(FeatherIcons.moon, size: 20.0, color: Theme.of(context).colorScheme.secondary),
child: Icon(FeatherIcons.moon,
size: 20.0, color: Theme.of(context).colorScheme.secondary),
),
Text(SettingsLocalization("dark").i18n),
const Spacer(),
@@ -219,7 +246,8 @@ class SettingsHelper {
static void accentColor(BuildContext context) {
Navigator.of(context, rootNavigator: true).push(
PageRouteBuilder(
pageBuilder: (context, _, __) => const PremiumCustomAccentColorSetting(),
pageBuilder: (context, _, __) =>
const PremiumCustomAccentColorSetting(),
transitionDuration: Duration.zero,
reverseTransitionDuration: Duration.zero,
),
@@ -241,7 +269,8 @@ class SettingsHelper {
return BottomSheetMenuItem(
onPressed: () {
Provider.of<SettingsProvider>(context, listen: false).update(vibrate: value);
Provider.of<SettingsProvider>(context, listen: false)
.update(vibrate: value);
Navigator.of(context).maybePop();
},
title: Row(
@@ -250,14 +279,18 @@ class SettingsHelper {
width: 12.0,
height: 12.0,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.secondary.withOpacity((index + 1) / (vibrationTitle.length + 1)),
color: Theme.of(context)
.colorScheme
.secondary
.withOpacity((index + 1) / (vibrationTitle.length + 1)),
shape: BoxShape.circle,
),
),
const SizedBox(width: 16.0),
Text(localizedVibrationTitles()[value] ?? "?"),
const Spacer(),
if (value == Provider.of<SettingsProvider>(context, listen: false).vibrate)
if (value ==
Provider.of<SettingsProvider>(context, listen: false).vibrate)
Icon(
Icons.check_circle,
color: Theme.of(context).colorScheme.secondary,
@@ -291,7 +324,8 @@ class _RoundingSettingState extends State<RoundingSetting> {
@override
void initState() {
super.initState();
rounding = Provider.of<SettingsProvider>(context, listen: false).rounding / 10;
rounding =
Provider.of<SettingsProvider>(context, listen: false).rounding / 10;
}
@override
@@ -336,12 +370,14 @@ class _RoundingSettingState extends State<RoundingSetting> {
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("4.5", style: TextStyle(fontSize: 26.0, fontWeight: FontWeight.w500)),
const Text("4.5",
style: TextStyle(fontSize: 26.0, fontWeight: FontWeight.w500)),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: Icon(FeatherIcons.arrowRight, color: Colors.grey),
),
GradeValueWidget(GradeValue(roundingResult, "", "", 100), fill: true, size: 32.0),
GradeValueWidget(GradeValue(roundingResult, "", "", 100),
fill: true, size: 32.0),
],
),
Padding(
@@ -349,7 +385,8 @@ class _RoundingSettingState extends State<RoundingSetting> {
child: MaterialActionButton(
child: Text(SettingsLocalization("done").i18n),
onPressed: () {
Provider.of<SettingsProvider>(context, listen: false).update(rounding: (rounding * 10).toInt());
Provider.of<SettingsProvider>(context, listen: false)
.update(rounding: (rounding * 10).toInt());
Navigator.of(context).maybePop();
},
),
@@ -367,15 +404,24 @@ class BellDelaySetting extends StatefulWidget {
State<BellDelaySetting> createState() => _BellDelaySettingState();
}
class _BellDelaySettingState extends State<BellDelaySetting> with SingleTickerProviderStateMixin {
class _BellDelaySettingState extends State<BellDelaySetting>
with SingleTickerProviderStateMixin {
late TabController _tabController;
late Duration currentDelay;
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this, initialIndex: Provider.of<SettingsProvider>(context, listen: false).bellDelay > 0 ? 1 : 0);
currentDelay = Duration(seconds: Provider.of<SettingsProvider>(context, listen: false).bellDelay);
_tabController = TabController(
length: 2,
vsync: this,
initialIndex:
Provider.of<SettingsProvider>(context, listen: false).bellDelay > 0
? 1
: 0);
currentDelay = Duration(
seconds:
Provider.of<SettingsProvider>(context, listen: false).bellDelay);
}
@override
@@ -416,7 +462,10 @@ class _BellDelaySettingState extends State<BellDelaySetting> with SingleTickerPr
),
Text(SettingsLocalization("sync_help").i18n,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 12.0, fontWeight: FontWeight.w500, color: AppColors.of(context).text.withOpacity(.75))),
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.w500,
color: AppColors.of(context).text.withOpacity(.75))),
Padding(
padding: const EdgeInsets.only(bottom: 12.0, top: 6.0),
child: Column(
@@ -425,21 +474,25 @@ class _BellDelaySettingState extends State<BellDelaySetting> with SingleTickerPr
backgroundColor: AppColors.of(context).filc,
child: Text(SettingsLocalization("sync").i18n),
onPressed: () {
final lessonProvider = Provider.of<TimetableProvider>(context, listen: false);
final lessonProvider =
Provider.of<TimetableProvider>(context, listen: false);
Duration? closest;
DateTime now = DateTime.now();
for (var lesson in lessonProvider.getWeek(Week.current()) ?? []) {
for (var lesson
in lessonProvider.getWeek(Week.current()) ?? []) {
Duration sdiff = lesson.start.difference(now);
Duration ediff = lesson.end.difference(now);
if (closest == null || sdiff.abs() < closest.abs()) closest = sdiff;
if (closest == null || sdiff.abs() < closest.abs())
closest = sdiff;
if (ediff.abs() < closest.abs()) closest = ediff;
}
if (closest != null) {
if (closest.inHours.abs() >= 1) return;
currentDelay = closest;
Provider.of<SettingsProvider>(context, listen: false).update(bellDelay: currentDelay.inSeconds);
Provider.of<SettingsProvider>(context, listen: false)
.update(bellDelay: currentDelay.inSeconds);
_tabController.index = currentDelay.inSeconds > 0 ? 1 : 0;
setState(() {});
}
@@ -449,7 +502,8 @@ class _BellDelaySettingState extends State<BellDelaySetting> with SingleTickerPr
child: Text(SettingsLocalization("done").i18n),
onPressed: () {
//Provider.of<SettingsProvider>(context, listen: false).update(context, rounding: (r * 10).toInt());
Provider.of<SettingsProvider>(context, listen: false).update(bellDelay: currentDelay.inSeconds);
Provider.of<SettingsProvider>(context, listen: false)
.update(bellDelay: currentDelay.inSeconds);
Navigator.of(context).maybePop();
},
),
@@ -513,8 +567,11 @@ class _GradeColorsSettingState extends State<GradeColorsSetting> {
children: [
MaterialActionButton(
onPressed: () {
List<Color> colors = List.castFrom(settings.gradeColors);
var defaultColors = SettingsProvider.defaultSettings().gradeColors;
List<Color> colors =
List.castFrom(settings.gradeColors);
var defaultColors =
SettingsProvider.defaultSettings()
.gradeColors;
colors[index] = defaultColors[index];
settings.update(gradeColors: colors);
Navigator.of(context).maybePop();
@@ -523,9 +580,11 @@ class _GradeColorsSettingState extends State<GradeColorsSetting> {
),
MaterialActionButton(
onPressed: () {
List<Color> colors = List.castFrom(settings.gradeColors);
List<Color> colors =
List.castFrom(settings.gradeColors);
colors[index] = currentColor.withAlpha(255);
settings.update(gradeColors: settings.gradeColors);
settings.update(
gradeColors: settings.gradeColors);
Navigator.of(context).maybePop();
},
child: Text(SettingsLocalization("done").i18n),
@@ -536,7 +595,8 @@ class _GradeColorsSettingState extends State<GradeColorsSetting> {
]),
).then((value) => setState(() {}));
},
child: GradeValueWidget(GradeValue(index + 1, "", "", 0), fill: true, size: 36.0),
child: GradeValueWidget(GradeValue(index + 1, "", "", 0),
fill: true, size: 36.0),
),
),
);

View File

@@ -51,11 +51,10 @@ class SettingsScreen extends StatefulWidget {
class _SettingsScreenState extends State<SettingsScreen>
with SingleTickerProviderStateMixin {
int devmodeCountdown = 3;
int devmodeCountdown = 5;
bool __ss = false; // secret settings
late Future<Map> futureRelease =
Provider.of<UpdateProvider>(context).installedVersion();
Future<Map>? futureRelease;
late UserProvider user;
late UpdateProvider updateProvider;
@@ -153,7 +152,9 @@ class _SettingsScreenState extends State<SettingsScreen>
@override
void initState() {
super.initState();
futureRelease = Provider.of<UpdateProvider>(context).installedVersion();
Future.delayed(Duration.zero, () {
futureRelease = Provider.of<UpdateProvider>(context).installedVersion();
});
_hideContainersController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 200));
}
@@ -528,14 +529,34 @@ class _SettingsScreenState extends State<SettingsScreen>
contentPadding: const EdgeInsets.only(left: 12.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0)),
title: const Text("Presentation Mode",
style: TextStyle(fontWeight: FontWeight.w500)),
title: Text("presentation".i18n,
style:
const TextStyle(fontWeight: FontWeight.w500)),
onChanged: (v) =>
settings.update(presentationMode: v),
value: settings.presentationMode,
activeColor: Theme.of(context).colorScheme.secondary,
),
),
// UwU-fied mode (why????)
// Material(
// type: MaterialType.transparency,
// child: SwitchListTile(
// contentPadding: const EdgeInsets.only(left: 12.0),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(12.0)),
// title: Text("uwufymode".i18n,
// style:
// const TextStyle(fontWeight: FontWeight.w500)),
// onChanged: (v) {
// SettingsHelper.uwuMode(context, v);
// setState(() {});
// },
// value: settings.presentationMode,
// activeColor: Theme.of(context).colorScheme.secondary,
// ),
// ),
],
),
),
@@ -613,7 +634,7 @@ class _SettingsScreenState extends State<SettingsScreen>
? Theme.of(context).colorScheme.secondary
: AppColors.of(context).text.withOpacity(.25),
),
const SizedBox(width: 24.0),
const SizedBox(width: 14.0),
Expanded(
child: Text(
"graph_class_avg".i18n,
@@ -658,7 +679,7 @@ class _SettingsScreenState extends State<SettingsScreen>
? Theme.of(context).colorScheme.secondary
: AppColors.of(context).text.withOpacity(.25),
),
const SizedBox(width: 24.0),
const SizedBox(width: 14.0),
Expanded(
child: Text(
"news".i18n,
@@ -703,7 +724,7 @@ class _SettingsScreenState extends State<SettingsScreen>
? Theme.of(context).colorScheme.secondary
: AppColors.of(context).text.withOpacity(.25),
),
const SizedBox(width: 24.0),
const SizedBox(width: 14.0),
Expanded(
child: Text(
"surprise_grades".i18n,

View File

@@ -64,6 +64,8 @@ extension SettingsLocalization on String {
"Background Color": "Background Color",
"Highlight Color": "Highlight Color",
"Adaptive Theme": "Adaptive Theme",
"presentation": "Presentation mode",
"uwufymode": "UwU-fied mode (hungarian)",
},
"hu_hu": {
"personal_details": "Személyes információk",
@@ -126,6 +128,8 @@ extension SettingsLocalization on String {
"Background Color": "Háttér színe",
"Highlight Color": "Panelek színe",
"Adaptive Theme": "Adaptív téma",
"presentation": "Bemutató mód",
"uwufymode": "UwU mód (magyar)",
},
"de_de": {
"personal_details": "Persönliche Angaben",
@@ -187,6 +191,8 @@ extension SettingsLocalization on String {
"Background Color": "Background Color",
"Highlight Color": "Highlight Color",
"Adaptive Theme": "Adaptive Theme",
"presentation": "Präsentationsmodus",
"uwufymode": "UwU-Modus (ungarisch)",
},
};

View File

@@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
class GradesBody extends StatelessWidget {
const GradesBody({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column();
}
}

View File

@@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
class PersonalityBody extends StatelessWidget {
const PersonalityBody({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column();
}
}

View File

@@ -0,0 +1,55 @@
import 'package:flutter/material.dart';
import 'pages/grades_page.dart';
class SummaryScreen extends StatefulWidget {
final String currentPage;
const SummaryScreen({Key? key, this.currentPage = 'personality'})
: super(key: key);
@override
_SummaryScreenState createState() => _SummaryScreenState();
}
class _SummaryScreenState extends State<SummaryScreen> {
final LinearGradient _backgroundGradient = const LinearGradient(
colors: [
Color(0xff1d56ac),
Color(0xff170a3d),
],
begin: Alignment(-0.8, -1.0),
end: Alignment(0.8, 1.0),
stops: [-1.0, 1.0],
);
@override
Widget build(BuildContext context) {
return Scaffold(
body: 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(),
),
),
),
),
);
}
}

View File

@@ -0,0 +1,15 @@
import 'package:i18n_extension/i18n_extension.dart';
extension SettingsLocalization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {},
"hu_hu": {},
"de_de": {},
};
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

@@ -307,6 +307,7 @@ class _PremiumCustomAccentColorSettingState
controller: _testTabController,
padding: EdgeInsets.zero,
censored: true,
disableFading: true,
),
),
Padding(

View File

@@ -19,7 +19,7 @@ extension SettingsLocalization on String {
"colorpicker_panels": "Panelek",
"colorpicker_accent": "Színtónus",
"need_sub": "A módosításhoz Kupak szintű támogatás szükséges.",
"advanced": "Fejlett",
"advanced": "Haladó",
},
"de_de": {
"theme_prev": "Vorschau",

View File

@@ -11,7 +11,8 @@ import 'package:intl/intl.dart';
import 'package:i18n_extension/i18n_widget.dart';
class PremiumFSTimetable extends StatefulWidget {
const PremiumFSTimetable({Key? key, required this.controller}) : super(key: key);
const PremiumFSTimetable({Key? key, required this.controller})
: super(key: key);
final TimetableController controller;
@@ -45,16 +46,25 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
final everyLesson = days.expand((x) => x).toList();
everyLesson.sort((a, b) => a.start.compareTo(b.start));
final int maxLessonCount = days.fold(0, (a, b) => math.max(a, b.where((l) => l.subject.id != "" || l.isEmpty).length));
final int maxLessonCount = days.fold(
0,
(a, b) => math.max(
a, b.where((l) => l.subject.id != "" || l.isEmpty).length));
final int minIndex = int.tryParse(everyLesson.first.lessonIndex) ?? 0;
final int maxIndex = int.tryParse(everyLesson.last.lessonIndex) ?? maxLessonCount;
final int maxIndex =
int.tryParse(everyLesson.last.lessonIndex) ?? maxLessonCount;
const prefixw = 40;
const padding = prefixw + 6 * 2;
final colw = (MediaQuery.of(context).size.width - padding) / days.length;
return Scaffold(
appBar: AppBar(
surfaceTintColor: Theme.of(context).scaffoldBackgroundColor,
leading: BackButton(color: AppColors.of(context).text),
shadowColor: Colors.transparent,
),
body: ListView.builder(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.symmetric(horizontal: 6.0, vertical: 24.0),
@@ -63,7 +73,10 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
List<Widget> columns = [];
for (int dayIndex = -1; dayIndex < days.length; dayIndex++) {
final dayOffset = dayIndex == -1 ? 0 : (int.tryParse(days[dayIndex].first.lessonIndex) ?? 0) - minIndex;
final dayOffset = dayIndex == -1
? 0
: (int.tryParse(days[dayIndex].first.lessonIndex) ?? 0) -
minIndex;
final lessonIndex = index - 1;
if (dayIndex == -1) {
@@ -75,7 +88,9 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
"${minIndex + lessonIndex}.",
style: TextStyle(fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.secondary),
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.secondary),
),
),
));
@@ -85,12 +100,15 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
continue;
}
final lessons = days[dayIndex].where((l) => l.subject.id != "" || l.isEmpty).toList();
final lessons = days[dayIndex]
.where((l) => l.subject.id != "" || l.isEmpty)
.toList();
if (lessons.isEmpty) continue;
if (lessonIndex >= lessons.length) continue;
if (dayIndex >= days.length || (lessonIndex + dayOffset) >= lessons.length) {
if (dayIndex >= days.length ||
(lessonIndex + dayOffset) >= lessons.length) {
columns.add(SizedBox(width: colw));
continue;
}
@@ -100,8 +118,11 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
width: colw,
height: 40.0,
child: Text(
DateFormat("EEEE", I18n.of(context).locale.languageCode).format(lessons.first.date).capital(),
style: const TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold),
DateFormat("EEEE", I18n.of(context).locale.languageCode)
.format(lessons.first.date)
.capital(),
style: const TextStyle(
fontSize: 24.0, fontWeight: FontWeight.bold),
),
));
continue;
@@ -113,11 +134,14 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(FeatherIcons.slash, size: 18.0, color: AppColors.of(context).text.withOpacity(.3)),
Icon(FeatherIcons.slash,
size: 18.0,
color: AppColors.of(context).text.withOpacity(.3)),
const SizedBox(width: 8.0),
Text(
"Lyukas óra",
style: TextStyle(color: AppColors.of(context).text.withOpacity(.3)),
style: TextStyle(
color: AppColors.of(context).text.withOpacity(.3)),
),
],
),
@@ -139,16 +163,27 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
Row(
children: [
Icon(
SubjectIcon.resolveVariant(context: context, subject: lessons[lessonIndex - dayOffset].subject),
SubjectIcon.resolveVariant(
context: context,
subject: lessons[lessonIndex - dayOffset].subject),
size: 18.0,
color: AppColors.of(context).text.withOpacity(.7),
),
const SizedBox(width: 8.0),
Expanded(
child: Text(
lessons[lessonIndex - dayOffset].subject.renamedTo ?? lessons[lessonIndex - dayOffset].subject.name.capital(),
lessons[lessonIndex - dayOffset].subject.renamedTo ??
lessons[lessonIndex - dayOffset]
.subject
.name
.capital(),
maxLines: 1,
style: TextStyle(fontStyle: lessons[lessonIndex - dayOffset].subject.isRenamed ? FontStyle.italic : null),
style: TextStyle(
fontStyle: lessons[lessonIndex - dayOffset]
.subject
.isRenamed
? FontStyle.italic
: null),
overflow: TextOverflow.clip,
softWrap: false,
),
@@ -160,7 +195,9 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
padding: const EdgeInsets.only(left: 26.0),
child: Text(
lessons[lessonIndex - dayOffset].room,
style: TextStyle(color: AppColors.of(context).text.withOpacity(.5), overflow: TextOverflow.ellipsis),
style: TextStyle(
color: AppColors.of(context).text.withOpacity(.5),
overflow: TextOverflow.ellipsis),
),
),
],