You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
3.8 KiB
Dart

import 'dart:ui' show FontFeature;
import 'package:flutter/material.dart';
import '../models/work_day.dart';
String monthTitle(DateTime m) {
const months = [
'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'
];
return '${months[m.month - 1]} ${m.year}';
}
String leftDayLabel(DateTime d) => '${ddmm(d)} ${weekdayShort(d)}';
String rightDayLabel(DateTime d) => '${weekdayShort(d)} ${ddmm(d)}';
String weekdayShort(DateTime d) {
switch (d.weekday) {
case DateTime.monday: return 'Mo';
case DateTime.tuesday: return 'Di';
case DateTime.wednesday: return 'Mi';
case DateTime.thursday: return 'Do';
case DateTime.friday: return 'Fr';
case DateTime.saturday: return 'Sa';
case DateTime.sunday: return 'So';
default: return '';
}
}
String ddmm(DateTime d) =>
'${d.day.toString().padLeft(2, '0')}.${d.month.toString().padLeft(2, '0')}';
Widget mono(String s) =>
Text(s, style: const TextStyle(fontFeatures: [FontFeature.tabularFigures()]));
String fmtTimeOfDay(TimeOfDay t) =>
'${t.hour.toString().padLeft(2, '0')}:${t.minute.toString().padLeft(2, '0')}';
String minutesToHHMM(int minutes) {
final h = minutes ~/ 60;
final m = minutes % 60;
return '${h.toString().padLeft(2, '0')}:${m.toString().padLeft(2, '0')}';
}
String minutesToSignedHHMM(int minutes) {
final sign = minutes < 0 ? '-' : '+';
final absMin = minutes.abs();
final h = absMin ~/ 60;
final m = absMin % 60;
return '$sign${h.toString().padLeft(2, '0')}:${m.toString().padLeft(2, '0')}';
}
TimeOfDay? parseHHMM(dynamic v) {
if (v == null) return null;
final s = v.toString().trim();
if (s.isEmpty) return null;
final parts = s.split(':');
if (parts.length < 2) return null;
final h = int.tryParse(parts[0]) ?? 0;
final m = int.tryParse(parts[1]) ?? 0;
if (h < 0 || h > 23 || m < 0 || m > 59) return null;
return TimeOfDay(hour: h, minute: m);
}
TimeOfDay? parseTextHHMM(String s) {
final t = s.trim();
if (t.length != 5 || t[2] != ':') return null;
final h = int.tryParse(t.substring(0, 2));
final m = int.tryParse(t.substring(3, 5));
if (h == null || m == null) return null;
if (h < 0 || h > 23 || m < 0 || m > 59) return null;
return TimeOfDay(hour: h, minute: m);
}
String ymd(DateTime d) =>
'${d.year.toString().padLeft(4, '0')}-${d.month.toString().padLeft(2, '0')}-${d.day.toString().padLeft(2, '0')}';
// Füllt alle Tage des Monats auf
List<WorkDay> fillMonth(DateTime monthStart, List<WorkDay> existing) {
final map = <String, WorkDay>{for (final w in existing) ymd(w.date): w};
final nextMonth = DateTime(monthStart.year, monthStart.month + 1, 1);
final out = <WorkDay>[];
for (DateTime d = monthStart; d.isBefore(nextMonth); d = d.add(const Duration(days: 1))) {
final key = ymd(d);
final wd = map[key];
if (wd != null) {
out.add(wd);
} else {
final isWeekend = d.weekday == DateTime.saturday || d.weekday == DateTime.sunday;
final target = isWeekend ? 0 : 8 * 60;
out.add(WorkDay(date: d, intervals: const [], targetMinutes: target));
}
}
return out;
}
/// "HH:MM:SS" → Minuten (Sekunden ignoriert). Ungültig => null.
int? minutesFromHHMMSS(String? s) {
if (s == null) return null;
final parts = s.split(':');
if (parts.length != 3) return null;
final h = int.tryParse(parts[0]) ?? 0;
final m = int.tryParse(parts[1]) ?? 0;
return h * 60 + m;
}
// Abwesenheitscodes und Labels
const List<String> kAbsenceCodes = ['GZ', 'K', 'U', 'SU', 'T'];
String codeLabel(String? code) {
switch (code) {
case 'GZ': return 'Gleitzeit';
case 'K': return 'Krankenstand';
case 'U': return 'Urlaub';
case 'SU': return 'Sonderurlaub';
case 'T': return 'Training';
default: return '';
}
}