focus-flow/apps/focus_flow_flutter/lib/widgets/timeline/timeline_geometry.dart

75 lines
1.9 KiB
Dart

/// Renders Timeline Geometry pieces for the FocusFlow Flutter timeline.
library;
import 'package:flutter/material.dart';
class TimelineGeometry {
const TimelineGeometry({
required this.visibleStart,
required this.visibleEnd,
required this.pixelsPerMinute,
this.minCardHeight = 72,
});
final TimeOfDay visibleStart;
final TimeOfDay visibleEnd;
final double pixelsPerMinute;
final double minCardHeight;
int get startMinutes => visibleStart.hour * 60 + visibleStart.minute;
int get endMinutes => visibleEnd.hour * 60 + visibleEnd.minute;
double get totalHeight => (endMinutes - startMinutes) * pixelsPerMinute;
double yForMinutesSinceMidnight(int minutes) {
return (minutes - startMinutes) * pixelsPerMinute;
}
double heightForDuration(int minutes) {
final height = minutes * pixelsPerMinute;
return height < minCardHeight ? minCardHeight : height;
}
List<TimelineTick> ticks({int stepMinutes = 15}) {
return [
for (
var minute = startMinutes;
minute <= endMinutes;
minute += stepMinutes
)
TimelineTick(
minutesSinceMidnight: minute,
y: yForMinutesSinceMidnight(minute),
label: _labelFor(minute),
major: minute % 60 == 0,
),
];
}
static String _labelFor(int minutes) {
final hour24 = minutes ~/ 60;
final minute = minutes % 60;
final period = hour24 >= 12 ? 'PM' : 'AM';
final rawHour = hour24 % 12;
final hour = rawHour == 0 ? 12 : rawHour;
if (minute == 0) {
return '$hour:00 $period';
}
return '$hour:${minute.toString().padLeft(2, '0')}';
}
}
class TimelineTick {
const TimelineTick({
required this.minutesSinceMidnight,
required this.y,
required this.label,
required this.major,
});
final int minutesSinceMidnight;
final double y;
final String label;
final bool major;
}