75 lines
1.9 KiB
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;
|
|
}
|