Merge pull request #53 from refilc/dev

Dev
This commit is contained in:
Márton Kiss 2023-09-18 19:36:20 +02:00 committed by GitHub
commit 151e97b243
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 81 additions and 24 deletions

View File

@ -2,7 +2,7 @@ import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
enum Status { network, maintenance, syncing } enum Status { network, maintenance, syncing, apiError }
class StatusProvider extends ChangeNotifier { class StatusProvider extends ChangeNotifier {
final List<Status> _stack = []; final List<Status> _stack = [];
@ -37,7 +37,8 @@ class StatusProvider extends ChangeNotifier {
} }
void triggerRequest(http.Response res) { void triggerRequest(http.Response res) {
if (res.headers.containsKey("x-maintenance-mode") || res.statusCode == 503) { if (res.headers.containsKey("x-maintenance-mode") ||
res.statusCode == 503) {
if (!_stack.contains(Status.maintenance)) { if (!_stack.contains(Status.maintenance)) {
_stack.insert(0, Status.maintenance); _stack.insert(0, Status.maintenance);
notifyListeners(); notifyListeners();
@ -48,6 +49,21 @@ class StatusProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
} }
if (res.body == "invalid_grant" ||
res.body.replaceAll(' ', '') == '' ||
res.statusCode == 400) {
if (!_stack.contains(Status.apiError)) {
_stack.insert(0, Status.apiError);
notifyListeners();
}
} else {
if (_stack.contains(Status.apiError) &&
res.request?.url.path != '/nonce') {
_stack.remove(Status.apiError);
notifyListeners();
}
}
} }
void triggerSync({required int current, required int max}) { void triggerSync({required int current, required int max}) {

View File

@ -44,7 +44,7 @@ dependencies:
quick_actions: ^1.0.1 quick_actions: ^1.0.1
animated_list_plus: ^0.5.0 animated_list_plus: ^0.5.0
dynamic_color: ^1.2.2 dynamic_color: ^1.2.2
material_color_utilities: ^0.2.0 material_color_utilities: ^0.5.0
crypto: ^3.0.2 crypto: ^3.0.2
elegant_notification: ^1.6.1 elegant_notification: ^1.6.1
flutter_feather_icons: ^2.0.0+1 flutter_feather_icons: ^2.0.0+1

View File

@ -15,11 +15,11 @@ import 'login_screen.i18n.dart';
const LinearGradient _backgroundGradient = LinearGradient( const LinearGradient _backgroundGradient = LinearGradient(
colors: [ colors: [
Color.fromARGB(255, 0, 0, 0), Color.fromARGB(255, 61, 122, 244),
Color.fromARGB(255, 23, 77, 185), Color.fromARGB(255, 23, 77, 185),
Color.fromARGB(255, 7, 42, 112), Color.fromARGB(255, 7, 42, 112),
], ],
begin: Alignment(-0.8, -2), begin: Alignment(-0.8, -2.0),
end: Alignment(0.8, 1.0), end: Alignment(0.8, 1.0),
stops: [-1.0, 0.0, 1.0], stops: [-1.0, 0.0, 1.0],
); );
@ -90,7 +90,7 @@ class _LoginScreenState extends State<LoginScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
body: Container( body: Container(
decoration: BoxDecoration( decoration: const BoxDecoration(
gradient: _backgroundGradient, gradient: _backgroundGradient,
), ),
child: SafeArea( child: SafeArea(

View File

@ -89,6 +89,9 @@ class KretaClient {
} }
if (res == null) throw "Login error"; if (res == null) throw "Login error";
if (res.body == 'invalid_grant' || res.body.replaceAll(' ', '') == '') {
throw "Auth error";
}
if (json) { if (json) {
return jsonDecode(res.body); return jsonDecode(res.body);

View File

@ -5,6 +5,7 @@ import 'package:filcnaplo/models/user.dart';
import 'package:filcnaplo_kreta_api/client/api.dart'; import 'package:filcnaplo_kreta_api/client/api.dart';
import 'package:filcnaplo_kreta_api/client/client.dart'; import 'package:filcnaplo_kreta_api/client/client.dart';
import 'package:filcnaplo_kreta_api/models/homework.dart'; import 'package:filcnaplo_kreta_api/models/homework.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -83,7 +84,10 @@ class HomeworkProvider with ChangeNotifier {
// error fetcing homework (unknown error) // error fetcing homework (unknown error)
} }
if (homeworkJson == null) throw "Cannot fetch Homework for User ${user.id}"; if (homeworkJson == null) {
if (kDebugMode) print("Cannot fetch Homework for User ${user.id}");
return;
}
List<Homework> homework = []; List<Homework> homework = [];
await Future.forEach(homeworkJson.cast<Map>(), (Map hw) async { await Future.forEach(homeworkJson.cast<Map>(), (Map hw) async {

View File

@ -67,15 +67,21 @@ class TimetableProvider with ChangeNotifier {
String iss = user.instituteCode; String iss = user.instituteCode;
List? lessonsJson = await _kreta List? lessonsJson = await _kreta
.getAPI(KretaAPI.timetable(iss, start: week.start, end: week.end)); .getAPI(KretaAPI.timetable(iss, start: week.start, end: week.end));
if (lessonsJson == null) throw "Cannot fetch Lessons for User ${user.id}";
List<Lesson> lessonsList = lessonsJson.map((e) => Lesson.fromJson(e)).toList();
if (lessons.isEmpty && lessons.isEmpty) return; if (lessonsJson == null) {
return;
// throw "Cannot fetch Lessons for User ${user.id}";
} else {
List<Lesson> lessonsList =
lessonsJson.map((e) => Lesson.fromJson(e)).toList();
lessons[week] = lessonsList; if (lessons.isEmpty) return;
await store(); lessons[week] = lessonsList;
await convertBySettings();
await store();
await convertBySettings();
}
} }
// Stores Lessons in the database // Stores Lessons in the database

View File

@ -15,7 +15,8 @@ class MissedExamView extends StatelessWidget {
final List<Lesson> missedExams; final List<Lesson> missedExams;
static show(List<Lesson> missedExams, {required BuildContext context}) => showRoundedModalBottomSheet(context, child: MissedExamView(missedExams)); static show(List<Lesson> missedExams, {required BuildContext context}) =>
showRoundedModalBottomSheet(context, child: MissedExamView(missedExams));
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -25,7 +26,8 @@ class MissedExamView extends StatelessWidget {
} }
class MissedExamViewTile extends StatelessWidget { class MissedExamViewTile extends StatelessWidget {
const MissedExamViewTile(this.lesson, {Key? key, this.padding}) : super(key: key); const MissedExamViewTile(this.lesson, {Key? key, this.padding})
: super(key: key);
final EdgeInsetsGeometry? padding; final EdgeInsetsGeometry? padding;
final Lesson lesson; final Lesson lesson;
@ -33,23 +35,36 @@ class MissedExamViewTile extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SettingsProvider settingsProvider = Provider.of<SettingsProvider>(context); SettingsProvider settingsProvider = Provider.of<SettingsProvider>(context);
String? teacherName = lesson.teacher.isRenamed
? lesson.teacher.renamedTo
: lesson.teacher.name;
return Material( return Material(
type: MaterialType.transparency, type: MaterialType.transparency,
child: Padding( child: Padding(
padding: padding ?? const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), padding: padding ??
const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
child: ListTile( child: ListTile(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)), shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)),
leading: Icon( leading: Icon(
SubjectIcon.resolveVariant(subject: lesson.subject, context: context), SubjectIcon.resolveVariant(
subject: lesson.subject, context: context),
color: AppColors.of(context).text.withOpacity(.8), color: AppColors.of(context).text.withOpacity(.8),
size: 32.0, size: 32.0,
), ),
title: Text( title: Text(
"${lesson.subject.renamedTo ?? lesson.subject.name.capital()}${lesson.date.format(context)}", "${lesson.subject.renamedTo ?? lesson.subject.name.capital()}${lesson.date.format(context)}",
style: TextStyle(fontWeight: FontWeight.w600, fontStyle: lesson.subject.isRenamed && settingsProvider.renamedSubjectsItalics ? FontStyle.italic : null), style: TextStyle(
fontWeight: FontWeight.w600,
fontStyle: lesson.subject.isRenamed &&
settingsProvider.renamedSubjectsItalics
? FontStyle.italic
: null),
), ),
subtitle: Text( subtitle: Text(
"missed_exam_contact".i18n.fill([lesson.teacher]), "missed_exam_contact".i18n.fill([teacherName ?? '']),
style: const TextStyle(fontWeight: FontWeight.w500), style: const TextStyle(fontWeight: FontWeight.w500),
), ),
trailing: const Icon(FeatherIcons.arrowRight), trailing: const Icon(FeatherIcons.arrowRight),

View File

@ -39,7 +39,9 @@ class _StatusBarState extends State<StatusBar> {
height: currentStatus != null ? 28.0 : 0, height: currentStatus != null ? 28.0 : 0,
decoration: BoxDecoration( decoration: BoxDecoration(
color: backgroundColor, color: backgroundColor,
boxShadow: [BoxShadow(color: Theme.of(context).shadowColor, blurRadius: 8.0)], boxShadow: [
BoxShadow(color: Theme.of(context).shadowColor, blurRadius: 8.0)
],
borderRadius: BorderRadius.circular(45.0), borderRadius: BorderRadius.circular(45.0),
), ),
), ),
@ -53,9 +55,12 @@ class _StatusBarState extends State<StatusBar> {
height: currentStatus != null ? 28.0 : 0, height: currentStatus != null ? 28.0 : 0,
duration: const Duration(milliseconds: 250), duration: const Duration(milliseconds: 250),
curve: Curves.easeInOut, curve: Curves.easeInOut,
width: MediaQuery.of(context).size.width * statusProvider.progress - 16.0, width: MediaQuery.of(context).size.width *
statusProvider.progress -
16.0,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.secondary.withOpacity(0.8), color:
Theme.of(context).colorScheme.secondary.withOpacity(0.8),
borderRadius: BorderRadius.circular(45.0), borderRadius: BorderRadius.circular(45.0),
), ),
), ),
@ -82,6 +87,8 @@ class _StatusBarState extends State<StatusBar> {
return "Syncing data".i18n; return "Syncing data".i18n;
case Status.maintenance: case Status.maintenance:
return "KRETA Maintenance".i18n; return "KRETA Maintenance".i18n;
case Status.apiError:
return "KRETA API error".i18n;
case Status.network: case Status.network:
return "No connection".i18n; return "No connection".i18n;
default: default:
@ -93,10 +100,13 @@ class _StatusBarState extends State<StatusBar> {
switch (status) { switch (status) {
case Status.maintenance: case Status.maintenance:
return AppColors.of(context).red; return AppColors.of(context).red;
case Status.apiError:
return AppColors.of(context).red;
case Status.network: case Status.network:
case Status.syncing: case Status.syncing:
default: default:
HSLColor color = HSLColor.fromColor(Theme.of(context).scaffoldBackgroundColor); HSLColor color =
HSLColor.fromColor(Theme.of(context).scaffoldBackgroundColor);
if (color.lightness >= 0.5) { if (color.lightness >= 0.5) {
color = color.withSaturation(0.3); color = color.withSaturation(0.3);
color = color.withLightness(color.lightness - 0.1); color = color.withLightness(color.lightness - 0.1);

View File

@ -6,16 +6,19 @@ extension Localization on String {
"en_en": { "en_en": {
"Syncing data": "Syncing data", "Syncing data": "Syncing data",
"KRETA Maintenance": "KRETA Maintenance", "KRETA Maintenance": "KRETA Maintenance",
"KRETA API error": "KRETA API Error",
"No connection": "No connection", "No connection": "No connection",
}, },
"hu_hu": { "hu_hu": {
"Syncing data": "Adatok frissítése", "Syncing data": "Adatok frissítése",
"KRETA Maintenance": "KRÉTA Karbantartás", "KRETA Maintenance": "KRÉTA Karbantartás",
"KRETA API error": "KRÉTA API Hiba",
"No connection": "Nincs kapcsolat", "No connection": "Nincs kapcsolat",
}, },
"de_de": { "de_de": {
"Syncing data": "Daten aktualisieren", "Syncing data": "Daten aktualisieren",
"KRETA Maintenance": "KRETA Wartung", "KRETA Maintenance": "KRETA Wartung",
"KRETA API error": "KRETA API Fehler",
"No connection": "Keine Verbindung", "No connection": "Keine Verbindung",
}, },
}; };