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.

100 lines
3.2 KiB
Dart

import 'package:flutter/material.dart';
import '../models/work_day.dart';
/// Kurzcode-Liste & Label
const List<String> kAbsenceCodes = ['G', 'K', 'U', 'SU', 'T'];
String codeLabel(String code) {
switch (code) {
case 'G': return 'Gleitzeit';
case 'K': return 'Krankenstand';
case 'U': return 'Urlaub';
case 'SU': return 'Sonderurlaub';
case 'T': return 'Training';
default: return code;
}
}
/// Zeit-Helfer
TimeOfDay? parseDbTime(String? hhmmss) {
if (hhmmss == null || hhmmss.isEmpty) return null;
final parts = hhmmss.split(':');
if (parts.length < 2) return null;
final h = int.tryParse(parts[0]) ?? 0;
final m = int.tryParse(parts[1]) ?? 0;
return TimeOfDay(hour: h, minute: m);
}
String fmtTimeOfDay(TimeOfDay? t) {
if (t == null) return '';
final hh = t.hour.toString().padLeft(2, '0');
final mm = t.minute.toString().padLeft(2, '0');
return '$hh:$mm';
}
TimeOfDay? parseTextHHMM(String s) {
if (s.length != 5 || s[2] != ':') return null;
final h = int.tryParse(s.substring(0, 2));
final m = int.tryParse(s.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 minutesToHHMM(int minutes) {
final sign = minutes < 0 ? '-' : '';
final m = minutes.abs();
final hh = (m ~/ 60).toString().padLeft(2, '0');
final mm = (m % 60).toString().padLeft(2, '0');
return '$sign$hh:$mm';
}
String minutesToSignedHHMM(int minutes) => minutesToHHMM(minutes);
/// Datums-Formatierungen
String ymd(DateTime d) =>
'${d.year.toString().padLeft(4, '0')}-${d.month.toString().padLeft(2, '0')}-${d.day.toString().padLeft(2, '0')}';
const _weekdayShort = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'];
String _shortWeekday(DateTime d) => _weekdayShort[(d.weekday - 1) % 7];
String _shortDate(DateTime d) =>
'${d.day.toString().padLeft(2, '0')}.${d.month.toString().padLeft(2, '0')}.';
/// Links in der Tabelle (Tag vor Datum)
String rightDayLabel(DateTime d) => '${_shortWeekday(d)} ${_shortDate(d)}';
/// Rechts in der Tabelle (Datum vor Tag)
String leftDayLabel(DateTime d) => '${_shortDate(d)} ${_shortWeekday(d)}';
const _monthNames = [
'Jänner', 'Februar', 'März', 'April', 'Mai', 'Juni',
'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'
];
String monthTitle(DateTime m) => '${_monthNames[m.month - 1]} ${m.year}';
/// Füllt den kompletten Monat mit leeren Tagen, ersetzt vorhandene Einträge
List<WorkDay> fillMonth(DateTime monthStart, List<WorkDay> fromApi) {
final m0 = DateTime(monthStart.year, monthStart.month, 1);
final m1 = DateTime(monthStart.year, monthStart.month + 1, 1);
final byDay = <String, WorkDay>{for (final d in fromApi) ymd(d.date): d};
final days = <WorkDay>[];
for (DateTime d = m0; d.isBefore(m1); d = d.add(const Duration(days: 1))) {
final k = ymd(d);
if (byDay.containsKey(k)) {
final v = byDay[k]!;
days.add(WorkDay(
date: d,
intervals: v.intervals,
targetMinutes: v.targetMinutes,
code: v.code,
));
} else {
days.add(WorkDay(date: d, intervals: const [], targetMinutes: 0, code: null));
}
}
return days;
}