clock_block.dart 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. import 'package:intl/intl.dart';
  4. import '../../../core/theme/app_colors.dart';
  5. /// Large, quiet clock. It sleeps until the next minute instead of ticking
  6. /// every second.
  7. class ClockBlock extends StatefulWidget {
  8. const ClockBlock({super.key, required this.compact});
  9. final bool compact;
  10. @override
  11. State<ClockBlock> createState() => _ClockBlockState();
  12. }
  13. class _ClockBlockState extends State<ClockBlock> {
  14. late DateTime _now = DateTime.now();
  15. Timer? _timer;
  16. @override
  17. void initState() {
  18. super.initState();
  19. _scheduleTick();
  20. }
  21. void _scheduleTick() {
  22. _timer?.cancel();
  23. final now = DateTime.now();
  24. final next = DateTime(
  25. now.year,
  26. now.month,
  27. now.day,
  28. now.hour,
  29. now.minute,
  30. ).add(const Duration(minutes: 1));
  31. _timer = Timer(next.difference(now) + const Duration(milliseconds: 80), () {
  32. if (!mounted) return;
  33. setState(() => _now = DateTime.now());
  34. _scheduleTick();
  35. });
  36. }
  37. @override
  38. void dispose() {
  39. _timer?.cancel();
  40. super.dispose();
  41. }
  42. @override
  43. Widget build(BuildContext context) {
  44. final theme = Theme.of(context);
  45. final colors = context.colors;
  46. final locale = Localizations.localeOf(context).toLanguageTag();
  47. final use24Hour = MediaQuery.alwaysUse24HourFormatOf(context);
  48. final time = (use24Hour ? DateFormat.Hm(locale) : DateFormat.jm(locale))
  49. .format(_now);
  50. final date = DateFormat('EEEE, d MMMM', locale).format(_now);
  51. return Column(
  52. mainAxisSize: MainAxisSize.min,
  53. crossAxisAlignment: CrossAxisAlignment.start,
  54. children: [
  55. Text(
  56. time,
  57. maxLines: 1,
  58. style: theme.textTheme.displayLarge?.copyWith(
  59. fontSize: widget.compact ? 56 : 72,
  60. fontFeatures: const [FontFeature.tabularFigures()],
  61. height: 0.95,
  62. ),
  63. ),
  64. const SizedBox(height: 10),
  65. Row(
  66. mainAxisSize: MainAxisSize.min,
  67. children: [
  68. Container(
  69. width: 6,
  70. height: 6,
  71. decoration: BoxDecoration(
  72. color: colors.accent,
  73. shape: BoxShape.circle,
  74. ),
  75. ),
  76. const SizedBox(width: 10),
  77. Text(
  78. date,
  79. maxLines: 1,
  80. overflow: TextOverflow.ellipsis,
  81. style: theme.textTheme.titleMedium?.copyWith(
  82. color: colors.inkMuted,
  83. fontWeight: FontWeight.w500,
  84. fontSize: widget.compact ? 14 : 16,
  85. ),
  86. ),
  87. ],
  88. ),
  89. ],
  90. );
  91. }
  92. }