Created with <3 with dartpad.dev.
Last active
September 23, 2023 14:57
-
-
Save plotsklapps/2a4366f027a4193fd9893fc1de372220 to your computer and use it in GitHub Desktop.
Flutter Fullstack #2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'package:flutter/material.dart'; | |
| import 'package:google_fonts/google_fonts.dart'; | |
| void main() { | |
| runApp(const FlutterBankApp()); | |
| } | |
| class FlutterBankApp extends StatelessWidget { | |
| const FlutterBankApp({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return MaterialApp( | |
| debugShowCheckedModeBanner: false, | |
| theme: ThemeData( | |
| textTheme: GoogleFonts.poppinsTextTheme( | |
| Theme.of(context).textTheme, | |
| ), | |
| ), | |
| home: const FlutterBankSplash(), | |
| ); | |
| } | |
| } | |
| class FlutterBankSplash extends StatelessWidget { | |
| const FlutterBankSplash({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| // Future.delayed takes two parameters: a Duration object with is seconds | |
| // property set to 2, and a callback. When the 2 seconds have ellapsed, it will call the callback. The callback has inside a trigger to perform a navigation | |
| Future.delayed(const Duration(seconds: 2), () { | |
| Navigator.push( | |
| context, | |
| MaterialPageRoute(builder: (context) { | |
| return const FlutterBankLogin(); | |
| }), | |
| ); | |
| }); | |
| return const Scaffold( | |
| backgroundColor: Utils.mainThemeColor, | |
| body: Stack( | |
| children: [ | |
| Center( | |
| child: Icon( | |
| Icons.savings, | |
| size: 60.0, | |
| color: Colors.white, | |
| ), | |
| ), | |
| Center( | |
| child: SizedBox( | |
| height: 100.0, | |
| width: 100.0, | |
| child: CircularProgressIndicator( | |
| strokeWidth: 8.0, | |
| valueColor: AlwaysStoppedAnimation<Color>(Colors.white), | |
| ), | |
| )), | |
| ], | |
| ), | |
| ); | |
| } | |
| } | |
| class FlutterBankLogin extends StatefulWidget { | |
| const FlutterBankLogin({super.key}); | |
| @override | |
| State<FlutterBankLogin> createState() { | |
| return _FlutterBankLoginState(); | |
| } | |
| } | |
| class _FlutterBankLoginState extends State<FlutterBankLogin> { | |
| // At the top of the FlutterBankLoginState class, add two TextEditingController instances, one for each of our fields. The TextEditingController allows us to controller the actions on a TextField widget, get notifications on text field updates, set initial values, get its provided input, etc. | |
| final TextEditingController emailController = TextEditingController(); | |
| final TextEditingController passwordController = TextEditingController(); | |
| @override | |
| Widget build(BuildContext context) { | |
| return SafeArea( | |
| child: Scaffold( | |
| body: Container( | |
| padding: const EdgeInsets.all(30.0), | |
| child: Column( | |
| crossAxisAlignment: CrossAxisAlignment.start, | |
| children: [ | |
| Container( | |
| width: 80.0, | |
| height: 80.0, | |
| decoration: BoxDecoration( | |
| border: Border.all( | |
| color: Utils.mainThemeColor, | |
| width: 7.0, | |
| ), | |
| borderRadius: BorderRadius.circular(100.0), | |
| ), | |
| child: const Icon( | |
| Icons.savings, | |
| size: 45.0, | |
| color: Utils.mainThemeColor, | |
| ), | |
| ), | |
| const SizedBox(height: 30.0), | |
| const Text( | |
| 'Welcome to', | |
| style: TextStyle( | |
| color: Colors.grey, | |
| fontSize: 15.0, | |
| ), | |
| ), | |
| const Text( | |
| 'Flutter\nSavings Bank', | |
| style: TextStyle( | |
| color: Utils.mainThemeColor, | |
| fontSize: 30.0, | |
| ), | |
| ), | |
| Expanded( | |
| child: Center( | |
| child: Column( | |
| mainAxisAlignment: MainAxisAlignment.center, | |
| crossAxisAlignment: CrossAxisAlignment.stretch, | |
| children: [ | |
| const Text( | |
| 'Sign Into Your Bank Account', | |
| style: TextStyle( | |
| color: Colors.grey, | |
| fontSize: 12.0, | |
| ), | |
| textAlign: TextAlign.center, | |
| ), | |
| const SizedBox(height: 12.0), | |
| Container( | |
| padding: const EdgeInsets.all(5.0), | |
| decoration: BoxDecoration( | |
| color: Colors.grey.withOpacity(0.2), | |
| borderRadius: BorderRadius.circular(50.0), | |
| ), | |
| child: TextField( | |
| onChanged: (text) { | |
| setState(() { | |
| // We use setState to update the state of the widget. In this case, we are updating the state of the emailController | |
| emailController.text = text; | |
| }); | |
| }, | |
| controller: emailController, | |
| decoration: const InputDecoration( | |
| prefixIcon: Icon( | |
| Icons.email, | |
| color: Utils.mainThemeColor, | |
| ), | |
| border: InputBorder.none, | |
| focusedBorder: InputBorder.none, | |
| enabledBorder: InputBorder.none, | |
| errorBorder: InputBorder.none, | |
| disabledBorder: InputBorder.none, | |
| contentPadding: | |
| EdgeInsets.fromLTRB(15.0, 11.0, 15.0, 11.0), | |
| hintText: 'Email Address', | |
| ), | |
| style: const TextStyle( | |
| fontSize: 16.0, | |
| ), | |
| ), | |
| ), | |
| const SizedBox(height: 16.0), | |
| Container( | |
| padding: const EdgeInsets.all(5.0), | |
| decoration: BoxDecoration( | |
| color: Colors.grey.withOpacity(0.2), | |
| borderRadius: BorderRadius.circular(50.0), | |
| ), | |
| child: TextField( | |
| onChanged: (text) { | |
| setState(() { | |
| // We use setState to update the state of the widget. In this case, we are updating the state of the passwordController | |
| passwordController.text = text; | |
| }); | |
| }, | |
| controller: passwordController, | |
| obscureText: true, | |
| decoration: const InputDecoration( | |
| prefixIcon: Icon( | |
| Icons.lock, | |
| color: Utils.mainThemeColor, | |
| ), | |
| border: InputBorder.none, | |
| focusedBorder: InputBorder.none, | |
| enabledBorder: InputBorder.none, | |
| errorBorder: InputBorder.none, | |
| disabledBorder: InputBorder.none, | |
| contentPadding: | |
| EdgeInsets.fromLTRB(20.0, 11.0, 15.0, 11.0), | |
| hintText: 'Password', | |
| ), | |
| style: const TextStyle( | |
| fontSize: 16.0, | |
| ), | |
| ), | |
| ), | |
| ], | |
| ), | |
| ), | |
| ), | |
| FlutterBankMainButton( | |
| label: 'Sign In', | |
| enabled: true, | |
| onTap: () {}, | |
| ), | |
| const SizedBox(height: 16.0), | |
| FlutterBankMainButton( | |
| label: 'Register', | |
| icon: Icons.account_circle, | |
| enabled: true, | |
| onTap: () {}, | |
| backgroundColor: Utils.mainThemeColor.withOpacity(0.1), | |
| iconColor: Utils.mainThemeColor, | |
| labelColor: Utils.mainThemeColor, | |
| ), | |
| ], | |
| ), | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| // Widgets | |
| class FlutterBankMainButton extends StatelessWidget { | |
| final Function? onTap; | |
| final String? label; | |
| final bool? enabled; | |
| final IconData? icon; | |
| final Color? backgroundColor; | |
| final Color? iconColor; | |
| final Color? labelColor; | |
| const FlutterBankMainButton({ | |
| super.key, | |
| this.onTap, | |
| this.label, | |
| this.enabled = true, | |
| this.icon, | |
| this.backgroundColor = Utils.mainThemeColor, | |
| this.iconColor = Colors.white, | |
| this.labelColor = Colors.white, | |
| }); | |
| @override | |
| Widget build(BuildContext context) { | |
| return Column( | |
| crossAxisAlignment: CrossAxisAlignment.stretch, | |
| children: [ | |
| ClipRRect( | |
| borderRadius: BorderRadius.circular(50.0), | |
| child: Material( | |
| color: | |
| enabled! ? backgroundColor : backgroundColor!.withOpacity(0.5), | |
| child: InkWell( | |
| // Assign a callback that wraps the trigger this widget's onTap event only if the enabled property is true, null otherwise. | |
| onTap: enabled! | |
| ? () { | |
| onTap!(); | |
| } | |
| : null, | |
| highlightColor: Colors.white.withOpacity(0.2), | |
| splashColor: Colors.white.withOpacity(0.1), | |
| child: Container( | |
| padding: const EdgeInsets.all(15.0), | |
| decoration: BoxDecoration( | |
| borderRadius: BorderRadius.circular(50.0), | |
| ), | |
| child: Row( | |
| mainAxisAlignment: MainAxisAlignment.center, | |
| crossAxisAlignment: CrossAxisAlignment.center, | |
| children: [ | |
| Visibility( | |
| visible: icon != null, | |
| child: Container( | |
| margin: const EdgeInsets.only(right: 20.0), | |
| child: Icon( | |
| icon, | |
| color: iconColor, | |
| size: 20.0, | |
| ), | |
| )), | |
| Text( | |
| label!, | |
| textAlign: TextAlign.center, | |
| style: TextStyle( | |
| color: labelColor, | |
| fontWeight: FontWeight.bold, | |
| ), | |
| ), | |
| ], | |
| ), | |
| ), | |
| ), | |
| ), | |
| ), | |
| ], | |
| ); | |
| } | |
| } | |
| class Utils { | |
| static const Color mainThemeColor = Color(0xFF8700C3); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment