main_page.dart 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import 'package:flutter/material.dart';
  2. import 'dart:async';
  3. import 'dart:math' as math;
  4. import 'package:intl/intl.dart';
  5. class MainPage extends StatefulWidget {
  6. @override
  7. State<StatefulWidget> createState() {
  8. @override
  9. _MainPageState createState() => _MainPageState();
  10. }
  11. }
  12. class _MainPageState extends State<MainPage> {
  13. final _utcMidnightRadiansOffset = radiansFromDegrees(-64);
  14. static const _secondsInDay = 86400;
  15. DateTime _localTime = DateTime.now();
  16. @override
  17. void initState() {
  18. super.initState();
  19. Timer.periodic(Duration(seconds: 1),
  20. (_) => setState(() => _localTime = DateTime.now()));
  21. }
  22. @override
  23. Widget build(BuildContext context) => Scaffold(
  24. backgroundColor: Colors.white,
  25. appBar: AppBar(title: Text('xkcd clock')),
  26. body: Column(
  27. children: [
  28. Stack(
  29. children: [
  30. Image.asset('assets/face.png'),
  31. Transform.rotate(
  32. angle: -(radiansFromTime(_localTime.toUtc()) +
  33. _utcMidnightRadiansOffset),
  34. child: ClipOval(
  35. clipper: InnerFaceClipper(),
  36. child: Image.asset('assets/face.png'),
  37. ),
  38. ),
  39. ],
  40. ),
  41. Text(DateFormat.EEEE().format(_localTime),
  42. style: TextStyle(fontSize: 48)),
  43. Text(DateFormat.yMMMMd().format(_localTime),
  44. style: TextStyle(fontSize: 20)),
  45. Text(DateFormat.jm().format(_localTime),
  46. style: TextStyle(fontSize: 42)),
  47. ],
  48. ),
  49. );
  50. static double radiansFromDegrees(double degrees) => degrees * math.pi / 180;
  51. static double radiansFromTime(DateTime time) {
  52. final midnightToday = DateTime(time.year, time.month, time.day);
  53. final secondsSinceMidnight = midnightToday.difference(time).inSeconds;
  54. final percent = secondsSinceMidnight / _secondsInDay;
  55. final degrees = percent * 360;
  56. return radiansFromDegrees(degrees);
  57. }
  58. }
  59. class InnerFaceClipper extends CustomClipper<Rect> {
  60. final percent = 0.85;
  61. @override
  62. Rect getClip(Size size) => Rect.fromCenter(
  63. center: size.center(Offset(0, 0)),
  64. width: size.width * percent,
  65. height: size.height * percent,
  66. );
  67. @override
  68. bool shouldReclip(CustomClipper oldClipper) => true;
  69. }