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 fillMonth(DateTime monthStart, List existing) { final map = {for (final w in existing) ymd(w.date): w}; final nextMonth = DateTime(monthStart.year, monthStart.month + 1, 1); final out = []; 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 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 '—'; } }