Skip to content

Commit b4d4b88

Browse files
author
Pedro Massango
committed
added code of World Clock challenge
1 parent 78a8781 commit b4d4b88

File tree

2 files changed

+361
-0
lines changed

2 files changed

+361
-0
lines changed

lib/world_clock.dart

Lines changed: 361 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,361 @@
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+
}

screenshots/world_clock.png

174 KB
Loading

0 commit comments

Comments
 (0)