mirror of
https://github.com/Iconica-Development/flutter_timetable.git
synced 2025-05-19 03:43:43 +02:00
commit
f0ffd233c7
10 changed files with 156 additions and 97 deletions
|
@ -124,7 +124,7 @@ linter:
|
||||||
prefer_asserts_with_message: true
|
prefer_asserts_with_message: true
|
||||||
prefer_collection_literals: true
|
prefer_collection_literals: true
|
||||||
prefer_conditional_assignment: true
|
prefer_conditional_assignment: true
|
||||||
prefer_const_constructors: false
|
prefer_const_constructors: true
|
||||||
prefer_const_constructors_in_immutables: true
|
prefer_const_constructors_in_immutables: true
|
||||||
prefer_const_declarations: false
|
prefer_const_declarations: false
|
||||||
prefer_const_literals_to_create_immutables: false
|
prefer_const_literals_to_create_immutables: false
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:timetable/timetable.dart';
|
import 'package:timetable/timetable.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(MaterialApp(home: TimetableDemo()));
|
runApp(const MaterialApp(home: TimetableDemo()));
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimetableDemo extends StatefulWidget {
|
class TimetableDemo extends StatefulWidget {
|
||||||
|
@ -17,54 +17,54 @@ class _TimetableDemoState extends State<TimetableDemo> {
|
||||||
final ScrollController _scrollController = ScrollController();
|
final ScrollController _scrollController = ScrollController();
|
||||||
final List<TimeBlock> blocks = [
|
final List<TimeBlock> blocks = [
|
||||||
TimeBlock(
|
TimeBlock(
|
||||||
start: TimeOfDay(hour: 14, minute: 0),
|
start: const TimeOfDay(hour: 14, minute: 0),
|
||||||
end: TimeOfDay(hour: 15, minute: 0),
|
end: const TimeOfDay(hour: 15, minute: 0),
|
||||||
id: 0,
|
id: 0,
|
||||||
),
|
),
|
||||||
TimeBlock(
|
TimeBlock(
|
||||||
start: TimeOfDay(hour: 8, minute: 0),
|
start: const TimeOfDay(hour: 8, minute: 0),
|
||||||
end: TimeOfDay(hour: 9, minute: 0),
|
end: const TimeOfDay(hour: 9, minute: 0),
|
||||||
id: 1,
|
id: 1,
|
||||||
),
|
),
|
||||||
TimeBlock(
|
TimeBlock(
|
||||||
start: TimeOfDay(hour: 9, minute: 15),
|
start: const TimeOfDay(hour: 9, minute: 15),
|
||||||
end: TimeOfDay(hour: 10, minute: 0),
|
end: const TimeOfDay(hour: 10, minute: 0),
|
||||||
id: 1,
|
id: 1,
|
||||||
),
|
),
|
||||||
TimeBlock(
|
TimeBlock(
|
||||||
start: TimeOfDay(hour: 10, minute: 15),
|
start: const TimeOfDay(hour: 10, minute: 15),
|
||||||
end: TimeOfDay(hour: 11, minute: 0),
|
end: const TimeOfDay(hour: 11, minute: 0),
|
||||||
child: Container(color: Colors.purple, height: 300, width: 50),
|
child: Container(color: Colors.purple, height: 300, width: 50),
|
||||||
id: 2,
|
id: 2,
|
||||||
),
|
),
|
||||||
TimeBlock(
|
TimeBlock(
|
||||||
start: TimeOfDay(hour: 6, minute: 15),
|
start: const TimeOfDay(hour: 6, minute: 15),
|
||||||
end: TimeOfDay(hour: 7, minute: 0),
|
end: const TimeOfDay(hour: 7, minute: 0),
|
||||||
child: Container(color: Colors.blue, height: 300, width: 200),
|
child: Container(color: Colors.blue, height: 300, width: 200),
|
||||||
id: 2,
|
id: 2,
|
||||||
),
|
),
|
||||||
TimeBlock(
|
TimeBlock(
|
||||||
start: TimeOfDay(hour: 18, minute: 0),
|
start: const TimeOfDay(hour: 18, minute: 0),
|
||||||
end: TimeOfDay(hour: 18, minute: 15),
|
end: const TimeOfDay(hour: 18, minute: 15),
|
||||||
child: Text('High Tea'),
|
child: const Text('High Tea'),
|
||||||
id: 10,
|
id: 10,
|
||||||
),
|
),
|
||||||
TimeBlock(
|
TimeBlock(
|
||||||
start: TimeOfDay(hour: 18, minute: 0),
|
start: const TimeOfDay(hour: 18, minute: 0),
|
||||||
end: TimeOfDay(hour: 18, minute: 15),
|
end: const TimeOfDay(hour: 18, minute: 15),
|
||||||
child: Text('High Tea'),
|
child: const Text('High Tea'),
|
||||||
id: 10,
|
id: 10,
|
||||||
),
|
),
|
||||||
TimeBlock(
|
TimeBlock(
|
||||||
start: TimeOfDay(hour: 18, minute: 0),
|
start: const TimeOfDay(hour: 18, minute: 0),
|
||||||
end: TimeOfDay(hour: 18, minute: 15),
|
end: const TimeOfDay(hour: 18, minute: 15),
|
||||||
child: Text('High Tea'),
|
child: const Text('High Tea'),
|
||||||
id: 10,
|
id: 10,
|
||||||
),
|
),
|
||||||
TimeBlock(
|
TimeBlock(
|
||||||
start: TimeOfDay(hour: 18, minute: 0),
|
start: const TimeOfDay(hour: 18, minute: 0),
|
||||||
end: TimeOfDay(hour: 18, minute: 15),
|
end: const TimeOfDay(hour: 18, minute: 15),
|
||||||
child: Text('High Tea'),
|
child: const Text('High Tea'),
|
||||||
id: 0,
|
id: 0,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
@ -88,7 +88,7 @@ class _TimetableDemoState extends State<TimetableDemo> {
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text('Grouped'),
|
const Text('Grouped'),
|
||||||
Switch(
|
Switch(
|
||||||
value: _grouped,
|
value: _grouped,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
@ -106,7 +106,7 @@ class _TimetableDemoState extends State<TimetableDemo> {
|
||||||
timeBlocks: blocks,
|
timeBlocks: blocks,
|
||||||
scrollController: _scrollController,
|
scrollController: _scrollController,
|
||||||
tablePaddingStart: 0,
|
tablePaddingStart: 0,
|
||||||
collapseBlocks: true,
|
combineBlocks: true,
|
||||||
mergeBlocks: false,
|
mergeBlocks: false,
|
||||||
)
|
)
|
||||||
] else ...[
|
] else ...[
|
||||||
|
@ -116,7 +116,7 @@ class _TimetableDemoState extends State<TimetableDemo> {
|
||||||
timeBlocks: blocks,
|
timeBlocks: blocks,
|
||||||
scrollController: _scrollController,
|
scrollController: _scrollController,
|
||||||
tablePaddingStart: 0,
|
tablePaddingStart: 0,
|
||||||
collapseBlocks: true,
|
combineBlocks: true,
|
||||||
mergeBlocks: true,
|
mergeBlocks: true,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,26 +1,19 @@
|
||||||
part of timetable;
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:timetable/src/models/time_block.dart';
|
||||||
|
|
||||||
/// Combine blocks that have the same id and the same time.
|
/// Combine blocks that have the same id and the same time.
|
||||||
List<TimeBlock> collapseBlocks(List<TimeBlock> blocks) {
|
List<TimeBlock> combineBlocksWithId(List<TimeBlock> blocks) {
|
||||||
var newBlocks = <TimeBlock>[];
|
var newBlocks = <TimeBlock>[];
|
||||||
var groupedBlocks = <List<TimeBlock>>[];
|
var groupedBlocks = <List<TimeBlock>>[];
|
||||||
// order blocks by id and collides with another block
|
|
||||||
for (var block in blocks) {
|
for (var block in blocks) {
|
||||||
// check if the block is already in one of the grouped blocks
|
|
||||||
var found = false;
|
var found = false;
|
||||||
if (block.id == 0) {
|
if (block.id == 0) {
|
||||||
newBlocks.add(block);
|
newBlocks.add(block);
|
||||||
continue;
|
found = true;
|
||||||
}
|
} else {
|
||||||
for (var groupedBlock in groupedBlocks) {
|
found = _checkIfBlockWithIdExists(groupedBlocks, block);
|
||||||
if (groupedBlock.first.id == block.id &&
|
|
||||||
groupedBlock.first.start == block.start &&
|
|
||||||
groupedBlock.first.end == block.end) {
|
|
||||||
groupedBlock.add(block);
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
if (blocks
|
if (blocks
|
||||||
.where(
|
.where(
|
||||||
|
@ -38,16 +31,24 @@ List<TimeBlock> collapseBlocks(List<TimeBlock> blocks) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_combineGroupedBlocks(groupedBlocks, newBlocks);
|
||||||
|
return newBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _combineGroupedBlocks(
|
||||||
|
List<List<TimeBlock>> groupedBlocks,
|
||||||
|
List<TimeBlock> newBlocks,
|
||||||
|
) {
|
||||||
for (var block in groupedBlocks) {
|
for (var block in groupedBlocks) {
|
||||||
// combine the blocks into one block
|
var startMinute = block.first.start.minute +
|
||||||
// calculate the endtime of the combined block
|
block.first.start.hour * Duration.minutesPerHour;
|
||||||
var startMinute = block.first.start.minute + block.first.start.hour * 60;
|
var endMinute =
|
||||||
var endMinute = block.first.end.minute + block.first.end.hour * 60;
|
block.first.end.minute + block.first.end.hour * Duration.minutesPerHour;
|
||||||
var durationMinute = (endMinute - startMinute) * block.length;
|
var durationMinute = (endMinute - startMinute) * block.length;
|
||||||
|
|
||||||
var endTime = TimeOfDay(
|
var endTime = TimeOfDay(
|
||||||
hour: (startMinute + durationMinute) ~/ 60,
|
hour: (startMinute + durationMinute) ~/ Duration.minutesPerHour,
|
||||||
minute: (startMinute + durationMinute) % 60,
|
minute: (startMinute + durationMinute) % Duration.minutesPerHour,
|
||||||
);
|
);
|
||||||
var newBlock = TimeBlock(
|
var newBlock = TimeBlock(
|
||||||
start: block.first.start,
|
start: block.first.start,
|
||||||
|
@ -61,7 +62,21 @@ List<TimeBlock> collapseBlocks(List<TimeBlock> blocks) {
|
||||||
);
|
);
|
||||||
newBlocks.add(newBlock);
|
newBlocks.add(newBlock);
|
||||||
}
|
}
|
||||||
return newBlocks;
|
}
|
||||||
|
|
||||||
|
bool _checkIfBlockWithIdExists(
|
||||||
|
List<List<TimeBlock>> groupedBlocks,
|
||||||
|
TimeBlock block,
|
||||||
|
) {
|
||||||
|
for (var groupedBlock in groupedBlocks) {
|
||||||
|
if (groupedBlock.first.id == block.id &&
|
||||||
|
groupedBlock.first.start == block.start &&
|
||||||
|
groupedBlock.first.end == block.end) {
|
||||||
|
groupedBlock.add(block);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Group blocks with the same id together.
|
/// Group blocks with the same id together.
|
||||||
|
@ -95,7 +110,6 @@ List<List<TimeBlock>> groupBlocksById(List<TimeBlock> blocks) {
|
||||||
/// Nerge blocks that fit below eachother into one column.
|
/// Nerge blocks that fit below eachother into one column.
|
||||||
List<List<TimeBlock>> mergeBlocksInColumns(List<TimeBlock> blocks) {
|
List<List<TimeBlock>> mergeBlocksInColumns(List<TimeBlock> blocks) {
|
||||||
var mergedBlocks = <List<TimeBlock>>[];
|
var mergedBlocks = <List<TimeBlock>>[];
|
||||||
// try to put blocks in the same column if the time doesn´t collide
|
|
||||||
for (var block in blocks) {
|
for (var block in blocks) {
|
||||||
var mergeIndex = 0;
|
var mergeIndex = 0;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
part of timetable;
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class TableTheme {
|
class TableTheme {
|
||||||
|
/// The [TableTheme] to style the [Table] with. Configure the line, text
|
||||||
|
/// and offsets here.
|
||||||
const TableTheme({
|
const TableTheme({
|
||||||
this.lineColor = const Color(0x809E9E9E),
|
this.lineColor = const Color(0x809E9E9E),
|
||||||
this.lineHeight = 2,
|
this.lineHeight = 2,
|
||||||
|
this.tableTextOffset = 5,
|
||||||
|
this.lineDashFrequency = 25,
|
||||||
this.timeStyle = const TextStyle(),
|
this.timeStyle = const TextStyle(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -13,6 +17,12 @@ class TableTheme {
|
||||||
/// The height of the lines.
|
/// The height of the lines.
|
||||||
final double lineHeight;
|
final double lineHeight;
|
||||||
|
|
||||||
|
/// The amount of dashes on the line.
|
||||||
|
final int lineDashFrequency;
|
||||||
|
|
||||||
|
/// Distance between the time text and the line.
|
||||||
|
final double tableTextOffset;
|
||||||
|
|
||||||
/// The style of the time text.
|
/// The style of the time text.
|
||||||
final TextStyle timeStyle;
|
final TextStyle timeStyle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
part of timetable;
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class TimeBlock {
|
class TimeBlock {
|
||||||
|
/// The model used for a [Block] in a [TimeTable] which can contain a Widget.
|
||||||
TimeBlock({
|
TimeBlock({
|
||||||
required this.start,
|
required this.start,
|
||||||
required this.end,
|
required this.end,
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
part of timetable;
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/scheduler.dart';
|
||||||
|
import 'package:timetable/src/block_service.dart';
|
||||||
|
import 'package:timetable/src/models/table_theme.dart';
|
||||||
|
import 'package:timetable/src/models/time_block.dart';
|
||||||
|
import 'package:timetable/src/widgets/block.dart';
|
||||||
|
import 'package:timetable/src/widgets/table.dart' as table;
|
||||||
|
|
||||||
class Timetable extends StatefulWidget {
|
class Timetable extends StatefulWidget {
|
||||||
|
/// [Timetable] widget that displays a timetable with [TimeBlock]s.
|
||||||
|
/// The timetable automatically scrolls to the first item.
|
||||||
|
/// A [TableTheme] can be provided to customize the look of the timetable.
|
||||||
|
/// [mergeBlocks] and [combineBlocks] can be used to combine blocks
|
||||||
|
/// and merge columns of blocks when possible.
|
||||||
const Timetable({
|
const Timetable({
|
||||||
this.timeBlocks = const [],
|
this.timeBlocks = const [],
|
||||||
this.scrollController,
|
this.scrollController,
|
||||||
|
@ -14,7 +25,7 @@ class Timetable extends StatefulWidget {
|
||||||
this.tablePaddingEnd = 15,
|
this.tablePaddingEnd = 15,
|
||||||
this.theme = const TableTheme(),
|
this.theme = const TableTheme(),
|
||||||
this.mergeBlocks = false,
|
this.mergeBlocks = false,
|
||||||
this.collapseBlocks = true,
|
this.combineBlocks = true,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@ -56,7 +67,7 @@ class Timetable extends StatefulWidget {
|
||||||
|
|
||||||
/// Whether or not to collapse blocks in 1 column if they have the same id.
|
/// Whether or not to collapse blocks in 1 column if they have the same id.
|
||||||
/// If blocks have the same id and time they will be combined into one block.
|
/// If blocks have the same id and time they will be combined into one block.
|
||||||
final bool collapseBlocks;
|
final bool combineBlocks;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<Timetable> createState() => _TimetableState();
|
State<Timetable> createState() => _TimetableState();
|
||||||
|
@ -83,8 +94,8 @@ class _TimetableState extends State<Timetable> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
List<TimeBlock> blocks;
|
List<TimeBlock> blocks;
|
||||||
if (widget.collapseBlocks) {
|
if (widget.combineBlocks) {
|
||||||
blocks = collapseBlocks(widget.timeBlocks);
|
blocks = combineBlocksWithId(widget.timeBlocks);
|
||||||
} else {
|
} else {
|
||||||
blocks = widget.timeBlocks;
|
blocks = widget.timeBlocks;
|
||||||
}
|
}
|
||||||
|
@ -93,17 +104,16 @@ class _TimetableState extends State<Timetable> {
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Table(
|
table.Table(
|
||||||
startHour: widget.startHour,
|
startHour: widget.startHour,
|
||||||
endHour: widget.endHour,
|
endHour: widget.endHour,
|
||||||
columnHeight: widget.hourHeight,
|
hourHeight: widget.hourHeight,
|
||||||
|
tableOffset: _calculateTableStart(),
|
||||||
theme: widget.theme,
|
theme: widget.theme,
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
margin: EdgeInsets.only(
|
margin: EdgeInsets.only(
|
||||||
left: _calculateTableTextSize().width +
|
left: _calculateTableStart(),
|
||||||
widget.tablePaddingStart +
|
|
||||||
5,
|
|
||||||
),
|
),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
physics: widget.scrollPhysics ?? const BouncingScrollPhysics(),
|
physics: widget.scrollPhysics ?? const BouncingScrollPhysics(),
|
||||||
|
@ -112,7 +122,7 @@ class _TimetableState extends State<Timetable> {
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (widget.mergeBlocks || widget.collapseBlocks) ...[
|
if (widget.mergeBlocks || widget.combineBlocks) ...[
|
||||||
for (var orderedBlocks in (widget.mergeBlocks)
|
for (var orderedBlocks in (widget.mergeBlocks)
|
||||||
? mergeBlocksInColumns(blocks)
|
? mergeBlocksInColumns(blocks)
|
||||||
: groupBlocksById(blocks)) ...[
|
: groupBlocksById(blocks)) ...[
|
||||||
|
@ -132,7 +142,9 @@ class _TimetableState extends State<Timetable> {
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: widget.tablePaddingEnd,
|
width: widget.tablePaddingEnd,
|
||||||
height: widget.hourHeight *
|
height: widget.hourHeight *
|
||||||
(widget.endHour - widget.startHour + 0.5),
|
(widget.endHour -
|
||||||
|
widget.startHour +
|
||||||
|
0.5), // empty halfhour at the end
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -144,6 +156,12 @@ class _TimetableState extends State<Timetable> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double _calculateTableStart() {
|
||||||
|
return _calculateTableTextSize().width +
|
||||||
|
widget.tablePaddingStart +
|
||||||
|
widget.theme.tableTextOffset;
|
||||||
|
}
|
||||||
|
|
||||||
Widget _showBlock(TimeBlock block) {
|
Widget _showBlock(TimeBlock block) {
|
||||||
return Block(
|
return Block(
|
||||||
start: block.start,
|
start: block.start,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
part of timetable;
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class Block extends StatelessWidget {
|
class Block extends StatelessWidget {
|
||||||
|
/// The [Block] to create a Widget or container in a [TimeTable].
|
||||||
const Block({
|
const Block({
|
||||||
required this.start,
|
required this.start,
|
||||||
required this.end,
|
required this.end,
|
||||||
|
@ -41,24 +42,28 @@ class Block extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.only(
|
margin: EdgeInsets.only(
|
||||||
top:
|
top: (((start.hour - startHour) * Duration.minutesPerHour) +
|
||||||
(((start.hour - startHour) * 60) + start.minute) * sizePerMinute() +
|
start.minute) *
|
||||||
linePadding,
|
_sizePerMinute() +
|
||||||
|
linePadding,
|
||||||
),
|
),
|
||||||
height: (((end.hour - start.hour) * 60) + end.minute - start.minute) *
|
height: (((end.hour - start.hour) * Duration.minutesPerHour) +
|
||||||
sizePerMinute(),
|
end.minute -
|
||||||
|
start.minute) *
|
||||||
|
_sizePerMinute(),
|
||||||
child: child ??
|
child: child ??
|
||||||
Container(
|
Container(
|
||||||
height:
|
height: (((end.hour - start.hour) * Duration.minutesPerHour) +
|
||||||
(((end.hour - start.hour) * 60) + end.minute - start.minute) *
|
end.minute -
|
||||||
sizePerMinute(),
|
start.minute) *
|
||||||
|
_sizePerMinute(),
|
||||||
width: blockWidth,
|
width: blockWidth,
|
||||||
color: blockColor,
|
color: blockColor,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
double sizePerMinute() {
|
double _sizePerMinute() {
|
||||||
return hourHeight / 60;
|
return hourHeight / Duration.minutesPerHour;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,30 @@
|
||||||
part of timetable;
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:timetable/src/models/table_theme.dart';
|
||||||
|
|
||||||
class Table extends StatelessWidget {
|
class Table extends StatelessWidget {
|
||||||
|
/// The [Table] to draw an overview of timerange with corresponding hour lines
|
||||||
const Table({
|
const Table({
|
||||||
required this.startHour,
|
required this.startHour,
|
||||||
required this.endHour,
|
required this.endHour,
|
||||||
this.columnHeight = 80,
|
this.hourHeight = 80,
|
||||||
|
this.tableOffset = 40,
|
||||||
this.theme = const TableTheme(),
|
this.theme = const TableTheme(),
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
/// The hour the table starts at.
|
||||||
final int startHour;
|
final int startHour;
|
||||||
|
|
||||||
|
/// The hour the table ends at.
|
||||||
final int endHour;
|
final int endHour;
|
||||||
final double columnHeight;
|
|
||||||
|
/// The height of a single hour in the table.
|
||||||
|
final double hourHeight;
|
||||||
|
|
||||||
|
/// The offset of the table;
|
||||||
|
final double tableOffset;
|
||||||
|
|
||||||
|
/// The theme used by the table.
|
||||||
final TableTheme theme;
|
final TableTheme theme;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -20,7 +33,7 @@ class Table extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
for (int i = startHour; i <= endHour; i++) ...[
|
for (int i = startHour; i <= endHour; i++) ...[
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: i == endHour ? columnHeight / 2 : columnHeight,
|
height: i == endHour ? hourHeight / 2 : hourHeight,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
|
@ -29,8 +42,8 @@ class Table extends StatelessWidget {
|
||||||
'${i.toString().padLeft(2, '0')}:00',
|
'${i.toString().padLeft(2, '0')}:00',
|
||||||
style: theme.timeStyle,
|
style: theme.timeStyle,
|
||||||
),
|
),
|
||||||
const SizedBox(
|
SizedBox(
|
||||||
width: 5,
|
width: theme.tableTextOffset,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
|
@ -43,16 +56,17 @@ class Table extends StatelessWidget {
|
||||||
if (i != endHour) ...[
|
if (i != endHour) ...[
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.only(
|
margin: EdgeInsets.only(
|
||||||
left: 40,
|
left: tableOffset,
|
||||||
),
|
),
|
||||||
height: theme.lineHeight,
|
height: theme.lineHeight,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
for (int i = 0; i < 25; i++) ...[
|
for (int i = 0; i < theme.lineDashFrequency; i++) ...[
|
||||||
Container(
|
Container(
|
||||||
width:
|
width: (MediaQuery.of(context).size.width -
|
||||||
(MediaQuery.of(context).size.width - 40) / 25,
|
tableOffset) /
|
||||||
|
theme.lineDashFrequency,
|
||||||
height: theme.lineHeight,
|
height: theme.lineHeight,
|
||||||
color:
|
color:
|
||||||
i.isEven ? theme.lineColor : Colors.transparent,
|
i.isEven ? theme.lineColor : Colors.transparent,
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
library timetable;
|
library timetable;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
export 'src/models/table_theme.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
export 'src/models/time_block.dart';
|
||||||
|
export 'src/timetable.dart';
|
||||||
part 'src/timetable.dart';
|
export 'src/widgets/block.dart';
|
||||||
part 'src/block_service.dart';
|
export 'src/widgets/table.dart';
|
||||||
part 'src/widgets/table.dart';
|
|
||||||
part 'src/models/time_block.dart';
|
|
||||||
part 'src/models/table_theme.dart';
|
|
||||||
part 'src/widgets/block.dart';
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:timetable/src/block_service.dart';
|
||||||
import 'package:timetable/timetable.dart';
|
import 'package:timetable/timetable.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('test collapseBlocks', () {
|
group('test combineBlocksWithId', () {
|
||||||
test('new block creation success', () {
|
test('new block creation success', () {
|
||||||
//Arrange
|
//Arrange
|
||||||
var blocks = [
|
var blocks = [
|
||||||
|
@ -25,7 +26,7 @@ void main() {
|
||||||
];
|
];
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var result = collapseBlocks(blocks);
|
var result = combineBlocksWithId(blocks);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(result.length, 2);
|
expect(result.length, 2);
|
||||||
|
@ -51,7 +52,7 @@ void main() {
|
||||||
];
|
];
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var result = collapseBlocks(blocks);
|
var result = combineBlocksWithId(blocks);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(result.length, 2);
|
expect(result.length, 2);
|
||||||
|
|
Loading…
Reference in a new issue