diff --git a/example/lib/main.dart b/example/lib/main.dart index 44a754d..1698d16 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -9,12 +9,14 @@ class MyApp extends StatelessWidget { MyApp({Key? key}) : super(key: key); // Data must be sorted. - final smallDataList = [ - DateTimeRange( + final List smallDataList = [ + DateTimeRangeWithColor( start: DateTime(2021, 2, 24, 23, 15), end: DateTime(2021, 2, 25, 7, 30), + color: Colors.green, ), - DateTimeRange( + DateTimeRangeWithColor( + color: Colors.red, start: DateTime(2021, 2, 22, 1, 55), end: DateTime(2021, 2, 22, 9, 12), ), @@ -34,7 +36,8 @@ class MyApp extends StatelessWidget { start: DateTime(2021, 2, 1, 9, 32), end: DateTime(2021, 2, 1, 15, 22), ), - DateTimeRange( + DateTimeRangeWithColor( + color: Colors.yellow, start: DateTime(2021, 1, 22, 12, 10), end: DateTime(2021, 1, 22, 16, 20), ), @@ -87,7 +90,6 @@ class MyApp extends StatelessWidget { const Text('Weekly amount chart'), TimeChart( data: smallDataList, - chartType: ChartType.amount, viewMode: ViewMode.weekly, barColor: Colors.deepPurple, ), diff --git a/lib/src/components/painter/amount_chart/amount_bar_painter.dart b/lib/src/components/painter/amount_chart/amount_bar_painter.dart index 079b5f9..9f6a3ea 100644 --- a/lib/src/components/painter/amount_chart/amount_bar_painter.dart +++ b/lib/src/components/painter/amount_chart/amount_bar_painter.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:time_chart/src/components/painter/bar_painter.dart'; +import 'package:time_chart/src/date_time_range_types.dart'; import 'package:touchable/touchable.dart'; import '../../utils/time_assistant.dart'; import '../chart_engine.dart'; @@ -25,14 +26,12 @@ class AmountBarPainter extends BarPainter { final touchyCanvas = TouchyCanvas(context, canvas, scrollController: scrollController, scrollDirection: AxisDirection.left); - final paint = Paint() + final gloabalPaint = Paint() ..color = barColor ?? Theme.of(context).colorScheme.secondary ..style = PaintingStyle.fill ..strokeCap = StrokeCap.round; - for (int index = 0; index < coordinates.length; index++) { - final AmountBarItem offsetWithAmount = coordinates[index]; - + for (final offsetWithAmount in coordinates) { final double left = paddingForAlignedBar + offsetWithAmount.dx; final double right = paddingForAlignedBar + offsetWithAmount.dx + barWidth; @@ -53,9 +52,25 @@ class AmountBarPainter extends BarPainter { barWidth: barWidth, ); + Paint barPaint; + + switch (offsetWithAmount.dateTime.runtimeType) { + case DateTime: + barPaint = gloabalPaint; + break; + case DateTimeWithColor: + barPaint = Paint() + ..color = (offsetWithAmount.dateTime as DateTimeWithColor).color + ..style = PaintingStyle.fill + ..strokeCap = StrokeCap.round; + break; + default: + throw UnimplementedError(); + } + touchyCanvas.drawRRect( rRect, - paint, + barPaint, onTapUp: callback, onLongPressStart: callback, onLongPressMoveUpdate: callback, diff --git a/lib/src/components/painter/time_chart/time_bar_painter.dart b/lib/src/components/painter/time_chart/time_bar_painter.dart index 514dc16..de8e7fd 100644 --- a/lib/src/components/painter/time_chart/time_bar_painter.dart +++ b/lib/src/components/painter/time_chart/time_bar_painter.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:time_chart/src/components/painter/bar_painter.dart'; +import 'package:time_chart/src/date_time_range_types.dart'; import 'package:touchable/touchable.dart'; import '../../utils/time_assistant.dart' as time_assistant; import '../chart_engine.dart'; @@ -82,15 +83,13 @@ class TimeBarPainter extends BarPainter { final touchyCanvas = TouchyCanvas(context, canvas, scrollController: scrollController, scrollDirection: AxisDirection.left); - final paint = Paint() + final globalPaint = Paint() ..color = barColor ?? Theme.of(context).colorScheme.secondary ..style = PaintingStyle.fill ..strokeCap = StrokeCap.round; final maxBottom = size.height; - for (int index = 0; index < coordinates.length; index++) { - final TimeBarItem offsetRange = coordinates[index]; - + for (final offsetRange in coordinates) { final double left = paddingForAlignedBar + offsetRange.dx; final double right = paddingForAlignedBar + offsetRange.dx + barWidth; double top = offsetRange.topY; @@ -99,19 +98,34 @@ class TimeBarPainter extends BarPainter { Radius topRadius = barRadius; Radius bottomRadius = barRadius; + Paint barPaint; + switch (offsetRange.data.runtimeType) { + case DateTimeRange: + barPaint = globalPaint; + break; + case DateTimeRangeWithColor: + barPaint = barPaint = Paint() + ..color = (offsetRange.data as DateTimeRangeWithColor).color + ..style = PaintingStyle.fill + ..strokeCap = StrokeCap.round; + break; + default: + throw UnimplementedError(); + } + if (top < 0.0) { - _drawOutRangedBar(touchyCanvas, paint, size, + _drawOutRangedBar(touchyCanvas, barPaint, size, Rect.fromLTRB(left, top, right, bottom), offsetRange.data); top = 0.0; topRadius = Radius.zero; } else if (bottom > maxBottom) { - _drawOutRangedBar(touchyCanvas, paint, size, + _drawOutRangedBar(touchyCanvas, barPaint, size, Rect.fromLTRB(left, top, right, bottom), offsetRange.data); bottom = maxBottom; bottomRadius = Radius.zero; } - _drawRRect(touchyCanvas, paint, offsetRange.data, + _drawRRect(touchyCanvas, barPaint, offsetRange.data, Rect.fromLTRB(left, top, right, bottom), topRadius, bottomRadius); } } diff --git a/lib/src/components/scroll/my_single_child_scroll_view.dart b/lib/src/components/scroll/my_single_child_scroll_view.dart index 8ed199e..4bf6cc5 100644 --- a/lib/src/components/scroll/my_single_child_scroll_view.dart +++ b/lib/src/components/scroll/my_single_child_scroll_view.dart @@ -3,7 +3,8 @@ import 'dart:math' as math; import 'package:flutter/widgets.dart'; import 'package:flutter/rendering.dart'; -import 'package:flutter/gestures.dart' show DragStartBehavior; +import 'package:flutter/gestures.dart' + show DragStartBehavior, PointerScrollEvent; class MySingleChildScrollView extends StatelessWidget { /// Creates a box in which a single widget can be scrolled. @@ -99,19 +100,30 @@ class MySingleChildScrollView extends StatelessWidget { if (padding != null) contents = Padding(padding: padding!, child: contents); final ScrollController? scrollController = primary ? PrimaryScrollController.of(context) : controller; - final Scrollable scrollable = Scrollable( - dragStartBehavior: dragStartBehavior, - axisDirection: axisDirection, - controller: scrollController, - physics: physics, - viewportBuilder: (BuildContext context, ViewportOffset offset) { - return _SingleChildViewport( + final scrollable = Listener( + onPointerSignal: (event) { + if (event is PointerScrollEvent) { + final offset = event.scrollDelta.dy; + scrollController?.jumpTo(scrollController.offset * 2 + offset); + // scrollControler.jumpTo(outerController.offset - offset); + } else if (event is PointerMoveEvent) { + final offset = event.delta.dx; + scrollController?.jumpTo(scrollController.offset + offset); + } + }, + child: Scrollable( + dragStartBehavior: dragStartBehavior, axisDirection: axisDirection, - offset: offset, - child: contents, - ); - }, - ); + controller: scrollController, + physics: physics, + viewportBuilder: (BuildContext context, ViewportOffset offset) { + return _SingleChildViewport( + axisDirection: axisDirection, + offset: offset, + child: contents, + ); + }, + )); return primary && scrollController != null ? PrimaryScrollController.none(child: scrollable) : scrollable; @@ -360,7 +372,7 @@ class _RenderSingleChildViewport extends RenderBox @override RevealedOffset getOffsetToReveal(RenderObject target, double alignment, - {Rect? rect}) { + {Rect? rect, Axis? axis}) { rect ??= target.paintBounds; if (target is! RenderBox) { return RevealedOffset(offset: offset.pixels, rect: rect); diff --git a/lib/src/components/utils/time_data_processor.dart b/lib/src/components/utils/time_data_processor.dart index 712cc1c..d1ece3a 100644 --- a/lib/src/components/utils/time_data_processor.dart +++ b/lib/src/components/utils/time_data_processor.dart @@ -57,6 +57,7 @@ mixin TimeDataProcessor { _handleEmptyData(chart); return; } + // print("preprocessing i0: ${chart.data[0].runtimeType}"); _processedData = [...chart.data]; _isFirstDataMovedNextDay = false; @@ -69,7 +70,9 @@ mixin TimeDataProcessor { break; case ChartType.amount: _calcAmountPivotHeights(chart.data); + break; } + // print("postprocessing i0: ${_processedData[0].runtimeType}"); } void _handleEmptyData(Chart chart) { @@ -197,7 +200,7 @@ mixin TimeDataProcessor { if (_isNextCellPosition(startTimeDouble) && _isNextCellPosition(endTimeDouble)) { - _processedData[i] = DateTimeRange( + _processedData[i] = _processedData[i].copy( start: startTime.add(_oneDayDuration), end: endTime.add(_oneDayDuration), ); diff --git a/lib/src/date_time_range_types.dart b/lib/src/date_time_range_types.dart new file mode 100644 index 0000000..5d1f42c --- /dev/null +++ b/lib/src/date_time_range_types.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; + +class DateTimeRangeWithColor extends DateTimeRange { + DateTimeRangeWithColor( + {required super.start, required super.end, required this.color}); + + final Color color; + + @override + DateTime get end => DateTimeWithColor.fromDateTime(super.end, color); + + factory DateTimeRangeWithColor.fromDateTimeRange( + DateTimeRange dtr, Color color) { + return DateTimeRangeWithColor(start: dtr.start, end: dtr.end, color: color); + } + + //overrides extension so a warning is given + @override + DateTimeRangeWithColor copy({DateTime? start, DateTime? end, Color? color}) => + DateTimeRangeWithColor( + start: start ?? this.start, + end: end ?? this.end, + color: color ?? this.color); +} + +class DateTimeWithColor extends DateTime { + DateTimeWithColor(this.color, super.year, + [super.month, + super.day, + super.hour, + super.minute, + super.second, + super.millisecond, + super.microsecond]); + + final Color color; + + factory DateTimeWithColor.fromDateTime(DateTime dt, Color color) { + return DateTimeWithColor(color, dt.year, dt.month, dt.day, dt.hour, + dt.minute, dt.second, dt.millisecond, dt.microsecond); + } +} + +extension Copy on DateTimeRange { + DateTimeRange copy({DateTime? start, DateTime? end, Color? color}) => + DateTimeRange(start: start ?? this.start, end: end ?? this.end); +} diff --git a/lib/time_chart.dart b/lib/time_chart.dart index a09e175..a7037ba 100644 --- a/lib/time_chart.dart +++ b/lib/time_chart.dart @@ -3,3 +3,4 @@ library time_chart; export 'src/time_chart.dart'; export 'src/components/view_mode.dart'; export 'src/components/chart_type.dart'; +export 'src/date_time_range_types.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index b0360bd..c2010a1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: linked_scroll_controller: ^0.2.0 touchable: ^1.0.2 path_drawing: ^1.0.0 - intl: ^0.17.0 + intl: ^0.18.0 dev_dependencies: flutter_test: