implemented custom subject colors for the timetable and unified the color palette system
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Kuratierte Palette für Timetable-Farben (Fächer **und** eigene Termine). Die
|
||||
/// Werte sind bewusst von den Status-Signalfarben in [lesson_color.dart]
|
||||
/// abgesetzt (Marianum-Rot, Schwarz, Signallila, Signalblau, Event-Grün,
|
||||
/// Duty-Petrol), damit gefärbte Regelstunden nicht mit Entfall/Vertretung
|
||||
/// verwechselt werden. Der Server speichert nur den Enum-Namen; die konkrete
|
||||
/// [Color] wird hier gemappt.
|
||||
enum SubjectColor {
|
||||
amber,
|
||||
deepOrange,
|
||||
pink,
|
||||
purple,
|
||||
indigo,
|
||||
cyan,
|
||||
teal,
|
||||
lime,
|
||||
brown,
|
||||
blueGrey,
|
||||
}
|
||||
|
||||
class SubjectColorPalette {
|
||||
const SubjectColorPalette._();
|
||||
|
||||
/// Standardfarbe für neue eigene Termine (Fächer haben keinen Default —
|
||||
/// dort bedeutet „keine Farbe" das Status-Rot).
|
||||
static const SubjectColor defaultColor = SubjectColor.amber;
|
||||
|
||||
/// Altbestand: eigene Termine wurden früher mit der 4er-Palette
|
||||
/// (orange/red/green/blue) gespeichert. Diese Namen bleiben auflösbar und
|
||||
/// bilden auf die nächstliegende neue Farbe ab, damit bestehende Termine
|
||||
/// nicht ihre Farbe verlieren.
|
||||
static const Map<String, SubjectColor> _legacyAliases = {
|
||||
'orange': SubjectColor.amber,
|
||||
'red': SubjectColor.deepOrange,
|
||||
'green': SubjectColor.teal,
|
||||
'blue': SubjectColor.indigo,
|
||||
};
|
||||
|
||||
static ColorModeDisplay displayOf(SubjectColor color) => switch (color) {
|
||||
SubjectColor.amber => ColorModeDisplay(
|
||||
color: Colors.amber.shade700,
|
||||
displayName: 'Bernstein',
|
||||
),
|
||||
SubjectColor.deepOrange => ColorModeDisplay(
|
||||
color: Colors.deepOrange.shade600,
|
||||
displayName: 'Dunkelorange',
|
||||
),
|
||||
SubjectColor.pink => ColorModeDisplay(
|
||||
color: Colors.pink.shade500,
|
||||
displayName: 'Pink',
|
||||
),
|
||||
SubjectColor.purple => ColorModeDisplay(
|
||||
color: Colors.deepPurple.shade400,
|
||||
displayName: 'Violett',
|
||||
),
|
||||
SubjectColor.indigo => ColorModeDisplay(
|
||||
color: Colors.indigo.shade400,
|
||||
displayName: 'Indigo',
|
||||
),
|
||||
SubjectColor.cyan => ColorModeDisplay(
|
||||
color: Colors.cyan.shade700,
|
||||
displayName: 'Cyan',
|
||||
),
|
||||
SubjectColor.teal => ColorModeDisplay(
|
||||
color: Colors.teal.shade400,
|
||||
displayName: 'Türkis',
|
||||
),
|
||||
SubjectColor.lime => ColorModeDisplay(
|
||||
color: Colors.lime.shade800,
|
||||
displayName: 'Limette',
|
||||
),
|
||||
SubjectColor.brown => ColorModeDisplay(
|
||||
color: Colors.brown.shade400,
|
||||
displayName: 'Braun',
|
||||
),
|
||||
SubjectColor.blueGrey => ColorModeDisplay(
|
||||
color: Colors.blueGrey.shade400,
|
||||
displayName: 'Blaugrau',
|
||||
),
|
||||
};
|
||||
|
||||
/// Löst einen gespeicherten Namen (neue Palette oder Legacy-Alias) zum
|
||||
/// [SubjectColor] auf. `null`, wenn der Name leer/unbekannt ist.
|
||||
static SubjectColor? fromName(String? name) {
|
||||
if (name == null || name.isEmpty) return null;
|
||||
final match = SubjectColor.values.where((e) => e.name == name).firstOrNull;
|
||||
return match ?? _legacyAliases[name];
|
||||
}
|
||||
|
||||
/// Wie [fromName], liefert aber die konkrete [Color]. `null`, wenn der Name
|
||||
/// leer/unbekannt ist — der Aufrufer fällt dann auf die Status-Farbe zurück.
|
||||
static Color? colorFromName(String? name) {
|
||||
final option = fromName(name);
|
||||
return option == null ? null : displayOf(option).color;
|
||||
}
|
||||
}
|
||||
|
||||
class ColorModeDisplay {
|
||||
final Color color;
|
||||
final String displayName;
|
||||
|
||||
ColorModeDisplay({required this.color, required this.displayName});
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncfusion_flutter_calendar/calendar.dart';
|
||||
|
||||
import '../../../../api/marianumconnect/models/mc_holiday.dart';
|
||||
@@ -5,12 +6,12 @@ import '../../../../api/marianumconnect/queries/timetable_get_subjects/timetable
|
||||
import '../../../../api/marianumconnect/queries/timetable_get_week/timetable_get_week_response.dart';
|
||||
import '../../../../api/mhsl/custom_timetable_event/custom_timetable_event.dart';
|
||||
import '../../../../storage/timetable_settings.dart';
|
||||
import '../custom_events/custom_event_colors.dart';
|
||||
import 'arbitrary_appointment.dart';
|
||||
import 'lesson_color.dart';
|
||||
import 'lesson_status.dart';
|
||||
import 'lesson_type_label.dart';
|
||||
import 'rrule_with_exceptions.dart';
|
||||
import 'subject_color_palette.dart';
|
||||
import 'timetable_name_mode.dart';
|
||||
|
||||
class TimetableAppointmentFactory {
|
||||
@@ -65,7 +66,7 @@ class TimetableAppointmentFactory {
|
||||
endTime: endTime,
|
||||
subject: _subjectName(subjectShortName, lesson),
|
||||
location: _locationLabel(lesson),
|
||||
color: LessonColor.forStatus(status),
|
||||
color: _lessonColor(status, subjectShortName),
|
||||
);
|
||||
} catch (_) {
|
||||
return Appointment(
|
||||
@@ -131,9 +132,9 @@ class TimetableAppointmentFactory {
|
||||
subject: _collapseWhitespace(event.title) ?? event.title,
|
||||
recurrenceRule: parsed.rule,
|
||||
recurrenceExceptionDates: exceptionDates.isEmpty ? null : exceptionDates,
|
||||
color: TimetableColors.getColorFromString(
|
||||
event.color ?? TimetableColors.defaultColor.name,
|
||||
),
|
||||
color:
|
||||
SubjectColorPalette.colorFromName(event.color) ??
|
||||
SubjectColorPalette.displayOf(SubjectColorPalette.defaultColor).color,
|
||||
startTimeZone: '',
|
||||
endTimeZone: '',
|
||||
);
|
||||
@@ -187,10 +188,32 @@ class TimetableAppointmentFactory {
|
||||
e.second == 0;
|
||||
}
|
||||
|
||||
/// Regelstunden (regulär/laufend/vergangen) übernehmen die persönliche
|
||||
/// Fach-Farbe, sofern gesetzt. Sonderstatus (Entfall, Vertretung, Aufsicht,
|
||||
/// Event) behalten immer ihre Signalfarbe, damit die Abgrenzung erhalten
|
||||
/// bleibt.
|
||||
Color _lessonColor(LessonStatus status, String? subjectShort) {
|
||||
final isRegular =
|
||||
status == LessonStatus.regular ||
|
||||
status == LessonStatus.ongoing ||
|
||||
status == LessonStatus.past;
|
||||
if (isRegular) {
|
||||
final custom = SubjectColorPalette.colorFromName(
|
||||
_findSubject(subjectShort)?.color,
|
||||
);
|
||||
if (custom != null) return custom;
|
||||
}
|
||||
return LessonColor.forStatus(status);
|
||||
}
|
||||
|
||||
McSubject? _findSubject(String? subjectShort) {
|
||||
if (subjectShort == null) return null;
|
||||
return subjects.where((s) => s.shortName == subjectShort).firstOrNull;
|
||||
}
|
||||
|
||||
String _subjectName(String? subjectShort, McTimetableEntry lesson) {
|
||||
if (subjectShort != null) {
|
||||
final lookup =
|
||||
subjects.where((s) => s.shortName == subjectShort).firstOrNull;
|
||||
final lookup = _findSubject(subjectShort);
|
||||
final name = switch (settings.timetableNameMode) {
|
||||
// Backend liefert nur shortName + longName; alternateName fällt auf
|
||||
// longName zurück.
|
||||
|
||||
Reference in New Issue
Block a user