teacher rename base and settings done :orbnsmirk:

This commit is contained in:
Kima 2023-08-26 14:56:57 +02:00
parent 2d11c45972
commit e64ab75753
11 changed files with 718 additions and 106 deletions

View File

@ -25,7 +25,8 @@ const settingsDB = DatabaseStruct("settings", {
"grade_opening_fun": int, "icon_pack": String, "premium_scopes": String, "grade_opening_fun": int, "icon_pack": String, "premium_scopes": String,
"premium_token": String, "premium_login": String, "premium_token": String, "premium_login": String,
"last_account_id": String, "renamed_subjects_enabled": int, "last_account_id": String, "renamed_subjects_enabled": int,
"renamed_subjects_italics": int, "renamed_subjects_italics": int, "renamed_teachers_enabled": int,
"renamed_teachers_italics": int,
}); });
// DON'T FORGET TO UPDATE DEFAULT VALUES IN `initDB` MIGRATION OR ELSE PARENTS WILL COMPLAIN ABOUT THEIR CHILDREN MISSING // DON'T FORGET TO UPDATE DEFAULT VALUES IN `initDB` MIGRATION OR ELSE PARENTS WILL COMPLAIN ABOUT THEIR CHILDREN MISSING
// YOU'VE BEEN WARNED!!! // YOU'VE BEEN WARNED!!!
@ -40,6 +41,8 @@ const userDataDB = DatabaseStruct("user_data", {
"events": String, "absences": String, "group_averages": String, "events": String, "absences": String, "group_averages": String,
// renamed subjects // non kreta data // renamed subjects // non kreta data
"renamed_subjects": String, "renamed_subjects": String,
// renamed teachers // non kreta data
"renamed_teachers": String,
// "subject_lesson_count": String, // non kreta data // "subject_lesson_count": String, // non kreta data
"last_seen_grade": int, "last_seen_grade": int,
}); });

View File

@ -26,7 +26,8 @@ class DatabaseQuery {
Future<SettingsProvider> getSettings(DatabaseProvider database) async { Future<SettingsProvider> getSettings(DatabaseProvider database) async {
Map settingsMap = (await db.query("settings")).elementAt(0); Map settingsMap = (await db.query("settings")).elementAt(0);
SettingsProvider settings = SettingsProvider.fromMap(settingsMap, database: database); SettingsProvider settings =
SettingsProvider.fromMap(settingsMap, database: database);
return settings; return settings;
} }
@ -36,7 +37,10 @@ class DatabaseQuery {
for (var user in usersMap) { for (var user in usersMap) {
userProvider.addUser(User.fromMap(user)); userProvider.addUser(User.fromMap(user));
} }
if (userProvider.getUsers().map((e) => e.id).contains(settings.lastAccountId)) { if (userProvider
.getUsers()
.map((e) => e.id)
.contains(settings.lastAccountId)) {
userProvider.setUser(settings.lastAccountId); userProvider.setUser(settings.lastAccountId);
} else { } else {
if (usersMap.isNotEmpty) { if (usersMap.isNotEmpty) {
@ -54,100 +58,133 @@ class UserDatabaseQuery {
final Database db; final Database db;
Future<List<Grade>> getGrades({required String userId}) async { Future<List<Grade>> getGrades({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? gradesJson = userData.elementAt(0)["grades"] as String?; String? gradesJson = userData.elementAt(0)["grades"] as String?;
if (gradesJson == null) return []; if (gradesJson == null) return [];
List<Grade> grades = (jsonDecode(gradesJson) as List).map((e) => Grade.fromJson(e)).toList(); List<Grade> grades =
(jsonDecode(gradesJson) as List).map((e) => Grade.fromJson(e)).toList();
return grades; return grades;
} }
Future<Map<Week, List<Lesson>>> getLessons({required String userId}) async { Future<Map<Week, List<Lesson>>> getLessons({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return {}; if (userData.isEmpty) return {};
String? lessonsJson = userData.elementAt(0)["timetable"] as String?; String? lessonsJson = userData.elementAt(0)["timetable"] as String?;
if (lessonsJson == null) return {}; if (lessonsJson == null) return {};
if (jsonDecode(lessonsJson) is List) return {}; if (jsonDecode(lessonsJson) is List) return {};
Map<Week, List<Lesson>> lessons = (jsonDecode(lessonsJson) as Map).cast<String, List>().map((key, value) { Map<Week, List<Lesson>> lessons =
return MapEntry(Week.fromId(int.parse(key)), value.cast<Map<String, Object?>>().map((e) => Lesson.fromJson(e)).toList()); (jsonDecode(lessonsJson) as Map).cast<String, List>().map((key, value) {
return MapEntry(
Week.fromId(int.parse(key)),
value
.cast<Map<String, Object?>>()
.map((e) => Lesson.fromJson(e))
.toList());
}).cast(); }).cast();
return lessons; return lessons;
} }
Future<List<Exam>> getExams({required String userId}) async { Future<List<Exam>> getExams({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? examsJson = userData.elementAt(0)["exams"] as String?; String? examsJson = userData.elementAt(0)["exams"] as String?;
if (examsJson == null) return []; if (examsJson == null) return [];
List<Exam> exams = (jsonDecode(examsJson) as List).map((e) => Exam.fromJson(e)).toList(); List<Exam> exams =
(jsonDecode(examsJson) as List).map((e) => Exam.fromJson(e)).toList();
return exams; return exams;
} }
Future<List<Homework>> getHomework({required String userId}) async { Future<List<Homework>> getHomework({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? homeworkJson = userData.elementAt(0)["homework"] as String?; String? homeworkJson = userData.elementAt(0)["homework"] as String?;
if (homeworkJson == null) return []; if (homeworkJson == null) return [];
List<Homework> homework = (jsonDecode(homeworkJson) as List).map((e) => Homework.fromJson(e)).toList(); List<Homework> homework = (jsonDecode(homeworkJson) as List)
.map((e) => Homework.fromJson(e))
.toList();
return homework; return homework;
} }
Future<List<Message>> getMessages({required String userId}) async { Future<List<Message>> getMessages({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? messagesJson = userData.elementAt(0)["messages"] as String?; String? messagesJson = userData.elementAt(0)["messages"] as String?;
if (messagesJson == null) return []; if (messagesJson == null) return [];
List<Message> messages = (jsonDecode(messagesJson) as List).map((e) => Message.fromJson(e)).toList(); List<Message> messages = (jsonDecode(messagesJson) as List)
.map((e) => Message.fromJson(e))
.toList();
return messages; return messages;
} }
Future<List<Note>> getNotes({required String userId}) async { Future<List<Note>> getNotes({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? notesJson = userData.elementAt(0)["notes"] as String?; String? notesJson = userData.elementAt(0)["notes"] as String?;
if (notesJson == null) return []; if (notesJson == null) return [];
List<Note> notes = (jsonDecode(notesJson) as List).map((e) => Note.fromJson(e)).toList(); List<Note> notes =
(jsonDecode(notesJson) as List).map((e) => Note.fromJson(e)).toList();
return notes; return notes;
} }
Future<List<Event>> getEvents({required String userId}) async { Future<List<Event>> getEvents({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? eventsJson = userData.elementAt(0)["events"] as String?; String? eventsJson = userData.elementAt(0)["events"] as String?;
if (eventsJson == null) return []; if (eventsJson == null) return [];
List<Event> events = (jsonDecode(eventsJson) as List).map((e) => Event.fromJson(e)).toList(); List<Event> events =
(jsonDecode(eventsJson) as List).map((e) => Event.fromJson(e)).toList();
return events; return events;
} }
Future<List<Absence>> getAbsences({required String userId}) async { Future<List<Absence>> getAbsences({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? absencesJson = userData.elementAt(0)["absences"] as String?; String? absencesJson = userData.elementAt(0)["absences"] as String?;
if (absencesJson == null) return []; if (absencesJson == null) return [];
List<Absence> absences = (jsonDecode(absencesJson) as List).map((e) => Absence.fromJson(e)).toList(); List<Absence> absences = (jsonDecode(absencesJson) as List)
.map((e) => Absence.fromJson(e))
.toList();
return absences; return absences;
} }
Future<List<GroupAverage>> getGroupAverages({required String userId}) async { Future<List<GroupAverage>> getGroupAverages({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? groupAveragesJson = userData.elementAt(0)["group_averages"] as String?; String? groupAveragesJson =
userData.elementAt(0)["group_averages"] as String?;
if (groupAveragesJson == null) return []; if (groupAveragesJson == null) return [];
List<GroupAverage> groupAverages = (jsonDecode(groupAveragesJson) as List).map((e) => GroupAverage.fromJson(e)).toList(); List<GroupAverage> groupAverages = (jsonDecode(groupAveragesJson) as List)
.map((e) => GroupAverage.fromJson(e))
.toList();
return groupAverages; return groupAverages;
} }
Future<SubjectLessonCount> getSubjectLessonCount({required String userId}) async { Future<SubjectLessonCount> getSubjectLessonCount(
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); {required String userId}) async {
List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return SubjectLessonCount.fromMap({}); if (userData.isEmpty) return SubjectLessonCount.fromMap({});
String? lessonCountJson = userData.elementAt(0)["subject_lesson_count"] as String?; String? lessonCountJson =
userData.elementAt(0)["subject_lesson_count"] as String?;
if (lessonCountJson == null) return SubjectLessonCount.fromMap({}); if (lessonCountJson == null) return SubjectLessonCount.fromMap({});
SubjectLessonCount lessonCount = SubjectLessonCount.fromMap(jsonDecode(lessonCountJson) as Map); SubjectLessonCount lessonCount =
SubjectLessonCount.fromMap(jsonDecode(lessonCountJson) as Map);
return lessonCount; return lessonCount;
} }
Future<DateTime> lastSeenGrade({required String userId}) async { Future<DateTime> lastSeenGrade({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return DateTime(0); if (userData.isEmpty) return DateTime(0);
int? lastSeenDate = userData.elementAt(0)["last_seen_grade"] as int?; int? lastSeenDate = userData.elementAt(0)["last_seen_grade"] as int?;
if (lastSeenDate == null) return DateTime(0); if (lastSeenDate == null) return DateTime(0);
@ -156,10 +193,24 @@ class UserDatabaseQuery {
} }
Future<Map<String, String>> renamedSubjects({required String userId}) async { Future<Map<String, String>> renamedSubjects({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return {}; if (userData.isEmpty) return {};
String? renamedSubjectsJson = userData.elementAt(0)["renamed_subjects"] as String?; String? renamedSubjectsJson =
userData.elementAt(0)["renamed_subjects"] as String?;
if (renamedSubjectsJson == null) return {}; if (renamedSubjectsJson == null) return {};
return (jsonDecode(renamedSubjectsJson) as Map).map((key, value) => MapEntry(key.toString(), value.toString())); return (jsonDecode(renamedSubjectsJson) as Map)
.map((key, value) => MapEntry(key.toString(), value.toString()));
}
Future<Map<String, String>> renamedTeachers({required String userId}) async {
List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return {};
String? renamedTeachersJson =
userData.elementAt(0)["renamed_teachers"] as String?;
if (renamedTeachersJson == null) return {};
return (jsonDecode(renamedTeachersJson) as Map)
.map((key, value) => MapEntry(key.toString(), value.toString()));
} }
} }

View File

@ -27,9 +27,11 @@ class DatabaseStore {
} }
Future<void> storeUser(User user) async { Future<void> storeUser(User user) async {
List userRes = await db.query("users", where: "id = ?", whereArgs: [user.id]); List userRes =
await db.query("users", where: "id = ?", whereArgs: [user.id]);
if (userRes.isNotEmpty) { if (userRes.isNotEmpty) {
await db.update("users", user.toMap(), where: "id = ?", whereArgs: [user.id]); await db
.update("users", user.toMap(), where: "id = ?", whereArgs: [user.id]);
} else { } else {
await db.insert("users", user.toMap()); await db.insert("users", user.toMap());
await db.insert("user_data", {"id": user.id}); await db.insert("user_data", {"id": user.id});
@ -49,64 +51,93 @@ class UserDatabaseStore {
Future<void> storeGrades(List<Grade> grades, {required String userId}) async { Future<void> storeGrades(List<Grade> grades, {required String userId}) async {
String gradesJson = jsonEncode(grades.map((e) => e.json).toList()); String gradesJson = jsonEncode(grades.map((e) => e.json).toList());
await db.update("user_data", {"grades": gradesJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"grades": gradesJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeLessons(Map<Week, List<Lesson>?> lessons, {required String userId}) async { Future<void> storeLessons(Map<Week, List<Lesson>?> lessons,
{required String userId}) async {
final map = lessons.map<String, List<Map<String, Object?>>>( final map = lessons.map<String, List<Map<String, Object?>>>(
(k, v) => MapEntry(k.id.toString(), v!.where((e) => e.json != null).map((e) => e.json!).toList().cast()), (k, v) => MapEntry(k.id.toString(),
v!.where((e) => e.json != null).map((e) => e.json!).toList().cast()),
); );
String lessonsJson = jsonEncode(map); String lessonsJson = jsonEncode(map);
await db.update("user_data", {"timetable": lessonsJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"timetable": lessonsJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeExams(List<Exam> exams, {required String userId}) async { Future<void> storeExams(List<Exam> exams, {required String userId}) async {
String examsJson = jsonEncode(exams.map((e) => e.json).toList()); String examsJson = jsonEncode(exams.map((e) => e.json).toList());
await db.update("user_data", {"exams": examsJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"exams": examsJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeHomework(List<Homework> homework, {required String userId}) async { Future<void> storeHomework(List<Homework> homework,
{required String userId}) async {
String homeworkJson = jsonEncode(homework.map((e) => e.json).toList()); String homeworkJson = jsonEncode(homework.map((e) => e.json).toList());
await db.update("user_data", {"homework": homeworkJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"homework": homeworkJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeMessages(List<Message> messages, {required String userId}) async { Future<void> storeMessages(List<Message> messages,
{required String userId}) async {
String messagesJson = jsonEncode(messages.map((e) => e.json).toList()); String messagesJson = jsonEncode(messages.map((e) => e.json).toList());
await db.update("user_data", {"messages": messagesJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"messages": messagesJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeNotes(List<Note> notes, {required String userId}) async { Future<void> storeNotes(List<Note> notes, {required String userId}) async {
String notesJson = jsonEncode(notes.map((e) => e.json).toList()); String notesJson = jsonEncode(notes.map((e) => e.json).toList());
await db.update("user_data", {"notes": notesJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"notes": notesJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeEvents(List<Event> events, {required String userId}) async { Future<void> storeEvents(List<Event> events, {required String userId}) async {
String eventsJson = jsonEncode(events.map((e) => e.json).toList()); String eventsJson = jsonEncode(events.map((e) => e.json).toList());
await db.update("user_data", {"events": eventsJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"events": eventsJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeAbsences(List<Absence> absences, {required String userId}) async { Future<void> storeAbsences(List<Absence> absences,
{required String userId}) async {
String absencesJson = jsonEncode(absences.map((e) => e.json).toList()); String absencesJson = jsonEncode(absences.map((e) => e.json).toList());
await db.update("user_data", {"absences": absencesJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"absences": absencesJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeGroupAverages(List<GroupAverage> groupAverages, {required String userId}) async { Future<void> storeGroupAverages(List<GroupAverage> groupAverages,
String groupAveragesJson = jsonEncode(groupAverages.map((e) => e.json).toList()); {required String userId}) async {
await db.update("user_data", {"group_averages": groupAveragesJson}, where: "id = ?", whereArgs: [userId]); String groupAveragesJson =
jsonEncode(groupAverages.map((e) => e.json).toList());
await db.update("user_data", {"group_averages": groupAveragesJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeSubjectLessonCount(SubjectLessonCount lessonCount, {required String userId}) async { Future<void> storeSubjectLessonCount(SubjectLessonCount lessonCount,
{required String userId}) async {
String lessonCountJson = jsonEncode(lessonCount.toMap()); String lessonCountJson = jsonEncode(lessonCount.toMap());
await db.update("user_data", {"subject_lesson_count": lessonCountJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"subject_lesson_count": lessonCountJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeLastSeenGrade(DateTime date, {required String userId}) async { Future<void> storeLastSeenGrade(DateTime date,
{required String userId}) async {
int lastSeenDate = date.millisecondsSinceEpoch; int lastSeenDate = date.millisecondsSinceEpoch;
await db.update("user_data", {"last_seen_grade": lastSeenDate}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"last_seen_grade": lastSeenDate},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeRenamedSubjects(Map<String, String> subjects, {required String userId}) async { Future<void> storeRenamedSubjects(Map<String, String> subjects,
{required String userId}) async {
String renamedSubjectsJson = jsonEncode(subjects); String renamedSubjectsJson = jsonEncode(subjects);
await db.update("user_data", {"renamed_subjects": renamedSubjectsJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"renamed_subjects": renamedSubjectsJson},
where: "id = ?", whereArgs: [userId]);
}
Future<void> storeRenamedTeachers(Map<String, String> teachers,
{required String userId}) async {
String renamedTeachersJson = jsonEncode(teachers);
await db.update("user_data", {"renamed_teachers": renamedTeachersJson},
where: "id = ?", whereArgs: [userId]);
} }
} }

View File

@ -69,6 +69,8 @@ class SettingsProvider extends ChangeNotifier {
String _lastAccountId; String _lastAccountId;
bool _renamedSubjectsEnabled; bool _renamedSubjectsEnabled;
bool _renamedSubjectsItalics; bool _renamedSubjectsItalics;
bool _renamedTeachersEnabled;
bool _renamedTeachersItalics;
SettingsProvider({ SettingsProvider({
DatabaseProvider? database, DatabaseProvider? database,
@ -106,6 +108,8 @@ class SettingsProvider extends ChangeNotifier {
required String lastAccountId, required String lastAccountId,
required bool renameSubjectsEnabled, required bool renameSubjectsEnabled,
required bool renameSubjectsItalics, required bool renameSubjectsItalics,
required bool renameTeachersEnabled,
required bool renameTeachersItalics,
}) : _database = database, }) : _database = database,
_language = language, _language = language,
_startPage = startPage, _startPage = startPage,
@ -140,7 +144,9 @@ class SettingsProvider extends ChangeNotifier {
_premiumLogin = premiumLogin, _premiumLogin = premiumLogin,
_lastAccountId = lastAccountId, _lastAccountId = lastAccountId,
_renamedSubjectsEnabled = renameSubjectsEnabled, _renamedSubjectsEnabled = renameSubjectsEnabled,
_renamedSubjectsItalics = renameSubjectsItalics; _renamedSubjectsItalics = renameSubjectsItalics,
_renamedTeachersEnabled = renameTeachersEnabled,
_renamedTeachersItalics = renameTeachersItalics;
factory SettingsProvider.fromMap(Map map, factory SettingsProvider.fromMap(Map map,
{required DatabaseProvider database}) { {required DatabaseProvider database}) {
@ -195,6 +201,8 @@ class SettingsProvider extends ChangeNotifier {
lastAccountId: map["last_account_id"], lastAccountId: map["last_account_id"],
renameSubjectsEnabled: map["renamed_subjects_enabled"] == 1, renameSubjectsEnabled: map["renamed_subjects_enabled"] == 1,
renameSubjectsItalics: map["renamed_subjects_italics"] == 1, renameSubjectsItalics: map["renamed_subjects_italics"] == 1,
renameTeachersEnabled: map["renamed_teachers_enabled"] == 1,
renameTeachersItalics: map["renamed_teachers_italics"] == 1,
); );
} }
@ -236,7 +244,9 @@ class SettingsProvider extends ChangeNotifier {
"premium_login": _premiumLogin, "premium_login": _premiumLogin,
"last_account_id": _lastAccountId, "last_account_id": _lastAccountId,
"renamed_subjects_enabled": _renamedSubjectsEnabled ? 1 : 0, "renamed_subjects_enabled": _renamedSubjectsEnabled ? 1 : 0,
"renamed_subjects_italics": _renamedSubjectsItalics ? 1 : 0 "renamed_subjects_italics": _renamedSubjectsItalics ? 1 : 0,
"renamed_teachers_enabled": _renamedTeachersEnabled ? 1 : 0,
"renamed_teachers_italics": _renamedTeachersItalics ? 1 : 0,
}; };
} }
@ -283,6 +293,8 @@ class SettingsProvider extends ChangeNotifier {
lastAccountId: "", lastAccountId: "",
renameSubjectsEnabled: false, renameSubjectsEnabled: false,
renameSubjectsItalics: false, renameSubjectsItalics: false,
renameTeachersEnabled: false,
renameTeachersItalics: false,
); );
} }
@ -324,6 +336,8 @@ class SettingsProvider extends ChangeNotifier {
String get lastAccountId => _lastAccountId; String get lastAccountId => _lastAccountId;
bool get renamedSubjectsEnabled => _renamedSubjectsEnabled; bool get renamedSubjectsEnabled => _renamedSubjectsEnabled;
bool get renamedSubjectsItalics => _renamedSubjectsItalics; bool get renamedSubjectsItalics => _renamedSubjectsItalics;
bool get renamedTeachersEnabled => _renamedTeachersEnabled;
bool get renamedTeachersItalics => _renamedTeachersItalics;
Future<void> update({ Future<void> update({
bool store = true, bool store = true,
@ -361,6 +375,8 @@ class SettingsProvider extends ChangeNotifier {
String? lastAccountId, String? lastAccountId,
bool? renamedSubjectsEnabled, bool? renamedSubjectsEnabled,
bool? renamedSubjectsItalics, bool? renamedSubjectsItalics,
bool? renamedTeachersEnabled,
bool? renamedTeachersItalics,
}) async { }) async {
if (language != null && language != _language) _language = language; if (language != null && language != _language) _language = language;
if (startPage != null && startPage != _startPage) _startPage = startPage; if (startPage != null && startPage != _startPage) _startPage = startPage;
@ -448,6 +464,14 @@ class SettingsProvider extends ChangeNotifier {
renamedSubjectsItalics != _renamedSubjectsItalics) { renamedSubjectsItalics != _renamedSubjectsItalics) {
_renamedSubjectsItalics = renamedSubjectsItalics; _renamedSubjectsItalics = renamedSubjectsItalics;
} }
if (renamedTeachersEnabled != null &&
renamedTeachersEnabled != _renamedTeachersEnabled) {
_renamedTeachersEnabled = renamedTeachersEnabled;
}
if (renamedTeachersItalics != null &&
renamedTeachersItalics != _renamedTeachersItalics) {
_renamedTeachersItalics = renamedTeachersItalics;
}
if (store) await _database?.store.storeSettings(this); if (store) await _database?.store.storeSettings(this);
notifyListeners(); notifyListeners();
} }

View File

@ -0,0 +1,34 @@
import 'package:filcnaplo/utils/format.dart';
class Teacher {
String id;
String name;
String? renamedTo;
bool get isRenamed => renamedTo != null;
Teacher({required this.id, required this.name, this.renamedTo});
factory Teacher.fromJson(Map json) {
return Teacher(
id: json["Uid"] ?? "",
name: (json["Nev"] ?? "").trim(),
);
}
factory Teacher.fromString(String string) {
return Teacher(
id: string.trim().replaceAll(' ', '').toLowerCase().specialChars(),
name: string.trim(),
);
}
@override
bool operator ==(other) {
if (other is! Teacher) return false;
return id == other.id;
}
@override
int get hashCode => id.hashCode;
}

View File

@ -41,6 +41,7 @@ import 'package:filcnaplo_premium/ui/mobile/settings/nickname.dart';
import 'package:filcnaplo_premium/ui/mobile/settings/profile_pic.dart'; import 'package:filcnaplo_premium/ui/mobile/settings/profile_pic.dart';
import 'package:filcnaplo_premium/ui/mobile/settings/icon_pack.dart'; import 'package:filcnaplo_premium/ui/mobile/settings/icon_pack.dart';
import 'package:filcnaplo_premium/ui/mobile/settings/modify_subject_names.dart'; import 'package:filcnaplo_premium/ui/mobile/settings/modify_subject_names.dart';
import 'package:filcnaplo_premium/ui/mobile/settings/modify_teacher_names.dart';
class SettingsScreen extends StatefulWidget { class SettingsScreen extends StatefulWidget {
const SettingsScreen({Key? key}) : super(key: key); const SettingsScreen({Key? key}) : super(key: key);
@ -805,6 +806,9 @@ class _SettingsScreenState extends State<SettingsScreen>
MenuRenamedSubjects( MenuRenamedSubjects(
settings: settings, settings: settings,
), ),
MenuRenamedTeachers(
settings: settings,
),
], ],
), ),
), ),

View File

@ -18,6 +18,7 @@ class PremiumScopes {
/// Modify subject names /// Modify subject names
static const renameSubjects = "filc.premium.RENAME_SUBJECTS"; static const renameSubjects = "filc.premium.RENAME_SUBJECTS";
static const renameTeachers = "filc.premium.RENAME_TEACHERS";
/// Tinta /// Tinta

View File

@ -8,6 +8,7 @@ enum PremiumFeature {
profile, profile,
iconpack, iconpack,
subjectrename, subjectrename,
teacherrename,
weeklytimetable, weeklytimetable,
goalplanner, goalplanner,
widget, widget,

View File

@ -4,6 +4,7 @@ extension SettingsLocalization on String {
static final _t = Translations.byLocale("hu_hu") + static final _t = Translations.byLocale("hu_hu") +
{ {
"en_en": { "en_en": {
// subject rename
"renamed_subjects": "Renamed Subjects", "renamed_subjects": "Renamed Subjects",
"rename_subjects": "Rename Subjects", "rename_subjects": "Rename Subjects",
"rename_subject": "Rename Subject", "rename_subject": "Rename Subject",
@ -13,21 +14,37 @@ extension SettingsLocalization on String {
"cancel": "Cancel", "cancel": "Cancel",
"done": "Done", "done": "Done",
"rename_new_subject": "Rename New Subject", "rename_new_subject": "Rename New Subject",
"italics_toggle": "Toggle Italics", "italics_toggle": "Italic Font",
// teacher rename
"renamed_teachers": "Renamed Teachers",
"rename_teachers": "Rename Teachers",
"rename_teacher": "Rename Teacher",
"select_teacher": "Select Teacher",
"modify_teachers": "Modify Teachers",
"rename_new_teacher": "Rename New Teacher",
}, },
"hu_hu": { "hu_hu": {
// subject rename
"renamed_subjects": "Átnevezett Tantárgyaid", "renamed_subjects": "Átnevezett Tantárgyaid",
"rename_subjects": "Tantárgyak átnevezése", "rename_subjects": "Tantárgyak átnevezése",
"rename_subject": "Tantárgy átnevezése", "rename_subject": "Tantárgy átnevezése",
"select_subject": "Válassz tantárgyat", "select_subject": "Válassz tantárgyat",
"modified_name": "Módosított név", "modified_name": "Módosított név",
"modify_subjects": "Tantárgyak átnevezése", "modify_subjects": "Tantárgyak módosítása",
"cancel": "Mégse", "cancel": "Mégse",
"done": "Kész", "done": "Kész",
"rename_new_subject": "Új Tantárgy átnevezése", "rename_new_subject": "Új tantárgy átnevezése",
"italics_toggle": "Dőlt betűs megjelenítés", "italics_toggle": "Dőlt betűs megjelenítés",
// teacher rename
"renamed_teachers": "Átnevezett tanáraid",
"rename_teachers": "Tanárok átnevezése",
"rename_teacher": "Tanár átnevezése",
"select_teacher": "Válassz tanárt",
"modify_teachers": "Tanárok módosítása",
"rename_new_teacher": "Új tanár átnevezése",
}, },
"de_de": { "de_de": {
// subject rename
"renamed_subjects": "Umbenannte Fächer", "renamed_subjects": "Umbenannte Fächer",
"rename_subjects": "Fächer umbenennen", "rename_subjects": "Fächer umbenennen",
"rename_subject": "Fach umbenennen", "rename_subject": "Fach umbenennen",
@ -38,6 +55,13 @@ extension SettingsLocalization on String {
"done": "Erledigt", "done": "Erledigt",
"rename_new_subject": "Neues Fach umbenennen", "rename_new_subject": "Neues Fach umbenennen",
"italics_toggle": "Kursivschrift umschalten", "italics_toggle": "Kursivschrift umschalten",
// teacher rename
"renamed_teachers": "Renamed Teachers",
"rename_teachers": "Rename Teachers",
"rename_teacher": "Rename Teacher",
"select_teacher": "Select Teacher",
"modify_teachers": "Modify Teachers",
"rename_new_teacher": "Rename New Teacher",
}, },
}; };

View File

@ -19,7 +19,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'modify_subject_names.i18n.dart'; import 'modify_names.i18n.dart';
class MenuRenamedSubjects extends StatelessWidget { class MenuRenamedSubjects extends StatelessWidget {
const MenuRenamedSubjects({Key? key, required this.settings}) const MenuRenamedSubjects({Key? key, required this.settings})

View File

@ -0,0 +1,439 @@
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/theme/colors/colors.dart';
import 'package:filcnaplo/utils/format.dart';
import 'package:filcnaplo_kreta_api/models/teacher.dart';
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart';
import 'package:filcnaplo_mobile_ui/common/panel/panel.dart';
import 'package:filcnaplo_mobile_ui/common/panel/panel_button.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_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart';
import 'modify_names.i18n.dart';
class MenuRenamedTeachers extends StatelessWidget {
const MenuRenamedTeachers({Key? key, required this.settings})
: super(key: key);
final SettingsProvider settings;
@override
Widget build(BuildContext context) {
return PanelButton(
padding: const EdgeInsets.only(left: 14.0),
onPressed: () {
if (!Provider.of<PremiumProvider>(context, listen: false)
.hasScope(PremiumScopes.renameTeachers)) {
PremiumLockedFeatureUpsell.show(
context: context, feature: PremiumFeature.teacherrename);
return;
}
Navigator.of(context, rootNavigator: true).push(
CupertinoPageRoute(builder: (context) => const ModifyTeacherNames()),
);
},
title: Text(
"rename_teachers".i18n,
style: TextStyle(
color: AppColors.of(context)
.text
.withOpacity(settings.renamedTeachersEnabled ? 1.0 : .5)),
),
leading: settings.renamedTeachersEnabled
? const Icon(FeatherIcons.penTool)
: Icon(FeatherIcons.penTool,
color: AppColors.of(context).text.withOpacity(.25)),
trailingDivider: true,
trailing: Switch(
onChanged: (v) async {
if (!Provider.of<PremiumProvider>(context, listen: false)
.hasScope(PremiumScopes.renameTeachers)) {
PremiumLockedFeatureUpsell.show(
context: context, feature: PremiumFeature.teacherrename);
return;
}
settings.update(renamedTeachersEnabled: v);
await Provider.of<GradeProvider>(context, listen: false)
.convertBySettings();
await Provider.of<TimetableProvider>(context, listen: false)
.convertBySettings();
await Provider.of<AbsenceProvider>(context, listen: false)
.convertBySettings();
},
value: settings.renamedTeachersEnabled,
activeColor: Theme.of(context).colorScheme.secondary,
),
);
}
}
class ModifyTeacherNames extends StatefulWidget {
const ModifyTeacherNames({Key? key}) : super(key: key);
@override
State<ModifyTeacherNames> createState() => _ModifyTeacherNamesState();
}
class _ModifyTeacherNamesState extends State<ModifyTeacherNames> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final _teacherName = TextEditingController();
String? selectedTeacherId;
late List<Teacher> teachers;
late UserProvider user;
late DatabaseProvider dbProvider;
late SettingsProvider settings;
@override
void initState() {
super.initState();
teachers = (Provider.of<GradeProvider>(context, listen: false)
.grades
.map((e) => e.teacher)
.toSet()
.toList()
..sort((a, b) => a.compareTo(b)))
.map((e) => Teacher.fromString(e))
.toList();
print(teachers.map((e) => e.name));
user = Provider.of<UserProvider>(context, listen: false);
dbProvider = Provider.of<DatabaseProvider>(context, listen: false);
}
Future<Map<String, String>> fetchRenamedTeachers() async {
return await dbProvider.userQuery.renamedTeachers(userId: user.id!);
}
void showRenameDialog() {
showDialog(
context: context,
builder: (context) => StatefulBuilder(builder: (context, setS) {
return AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(14.0))),
title: Text("rename_teacher".i18n),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
DropdownButton2(
items: teachers
.map((item) => DropdownMenuItem<String>(
value: item.id,
child: Text(
item.name,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: AppColors.of(context).text,
),
overflow: TextOverflow.ellipsis,
),
))
.toList(),
onChanged: (String? v) async {
final renamedSubs = await fetchRenamedTeachers();
setS(() {
selectedTeacherId = v;
if (renamedSubs.containsKey(selectedTeacherId)) {
_teacherName.text = renamedSubs[selectedTeacherId]!;
} else {
_teacherName.text = "";
}
});
},
iconSize: 14,
iconEnabledColor: AppColors.of(context).text,
iconDisabledColor: AppColors.of(context).text,
underline: const SizedBox(),
itemHeight: 40,
itemPadding: const EdgeInsets.only(left: 14, right: 14),
buttonWidth: 50,
dropdownWidth: 300,
dropdownPadding: null,
buttonDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
),
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(14),
),
dropdownElevation: 8,
scrollbarRadius: const Radius.circular(40),
scrollbarThickness: 6,
scrollbarAlwaysShow: true,
offset: const Offset(-10, -10),
buttonSplashColor: Colors.transparent,
customButton: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 2),
borderRadius: BorderRadius.circular(12.0),
),
padding: const EdgeInsets.symmetric(
vertical: 12.0, horizontal: 8.0),
child: Text(
selectedTeacherId == null
? "select_teacher".i18n
: teachers
.firstWhere(
(element) => element.id == selectedTeacherId)
.name,
style: Theme.of(context).textTheme.titleSmall!.copyWith(
fontWeight: FontWeight.w700,
color: AppColors.of(context).text.withOpacity(0.75)),
overflow: TextOverflow.ellipsis,
maxLines: 2,
textAlign: TextAlign.center,
),
),
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Icon(FeatherIcons.arrowDown, size: 32),
),
TextField(
controller: _teacherName,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide:
const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
focusedBorder: OutlineInputBorder(
borderSide:
const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
hintText: "modified_name".i18n,
suffixIcon: IconButton(
icon: const Icon(
FeatherIcons.x,
color: Colors.grey,
),
onPressed: () {
setState(() {
_teacherName.text = "";
});
},
),
),
),
],
),
actions: [
TextButton(
child: Text(
"cancel".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () {
Navigator.of(context).maybePop();
},
),
TextButton(
child: Text(
"done".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () async {
if (selectedTeacherId != null) {
final renamedSubs = await fetchRenamedTeachers();
renamedSubs[selectedTeacherId!] = _teacherName.text;
await dbProvider.userStore
.storeRenamedTeachers(renamedSubs, userId: user.id!);
await Provider.of<GradeProvider>(context, listen: false)
.convertBySettings();
await Provider.of<TimetableProvider>(context, listen: false)
.convertBySettings();
await Provider.of<AbsenceProvider>(context, listen: false)
.convertBySettings();
}
Navigator.of(context).pop(true);
setState(() {});
},
),
],
);
}),
).then((val) {
_teacherName.text = "";
selectedTeacherId = null;
});
}
@override
Widget build(BuildContext context) {
settings = Provider.of<SettingsProvider>(context);
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
surfaceTintColor: Theme.of(context).scaffoldBackgroundColor,
leading: BackButton(color: AppColors.of(context).text),
title: Text(
"modify_teachers".i18n,
style: TextStyle(color: AppColors.of(context).text),
),
),
body: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Panel(
child: SwitchListTile(
title: Text("italics_toggle".i18n),
onChanged: (value) =>
settings.update(renamedTeachersItalics: value),
value: settings.renamedTeachersItalics,
),
),
const SizedBox(
height: 20,
),
InkWell(
onTap: showRenameDialog,
borderRadius: BorderRadius.circular(12.0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 2),
borderRadius: BorderRadius.circular(12.0),
),
padding: const EdgeInsets.symmetric(
vertical: 18.0, horizontal: 12.0),
child: Center(
child: Text(
"rename_new_teacher".i18n,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 18,
color: AppColors.of(context).text.withOpacity(.85),
),
),
),
),
),
const SizedBox(
height: 30,
),
FutureBuilder<Map<String, String>>(
future: fetchRenamedTeachers(),
builder: (context, snapshot) {
if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Container();
}
return Panel(
title: Text("renamed_teachers".i18n),
child: Column(
children: snapshot.data!.keys.map(
(key) {
Teacher? teacher = teachers
.firstWhere((element) => key == element.id);
String renameTo = snapshot.data![key]!;
return RenamedTeacherItem(
teacher: teacher,
renamedTo: renameTo,
modifyCallback: () {
setState(() {
selectedTeacherId = teacher.id;
_teacherName.text = renameTo;
});
showRenameDialog();
},
removeCallback: () {
setState(() {
Map<String, String> subs =
Map.from(snapshot.data!);
subs.remove(key);
dbProvider.userStore.storeRenamedTeachers(
subs,
userId: user.id!);
});
},
);
},
).toList(),
),
);
},
),
],
),
),
));
}
}
class RenamedTeacherItem extends StatelessWidget {
const RenamedTeacherItem({
Key? key,
required this.teacher,
required this.renamedTo,
required this.modifyCallback,
required this.removeCallback,
}) : super(key: key);
final Teacher teacher;
final String renamedTo;
final void Function() modifyCallback;
final void Function() removeCallback;
@override
Widget build(BuildContext context) {
return ListTile(
minLeadingWidth: 32.0,
dense: true,
contentPadding:
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 6.0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)),
visualDensity: VisualDensity.compact,
onTap: () {},
leading: Icon(FeatherIcons.user,
color: AppColors.of(context).text.withOpacity(.75)),
title: InkWell(
onTap: modifyCallback,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
teacher.name.capital(),
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14,
color: AppColors.of(context).text.withOpacity(.75)),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Text(
renamedTo,
style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 16),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
),
),
trailing: InkWell(
onTap: removeCallback,
child: Icon(FeatherIcons.trash,
color: AppColors.of(context).red.withOpacity(.75)),
),
);
}
}