@@ -2,120 +2,130 @@ import 'package:flutter/material.dart';
22import 'package:touchtorch/fallback_screen.dart' ;
33import 'package:torch_light/torch_light.dart' ;
44
5- class Home extends StatelessWidget {
5+ class Home extends StatefulWidget {
66 const Home ({super .key});
77
8+ @override
9+ State <Home > createState () => _HomeState ();
10+ }
11+
12+ class _HomeState extends State <Home > {
13+ bool _isTorchOn = false ;
14+
815 @override
916 Widget build (BuildContext context) {
1017 return Scaffold (
1118 body: FutureBuilder <bool >(
1219 future: _isTorchAvailable (context),
13- builder: (BuildContext context, AsyncSnapshot < bool > snapshot) {
20+ builder: (context, snapshot) {
1421 if (snapshot.hasData && snapshot.data! ) {
15- return Center (
16- child: Container (
17- color: Colors .blueGrey.shade900,
18- height: MediaQuery .of (context).size.height,
19- width: MediaQuery .of (context).size.width,
20- child: Stack (alignment: Alignment .center, children: [
21- Positioned (
22- top: 35 ,
23- child: Row (
24- crossAxisAlignment: CrossAxisAlignment .start,
25- mainAxisAlignment: MainAxisAlignment .center,
22+ return GestureDetector (
23+ onTapDown: (_) => _toggleTorch (true ),
24+ onTapUp: (_) => _toggleTorch (false ),
25+ onPanEnd: (_) => _toggleTorch (false ),
26+ onPanCancel: () => _toggleTorch (false ),
27+ child: AnimatedContainer (
28+ duration: const Duration (milliseconds: 150 ),
29+ color: _isTorchOn
30+ ? Colors .yellow.shade700
31+ : Colors .blueGrey.shade900,
32+ width: double .infinity,
33+ height: double .infinity,
34+ child: SafeArea (
35+ child: Padding (
36+ padding: const EdgeInsets .all (20.0 ),
37+ child: Stack (
38+ alignment: Alignment .center,
2639 children: [
27- Text (
28- "Flashlight stays on as long\n as you touch the screen" ,
29- textAlign: TextAlign .end,
30- style: TextStyle (color: Colors .blueGrey.shade500)),
31- ]),
32- ),
33- Image .asset (
34- "assets/images/morse_alphabet.png" ,
35- cacheWidth:
36- (MediaQuery .of (context).devicePixelRatio * 200 ).round (),
37- color: Colors .blueGrey.shade800,
38- ),
39- Positioned (
40- right: 15 ,
41- bottom: 15 ,
42- child: Image .asset (
43- "assets/images/click_icon.png" ,
44- cacheWidth:
45- (MediaQuery .of (context).devicePixelRatio * 35 ).round (),
46- width: 35 ,
47- color: Colors .white,
40+ Column (
41+ crossAxisAlignment: CrossAxisAlignment .center,
42+ children: [
43+ const SizedBox (height: 20 ),
44+ Text (
45+ "Touch and hold the screen\n to turn on the flashlight" ,
46+ textAlign: TextAlign .center,
47+ style: TextStyle (
48+ fontSize: 18 ,
49+ color: Colors .blueGrey.shade200,
50+ fontWeight: FontWeight .w500,
51+ ),
52+ ),
53+ const SizedBox (height: 20 ),
54+ Image .asset (
55+ "assets/images/morse_alphabet.png" ,
56+ cacheWidth: (MediaQuery .of (context)
57+ .devicePixelRatio *
58+ 200 )
59+ .round (),
60+ color: Colors .blueGrey.shade800,
61+ ),
62+ ],
63+ ),
64+ Positioned (
65+ right: 15 ,
66+ bottom: 15 ,
67+ child: Image .asset (
68+ "assets/images/click_icon.png" ,
69+ cacheWidth: (MediaQuery .of (context)
70+ .devicePixelRatio *
71+ 35 )
72+ .round (),
73+ width: 35 ,
74+ color: Colors .white,
75+ ),
76+ ),
77+ ],
78+ ),
4879 ),
4980 ),
50- GestureDetector (
51- onTapDown: (details) async {
52- _enableTorch (context);
53- },
54- onTapUp: (details) async {
55- _disableTorch (context);
56- },
57- onPanEnd: (details) async {
58- _disableTorch (context);
59- },
60- onPanCancel: () async {
61- _disableTorch (context);
62- },
63- ),
64- ]),
65- ));
81+ ),
82+ );
6683 } else if (snapshot.hasData) {
6784 return const FallbackScreen (
68- fallbackText: "Device's torch is not available." );
85+ fallbackText: "Device's torch is not available." ,
86+ );
6987 } else {
7088 return const FallbackScreen (
71- fallbackText:
72- "An unhandled situation occurred\n\n Please, contact the developer of this app!" );
89+ fallbackText:
90+ "An unexpected error occurred.\n Please contact the developer." ,
91+ );
7392 }
7493 },
7594 ),
7695 );
7796 }
7897
7998 Future <bool > _isTorchAvailable (BuildContext context) async {
80- final scaffoldMessenger = ScaffoldMessenger .of (context);
81-
8299 try {
83100 return await TorchLight .isTorchAvailable ();
84- } on Exception catch (_) {
85- scaffoldMessenger.showSnackBar (
86- const SnackBar (
87- content: Text ('Could not check if the device has an available torch' ),
88- ),
89- );
101+ } catch (_) {
102+ _showError ("Could not check if the device has a torch." );
90103 rethrow ;
91104 }
92105 }
93106
94- Future <void > _enableTorch (BuildContext context) async {
95- final scaffoldMessenger = ScaffoldMessenger .of (context);
107+ Future <void > _toggleTorch (bool turnOn) async {
108+ if (_isTorchOn == turnOn) return ;
109+
110+ setState (() {
111+ _isTorchOn = turnOn;
112+ });
96113
97114 try {
98- await TorchLight . enableTorch ();
99- } on Exception catch (_) {
100- scaffoldMessenger. showSnackBar (
101- const SnackBar (
102- content : Text ( 'Could not enable torch' ),
103- ),
104- );
115+ if (turnOn) {
116+ await TorchLight . enableTorch ();
117+ } else {
118+ await TorchLight . disableTorch ();
119+ }
120+ } catch (_) {
121+ _showError ( "Failed to ${ turnOn ? "enable" : "disable" } torch." );
105122 }
106123 }
107124
108- Future <void > _disableTorch (BuildContext context) async {
109- final scaffoldMessenger = ScaffoldMessenger .of (context);
110-
111- try {
112- await TorchLight .disableTorch ();
113- } on Exception catch (_) {
114- scaffoldMessenger.showSnackBar (
115- const SnackBar (
116- content: Text ('Could not disable torch' ),
117- ),
118- );
119- }
125+ void _showError (String message) {
126+ ScaffoldMessenger .of (context).showSnackBar (
127+ SnackBar (content: Text (message)),
128+ );
120129 }
121130}
131+
0 commit comments