diff --git a/app/lib/pages/dashboard/page.dart b/app/lib/pages/dashboard/page.dart index 0e331eb4eeb..9c1d2f66a08 100644 --- a/app/lib/pages/dashboard/page.dart +++ b/app/lib/pages/dashboard/page.dart @@ -1,4 +1,5 @@ import 'package:flow/pages/dashboard/notes.dart'; +import 'package:flow/widgets/clock.dart'; import 'package:flow/widgets/navigation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -25,6 +26,19 @@ class _DashboardPageState extends State { builder: (context, constraints) { return ListView( children: [ + Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: ConstrainedBox( + constraints: const BoxConstraints( + minHeight: 300, + minWidth: 300, + maxWidth: 600, + maxHeight: 600), + child: const ClockView(), + ), + )), + const SizedBox(height: 16), Card( child: Padding( padding: const EdgeInsets.all(16.0), diff --git a/app/lib/widgets/clock.dart b/app/lib/widgets/clock.dart new file mode 100644 index 00000000000..24fb8832ef7 --- /dev/null +++ b/app/lib/widgets/clock.dart @@ -0,0 +1,147 @@ +import 'dart:async'; +import 'dart:math'; + +import 'package:flutter/material.dart'; + +class ClockView extends StatefulWidget { + const ClockView({super.key}); + + @override + _ClockViewState createState() => _ClockViewState(); +} + +class _ClockViewState extends State { + late final Timer _timer; + late DateTime _dateTime; + + @override + void initState() { + super.initState(); + _dateTime = DateTime.now(); + _timer = Timer.periodic(const Duration(seconds: 1), (timer) { + setState(() { + _dateTime = DateTime.now(); + }); + }); + } + + @override + void dispose() { + _timer.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final colorScheme = Theme.of(context).colorScheme; + return CustomPaint( + painter: _ClockPainter( + dateTime: _dateTime, + hourHandColor: colorScheme.primary, + minuteHandColor: colorScheme.primary, + secondHandColor: colorScheme.secondary, + indicatorColor: colorScheme.onSurface, + backgroundColor: colorScheme.surface, + ), + ); + } +} + +class _ClockPainter extends CustomPainter { + _ClockPainter({ + required this.dateTime, + required this.hourHandColor, + required this.minuteHandColor, + required this.secondHandColor, + required this.indicatorColor, + required this.backgroundColor, + }); + + final DateTime dateTime; + final Color hourHandColor, + minuteHandColor, + secondHandColor, + indicatorColor, + backgroundColor; + + @override + void paint(Canvas canvas, Size size) { + canvas.drawColor(backgroundColor, BlendMode.color); + + final center = size.center(Offset.zero); + final radius = size.shortestSide / 2; + + final indicatorPaint = Paint()..color = indicatorColor; + canvas.drawCircle(center, 10, indicatorPaint); + var textStyle = TextStyle( + color: indicatorColor, + fontSize: 18, + fontWeight: FontWeight.w500, + ); + final textPainter = TextPainter( + textDirection: TextDirection.ltr, + textAlign: TextAlign.center, + ); + for (var i = 0; i < 12; i++) { + final angle = (i - 2) * 2 * pi / 12; + final line = Offset.fromDirection(angle, radius); + canvas.drawLine(center + line * 0.9, center + line, indicatorPaint); + final textSpan = TextSpan( + text: '${i + 1}', + style: textStyle, + ); + textPainter.text = textSpan; + textPainter.layout(); + final textOffset = + center + line * 0.8 - textPainter.size.center(Offset.zero); + textPainter.paint(canvas, textOffset); + } + + void drawHand(double angle, Paint paint, [double length = 1]) { + angle -= pi / 2; + final line = Offset.fromDirection(angle, radius * length); + canvas.drawLine(center, center + line, paint); + } + + final hourAngle = + dateTime.hour * 2 * pi / 12 + dateTime.minute * 2 * pi / (12 * 60); + final hourHandPaint = Paint() + ..color = hourHandColor + ..strokeWidth = 5 + ..strokeCap = StrokeCap.round; + drawHand(hourAngle, hourHandPaint, 0.5); + + final minuteAngle = dateTime.minute * 2 * pi / 60; + final minuteHandPaint = Paint() + ..color = minuteHandColor + ..strokeWidth = 3 + ..strokeCap = StrokeCap.round; + drawHand(minuteAngle, minuteHandPaint, 0.7); + + final secondAngle = dateTime.second * 2 * pi / 60; + final secondHandPaint = Paint() + ..color = secondHandColor + ..strokeWidth = 1 + ..strokeCap = StrokeCap.round; + drawHand(secondAngle, secondHandPaint, 0.9); + + textStyle = textStyle.copyWith(fontSize: 20, fontWeight: FontWeight.bold); + textPainter.text = TextSpan( + text: '${dateTime.hour}:${dateTime.minute}:${dateTime.second}', + style: textStyle, + ); + textPainter.layout(); + final textOffset = + center - textPainter.size.center(Offset.zero) + Offset(0, radius * 0.4); + textPainter.paint(canvas, textOffset); + } + + @override + bool shouldRepaint(_ClockPainter oldDelegate) => + oldDelegate.dateTime != dateTime || + oldDelegate.hourHandColor != hourHandColor || + oldDelegate.minuteHandColor != minuteHandColor || + oldDelegate.secondHandColor != secondHandColor || + oldDelegate.indicatorColor != indicatorColor || + oldDelegate.backgroundColor != backgroundColor; +} diff --git a/fastlane/metadata/android/en-US/changelogs/7.txt b/fastlane/metadata/android/en-US/changelogs/7.txt new file mode 100644 index 00000000000..b1d0e7c5e06 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/7.txt @@ -0,0 +1 @@ +* Add clock to dashboard \ No newline at end of file