mirror of
https://github.com/Iconica-Development/flutter_timetable.git
synced 2025-05-18 19:43:43 +02:00
197 lines
6.7 KiB
Dart
197 lines
6.7 KiB
Dart
// SPDX-FileCopyrightText: 2022 Iconica
|
|
//
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_timetable/src/models/table_theme.dart';
|
|
|
|
class Table extends StatelessWidget {
|
|
/// The [Table] to draw an overview of timerange with corresponding hour lines
|
|
const Table({
|
|
required this.startHour,
|
|
required this.endHour,
|
|
this.hoursOffset = 0,
|
|
this.size,
|
|
this.tableDirection = Axis.vertical,
|
|
this.hourDimension = 80,
|
|
this.tableOffset = 20,
|
|
this.theme = const TableTheme(),
|
|
super.key,
|
|
});
|
|
|
|
/// The [Axis] in which the table is layed out.
|
|
final Axis tableDirection;
|
|
|
|
/// The [Size] used for the table rendering.
|
|
final Size? size;
|
|
|
|
/// The hour the table starts at.
|
|
final int startHour;
|
|
|
|
/// The hour the table ends at.
|
|
final int endHour;
|
|
|
|
/// The time offset to increase all hour labels with
|
|
final int hoursOffset;
|
|
|
|
/// The length in pixel of a single hour in the table.
|
|
final double hourDimension;
|
|
|
|
/// The offset of the table;
|
|
final double tableOffset;
|
|
|
|
/// The theme used by the table.
|
|
final TableTheme theme;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
// calculate the textheight of the hour indicator
|
|
var textSize = calculateTextHeight(context);
|
|
if (tableDirection == Axis.horizontal) {
|
|
return Row(
|
|
children: [
|
|
for (var i = startHour; i <= endHour; i++) ...[
|
|
SizedBox(
|
|
width: (i == endHour) ? hourDimension / 2 : hourDimension,
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Column(
|
|
children: [
|
|
Text(
|
|
'${(((i + hoursOffset) == 24) ? '00' : ((i + hoursOffset) % 24).toString()).padLeft(2, '0')}'
|
|
':00',
|
|
style: theme.timeStyle ??
|
|
Theme.of(context).textTheme.bodyLarge,
|
|
),
|
|
SizedBox(height: theme.tableTextOffset),
|
|
Container(
|
|
color: theme.lineColor,
|
|
width: theme.lineStrokeWidth,
|
|
height: (size ?? MediaQuery.of(context).size).height -
|
|
textSize.dy -
|
|
theme.tableTextOffset,
|
|
),
|
|
],
|
|
),
|
|
// if not the last block
|
|
if (i != endHour) ...[
|
|
SizedBox(
|
|
width: hourDimension / 2 -
|
|
textSize.dx / 2 -
|
|
theme.lineStrokeWidth,
|
|
),
|
|
Column(
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
children: [
|
|
SizedBox(
|
|
height: textSize.dy + theme.tableTextOffset,
|
|
),
|
|
// draw dotted line
|
|
for (int i = 0;
|
|
i <
|
|
(((size ?? MediaQuery.of(context).size)
|
|
.height) -
|
|
textSize.dy -
|
|
theme.tableTextOffset -
|
|
theme.lineDashDistance) /
|
|
((theme.lineDashLength +
|
|
theme.lineDashDistance) /
|
|
2);
|
|
i++) ...[
|
|
Container(
|
|
width: theme.lineStrokeWidth,
|
|
height: i.isEven
|
|
? theme.lineDashLength
|
|
: theme.lineDashDistance,
|
|
color:
|
|
i.isEven ? theme.lineColor : Colors.transparent,
|
|
),
|
|
],
|
|
],
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
],
|
|
],
|
|
);
|
|
}
|
|
return Column(
|
|
children: [
|
|
for (int i = startHour; i <= endHour; i++) ...[
|
|
SizedBox(
|
|
height: i == endHour ? hourDimension / 2 : hourDimension,
|
|
child: Column(
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Text(
|
|
'${((i + hoursOffset) % 24).toString().padLeft(2, '0')}:00',
|
|
style: theme.timeStyle ??
|
|
Theme.of(context).textTheme.bodyLarge,
|
|
),
|
|
SizedBox(
|
|
width: theme.tableTextOffset,
|
|
),
|
|
Expanded(
|
|
child: Container(
|
|
height: theme.lineStrokeWidth,
|
|
color: theme.lineColor,
|
|
),
|
|
)
|
|
],
|
|
),
|
|
if (i != endHour) ...[
|
|
const Spacer(),
|
|
Container(
|
|
margin: EdgeInsets.only(
|
|
left: tableOffset,
|
|
),
|
|
height: theme.lineStrokeWidth,
|
|
child: Row(
|
|
children: [
|
|
for (int i = 0;
|
|
i <
|
|
((size ?? MediaQuery.of(context).size).width -
|
|
tableOffset -
|
|
textSize.dx / 2) /
|
|
((theme.lineDashLength +
|
|
theme.lineDashDistance) /
|
|
2);
|
|
i++) ...[
|
|
Container(
|
|
width: i.isEven
|
|
? theme.lineDashLength
|
|
: theme.lineDashDistance,
|
|
height: theme.lineStrokeWidth,
|
|
color:
|
|
i.isEven ? theme.lineColor : Colors.transparent,
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
const Spacer(),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
],
|
|
],
|
|
);
|
|
}
|
|
|
|
Offset calculateTextHeight(BuildContext context, {String text = '00:00'}) {
|
|
var textPainter = TextPainter(
|
|
text: TextSpan(
|
|
text: text,
|
|
style: theme.timeStyle ?? Theme.of(context).textTheme.bodyLarge,
|
|
),
|
|
textDirection: TextDirection.ltr,
|
|
)..layout();
|
|
return Offset(textPainter.width, textPainter.height);
|
|
}
|
|
}
|