1+ import 'dart:async' ;
2+ import 'dart:ui' as ui;
3+
4+ import 'package:brain_fusion/brain_fusion.dart' ;
5+ import 'package:flutter/foundation.dart' ;
6+ import 'package:flutter/material.dart' ;
7+ import 'package:fluttertoast/fluttertoast.dart' ;
8+ import 'package:image_gallery_saver/image_gallery_saver.dart' ;
9+ import 'package:lottie/lottie.dart' ;
10+ import 'package:text_to_image_gen/Pages/about_page.dart' ;
11+ import 'package:url_launcher/url_launcher.dart' ;
12+ import 'package:flutter/rendering.dart' ;
13+
14+ class HomePage extends StatefulWidget {
15+ const HomePage ({Key ? key}) : super (key: key);
16+
17+ @override
18+ State <HomePage > createState () => _HomePageState ();
19+ }
20+
21+ class _HomePageState extends State <HomePage > {
22+ final TextEditingController _queryController = TextEditingController ();
23+
24+ final AI _ai = AI ();
25+
26+ Future <Uint8List > _generate (String query) async {
27+ Uint8List image = await _ai.runAI (query, AIStyle .render3D);
28+ return image;
29+ }
30+
31+ final GlobalKey _globalKey = GlobalKey ();
32+
33+ bool _isDownloading = false ;
34+ bool _isDownloadInitiated = false ;
35+ bool run = false ;
36+ String query = "" ;
37+
38+ @override
39+ void dispose () {
40+ _queryController.dispose ();
41+ super .dispose ();
42+ }
43+
44+ var scaffoldKey = GlobalKey <ScaffoldState >();
45+ @override
46+ Widget build (BuildContext context) {
47+ return Scaffold (
48+ key: scaffoldKey,
49+ backgroundColor: Colors .deepPurple.shade50,
50+ appBar: AppBar (
51+ iconTheme: IconThemeData (color: Colors .deepPurple.shade400),
52+ backgroundColor: Colors .transparent,
53+ title: RichText (
54+ text: TextSpan (
55+ text: 'Tex' ,
56+ style: TextStyle (color: Colors .amber.shade900, fontWeight: FontWeight .w500, fontSize: 18 ),
57+ children: [
58+ TextSpan (
59+ text: 'Fusion' ,
60+ style: TextStyle (color: Colors .deepPurple.shade500, fontWeight: FontWeight .w500, fontSize: 18 ),
61+ )
62+ ]
63+ ),
64+ ),
65+ elevation: 0 ,
66+ centerTitle: true ,
67+ leading: InkWell (
68+ onTap: (){
69+ scaffoldKey.currentState? .openDrawer ();
70+ },
71+ child: Padding (
72+ padding: const EdgeInsets .all (8.0 ),
73+ child: Lottie .asset (
74+ 'assets/animations/me.json' ,
75+ repeat: true ,
76+ reverse: true ,
77+ animate: true ,
78+ ),
79+ ),
80+ ),
81+ actions: [
82+ InkWell (
83+ onTap: (){
84+ Navigator .push (context, MaterialPageRoute (builder: (context) => const AboutPage ()));
85+ },
86+ child: Padding (
87+ padding: const EdgeInsets .all (12 ),
88+ child: Lottie .asset (
89+ 'assets/animations/set.json' ,
90+ repeat: true ,
91+ reverse: true ,
92+ animate: true ,
93+ ),
94+ ),
95+ ),
96+ ],
97+ ),
98+ drawer: Drawer (
99+ child: Container (
100+ color: Colors .deepPurple.shade50,
101+ child: Column (
102+ children: [
103+ Container (
104+ color: Colors .deepPurple.shade50,
105+ child: DrawerHeader (
106+ child: Center (
107+ child: Text (
108+ "TexFusion AI App" ,
109+ style: TextStyle (
110+ fontSize: 18 , color: Colors .deepPurple.shade400),
111+ ),
112+ ),
113+ ),
114+ ),
115+ ListTile (
116+ leading: const Icon (
117+ Icons .source_rounded,
118+ color: Colors .black54,
119+ ),
120+ title: Text (
121+ "Source Code" ,
122+ style: TextStyle (
123+ fontSize: 16 , color: Colors .deepPurple.shade400),
124+ ),
125+ onTap: () async {
126+ final Uri url = Uri .parse (
127+ 'https://github.com/VikramadityaDev/text_to_image_gen/' );
128+ if (! await launchUrl (url,
129+ mode: LaunchMode .externalApplication)) {
130+ throw Exception ('Could not launch $url ' );
131+ }
132+ },
133+ ),
134+ ListTile (
135+ leading: const Icon (
136+ Icons .update,
137+ color: Colors .black54,
138+ ),
139+ title: Text (
140+ "Check for update" ,
141+ style: TextStyle (
142+ fontSize: 16 , color: Colors .deepPurple.shade400),
143+ ),
144+ onTap: () async {
145+ final Uri url =
146+ Uri .parse ('https://telegram.me/vikimediaofficial/' );
147+ if (! await launchUrl (url,
148+ mode: LaunchMode .externalApplication)) {
149+ throw Exception ('Could not launch $url ' );
150+ }
151+ },
152+ ),
153+ Expanded (
154+ child: Padding (
155+ padding: const EdgeInsets .all (10 ),
156+ child: Align (
157+ alignment: Alignment .bottomCenter,
158+ child: Text (
159+ 'v1.0.2' ,
160+ style: TextStyle (
161+ fontSize: 16 ,
162+ color: Colors .deepPurple.shade400,
163+ fontWeight: FontWeight .w500),
164+ ),
165+ ),
166+ ),
167+ ),
168+ ],
169+ ),
170+ ),
171+ ),
172+ body: SingleChildScrollView (
173+ physics: const BouncingScrollPhysics (),
174+ child: Column (
175+ mainAxisAlignment: MainAxisAlignment .center,
176+ crossAxisAlignment: CrossAxisAlignment .center,
177+ children: < Widget > [
178+ const SizedBox (
179+ height: 10 ,
180+ ),
181+ Padding (
182+ padding: const EdgeInsets .all (6.0 ),
183+ child: TextField (
184+ keyboardType: TextInputType .multiline,
185+ minLines: 1 ,
186+ maxLines: 10 ,
187+ controller: _queryController,
188+ decoration: InputDecoration (
189+ hintText: 'Enter your imagination...' ,
190+ enabledBorder: OutlineInputBorder (
191+ borderRadius: BorderRadius .circular (8 ),
192+ borderSide: BorderSide (
193+ width: 1.5 ,
194+ color: Colors .deepPurple.shade400,
195+ ),
196+ ),
197+ focusedBorder: OutlineInputBorder (
198+ borderRadius: BorderRadius .circular (8 ),
199+ borderSide: BorderSide (
200+ width: 1.5 ,
201+ color: Colors .deepPurple.shade400,
202+ ),
203+ ),
204+ ),
205+ ),
206+ ),
207+ Padding (
208+ padding: const EdgeInsets .all (5 ),
209+ child: SizedBox (
210+ height: MediaQuery .of (context).size.height / 1.9 ,
211+ width: MediaQuery .of (context).size.width,
212+ child: run
213+ ? FutureBuilder <Uint8List >(
214+ future: _generate (_queryController.text),
215+ builder: (context, snapshot) {
216+ if (snapshot.connectionState ==
217+ ConnectionState .waiting) {
218+ return Padding (
219+ padding: const EdgeInsets .all (120.0 ),
220+ child: Lottie .asset (
221+ 'assets/animations/loading.json' ,
222+ repeat: true ,
223+ reverse: true ,
224+ animate: true ,
225+ ),
226+ );
227+ } else if (snapshot.hasError) {
228+ return const Center (
229+ child: Text (
230+ 'Something went wrong. Please Re-generate.' ,
231+ ),
232+ );
233+ } else if (snapshot.hasData) {
234+ return RepaintBoundary (
235+ key: _globalKey,
236+ child: InkWell (
237+ onTap: () {
238+ _saveScreen ();
239+ },
240+ child: Image .memory (snapshot.data! ),
241+ ),
242+ );
243+ } else {
244+ return Container ();
245+ }
246+ },
247+ )
248+ : const Center (
249+ child: Text (
250+ 'See Magic Here 🪄' ,
251+ style: TextStyle (
252+ fontWeight: FontWeight .w500,
253+ fontSize: 16 ,
254+ ),
255+ ),
256+ ),
257+ ),
258+ ),
259+ SizedBox (
260+ height: MediaQuery .of (context).size.width / 5.5 ,
261+ ),
262+ const Text (
263+ 'Click the image to save in Gallery.' ,
264+ softWrap: true ,
265+ style: TextStyle (fontSize: 15 , fontWeight: FontWeight .w500),
266+ ),
267+ const SizedBox (
268+ height: 5 ,
269+ ),
270+ const SizedBox (
271+ height: 15 ,
272+ ),
273+ Padding (
274+ padding: const EdgeInsets .only (left: 80 , right: 80 ),
275+ child: ElevatedButton (
276+ onPressed: () {
277+ String newQuery = _queryController.text;
278+ if (newQuery.isNotEmpty) {
279+ setState (() {
280+ query = newQuery;
281+ run = true ;
282+ });
283+ } else {
284+ if (newQuery.isEmpty) {
285+ Fluttertoast .showToast (
286+ msg: 'Query is empty !!' ,
287+ gravity: ToastGravity .BOTTOM ,
288+ backgroundColor: Colors .red,
289+ );
290+ print ('Query is empty !!' );
291+ }
292+ }
293+ },
294+ style: ButtonStyle (
295+ padding: MaterialStateProperty .all (
296+ const EdgeInsets .all (0.0 ),
297+ ),
298+ elevation: MaterialStateProperty .all (0 ),
299+ shape: MaterialStateProperty .all (
300+ RoundedRectangleBorder (
301+ borderRadius: BorderRadius .circular (5.0 ),
302+ ),
303+ ),
304+ ),
305+ child: Ink (
306+ decoration: BoxDecoration (
307+ gradient: LinearGradient (
308+ colors: [
309+ Colors .deepPurple.shade400,
310+ Colors .deepPurpleAccent.shade200,
311+ ],
312+ ),
313+ borderRadius: const BorderRadius .all (
314+ Radius .circular (5.0 ),
315+ ),
316+ ),
317+ child: Container (
318+ constraints: const BoxConstraints (
319+ minWidth: 88.0 ,
320+ minHeight: 45.0 ,
321+ ),
322+ alignment: Alignment .center,
323+ child: const Text (
324+ 'Generate' ,
325+ textAlign: TextAlign .center,
326+ style: TextStyle (fontSize: 18 ),
327+ ),
328+ ),
329+ ),
330+ ),
331+ ),
332+ ],
333+ ),
334+ ),
335+ bottomNavigationBar: const Padding (
336+ padding: EdgeInsets .only (bottom: 8 ),
337+ child: Text (
338+ "Made With Love ❤️ VikiMedia" ,
339+ textAlign: TextAlign .center,
340+ style: TextStyle (fontSize: 12 ),
341+ ),
342+ ),
343+ );
344+ }
345+ _saveScreen () async {
346+ if (_isDownloading) {
347+ // Do nothing if a download is already in progress.
348+ Fluttertoast .showToast (
349+ msg: 'Download in progress. Please wait.' ,
350+ gravity: ToastGravity .BOTTOM ,
351+ backgroundColor: Colors .amber,
352+ timeInSecForIosWeb: 3 ,
353+ );
354+ return ;
355+ }
356+ if (_isDownloadInitiated) {
357+ return ;
358+ }
359+ _isDownloadInitiated = true ;
360+ Fluttertoast .showToast (
361+ msg: 'Download Started !' ,
362+ gravity: ToastGravity .BOTTOM ,
363+ timeInSecForIosWeb: 3 ,
364+ );
365+ _isDownloading = true ;
366+ RenderRepaintBoundary boundary =
367+ _globalKey.currentContext! .findRenderObject () as RenderRepaintBoundary ;
368+ ui.Image image = await boundary.toImage (pixelRatio: 12 );
369+ ByteData ? byteData = await (image.toByteData (format: ui.ImageByteFormat .png));
370+ if (byteData != null ) {
371+ final result = await ImageGallerySaver .saveImage (
372+ byteData.buffer.asUint8List (),
373+ quality: 100 ,
374+ );
375+ print (result);
376+ Fluttertoast .showToast (
377+ msg: 'Image Successfully Saved To Gallery.' ,
378+ gravity: ToastGravity .BOTTOM ,
379+ backgroundColor: Colors .green,
380+ timeInSecForIosWeb: 3 ,
381+ );
382+ }
383+ _isDownloadInitiated = false ;
384+ _isDownloading = false ;
385+ }
386+ }
0 commit comments