1
+ import 'dart:async' ;
2
+ import 'dart:math' ;
3
+
4
+ import 'package:flutter/cupertino.dart' ;
5
+ import 'package:flutter/material.dart' ;
6
+ import 'package:flutter/services.dart' ;
7
+
8
+ class HomePage extends StatefulWidget {
9
+ @override
10
+ _HomePageState createState () => _HomePageState ();
11
+ }
12
+
13
+ //final Color bgColor = Color(0xFF142550);
14
+ final Color bgColor = Colors .white;
15
+
16
+ class _HomePageState extends State <HomePage > {
17
+
18
+ Stopwatch stopwatch;
19
+ double hour = 0 ;
20
+ double minute = 0 ;
21
+ double seconds = 0 ;
22
+ DateTime now = DateTime .now ();
23
+
24
+ int currentIndex = 0 ;
25
+ final items = ["Clock" , "List" , "Settings" ];
26
+ final icons = [Icons .alarm, Icons .list, Icons .settings];
27
+
28
+ double _secondPercent () => stopwatch.elapsed.inSeconds / 60 ;
29
+ double _minutesPercent () => minute / 60 ;
30
+ double _hoursPercent () => hour / 24 ;
31
+
32
+ @override
33
+ void initState () {
34
+ super .initState ();
35
+
36
+ SystemChrome .setEnabledSystemUIOverlays ([]);
37
+
38
+ stopwatch = Stopwatch ();
39
+ hour = now.hour.toDouble ();
40
+ minute = now.minute.toDouble ();
41
+
42
+ Timer .periodic (Duration .zero, (t){
43
+ if (stopwatch.elapsed.inSeconds == 60 ){
44
+ minute = DateTime .now ().minute.toDouble ();
45
+ stopwatch.reset ();
46
+ }else if (stopwatch.elapsed.inMinutes == 60 ){
47
+ hour = DateTime .now ().second.toDouble ();
48
+ stopwatch.reset ();
49
+ }
50
+
51
+ setState (() {});
52
+ });
53
+
54
+ stopwatch.start ();
55
+ }
56
+
57
+ Widget _addButton (){
58
+ return Container (
59
+ height: 50 ,
60
+ width: 50 ,
61
+ margin: EdgeInsets .only (left: 16 ),
62
+ decoration: BoxDecoration (
63
+ shape: BoxShape .circle,
64
+ color: Colors .redAccent,
65
+ boxShadow: [
66
+ BoxShadow (
67
+ color: Colors .redAccent.withOpacity (0.5 ),
68
+ blurRadius: 15 ,
69
+ spreadRadius: 2
70
+ )
71
+ ]
72
+ ),
73
+ child: Center (
74
+ child: Icon (Icons .add, color: Colors .white, size: 32 ,),
75
+ ),
76
+ );
77
+ }
78
+
79
+ Widget _editButton (){
80
+ return Container (
81
+ height: 50 ,
82
+ width: 50 ,
83
+ margin: EdgeInsets .only (left: 16 ),
84
+ decoration: BoxDecoration (
85
+ shape: BoxShape .circle,
86
+ color: Colors .white,
87
+ boxShadow: [
88
+ BoxShadow (
89
+ color: Colors .black12.withOpacity (0.05 ),
90
+ blurRadius: 10 ,
91
+ spreadRadius: 10
92
+ )
93
+ ]
94
+ ),
95
+ child: Center (
96
+ child: Icon (Icons .edit, color: Colors .redAccent, size: 32 ,),
97
+ ),
98
+ );
99
+ }
100
+
101
+ @override
102
+ void dispose () {
103
+ super .dispose ();
104
+
105
+ stopwatch? .stop ();
106
+ }
107
+
108
+ @override
109
+ Widget build (BuildContext context) {
110
+ return MaterialApp (
111
+ home: Scaffold (
112
+ backgroundColor: bgColor,
113
+ body: Container (
114
+ child: Stack (
115
+ children: < Widget > [
116
+
117
+ Positioned (
118
+ top: 40 ,
119
+ child: _addButton (),
120
+ ),
121
+
122
+ Positioned (
123
+ top: 40 ,
124
+ right: 16 ,
125
+ child: _editButton (),
126
+ ),
127
+
128
+ Column (
129
+ children: < Widget > [
130
+ Spacer (),
131
+ Spacer (),
132
+ Center (
133
+ child: Container (
134
+ height: 310 ,
135
+ width: 310 ,
136
+ decoration: BoxDecoration (
137
+ color: Colors .white,
138
+ shape: BoxShape .circle,
139
+ boxShadow: [
140
+ BoxShadow (
141
+ color: Colors .black26.withOpacity (0.04 ),
142
+ blurRadius: 10 ,
143
+ offset: Offset (- 12 , 0 ),
144
+ spreadRadius: 2
145
+ ),
146
+ BoxShadow (
147
+ color: Colors .black26.withOpacity (0.04 ),
148
+ blurRadius: 10 ,
149
+ offset: Offset (12 , 0 ),
150
+ spreadRadius: 5
151
+ ),
152
+ ]
153
+ ),
154
+ child: Padding (
155
+ padding: const EdgeInsets .all (8.0 ),
156
+ child: CustomPaint (
157
+ painter: LinesPainter (),
158
+ child: Container (
159
+ margin: const EdgeInsets .all (32.0 ),
160
+ decoration: BoxDecoration (
161
+ color: bgColor,
162
+ shape: BoxShape .circle,
163
+ boxShadow: [
164
+ BoxShadow (
165
+ color: Colors .black26.withOpacity (0.03 ),
166
+ blurRadius: 5 ,
167
+ spreadRadius: 8
168
+ ),
169
+ ]
170
+ ),
171
+ child: CustomPaint (
172
+ painter: TimeLinesPainter (
173
+ lineType: LineType .minute,
174
+ tick: _minutesPercent ()
175
+ ),
176
+ child: CustomPaint (
177
+ painter: TimeLinesPainter (
178
+ lineType: LineType .hour,
179
+ tick: _hoursPercent ()
180
+ ),
181
+ child: CustomPaint (
182
+ painter: TimeLinesPainter (
183
+ lineType: LineType .second,
184
+ tick: _secondPercent ()
185
+ )
186
+ ),
187
+ ),
188
+ ),
189
+ ),
190
+ ),
191
+ ),
192
+ ),
193
+ ),
194
+
195
+ SizedBox (height: 40 ,),
196
+ Text ("Luanda" , style: TextStyle (
197
+ color: Colors .redAccent,
198
+ fontSize: 32 ,
199
+ ),),
200
+ Text ("${hour .round ()}:${minute .round ()} ${TimeOfDay .fromDateTime (now ).period == DayPeriod .am ? 'AM' : 'PM' }" , style: TextStyle (
201
+ color: Colors .black,
202
+ fontSize: 50 ,
203
+ )),
204
+ Spacer ()
205
+ ],
206
+ ),
207
+
208
+ ],
209
+ ),
210
+ ),
211
+ bottomNavigationBar: Builder (
212
+ builder: (context){
213
+
214
+ return Container (
215
+ height: 70 ,
216
+ width: MediaQuery .of (context).size.width,
217
+ child: Row (
218
+ mainAxisAlignment: MainAxisAlignment .spaceAround,
219
+ children: items.map ((t){
220
+ return _getItem (t, items.indexOf (t));
221
+ }).toList (),
222
+ ),
223
+ );
224
+ },
225
+ ),
226
+ ),
227
+ );
228
+ }
229
+
230
+ Widget _getItem (String t, int index) {
231
+ final selected = index == currentIndex;
232
+ final color = selected ? Colors .black : Colors .grey;
233
+
234
+ return GestureDetector (
235
+ onTap: (){
236
+ setState (() {
237
+ currentIndex = index;
238
+ });
239
+ },
240
+ child: Column (
241
+ children: < Widget > [
242
+ Icon (icons.elementAt (index), size: selected ? 40 : 32 , color: color,),
243
+ Text (t, style: TextStyle (
244
+ color: color
245
+ ),)
246
+ ],
247
+ ),
248
+ );
249
+ }
250
+ }
251
+
252
+ enum LineType { hour, minute, second }
253
+
254
+
255
+ class LinesPainter extends CustomPainter {
256
+
257
+ final Paint linePainter;
258
+
259
+ final double lineHeight = 8 ;
260
+ final int maxLines = 30 ;
261
+
262
+ LinesPainter ():
263
+ linePainter = Paint ()
264
+ ..color = Colors .redAccent
265
+ ..style = PaintingStyle .stroke
266
+ ..strokeWidth = 1.5 ;
267
+
268
+ @override
269
+ void paint (Canvas canvas, Size size) {
270
+ canvas.translate (size.width/ 2 , size.height/ 2 );
271
+
272
+ canvas.save ();
273
+
274
+ final radius = size.width/ 2 ;
275
+
276
+ List .generate (maxLines, (i){
277
+
278
+ canvas.drawLine (
279
+ Offset (0 , radius),
280
+ Offset (0 , radius - 8 ),
281
+ linePainter
282
+ );
283
+
284
+ canvas.rotate (2 * pi / maxLines);
285
+ });
286
+
287
+ canvas.restore ();
288
+ }
289
+
290
+ @override
291
+ bool shouldRepaint (CustomPainter oldDelegate) => true ;
292
+ }
293
+
294
+ class TimeLinesPainter extends CustomPainter {
295
+
296
+ final Paint linePainter;
297
+ final Paint hourPainter;
298
+ final Paint minutePainter;
299
+ final double tick;
300
+ final LineType lineType;
301
+
302
+ TimeLinesPainter ({this .tick, this .lineType}):
303
+ linePainter = Paint ()
304
+ ..color = Colors .redAccent
305
+ ..style = PaintingStyle .stroke
306
+ ..strokeWidth = 2.5 ,
307
+ minutePainter = Paint ()
308
+ ..color = Colors .black38
309
+ ..style = PaintingStyle .stroke
310
+ ..strokeWidth = 3.5 ,
311
+ hourPainter = Paint ()
312
+ ..color = Colors .black
313
+ ..style = PaintingStyle .stroke
314
+ ..strokeWidth = 4.5 ;
315
+
316
+ @override
317
+ void paint (Canvas canvas, Size size) {
318
+
319
+ final radius = size.width / 2 ;
320
+
321
+ canvas.translate (radius, radius);
322
+
323
+ switch (lineType){
324
+ case LineType .hour:
325
+ canvas.rotate (24 * pi * tick );
326
+ canvas.drawPath (_hourPath (radius), hourPainter);
327
+ break ;
328
+ case LineType .minute:
329
+ canvas.rotate (2 * pi * tick );
330
+ canvas.drawPath (_minutePath (radius), minutePainter);
331
+ break ;
332
+ case LineType .second:
333
+ canvas.rotate (2 * pi * tick );
334
+ canvas.drawPath (_secondPath (radius), linePainter);
335
+ canvas.drawShadow (_secondPath (radius), Colors .black26, 100 , true );
336
+
337
+ break ;
338
+ }
339
+ }
340
+
341
+ Path _hourPath (double radius){
342
+ return Path ()
343
+ ..lineTo (0 , - ((radius/ 1.4 )/ 2 ))
344
+ ..close ();
345
+ }
346
+
347
+ Path _minutePath (double radius){
348
+ return Path ()
349
+ ..lineTo (0 , - (radius/ 1.4 ))
350
+ ..close ();
351
+ }
352
+
353
+ Path _secondPath (double radius){
354
+ return Path ()
355
+ ..lineTo (0 , - (radius+ 10 ))
356
+ ..close ();
357
+ }
358
+
359
+ @override
360
+ bool shouldRepaint (CustomPainter oldDelegate) => true ;
361
+ }
0 commit comments