Skip to content

Commit

Permalink
feat: add timezone support for current time display
Browse files Browse the repository at this point in the history
  • Loading branch information
MasterHiei committed Feb 19, 2025
1 parent 23b4d1b commit 45df60f
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 21 deletions.
7 changes: 7 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:time/time.dart';
import 'package:timetable/timetable.dart';
// import 'package:timezone/data/latest.dart' as tz;

// ignore: unused_import
import 'positioning_demo.dart';
import 'utils.dart';

Future<void> main() async {
initDebugOverlay();
// Please ensure the time zone database is initialized
// when you need to display current time indicator with specific time zone.
//
// More information: [https://pub.dev/packages/timezone]
// tz.initializeTimeZones();
runApp(const ExampleApp(child: TimetableExample()));
}

Expand Down Expand Up @@ -49,6 +55,7 @@ class _TimetableExampleState extends State<TimetableExample>
// maxDuration: 10.hours,
// initialRange: TimeRange(8.hours, 20.hours),
maxRange: TimeRange(0.hours, 24.hours),
// tzIdentifier: 'Europe/Berlin',
);

final _draggedEvents = <BasicEvent>[];
Expand Down
30 changes: 19 additions & 11 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -82,26 +82,26 @@ packages:
dependency: transitive
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.0"
clock:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.1.2"
collection:
dependency: "direct main"
description:
name: collection
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.0"
version: "1.19.1"
color:
dependency: transitive
description:
Expand Down Expand Up @@ -386,10 +386,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev"
source: hosted
version: "1.15.0"
version: "1.16.0"
oxidized:
dependency: transitive
description:
Expand Down Expand Up @@ -426,10 +426,10 @@ packages:
dependency: transitive
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
version: "1.9.1"
petitparser:
dependency: transitive
description:
Expand Down Expand Up @@ -604,6 +604,14 @@ packages:
relative: true
source: path
version: "1.0.0-alpha.15"
timezone:
dependency: "direct main"
description:
name: timezone
sha256: ffc9d5f4d1193534ef051f9254063fa53d588609418c84299956c3db9383587d
url: "https://pub.dev"
source: hosted
version: "0.10.0"
todo:
dependency: transitive
description:
Expand Down Expand Up @@ -685,5 +693,5 @@ packages:
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.5.0 <4.0.0"
dart: ">=3.7.0-0 <4.0.0"
flutter: ">=3.27.0-0"
2 changes: 2 additions & 0 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ dependencies:
time: ^2.1.4
timetable:
path: ../
# Optional: it is only required for displaying current time indicator with specific time zone
timezone: ^0.10.0

dev_dependencies:
supernova:
Expand Down
34 changes: 24 additions & 10 deletions lib/src/components/now_indicator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
import '../config.dart';
import '../date/controller.dart';
import '../theme.dart';
import '../time/controller.dart';
import '../utils.dart';

/// A widget that displays an indicator at the current date and time.
Expand Down Expand Up @@ -36,7 +37,8 @@ class NowIndicator extends StatelessWidget {
Widget build(BuildContext context) {
return CustomPaint(
foregroundPainter: _NowIndicatorPainter(
controller: DefaultDateController.of(context)!,
dateController: DefaultDateController.of(context)!,
timeController: DefaultTimeController.of(context)!,
style: style ?? TimetableTheme.orDefaultOf(context).nowIndicatorStyle,
devicePixelRatio: context.mediaQuery.devicePixelRatio,
),
Expand Down Expand Up @@ -287,28 +289,36 @@ class TriangleNowIndicatorShape extends NowIndicatorShape {

class _NowIndicatorPainter extends CustomPainter {
factory _NowIndicatorPainter({
required DateController controller,
required DateController dateController,
required TimeController timeController,
required NowIndicatorStyle style,
required double devicePixelRatio,
}) =>
_NowIndicatorPainter._(
controller: controller,
dateController: dateController,
timeController: timeController,
style: style,
devicePixelRatio: devicePixelRatio,
repaintNotifier: ValueNotifier(DateTimeTimetable.now()),
repaintNotifier: ValueNotifier(
timeController.useTimeZone
? DateTimeTimetable.nowAt(timeController.tzIdentifier!)
: DateTimeTimetable.now(),
),
);
_NowIndicatorPainter._({
required this.controller,
required this.dateController,
required this.timeController,
required this.style,
required this.devicePixelRatio,
required ValueNotifier<DateTime> repaintNotifier,
}) : _paint = Paint()
..color = style.lineColor
..strokeWidth = style.lineWidth,
_repaintNotifier = repaintNotifier,
super(repaint: Listenable.merge([controller, repaintNotifier]));
super(repaint: Listenable.merge([dateController, repaintNotifier]));

final DateController controller;
final DateController dateController;
final TimeController timeController;
final Paint _paint;
final NowIndicatorStyle style;
final double devicePixelRatio;
Expand All @@ -318,9 +328,11 @@ class _NowIndicatorPainter extends CustomPainter {
unawaited(_repaint?.cancel());
_repaint = null;

final pageValue = controller.value;
final pageValue = dateController.value;
final dateWidth = size.width / pageValue.visibleDayCount;
final now = DateTimeTimetable.now();
final now = timeController.useTimeZone
? DateTimeTimetable.nowAt(timeController.tzIdentifier!)
: DateTimeTimetable.now();
final temporalXOffset =
now.copyWith(isUtc: true).atStartOfDay.page - pageValue.page;
final left = temporalXOffset * dateWidth;
Expand All @@ -346,7 +358,9 @@ class _NowIndicatorPainter extends CustomPainter {
() {
// [ChangeNotifier.notifyListeners] is protected, so we use a
// [ValueNotifier] and always set a different time.
_repaintNotifier.value = DateTimeTimetable.now();
_repaintNotifier.value = timeController.useTimeZone
? DateTimeTimetable.nowAt(timeController.tzIdentifier!)
: DateTimeTimetable.now();
},
),
);
Expand Down
13 changes: 13 additions & 0 deletions lib/src/time/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class TimeController extends ValueNotifier<TimeRange> {
Duration? maxDuration,
TimeRange? initialRange,
TimeRange? maxRange,
this.tzIdentifier,
this.minDayHeight,
}) : assert(!minDuration.isNegative),
assert(minDuration <= maxPossibleDuration),
Expand All @@ -36,6 +37,7 @@ class TimeController extends ValueNotifier<TimeRange> {
maxRange == null ||
maxDuration <= maxRange.duration,
),
assert(tzIdentifier == null || tzIdentifier.isNotEmpty),
maxRange = maxRange ?? TimeRange.fullDay,
assert(minDayHeight == null || minDayHeight > 0),
assert(minDayHeight == null || minDayHeight.isFinite),
Expand Down Expand Up @@ -85,11 +87,22 @@ class TimeController extends ValueNotifier<TimeRange> {
Duration get actualMaxDuration =>
maxDuration.coerceAtMost(maxDurationFromMinDayHeightOrDefault);

/// Whether the specified time zone is used when displaying current time.
bool get useTimeZone => tzIdentifier != null;

static const maxPossibleDuration = Duration(days: 1);

/// The maximum range that can be revealed when zooming out.
final TimeRange maxRange;

/// The time zone identifier that be used when displaying current time.
/// If null, the system time zone is used.
///
/// Note: Ensure timezone database is initialized before use
///
/// More information: [https://pub.dev/packages/timezone#initialization]
final String? tzIdentifier;

@override
set value(TimeRange value) {
assert(_isValidRange(value));
Expand Down
7 changes: 7 additions & 0 deletions lib/src/utils.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:dart_date/dart_date.dart' show Interval;
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart' hide Interval;
import 'package:timezone/timezone.dart';

import 'week.dart';

Expand Down Expand Up @@ -88,6 +89,12 @@ extension DateTimeTimetable on DateTime {
return date;
}

static DateTime nowAt(String timezone) {
final date = TZDateTime.now(getLocation(timezone)).copyWith(isUtc: true);
assert(date.debugCheckIsValidTimetableDateTime());
return date;
}

static DateTime today() {
final date = DateTimeTimetable.now().atStartOfDay;
assert(date.debugCheckIsValidTimetableDate());
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies:
flutter_layout_grid: ^2.0.0
intl: '>=0.17.0 <0.21.0'
meta: ^1.3.0
timezone: ^0.10.0

dev_dependencies:
flutter_test:
Expand Down

0 comments on commit 45df60f

Please sign in to comment.