mirror of
https://github.com/Iconica-Development/flutter_timetable.git
synced 2025-05-18 19:43:43 +02:00
feat: collapse blocks with same id
This commit is contained in:
parent
5a54309a5d
commit
e31f284c22
2 changed files with 218 additions and 12 deletions
|
@ -13,6 +13,7 @@ class TimetableDemo extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _TimetableDemoState extends State<TimetableDemo> {
|
||||
bool _grouped = false;
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
final List<TimeBlock> blocks = [
|
||||
TimeBlock(
|
||||
|
@ -35,6 +36,72 @@ class _TimetableDemoState extends State<TimetableDemo> {
|
|||
end: TimeOfDay(hour: 7, minute: 0),
|
||||
child: Container(color: Colors.blue, height: 300, width: 200),
|
||||
),
|
||||
TimeBlock(
|
||||
start: TimeOfDay(hour: 18, minute: 0),
|
||||
end: TimeOfDay(hour: 18, minute: 15),
|
||||
child: Text('High Tea'),
|
||||
id: 10,
|
||||
),
|
||||
TimeBlock(
|
||||
start: TimeOfDay(hour: 18, minute: 0),
|
||||
end: TimeOfDay(hour: 18, minute: 15),
|
||||
child: Text('High Tea'),
|
||||
id: 10,
|
||||
),
|
||||
TimeBlock(
|
||||
start: TimeOfDay(hour: 18, minute: 0),
|
||||
end: TimeOfDay(hour: 18, minute: 15),
|
||||
child: Text('High Tea'),
|
||||
id: 10,
|
||||
),
|
||||
];
|
||||
|
||||
final List<TimeBlock> groupedBlocks = [
|
||||
TimeBlock(
|
||||
start: TimeOfDay(hour: 14, minute: 0),
|
||||
end: TimeOfDay(hour: 15, minute: 0),
|
||||
id: 0,
|
||||
),
|
||||
TimeBlock(
|
||||
start: TimeOfDay(hour: 8, minute: 0),
|
||||
end: TimeOfDay(hour: 9, minute: 0),
|
||||
id: 1,
|
||||
),
|
||||
TimeBlock(
|
||||
start: TimeOfDay(hour: 9, minute: 15),
|
||||
end: TimeOfDay(hour: 10, minute: 0),
|
||||
id: 1,
|
||||
),
|
||||
TimeBlock(
|
||||
start: TimeOfDay(hour: 10, minute: 15),
|
||||
end: TimeOfDay(hour: 11, minute: 0),
|
||||
child: Container(color: Colors.purple, height: 300, width: 50),
|
||||
id: 2,
|
||||
),
|
||||
TimeBlock(
|
||||
start: TimeOfDay(hour: 6, minute: 15),
|
||||
end: TimeOfDay(hour: 7, minute: 0),
|
||||
child: Container(color: Colors.blue, height: 300, width: 200),
|
||||
id: 2,
|
||||
),
|
||||
TimeBlock(
|
||||
start: TimeOfDay(hour: 18, minute: 0),
|
||||
end: TimeOfDay(hour: 18, minute: 15),
|
||||
child: Text('High Tea'),
|
||||
id: 10,
|
||||
),
|
||||
TimeBlock(
|
||||
start: TimeOfDay(hour: 18, minute: 0),
|
||||
end: TimeOfDay(hour: 18, minute: 15),
|
||||
child: Text('High Tea'),
|
||||
id: 10,
|
||||
),
|
||||
TimeBlock(
|
||||
start: TimeOfDay(hour: 18, minute: 0),
|
||||
end: TimeOfDay(hour: 18, minute: 15),
|
||||
child: Text('High Tea'),
|
||||
id: 10,
|
||||
),
|
||||
];
|
||||
|
||||
@override
|
||||
|
@ -48,13 +115,47 @@ class _TimetableDemoState extends State<TimetableDemo> {
|
|||
return Scaffold(
|
||||
body: Padding(
|
||||
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
|
||||
child: Timetable(
|
||||
startHour: 3,
|
||||
endHour: 22,
|
||||
timeBlocks: blocks,
|
||||
scrollController: _scrollController,
|
||||
tablePaddingStart: 0,
|
||||
mergeBlocks: true,
|
||||
child: SingleChildScrollView(
|
||||
controller: _scrollController,
|
||||
child: Column(
|
||||
children: [
|
||||
// toggle between grouped and ungrouped blocks
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Grouped'),
|
||||
Switch(
|
||||
value: _grouped,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_grouped = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
if (_grouped) ...[
|
||||
Timetable(
|
||||
startHour: 3,
|
||||
endHour: 22,
|
||||
timeBlocks: groupedBlocks,
|
||||
scrollController: _scrollController,
|
||||
tablePaddingStart: 0,
|
||||
collapseBlocks: true,
|
||||
)
|
||||
] else ...[
|
||||
Timetable(
|
||||
startHour: 3,
|
||||
endHour: 22,
|
||||
timeBlocks: blocks,
|
||||
scrollController: _scrollController,
|
||||
tablePaddingStart: 0,
|
||||
collapseBlocks: true,
|
||||
mergeBlocks: true,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -81,6 +81,7 @@ class _TimetableState extends State<Timetable> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var blocks = _collapseBlocks(widget.timeBlocks);
|
||||
return SingleChildScrollView(
|
||||
physics: widget.scrollPhysics ?? const BouncingScrollPhysics(),
|
||||
controller: _scrollController,
|
||||
|
@ -106,7 +107,7 @@ class _TimetableState extends State<Timetable> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (!widget.mergeBlocks && !widget.collapseBlocks) ...[
|
||||
for (var block in widget.timeBlocks) ...[
|
||||
for (var block in blocks) ...[
|
||||
Block(
|
||||
start: block.start,
|
||||
end: block.end,
|
||||
|
@ -118,11 +119,11 @@ class _TimetableState extends State<Timetable> {
|
|||
),
|
||||
],
|
||||
] else if (widget.mergeBlocks) ...[
|
||||
for (var blocks
|
||||
in _mergeBlocksInColumns(widget.timeBlocks)) ...[
|
||||
for (var mergedBlocks
|
||||
in _mergeBlocksInColumns(blocks)) ...[
|
||||
Stack(
|
||||
children: [
|
||||
for (var block in blocks) ...[
|
||||
for (var block in mergedBlocks) ...[
|
||||
Block(
|
||||
start: block.start,
|
||||
end: block.end,
|
||||
|
@ -135,7 +136,25 @@ class _TimetableState extends State<Timetable> {
|
|||
],
|
||||
],
|
||||
),
|
||||
]
|
||||
],
|
||||
] else if (widget.collapseBlocks) ...[
|
||||
for (var groupedBlocks in _groupBlocksById(blocks)) ...[
|
||||
Stack(
|
||||
children: [
|
||||
for (var block in groupedBlocks) ...[
|
||||
Block(
|
||||
start: block.start,
|
||||
end: block.end,
|
||||
startHour: widget.startHour,
|
||||
hourHeight: widget.hourHeight,
|
||||
blockWidth: widget.blockWidth,
|
||||
blockColor: widget.blockColor,
|
||||
child: block.child,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
],
|
||||
],
|
||||
SizedBox(
|
||||
width: widget.tablePaddingEnd,
|
||||
|
@ -152,6 +171,92 @@ class _TimetableState extends State<Timetable> {
|
|||
);
|
||||
}
|
||||
|
||||
/// Copmbine blocks that have the same id and the same time.
|
||||
List<TimeBlock> _collapseBlocks(List<TimeBlock> blocks) {
|
||||
var newBlocks = <TimeBlock>[];
|
||||
var groupedBlocks = <List<TimeBlock>>[];
|
||||
// order blocks by id and collides with another block
|
||||
for (var block in blocks) {
|
||||
// check if the block is already in one of the grouped blocks
|
||||
var found = false;
|
||||
for (var groupedBlock in groupedBlocks) {
|
||||
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 (blocks
|
||||
.where(
|
||||
(b) =>
|
||||
b != block &&
|
||||
b.id == block.id &&
|
||||
b.start == block.start &&
|
||||
b.end == block.end,
|
||||
)
|
||||
.isNotEmpty) {
|
||||
groupedBlocks.add([block]);
|
||||
} else {
|
||||
newBlocks.add(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 8.10 8.40 8.55
|
||||
//
|
||||
for (var block in groupedBlocks) {
|
||||
// combine the blocks into one block
|
||||
// calculate the endtime of the combined block
|
||||
var startMinute = block.first.start.minute + block.first.start.hour * 60;
|
||||
var endMinute = block.first.end.minute + block.first.end.hour * 60;
|
||||
var durationMinute = (endMinute - startMinute) * block.length;
|
||||
|
||||
var endTime = TimeOfDay(
|
||||
hour: (startMinute + durationMinute) ~/ 60,
|
||||
minute: (startMinute + durationMinute) % 60,
|
||||
);
|
||||
var newBlock = TimeBlock(
|
||||
start: block.first.start,
|
||||
end: endTime,
|
||||
child: Column(
|
||||
children: [
|
||||
for (var b in block) ...[b.child ?? Container()],
|
||||
],
|
||||
),
|
||||
);
|
||||
newBlocks.add(newBlock);
|
||||
}
|
||||
return newBlocks;
|
||||
}
|
||||
|
||||
List<List<TimeBlock>> _groupBlocksById(List<TimeBlock> blocks) {
|
||||
var groupedBlocks = <List<TimeBlock>>[];
|
||||
var defaultGroup = <TimeBlock>[];
|
||||
for (var block in blocks) {
|
||||
var found = false;
|
||||
if (block.id == 0) {
|
||||
defaultGroup.add(block);
|
||||
} else {
|
||||
for (var groupedBlock in groupedBlocks) {
|
||||
if (groupedBlock.first.id == block.id) {
|
||||
groupedBlock.add(block);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
groupedBlocks.add([block]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var block in defaultGroup) {
|
||||
groupedBlocks.add([block]);
|
||||
}
|
||||
return groupedBlocks;
|
||||
}
|
||||
|
||||
List<List<TimeBlock>> _mergeBlocksInColumns(List<TimeBlock> blocks) {
|
||||
var mergedBlocks = <List<TimeBlock>>[];
|
||||
// try to put blocks in the same column if the time doesn´t collide
|
||||
|
|
Loading…
Reference in a new issue