import 'dart:async';
import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      home: PendulumWidget(title:""),
    ),
  );
}

class PendulumWidget extends StatefulWidget {
  PendulumWidget({Key? key,required this.title}) : super(key: key);

  final String title;

  @override
  _PendulumWidgetState createState() => _PendulumWidgetState();
}

class _PendulumWidgetState extends State<PendulumWidget>
    with TickerProviderStateMixin {
  AnimationController? _backgroundController;
  Animatable<Color> background = TweenSequence<Color>([
    TweenSequenceItem(
      weight: 1.0,
      tween: ColorTween(
        begin: Constants.tolopea,
        end: Constants.grape,
      )as Animatable<Color>,
    ),
    TweenSequenceItem(
      weight: 1.0,
      tween: ColorTween(
        begin: Constants.valhalla,
        end: Constants.loulou,
      )as Animatable<Color>,
    ),
    TweenSequenceItem(
      weight: 1.0,
      tween: ColorTween(
        begin: Constants.green,
        end: Colors.black,
      )as Animatable<Color>,
    ),
  ]);

  AnimationController? _rotationController;
  Animation<double>? _rotationAnimation;

  double forwardAngle = 30;
  double backwardAngle = -30;
  // rotate the canvas
  double degrees = 15;
  double radians = 15 * 3.14 / 180;
  @override
  void initState() {
    super.initState();
    _backgroundController = AnimationController(
      duration: const Duration(seconds: 6),
      vsync: this,
    )..repeat();

    _rotationController = AnimationController(
      duration: const Duration(seconds: 1),
      vsync: this,
    )..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          radians = -15 * 3.14 / 180;
          _rotationController?.reverse();
        } else if (status == AnimationStatus.dismissed) {
          radians = 15 * 3.14 / 180;
          _rotationController?.forward();
        }
      });
    if(_rotationController!=null){
         _rotationAnimation =
        Tween<double>(begin: 0, end: 3.14 / 6).animate(_rotationController!); 
    }
    _rotationController?.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(children: [
        AnimatedBuilder(
            animation: _backgroundController!,
            builder: (context, child) {
              return Container(
                color: background.evaluate(
                    AlwaysStoppedAnimation(_backgroundController!.value)),
              );
            }),
        Center(
            child: RotationTransition(
          turns: new AlwaysStoppedAnimation(345 / 360),
          child: AnimatedBuilder(
              animation: _rotationAnimation!,
              builder: (context, child) {
                return Transform.rotate(
                  angle: _rotationAnimation!.value,
                  origin: Offset(0.0, 0.0),
                  child: CustomPaint(
                      child: Container(), painter: PendulumNeedle()),
                );
              }),
        )),
        Center(
            child: CustomPaint(child: Container(), painter: PendulumHouse())),
        Center(child: PendulumClock()),
      ]),
    );
  }
}

class Constants {
  static Color golden = Color(0xFFFFCC61);
  static Color paarl = Color(0xFFA15830);
  static Color rico = Color(0xFF4AC7B0);
  static Color horn = Color(0xFF4F3F3F);
  static Color tolopea = Color(0xFF230047);
  static Color grape = Color(0xFF4C1A55);
  static Color valhalla = Color(0xFF221655);
  static Color loulou = Color(0xFF50133F);
  static Color green = Color(0xFF1B5147);
  static Color alto = Color(0xFFDDDDDD);
}

class PendulumHouse extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint()
      ..color = Colors.teal
      ..strokeWidth = 5
      ..style = PaintingStyle.fill
      ..strokeCap = StrokeCap.round;

    //draw rectangle
    paint.color = Constants.paarl;
    canvas.drawRRect(
      RRect.fromRectAndRadius(
          Rect.fromLTWH(size.width / 2 - 87.5, size.height / 2 - 100, 175, 175),
          Radius.circular(0)),
      paint,
    );

    //draw triangle
    paint.color = Constants.paarl;
    var path1 = Path();
    path1.moveTo(size.width / 2, size.height / 2 - 175);
    path1.lineTo(size.width / 2 - 87.5, size.height / 2 - 100);
    path1.lineTo(size.width / 2 + 87.5, size.height / 2 - 100);
    canvas.drawPath(path1, paint);

    // //draw left rectangle
    paint.color = Constants.rico;
    var path2 = Path();
    path2.moveTo(size.width / 2 + 20, size.height / 2 - 220);
    path2.lineTo(size.width / 2 - 107.5, size.height / 2 - 110);
    path2.lineTo(size.width / 2 - 107.5, size.height / 2 - 80);
    path2.lineTo(size.width / 2 + 20, size.height / 2 - 190);
    path2.lineTo(size.width / 2 + 20, size.height / 2 - 195);

    canvas.drawPath(path2, paint);

    // //draw right rectangle
    paint.color = Constants.rico;
    var path3 = Path();
    path3.moveTo(size.width / 2 - 20, size.height / 2 - 220);
    path3.lineTo(size.width / 2 + 107.5, size.height / 2 - 110);
    path3.lineTo(size.width / 2 + 107.5, size.height / 2 - 80);
    path3.lineTo(size.width / 2 - 20, size.height / 2 - 190);
    path3.lineTo(size.width / 2 - 20, size.height / 2 - 195);

    canvas.drawPath(path3, paint);

    paint.color = Constants.rico;
    canvas.drawRRect(
      RRect.fromRectAndRadius(
          Rect.fromLTWH(size.width / 2 - 97.5, size.height / 2 + 75, 195, 20),
          Radius.circular(0)),
      paint,
    );
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

class PendulumNeedle extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint();
    paint.color = Constants.golden;
    var path2 = Path();
    path2.moveTo(size.width / 2, size.height / 2);
    path2.lineTo(size.width / 2 - 10, size.height / 2);
    path2.lineTo(size.width / 2 - 5, size.height / 2 + 175);
    path2.lineTo(size.width / 2 + 5, size.height / 2 + 175);
    path2.lineTo(size.width / 2 + 10, size.height / 2);
    path2.lineTo(size.width / 2, size.height / 2);

    canvas.drawPath(path2, paint);

    canvas.drawCircle(Offset(size.width / 2, size.height / 2 + 160), 20, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

final radiansPerTick = 3.14 / 180 * (360 / 60);
final radiansPerHour = 3.14 / 180 * (360 / 12);

class PendulumClock extends StatefulWidget {
  @override
  _PendulumClockState createState() => _PendulumClockState();
}

class _PendulumClockState extends State<PendulumClock> {
  var _now = DateTime.now();
  Timer? _timer;

  @override
  void initState() {
    super.initState();
    // Set the initial values.
    _updateTime();
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }

  void _updateTime() {
    setState(() {
      _now = DateTime.now();
      _timer = Timer(
        Duration(seconds: 1) - Duration(milliseconds: _now.millisecond),
        _updateTime,
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    final unit = 20 / 1;

    return ClockData(
      time: _now,
      unit: unit,
      child: Container(
        height: unit * 13,
        width: unit * 13,
        padding: EdgeInsets.all(2 * unit),
        child: Stack(
          children: [
            OuterCircle(),
            InnerCircle(),
            ClockTicks(),
            HourHand(),
            MinuteHand(),
            SecondHand(),
            ClockPin(),
          ],
        ),
      ),
    );
  }
}

class ClockData extends InheritedWidget {
  final DateTime time;
  final double unit;
  @override
  final Widget child;

  ClockData({
    required this.time,
    required this.unit,
    required this.child,
  }):super(child: child);

  @override
  bool updateShouldNotify(ClockData oldWidget) =>
      oldWidget.time != time && oldWidget.unit != unit;

  static ClockData of(BuildContext context) =>
      context.dependOnInheritedWidgetOfExactType<ClockData>()!;
}

abstract class Hand extends StatelessWidget {
  /// Create a const clock [Hand].
  ///
  /// All of the parameters are required and must not be null.
  const Hand({
    required this.color,
    required this.size,
    required this.angleRadians,
  })  : assert(color != null),
        assert(size != null),
        assert(angleRadians != null);

  final Color color;
  final double size;
  final double angleRadians;
}

class ContainerHand extends Hand {
  const ContainerHand({
    required Color color,
    required double size,
    required double angleRadians,
    required this.child,
  })  : assert(size != null),
        assert(angleRadians != null),
        super(
          color: color,
          size: size,
          angleRadians: angleRadians,
        );

  /// The child widget used as the clock hand and rotated by [angleRadians].
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: SizedBox.expand(
        child: Transform.rotate(
          angle: angleRadians,
          alignment: Alignment.center,
          child: Transform.scale(
            scale: size,
            alignment: Alignment.center,
            child: Container(
              color: color,
              child: Center(child: child),
            ),
          ),
        ),
      ),
    );
  }
}

class AnimatedContainerHand extends StatelessWidget {
  const AnimatedContainerHand({
    Key? key,
    required int now,
    required Widget child,
    required double size,
  })  : _now = now,
        _child = child,
        _size = size,
        super(key: key);

  final int _now;
  final Widget _child;
  final double _size;

  @override
  Widget build(BuildContext context) {
    if (_now == 0) {
      return TweenAnimationBuilder<double>(
        key: ValueKey('special_case_when_overflowing'),
        duration: Duration(milliseconds: 300),
        tween: Tween<double>(
          begin: value(_now - 1),
          end: value(_now),
        ),
        curve: Curves.easeInQuint,
        builder: (context, anim, child) {
          return ContainerHand(
            color: Colors.transparent,
            size: _size,
            angleRadians: anim,
            child: child!,
          );
        },
        child: _child,
      );
    }
    return TweenAnimationBuilder<double>(
      key: ValueKey('normal_case'),
      duration: Duration(milliseconds: 300),
      tween: Tween<double>(
        begin: value(_now - 1),
        end: value(_now),
      ),
      curve: Curves.easeInQuint,
      builder: (context, anim, child) {
        return ContainerHand(
          color: Colors.transparent,
          size: _size,
          angleRadians: anim,
          child: child!,
        );
      },
      child: _child,
    );
  }

  double value(int second) {
    return second * radiansPerTick;
  }
}

class OuterCircle extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final unit = ClockData.of(context).unit;
    return Center(
        child: Container(
      height: unit * 6,
      width: unit * 6,
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        color: Constants.golden,
      ),
    ));
  }
}

class InnerCircle extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final unit = ClockData.of(context).unit;
    return Padding(
      padding: EdgeInsets.all(unit / 2),
      child: Center(
          child: Container(
        height: unit * 5,
        width: unit * 5,
        decoration: BoxDecoration(
          shape: BoxShape.circle,
          color: Constants.horn,
        ),
      )),
    );
  }
}

class ClockTicks extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final unit = ClockData.of(context).unit * 0.8;
    return Stack(
      children: <Widget>[
        for (var i = 0; i < 4; i++)
          Center(
            child: Transform.rotate(
              // convert degrees to radians
              angle: 3.14 / 180 * 360 / 4 * i,
              child: Transform.translate(
                offset: Offset(0, i % 3 == 0 ? -2.5 * unit : -2.5 * unit),
                child: Container(
                  color: Constants.golden,
                  height: i % 3 == 0 ? 0.8 * unit : 1.0 * unit,
                  width: i % 3 == 0 ? 0.15 * unit : 0.15 * unit,
                ),
              ),
            ),
          )
      ],
    );
  }
}

class HourHand extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final unit = ClockData.of(context).unit;
    final time = ClockData.of(context).time;
    return Padding(
      padding: EdgeInsets.all(2 * unit),
      child: ContainerHand(
        color: Colors.transparent,
        size: 0.2,
        angleRadians:
            time.hour * radiansPerHour + (time.minute / 60) * radiansPerHour,
        child: Transform.translate(
          offset: Offset(0.0, -3 * unit),
          child: Container(
            width: 1 * unit,
            height: 6 * unit,
            decoration: BoxDecoration(
              color: Constants.golden,
            ),
          ),
        ),
      ),
    );
  }
}

class MinuteHand extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final unit = ClockData.of(context).unit;
    return Padding(
      padding: EdgeInsets.all(2 * unit),
      child: AnimatedContainerHand(
        size: 0.3,
        now: ClockData.of(context).time.minute,
        child: Transform.translate(
          offset: Offset(0.0, -2.5 * unit),
          child: Container(
            width: unit / 2,
            height: unit * 4,
            decoration: BoxDecoration(
              color: Constants.golden,
            ),
          ),
        ),
      ),
    );
  }
}

class SecondHand extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final second = ClockData.of(context).time.second;
    final unit = ClockData.of(context).unit;
    return AnimatedContainerHand(
      now: second,
      size: 0.4,
      child: Transform.translate(
        offset: Offset(0.0, -2.5 * unit),
        child: Container(
          width: unit / 4,
          height: unit * 4,
          decoration: BoxDecoration(
            color: Constants.alto,
          ),
        ),
      ),
    );
  }
}

class ClockPin extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        height: 0.4 * ClockData.of(context).unit,
        decoration: BoxDecoration(
          shape: BoxShape.circle,
          color: Colors.white,
        ),
      ),
    );
  }
}
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.