Merge pull request #123 from refilc/dev

dev to master (v5.0.2)
This commit is contained in:
Márton Kiss 2024-06-16 21:43:07 +02:00 committed by GitHub
commit 1a7b59f2fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 319 additions and 92 deletions

View File

@ -22,7 +22,7 @@ import 'package:intl/intl.dart';
import 'package:refilc_kreta_api/models/message.dart';
// if you want to add a new category, also add it to the DB or else the app will probably crash
enum LastSeenCategory {
enum LastSeenCategory {
grade,
surprisegrade,
absence,

View File

@ -0,0 +1,130 @@
import 'dart:math';
class Uwuifier {
final Map<String, double> _spacesModifier;
final double _wordsModifier;
final List<String> faces = [
"OwO",
"UwU",
">w<",
"^w^",
"^-^",
":3",
];
final List<List<String>> uwuMap = [
['(?:r|l)', 'w'],
['(?:R|L)', 'W'],
['na', 'nya'],
['ne', 'nye'],
['NA', 'NYA'],
['NE', 'NYE'],
['Na', 'Nya'],
['Ne', 'Nye'],
['no', 'nyo'],
['NO', 'NYO'],
['No', 'Nyo'],
['nO', 'NYo'],
['ove', 'uv'],
['no', 'nwo'],
];
final Map<String, String> _uwuCache = {};
Uwuifier({
Map<String, double>? spaces,
double? words,
}) : _spacesModifier = spaces ?? {
'faces': 0.05,
'actions': 0.0,
'stutters': 0.1,
},
_wordsModifier = words ?? 1.0;
String uwuifyWords(String sentence) {
final words = sentence.split(' ');
final uwuifiedSentence = words.map((word) {
if (isAt(word) || isUri(word)) return word;
var seed = Random().nextDouble();
for (final uwuMapEntry in uwuMap) {
final oldWord = RegExp(uwuMapEntry[0], caseSensitive: false);
final newWord = uwuMapEntry[1];
if (seed > _wordsModifier) continue;
word = word.replaceAll(oldWord, newWord);
}
return word;
}).join(' ');
return uwuifiedSentence;
}
String uwuifySpaces(String sentence) {
final words = sentence.split(' ');
final faceThreshold = _spacesModifier['faces']!;
final actionThreshold = _spacesModifier['actions']! + faceThreshold;
final stutterThreshold = _spacesModifier['stutters']! + actionThreshold;
final uwuifiedSentence = words.map((word) {
final seed = Random().nextDouble();
final firstCharacter = word[0];
if (seed <= faceThreshold && faces.isNotEmpty) {
word += ' ${faces[Random().nextInt(faces.length)]}';
} else if (seed <= actionThreshold) {
// Skip actions
} else if (seed <= stutterThreshold && !isUri(word)) {
if (Random().nextInt(10) == 0) {
final stutter = Random().nextInt(3);
return '${firstCharacter * (stutter + 1)}-$word';
}
}
return word;
}).join(' ');
return uwuifiedSentence;
}
String uwuifySentence(String sentence) {
if (_uwuCache.containsKey(sentence)) {
return _uwuCache[sentence]!;
}
var uwuifiedSentence = uwuifyWords(sentence);
uwuifiedSentence = uwuifySpaces(uwuifiedSentence);
_uwuCache[sentence] = uwuifiedSentence;
return uwuifiedSentence;
}
bool isAt(String value) {
return value.startsWith('@');
}
bool isUri(String? value) {
if (value == null) return false;
final split = RegExp(
r'''(?:([^:/?#]+):)?(?:\/\/([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?''')
.firstMatch(value);
if (split == null) return false;
final scheme = split.group(1);
final authority = split.group(2);
final path = split.group(3);
if (!(scheme?.isNotEmpty == true && path?.isNotEmpty == true)) return false;
if (authority != null && authority.isNotEmpty) {
if (!(path?.isEmpty == true || path!.startsWith('/'))) return false;
} else if (path?.startsWith('//') == true) {
return false;
}
if (!RegExp(r'''^[a-z][a-z0-9+\-\.]*$''', caseSensitive: false)
.hasMatch(scheme!.toLowerCase())) {
return false;
}
return true;
}
}

View File

@ -3,7 +3,7 @@ description: "Egy nem hivatalos e-KRÉTA kliens, diákoktól diákoknak."
homepage: https://refilc.hu
publish_to: "none"
version: 5.0.1+265
version: 5.0.2+266
environment:
sdk: ">=2.17.0 <=3.3.2"

View File

@ -80,8 +80,8 @@ class KretaClient {
_status.triggerRequest(res);
if (res.statusCode == 401) {
await refreshLogin();
headerMap.remove("authorization");
await refreshLogin();
} else {
break;
}
@ -212,8 +212,8 @@ class KretaClient {
res = await request.send();
if (res.statusCode == 401) {
headerMap.remove("authorization");
await refreshLogin();
headerMap.remove("authorization");
} else {
break;
}

View File

@ -1,6 +1,7 @@
// ignore_for_file: no_leading_underscores_for_local_identifiers
import 'package:refilc/utils/format.dart';
import 'package:uuid/uuid.dart';
import 'category.dart';
import 'subject.dart';
import 'teacher.dart';
@ -75,6 +76,40 @@ class Grade {
);
}
factory Grade.fromExportJson(Map json) {
return Grade(
id: const Uuid().v4(),
date: json["date"] != null ? DateTime.parse(json["date"]) : DateTime(0),
value: GradeValue(
json["value"] ?? 0,
json["value_name"] ?? "",
json["value_name"] ?? "",
json["weight"] ?? 0,
percentage: false,
),
teacher: Teacher.fromString((json["teacher"] ?? "").trim()),
description: json["description"] ?? "",
type: json["type"] != null
? Category.getGradeType(json["type"]
.replaceAll("midYear", "evkozi_jegy_ertekeles")
.replaceAll("halfYear", "felevi_jegy_ertekeles")
.replaceAll("endYear", "evvegi_jegy_ertekeles"))
: GradeType.unknown,
groupId: const Uuid().v4(),
subject: GradeSubject(
id: const Uuid().v4(),
category: Category.fromJson({}),
name: json["subject"] ?? ""),
mode: Category.fromJson({}),
writeDate:
json["date"] != null ? DateTime.parse(json["date"]) : DateTime(0),
seenDate:
json["date"] != null ? DateTime.parse(json["date"]) : DateTime(0),
form: "",
json: json,
);
}
bool compareTo(dynamic other) {
if (runtimeType != other.runtimeType) return false;

View File

@ -9,7 +9,7 @@ extension Localization on String {
"unexcused": "unexcused %s",
"absence": "absence",
"delay": "delay",
"minute": " minutes of ".one(" minute of "),
"minute": " minute(s) of ",
},
"hu_hu": {
"excused": "igazolt %s",
@ -25,7 +25,7 @@ extension Localization on String {
"unexcused": "unanerkannt %s",
"absence": "Abwesenheit",
"delay": "Verspätung",
"minute": " Minuten ".one(" Minute "),
"minute": " Minute(n) ",
}
};

View File

@ -9,7 +9,7 @@ extension Localization on String {
"Mode": "Mode",
"Submit date": "Submit Date",
"show in timetable": "Show in timetable",
"minutes": "minutes".one("minute"),
"minutes": "minute(s)",
"delay": "Delay",
},
"hu_hu": {
@ -27,7 +27,7 @@ extension Localization on String {
"Mode": "Typ",
"Submit date": "Datum einreichen",
"show in timetable": "im Stundenplan anzeigen",
"minutes": "Minuten".one("Minute"),
"minutes": "Minute(n)",
"delay": "Verspätung",
}
};

View File

@ -17,7 +17,7 @@ extension Localization on String {
"Messages": "Messages",
"Absences": "Absences",
"update_available": "Update Available",
"missed_exams": "You missed %s exams this week.".one("You missed an exam this week."),
"missed_exams": "You missed %s exam(s) this week.",
"missed_exam_contact": "Contact %s, to resolve it!",
},
"hu_hu": {
@ -34,7 +34,7 @@ extension Localization on String {
"Messages": "Üzenetek",
"Absences": "Hiányok",
"update_available": "Frissítés elérhető",
"missed_exams": "Ezen a héten hiányoztál %s dolgozatról.".one("Ezen a héten hiányoztál egy dolgozatról."),
"missed_exams": "Ezen a héten hiányoztál %s dolgozatról.",
"missed_exam_contact": "Keresd %s-t, ha pótolni szeretnéd!",
},
"de_de": {
@ -51,7 +51,7 @@ extension Localization on String {
"Messages": "Nachrichten",
"Absences": "Fehlen",
"update_available": "Update verfügbar",
"missed_exams": "Diese Woche haben Sie %s Prüfungen verpasst.".one("Diese Woche haben Sie eine Prüfung verpasst."),
"missed_exams": "Diese Woche haben Sie %s Prüfungen verpasst.",
"missed_exam_contact": "Wenden Sie sich an %s, um sie zu erneuern!",
},
};

View File

@ -1,9 +1,12 @@
// ignore_for_file: no_leading_underscores_for_local_identifiers
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:collection/collection.dart';
import 'package:file_picker/file_picker.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:refilc/api/providers/update_provider.dart';
import 'package:refilc/models/settings.dart';
@ -89,19 +92,18 @@ class GradesPageState extends State<GradesPage> {
int avgDropValue = 0;
bool gradeCalcMode = false;
bool importedViewMode = false;
List<Grade> jsonGrades = [];
List<Grade> getSubjectGrades(GradeSubject subject,
{int days = 0}) =>
!gradeCalcMode
? gradeProvider
.grades
? (importedViewMode ? jsonGrades : gradeProvider.grades)
.where((e) =>
e
.subject ==
subject &&
e.subject == subject &&
e.type == GradeType.midYear &&
(days ==
0 ||
(days == 0 ||
e.date.isBefore(
DateTime.now().subtract(Duration(days: days)))))
.toList()
@ -110,18 +112,19 @@ class GradesPageState extends State<GradesPage> {
.toList();
void generateTiles() {
List<GradeSubject> subjects = gradeProvider.grades
.map((e) => GradeSubject(
category: e.subject.category,
id: e.subject.id,
name: e.subject.name,
renamedTo: e.subject.renamedTo,
customRounding: e.subject.customRounding,
teacher: e.teacher,
))
.toSet()
.toList()
..sort((a, b) => a.name.compareTo(b.name));
List<GradeSubject> subjects =
(importedViewMode ? jsonGrades : gradeProvider.grades)
.map((e) => GradeSubject(
category: e.subject.category,
id: e.subject.id,
name: e.subject.name,
renamedTo: e.subject.renamedTo,
customRounding: e.subject.customRounding,
teacher: e.teacher,
))
.toSet()
.toList()
..sort((a, b) => a.name.compareTo(b.name));
List<Widget> tiles = [];
Map<GradeSubject, double> subjectAvgs = {};
@ -165,7 +168,8 @@ class GradesPageState extends State<GradesPage> {
e.subject.id == subject.id && e.writeDate.isAfter(DateTime.now()));
bool hasUnder = (hasHomework || nearestExam != null) &&
Provider.of<SettingsProvider>(context).qSubjectsSubTiles;
Provider.of<SettingsProvider>(context, listen: false)
.qSubjectsSubTiles;
return Padding(
padding: i > 1 ? const EdgeInsets.only(top: 9.0) : EdgeInsets.zero,
@ -220,7 +224,8 @@ class GradesPageState extends State<GradesPage> {
height: 6.0,
),
if (hasHomework &&
Provider.of<SettingsProvider>(context).qSubjectsSubTiles)
Provider.of<SettingsProvider>(context, listen: false)
.qSubjectsSubTiles)
Container(
decoration: BoxDecoration(
boxShadow: [
@ -448,25 +453,28 @@ class GradesPageState extends State<GradesPage> {
.fold(0.0, (double a, double b) => a + b) /
gradeProvider.groupAverages.length;
final now = gradeProvider.grades.isNotEmpty
? gradeProvider.grades
.reduce((v, e) => e.date.isAfter(v.date) ? e : v)
.date
: DateTime.now();
final now =
(importedViewMode ? jsonGrades : gradeProvider.grades).isNotEmpty
? (importedViewMode ? jsonGrades : gradeProvider.grades)
.reduce((v, e) => e.date.isAfter(v.date) ? e : v)
.date
: DateTime.now();
final currentStudentAvg = AverageHelper.averageEvals(!gradeCalcMode
? gradeProvider.grades
? (importedViewMode ? jsonGrades : gradeProvider.grades)
.where((e) => e.type == GradeType.midYear)
.toList()
: calculatorProvider.grades);
final prevStudentAvg = AverageHelper.averageEvals(gradeProvider.grades
final prevStudentAvg = AverageHelper.averageEvals((importedViewMode
? jsonGrades
: gradeProvider.grades)
.where((e) => e.type == GradeType.midYear)
.where((e) => e.date.isBefore(now.subtract(const Duration(days: 30))))
.toList());
List<Grade> graphGrades = !gradeCalcMode
? gradeProvider.grades
? (importedViewMode ? jsonGrades : gradeProvider.grades)
.where((e) =>
e.type == GradeType.midYear &&
(avgDropValue == 0 ||
@ -500,7 +508,7 @@ class GradesPageState extends State<GradesPage> {
// const SizedBox(width: 4.0),
TrendDisplay(
previous: prevStudentAvg, current: currentStudentAvg),
if (gradeProvider.grades
if ((importedViewMode ? jsonGrades : gradeProvider.grades)
.where((e) => e.type == GradeType.midYear)
.isNotEmpty)
AverageDisplay(average: currentStudentAvg),
@ -632,7 +640,8 @@ class GradesPageState extends State<GradesPage> {
void gradeCalcTotal(BuildContext context) {
calculatorProvider.clear();
calculatorProvider.addAllGrades(gradeProvider.grades);
calculatorProvider
.addAllGrades((importedViewMode ? jsonGrades : gradeProvider.grades));
_sheetController = _scaffoldKey.currentState?.showBottomSheet(
(context) => const RoundedBottomSheet(
@ -693,6 +702,64 @@ class GradesPageState extends State<GradesPage> {
const SizedBox(
height: 10.0,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: Theme.of(context).colorScheme.background),
child: ListTile(
title: Row(
children: [
const Icon(Icons.toll_rounded),
const SizedBox(
width: 10.0,
),
Text('import_grades'.i18n),
],
),
trailing: importedViewMode ? const Icon(FeatherIcons.x) : null,
onTap: () {
if (importedViewMode) {
importedViewMode = false;
generateTiles();
setState(() {});
Navigator.of(context, rootNavigator: true).pop();
return;
}
if (!Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.gradeExporting)) {
PlusLockedFeaturePopup.show(
context: context, feature: PremiumFeature.gradeExporting);
return;
}
// show file picker
FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['json'],
).then((value) {
if (value != null) {
final File file = File(value.files.single.path!);
final String content = file.readAsStringSync();
final List<dynamic> json = jsonDecode(content);
jsonGrades = json.map((e) => Grade.fromJson(e)).toList();
importedViewMode = true;
generateTiles();
setState(() {});
}
});
Navigator.of(context, rootNavigator: true).pop();
},
),
),
const SizedBox(
height: 10.0,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),

View File

@ -4,8 +4,9 @@ extension Localization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {
"Grades": "Subjects",
"Ghost Grades": "Grades",
"Grades": "Grades",
"page_title_grades": "Subjects",
"Ghost Grades": "Ghost Grades",
"Subjects": "Your Subjects",
"Subjects_changes": "Subject Differences",
"empty": "You don't have any subjects.",
@ -17,8 +18,7 @@ extension Localization on String {
"subjectavg": "Subject Average",
"classavg": "Class Average",
"fail_warning": "Failure warning",
"fail_warning_description":
"You are failing %d subjects!".one("You are failing a subject!"),
"fail_warning_description": "You are failing %d subject(s)!",
"data": "Data",
"you_have_hw": "You have %s homework(s) to do",
"grades_cnt": "Grade count: %s",
@ -29,6 +29,7 @@ extension Localization on String {
"grades": "Grades",
"show_exams_homework": "Exams and Homework",
"grade_calc": "Grade Calculator",
"import_grades": "Import Grades (JSON)",
},
"hu_hu": {
"Grades": "Jegyek",
@ -56,9 +57,11 @@ extension Localization on String {
"grades": "Jegyek",
"show_exams_homework": "Dolgozatok és házik",
"grade_calc": "Jegy kalkulátor",
"import_grades": "Jegyek importálása (JSON)",
},
"de_de": {
"Grades": "Fächer",
"Grades": "Klassen",
"page_title_grades": "Themen",
"Ghost Grades": "Geist Noten",
"Subjects": "Ihre Themen",
"Subjects_changes": "Betreff Änderungen",
@ -82,6 +85,7 @@ extension Localization on String {
"grades": "Noten",
"show_exams_homework": "Referate und Hausaufgaben",
"grade_calc": "Noten-Rechner",
"import_grades": "Noten importieren (JSON)",
},
};

View File

@ -19,8 +19,7 @@ extension Localization on String {
"Messages": "Messages",
"Absences": "Absences",
"update_available": "Update Available",
"missed_exams": "You missed %s exams this week."
.one("You missed an exam this week."),
"missed_exams": "You missed %s exam(s) this week.",
"missed_exam_contact": "Contact %s to resolve it!",
},
"hu_hu": {
@ -39,8 +38,7 @@ extension Localization on String {
"Messages": "Üzenetek",
"Absences": "Hiányzások",
"update_available": "Frissítés elérhető",
"missed_exams": "Ezen a héten hiányoztál %s dolgozatról."
.one("Ezen a héten hiányoztál egy dolgozatról."),
"missed_exams": "Ezen a héten hiányoztál %s dolgozatról.",
"missed_exam_contact": "Keresd %s tanár urat/hölgyet, hogy pótold!",
},
"de_de": {
@ -59,8 +57,7 @@ extension Localization on String {
"Messages": "Nachrichten",
"Absences": "Fehlen",
"update_available": "Update verfügbar",
"missed_exams": "Diese Woche haben Sie %s Prüfungen verpasst."
.one("Diese Woche haben Sie eine Prüfung verpasst."),
"missed_exams": "Diese Woche haben Sie %s Prüfungen verpasst.",
"missed_exam_contact": "Wenden Sie sich an %s, um sie zu erneuern!",
},
};

View File

@ -5,8 +5,8 @@ extension Localization on String {
{
"en_en": {
"next": "Next",
"remaining min": "%d mins".one("%d min"),
"remaining sec": "%d secs".one("%d sec"),
"remaining min": "%d min(s)",
"remaining sec": "%d sec(s)",
"break": "Break",
"go to room": "Go to room %s.",
"go ground floor": "Go to the ground floor.",
@ -27,8 +27,8 @@ extension Localization on String {
},
"hu_hu": {
"next": "Következő",
"remaining min": "%d perc".one("%d perc"),
"remaining sec": "%d másodperc".one("%d másodperc"),
"remaining min": "%d perc",
"remaining sec": "%d másodperc",
"break": "Szünet",
"go to room": "Menj a(z) %s terembe.",
"go ground floor": "Menj a földszintre.",
@ -49,8 +49,8 @@ extension Localization on String {
},
"de_de": {
"next": "Nächste",
"remaining min": "%d Minuten".one("%d Minute"),
"remaining sec": "%d Sekunden".one("%d Sekunden"),
"remaining min": "%d Minute(n)",
"remaining sec": "%d Sekunde(n)",
"break": "Pause",
"go to room": "Geh in den Raum %s.",
"go ground floor": "Geh dir Treppe hinunter.",

View File

@ -276,4 +276,4 @@ class ErrorDetail extends StatelessWidget {
),
);
}
}
}

View File

@ -5,7 +5,7 @@ extension SettingsLocalization on String {
{
"en_en": {
"ekretaYou": "e-KRÉTA, you",
"description": "An error occurred!",
"description": "Unexpected error while using the application!",
"submit": "Submit",
"goback": "Go back",
"details": "Details",
@ -15,11 +15,11 @@ extension SettingsLocalization on String {
"stack": "Stack Trace",
"done": "Done",
"smth_went_wrong":
"Something went wrong, it is of course the fault of Educational Development Informatikai Zrt. (e-KRÉTA) in any case! /s",
"An unexpected error occurred while using the app.",
},
"hu_hu": {
"ekretaYou": "e-KRÉTA, te",
"description": "Fasz-emulátor hivatásos balfasz!",
"description": "Váratlan hiba az alkalmazás használata közben!",
"submit": "Hiba jelentése",
"goback": "Vissza",
"details": "Részletek",
@ -29,11 +29,11 @@ extension SettingsLocalization on String {
"stack": "Stacktrace",
"done": "Kész",
"smth_went_wrong":
"Valami probléma történt, ez természetesen az Educational Development Informatikai Zrt. (e-KRÉTA) hibája minden esetben! /s",
"Nem várt hiba következett be az alkalmazás használata közben.",
},
"de_de": {
"ekretaYou": "e-KRÉTA, du",
"description": "Ein Fehler ist aufgetreten!",
"description": "Unerwarteter Fehler bei der Benutzung der Anwendung!",
"submit": "Abschicken",
"goback": "Zurück",
"details": "Details",
@ -43,7 +43,7 @@ extension SettingsLocalization on String {
"stack": "Stack Trace",
"done": "Fertig",
"smth_went_wrong":
"Irgendetwas ist schief gelaufen, es ist natürlich auf jeden Fall die Schuld der Educational Development Informatikai Zrt. (e-KRÉTA)! /s",
"Bei der Benutzung der Anwendung ist ein unerwarteter Fehler aufgetreten.",
},
};

View File

@ -59,10 +59,6 @@ class AccountView extends StatelessWidget {
const SizedBox(
height: 10.0,
),
// Detail(
// title: "parents".i18n,
// description: user.student.parents.join(", ")),
Detail(title: "school".i18n, description: user.student.school.name),
],
),
);

View File

@ -8,22 +8,22 @@ extension Localization on String {
"school": "School",
"class": "Class",
"address": "Home address",
"parents": "Parents".one("Parent"),
"parents_phone": "Parents' phone number: ".one("Parent"),
"parents": "Parent(s)",
"parents_phone": "Parents' phone number: ",
},
"hu_hu": {
"birthdate": "Születési dátum",
"school": "Iskola",
"class": "Osztály",
"address": "Lakcím",
"parents": "Szülők".one("Szülő"),
"parents": "Szülő(k)",
},
"de_de": {
"birthdate": "Geburtsdatum",
"school": "Schule",
"class": "Klasse",
"address": "Wohnanschrift",
"parents": "Eltern",
"parents": "Elter(n)",
},
};

View File

@ -4,6 +4,8 @@ extension SettingsLocalization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {
"heads_up": "Heads up!",
"export_warning": "Exported grades are currently not yet viewable in reFilc, you'll only be able to view them manually in JSON format. In the future, this functionality will be extended and you will be able to view the tickets in the app interface.",
"personal_details": "Personal Details",
"open_dkt": "Open DCS",
"edit_nickname": "Edit Nickname",
@ -126,6 +128,8 @@ extension SettingsLocalization on String {
"grade_exporting": "Grade Exporting",
},
"hu_hu": {
"heads_up": "Figyelem!",
"export_warning": "Az exportált jegyek jelenleg még nem megtekinthetők a reFilc-ben, csak te magad tudod átnézni őket JSON formátumban. A jövőben ez a funkció bővülni fog, és a jegyeket meg is tekintheted majd a reFilc felületén.",
"personal_details": "Személyes információk",
"open_dkt": "DKT megnyitása",
"edit_nickname": "Becenév szerkesztése",
@ -248,6 +252,8 @@ extension SettingsLocalization on String {
"grade_exporting": "Jegy exportálás",
},
"de_de": {
"heads_up": "Achtung!",
"export_warning": "Exportierte Tickets sind derzeit noch nicht in reFilc einsehbar, Sie können sie nur selbst im JSON- Format überprüfen. In Zukunft wird diese Funktionalität erweitert und Sie werden die Tickets in der reFilc-Oberfläche anzeigen können",
"personal_details": "Persönliche Angaben",
"open_dkt": "Öffnen RDZ",
"edit_nickname": "Spitznamen bearbeiten",

View File

@ -24,26 +24,17 @@ extension SettingsLocalization on String {
"dontfelt": "You didn't like this...",
"youlate": "You're late!",
// allsum page
"test": "tests"
.one("test"),
"closingtest": "module tests"
.one("module test"),
"grade": "grades"
.one("grade"),
"hw": "homeworks"
.one("homework"),
"subject": "subjects"
.one("subject"),
"lesson": "lessons"
.one("lesson"),
"absence_sum": "absences"
.one("absence"),
"test": "test(s)",
"closingtest": "module test(s)",
"grade": "grade(s)",
"hw": "homework(s)",
"subject": "subject(s)",
"lesson": "lesson(s)",
"absence_sum": "absence(s)",
"excused": "excused",
"unexcused": "unexcused",
"delay_sum": "delays"
.one("delay"),
"min": "minutes"
.one("minute"),
"delay_sum": "delay(s)",
"min": "minute(s)",
// personality page
"click_reveal": "Click to reveal...",
},

View File

@ -72,6 +72,7 @@ dependencies:
carousel_slider: ^4.2.1
flutter_portal: ^1.1.4
webview_flutter: ^4.8.0
file_picker: ^6.2.1
dev_dependencies:
flutter_lints: ^3.0.1