import 'dart:core'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'numberpicker.dart'; main() => runApp(MaterialApp(home: App(), debugShowCheckedModeBanner: false)); class App extends StatefulWidget { @override State createState() => TM(); } enum SI { pause, play, stop } List triangles; var percent = 0.0, cTime = 0.0, dur = 120000.0, rng = Random(), rebuild = true; class TM extends State { SI cState = SI.stop; Ticker t; var pTime = 0.0; @override initState() { // Screen.keepOn(true); t = Ticker(up); super.initState(); } up(Duration d) { if (cState == SI.play) { setState(() { if (cTime >= dur) stop(); else { cTime = d.inMilliseconds.toDouble() + pTime; percent = cTime / dur; } }); } } press() { if (cState == SI.play) pause(); else if (cState == SI.pause) play(); else { cState = SI.play; t.start(); } } pause() { setState(() { cState = SI.pause; t.stop(); }); } play() { setState(() { cState = SI.play; t.start(); pTime = cTime; }); } stop() { setState(() { cState = SI.stop; t.stop(); pTime = 0.0; cTime = 0.0; percent = 0.0; }); } openDialog() { showDialog( context: context, builder: (BuildContext context) { return NumberPickerDialog.integer( initialIntegerValue: (dur + 1.0) ~/ 60000, maxValue: 20, minValue: 1, title: Text('Minutes')); }).then((num v) { if (v != null) dur = 60000.0 * v; }); } @override Widget build(BuildContext context) { List w = List(); if (cState == SI.pause) { w.add(fab(Colors.green, play, Icons.play_arrow)); w.add(SizedBox(height: 10)); w.add(fab(Colors.red, stop, Icons.close)); w.add(SizedBox(height: 20)); } if (cState == SI.stop) { w.add(fab(Colors.lightBlue, openDialog, Icons.timer)); w.add(SizedBox(height: 10)); w.add(fab(Colors.yellow[900], () { rebuild = true; }, Icons.loop)); w.add(SizedBox(height: 20)); } Column r = Column(mainAxisAlignment: MainAxisAlignment.end, children: w); return Scaffold( backgroundColor: Colors.black, body: SizedBox.expand( child: Container( child: CustomPaint( painter: P(), child: FlatButton( onPressed: press, child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [r])))))); } } FloatingActionButton fab(Color c, VoidCallback f, IconData ic) => FloatingActionButton(backgroundColor: c, onPressed: f, child: Icon(ic)); class P extends CustomPainter { @override paint(Canvas canvas, Size size) { var w = size.width, h = size.height, d = 2 / 3 * w; if (w > 0.1 && h > 0.1) { if (rebuild) { rebuild = false; setupT(); for (var t in triangles) t.setupdP(w / d, h / d); } for (var t in triangles) { var cP = t.cP(), p = Path(); p.moveTo(cP[0].x * d + w / 2, cP[0].y * d + h / 2); for (i = 1; i < 3; i++) p.lineTo(cP[i].x * d + w / 2, cP[i].y * d + h / 2); p.close(); canvas.drawPath(p, t.p); } } } @override bool shouldRepaint(CustomPainter oldDelegate) => true; } int i; class T { List dP = List(3), sP = List(3); Paint p; T(Point p1, p2, p3, var c) { p = Paint()..style = PaintingStyle.fill; sP[0] = p1; sP[1] = p2; sP[2] = p3; p.color = c[100 * (rng.nextInt(9) + 1)]; double x = 0, y = 0; for (i = 0; i < 3; i++) { x += sP[i].x; y += sP[i].y; } x = 2 * x / 3; y = 2 * y / 3; if (x * x + y * y < 1) triangles.add(this); } setupdP(double wR, hR) { var x = (rng.nextDouble() - 0.5) * (wR - 0.1), y = (rng.nextDouble() - 0.5) * (hR - 0.1); dP[0] = Point(x, y); for (i = 1; i < 3; i++) dP[i] = Point(sP[i].x + x - sP[0].x, sP[i].y + y - sP[0].y); } List cP() { List res = List(3); var p, k, o = 6000, r; if (cTime < o) p = 1 - cTime / o; else p = (cTime - o) / (dur - o); k = 2 * ((cTime.toInt() % o) - o / 2).abs() / o; r = min(min(1, (dur - cTime) / o), cTime / o); this.p.color = this.p.color.withAlpha(255 - (200 * k * r).toInt()); for (i = 0; i < 3; i++) res[i] = Point( sP[i].x * p + dP[i].x * (1 - p), sP[i].y * p + dP[i].y * (1 - p)); if (cTime > o) { var d = res[0].distanceTo(sP[0]); var a = acos((sP[0].x - res[0].x) / d); if (sP[0].y > res[0].y) a = 2 * pi - a; var b = pi - a + p * pi * dur / 120000; var dX = cos(b) * d, dY = sin(b) * d; for (i = 0; i < 3; i++) res[i] = Point(sP[i].x + dX, sP[i].y + dY); } double mx = 0, my = 0; for (i = 0; i < 3; i++) { mx += res[i].x; my += res[i].y; } mx /= 3; my /= 3; for (i = 0; i < 3; i++) res[i] = Point(res[i].x + (res[i].x - mx) * (1 - k) * r / 2, res[i].y + (res[i].y - my) * (1 - k) * r / 2); return res; } } setupT() { int dim = 20, x, y; List tri = List(dim * dim); for (x = 0; x < dim; x++) { for (y = 0; y < dim; y++) { var dx = rng.nextDouble() - 0.5, dy = rng.nextDouble() - 0.5, off; if (x % 2 == 0) off = 0; else off = 0.5; tri[x * dim + y] = Point((x + dx) / (dim - 1) - 0.5, (y + off + dy) / (dim - 1) - 0.5); } } triangles = List(); var r = rng.nextInt(5), c; if (r == 0) c = Colors.lightBlue; if (r == 1) c = Colors.yellow; if (r == 2) c = Colors.lightGreen; if (r == 3) c = Colors.red; if (r == 4) c = Colors.pink; for (x = 0; x < dim - 1; x++) { for (y = 0; y < dim - 1; y++) { int off = x * dim; T(tri[y + off], tri[y + 1 + off], tri[y + off + dim], c); T(tri[y + off + dim], tri[y + 1 + off], tri[y + 1 + off + dim], c); } } }