initial commit
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
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')}';
|
||||
|
||||
int minutesBetween(TimeOfDay a, TimeOfDay b) {
|
||||
final aMin = a.hour * 60 + a.minute;
|
||||
final bMin = b.hour * 60 + b.minute;
|
||||
final d = bMin - aMin;
|
||||
if (d <= 0) return 0;
|
||||
if (d >= 24 * 60) return 24 * 60;
|
||||
return d;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import '../utils/helpers.dart';
|
||||
|
||||
Map<String, String> buildHolidayMapAT(int year) {
|
||||
final Map<String, String> m = {};
|
||||
void add(DateTime d, String name) => m[ymd(d)] = name;
|
||||
|
||||
add(DateTime(year, 1, 1), 'Neujahr');
|
||||
add(DateTime(year, 1, 6), 'Heilige Drei Könige');
|
||||
add(DateTime(year, 5, 1), 'Staatsfeiertag');
|
||||
add(DateTime(year, 8, 15), 'Mariä Himmelfahrt');
|
||||
add(DateTime(year, 10, 26), 'Nationalfeiertag');
|
||||
add(DateTime(year, 11, 1), 'Allerheiligen');
|
||||
add(DateTime(year, 12, 8), 'Mariä Empfängnis');
|
||||
add(DateTime(year, 12, 25), 'Christtag');
|
||||
add(DateTime(year, 12, 26), 'Stefanitag');
|
||||
|
||||
final easter = _easterSunday(year);
|
||||
add(easter.add(const Duration(days: 1)), 'Ostermontag');
|
||||
add(easter.add(const Duration(days: 39)), 'Christi Himmelfahrt');
|
||||
add(easter.add(const Duration(days: 50)), 'Pfingstmontag');
|
||||
add(easter.add(const Duration(days: 60)), 'Fronleichnam');
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
DateTime _easterSunday(int year) {
|
||||
final a = year % 19;
|
||||
final b = year ~/ 100;
|
||||
final c = year % 100;
|
||||
final d = b ~/ 4;
|
||||
final e = b % 4;
|
||||
final f = (b + 8) ~/ 25;
|
||||
final g = (b - f + 1) ~/ 3;
|
||||
final h = (19 * a + b - d - g + 15) % 30;
|
||||
final i = c ~/ 4;
|
||||
final k = c % 4;
|
||||
final l = (32 + 2 * e + 2 * i - h - k) % 7;
|
||||
final m = (a + 11 * h + 22 * l) ~/ 451;
|
||||
final month = (h + l - 7 * m + 114) ~/ 31; // 3=March, 4=April
|
||||
final day = ((h + l - 7 * m + 114) % 31) + 1;
|
||||
return DateTime(year, month, day);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class HHmmInputFormatter extends TextInputFormatter {
|
||||
const HHmmInputFormatter();
|
||||
|
||||
@override
|
||||
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
|
||||
String digits = newValue.text.replaceAll(RegExp(r'[^0-9]'), '');
|
||||
if (digits.isEmpty) {
|
||||
return const TextEditingValue(text: '', selection: TextSelection.collapsed(offset: 0));
|
||||
}
|
||||
if (digits.length > 4) digits = digits.substring(0, 4);
|
||||
|
||||
String text;
|
||||
if (digits.length <= 2) {
|
||||
text = digits;
|
||||
} else {
|
||||
final hh = digits.substring(0, 2);
|
||||
final mm = digits.substring(2);
|
||||
text = '$hh:$mm'; // ← Interpolation statt + ':' +
|
||||
}
|
||||
|
||||
final offset = text.length;
|
||||
return TextEditingValue(text: text, selection: TextSelection.collapsed(offset: offset));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user