Add LoginScreen and change HomeScreen to WelcomeScreen.

This commit is contained in:
vincemarcus
2022-04-30 13:16:32 +07:00
parent 21d6f2d1c2
commit 2c34b2964d
18 changed files with 482 additions and 133 deletions

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -1,4 +1,5 @@
import 'package:duolingo/views/login_screen/login_screen.dart';
import 'package:duolingo/views/welcome_screen/welcome_screen.dart';
import 'package:flutter/material.dart';
class MyDuolingo extends StatelessWidget {
@@ -6,10 +7,15 @@ class MyDuolingo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const MaterialApp(
return MaterialApp(
routes: {
'/': (context) => const WelcomeScreen(),
// When navigating to the "/second" route, build the SecondScreen widget.
'/login': (context) => const LoginScreen(),
},
debugShowCheckedModeBanner: false,
title: 'Duolingo',
home: LoginScreen(),
// home: const WelcomeScreen(),
);
}
}

View File

@@ -1,18 +0,0 @@
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return HomeScreenState();
}
}
class HomeScreenState extends State<HomeScreen>{
@override
Widget build(BuildContext context) {
// TODO: implement build
throw UnimplementedError();
}
}

View File

@@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
class LoginAppBar extends StatelessWidget implements PreferredSizeWidget {
const LoginAppBar({Key? key}) : super(key: key);
@override
// TODO: implement preferredSize
Size get preferredSize => const Size.fromHeight(100);
@override
Widget build(BuildContext context) {
return AppBar(
shadowColor: Colors.transparent,
backgroundColor: Colors.transparent,
title: Text(
'Enter your details',
style:
TextStyle(color: Colors.grey.shade600, fontWeight: FontWeight.bold),
),
centerTitle: true,
leading: IconButton(
icon: Icon(
Icons.close,
color: Colors.grey.shade600,
),
onPressed: () {
Navigator.pop(context);
},
),
);
}
}

View File

@@ -1,75 +0,0 @@
import 'package:flutter/material.dart';
class BottomButtons extends StatefulWidget {
const BottomButtons({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return BottomButtonsState();
}
}
class BottomButtonsState extends State<BottomButtons> {
@override
Widget build(BuildContext context) {
return Center(
child: Align(
alignment: Alignment.bottomCenter,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: double.infinity,
height: 50,
margin: const EdgeInsets.only(left: 10, right: 10, bottom: 10),
padding: const EdgeInsets.only(bottom: 2),
child: ElevatedButton(
onPressed: () {},
child: const Text(
'CHOOSE A LANGUAGE',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
style: ElevatedButton.styleFrom(
primary: const Color(0xFF7ac70c),
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
),
Container(
width: double.infinity,
height: 50,
margin: const EdgeInsets.only(left: 10, right: 10, bottom: 10),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(12)),
border: Border.all(width: 3, color: const Color(0xFF7ac70c)),
),
child: ElevatedButton(
onPressed: () {},
child: const Text(
'I ALREADY HAVE AN ACCOUNT',
style: TextStyle(
color: Colors.green,
fontSize: 18,
fontWeight: FontWeight.bold),
),
style: ElevatedButton.styleFrom(
primary: Colors.white,
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
),
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,51 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class FacebookButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Expanded(
flex: 1,
child: Container(
width: double.infinity,
height: 50,
margin: const EdgeInsets.only(left: 10, right: 10, bottom: 10),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(12)),
border: Border.all(width: 3, color: Colors.grey.shade400),
),
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/login');
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => const LoginScreen()),
// );
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/icons/facebook-icon.png',
height: 25,
),
Text(
' FACEBOOK',
style: TextStyle(
color: Colors.indigo.shade900,
fontSize: 16,
fontWeight: FontWeight.bold),
),
],
),
style: ElevatedButton.styleFrom(
primary: Colors.white,
elevation: 5,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
),
),
);
}
}

View File

@@ -0,0 +1,13 @@
import 'package:flutter/cupertino.dart';
class ForgotPassword extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const Text(
'FORGOT PASSWORD',
style: TextStyle(
fontSize: 17, fontWeight: FontWeight.bold, color: Color(0xFF1CB0F6)),
);
}
}

View File

@@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
class GoogleButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Expanded(
flex: 1,
child: Container(
width: double.infinity,
height: 50,
margin: const EdgeInsets.only(left: 10, right: 10, bottom: 10),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(12)),
border: Border.all(width: 3, color: Colors.grey.shade400)),
child: ElevatedButton(
onPressed: () {},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/icons/google-icon.png',
height: 20,
),
Text(
' GOOGLE',
style: TextStyle(
color: Colors.grey.shade900,
fontSize: 16,
fontWeight: FontWeight.bold),
),
],
),
style: ElevatedButton.styleFrom(
primary: Colors.white,
elevation: 5,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
),
),
);
}
}

View File

@@ -0,0 +1,75 @@
import 'package:flutter/material.dart';
class InputField extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return InputFieldState();
}
}
class InputFieldState extends State<InputField> {
final emailController = TextEditingController();
final passwordController = TextEditingController();
bool isObscure = true;
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(10),
child: Column(
children: [
accountField(),
passwordField(),
],
),
);
}
accountField() {
return TextFormField(
controller: emailController,
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.only(
topRight: Radius.circular(15.0),
topLeft: Radius.circular(15.0),
),
),
hintText: 'Username or email',
// errorText: snapshot.hasError ? snapshot.error as String : null
),
// validator: validateEmail,
onChanged: (value) {
// bloc.changeEmail(value);
},
);
}
passwordField() {
return TextFormField(
controller: passwordController,
obscureText: isObscure,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(
isObscure ? Icons.visibility : Icons.visibility_off,
color: const Color(0xFF1CB0F6),
),
onPressed: () {
isObscure = !isObscure;
setState(() {});
},
),
border: const OutlineInputBorder(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(15.0),
bottomLeft: Radius.circular(15.0),
),
),
hintText: 'Password',
),
// validator: validatePassword,
);
}
}

View File

@@ -0,0 +1,41 @@
import 'package:flutter/material.dart';
class LoginButton extends StatefulWidget {
const LoginButton({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return LoginButtonState();
}
}
class LoginButtonState extends State<LoginButton> {
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: 50,
margin: const EdgeInsets.only(left: 10, right: 10, bottom: 10),
padding: const EdgeInsets.only(bottom: 2),
child: ElevatedButton(
onPressed: () {},
child: const Text(
'SIGN IN',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
style: ElevatedButton.styleFrom(
primary: const Color(0xFF1CB0F6),
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
);
}
}

View File

@@ -0,0 +1,27 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class PolicyText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: TextStyle(
fontSize: 14.0,
height: 1.5,
color: Colors.grey.shade600,
),
children: const <TextSpan>[
TextSpan(text: 'By signing in to Duolingo, you agree to our '),
TextSpan(
text: 'Terms', style: TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: ' and '),
TextSpan(
text: '\nPrivacy Policy',
style: TextStyle(fontWeight: FontWeight.bold)),
],
),
);
}
}

View File

@@ -1,9 +1,13 @@
import 'dart:ui';
import 'package:duolingo/views/login_screen/components/facebook_button.dart';
import 'package:duolingo/views/login_screen/components/forgot_password.dart';
import 'package:duolingo/views/login_screen/components/google_button.dart';
import 'package:duolingo/views/login_screen/components/login_button.dart';
import 'package:duolingo/views/login_screen/components/policy_text.dart';
import 'package:flutter/material.dart';
import 'components/bottom_buttons.dart';
import 'components/center_display.dart';
import 'components/app_bar.dart';
import 'components/input_field.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({Key? key}) : super(key: key);
@@ -15,15 +19,50 @@ class LoginScreen extends StatefulWidget {
}
class LoginScreenState extends State<LoginScreen> {
final formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: const [
Expanded(child: CenterDisplay()),
BottomButtons(),
],
appBar: const LoginAppBar(),
body: Container(
margin: const EdgeInsets.only(bottom: 10),
child: Column(
children: [
Form(
key: formKey,
child: InputField(),
),
Container(margin: const EdgeInsets.only(top: 10)),
const LoginButton(),
Container(margin: const EdgeInsets.only(top: 10)),
ForgotPassword(),
bottomDisplay(),
],
),
),
);
}
bottomDisplay() {
return Expanded(
child: Align(
alignment: FractionalOffset.bottomCenter,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
// mainAxisSize: MainAxisSize.max,
children: [
FacebookButton(),
GoogleButton(),
],
),
PolicyText(),
],
),
),
);
}
}

View File

@@ -0,0 +1,86 @@
import 'package:flutter/material.dart';
class BottomButtons extends StatelessWidget {
const BottomButtons({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: Align(
alignment: Alignment.bottomCenter,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
chooseLanguageButton(),
logInButton(context),
],
),
),
);
}
logInButton(BuildContext context) {
return Container(
width: double.infinity,
height: 50,
margin: const EdgeInsets.only(left: 10, right: 10, bottom: 10),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(12)),
border: Border.all(width: 3, color: const Color(0xFF7ac70c)),
),
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/login');
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => const LoginScreen()),
// );
},
child: const Text(
'I ALREADY HAVE AN ACCOUNT',
style: TextStyle(
color: Colors.green, fontSize: 18, fontWeight: FontWeight.bold),
),
style: ElevatedButton.styleFrom(
primary: Colors.white,
elevation: 5,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
),
);
}
chooseLanguageButton() {
return Container(
width: double.infinity,
height: 50,
margin: const EdgeInsets.only(left: 10, right: 10, bottom: 10),
padding: const EdgeInsets.only(bottom: 2),
child: ElevatedButton(
onPressed: () {},
child: const Text(
'CHOOSE A LANGUAGE',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
style: ElevatedButton.styleFrom(
primary: const Color(0xFF7ac70c),
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
);
}
}
//
// class BottomButtonsState extends State<BottomButtons> {
// @override
// Widget build(BuildContext context) {
// return
// }

View File

@@ -9,7 +9,7 @@ class CenterDisplay extends StatelessWidget {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image.asset('assets/images/duo-wave.png', width: 200, height: 170),
Image.asset('assets/images/duo-wave.png', height: 150),
Container(padding: const EdgeInsets.all(5)),
Image.asset('assets/images/duolingo-logo.png',
width: 125, height: 40),

View File

@@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
import 'components/bottom_buttons.dart';
import 'components/center_display.dart';
class WelcomeScreen extends StatefulWidget {
const WelcomeScreen({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return WelcomeScreenState();
}
}
class WelcomeScreenState extends State<WelcomeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: const [
Expanded(child: CenterDisplay()),
BottomButtons(),
],
),
);
}
}

View File

@@ -60,6 +60,7 @@ flutter:
# To add assets to your application, add an assets section, like this:
assets:
- assets/images/
- assets/icons/
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg

View File

@@ -1,30 +1,30 @@
// This is a basic Flutter widget test.
// // This is a basic Flutter widget test.
// //
// // To perform an interaction with a widget in your test, use the WidgetTester
// // utility that Flutter provides. For example, you can send tap and scroll
// // gestures. You can also use WidgetTester to find child widgets in the widget
// // tree, read text, and verify that the values of widget properties are correct.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:duolingo/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
// import 'package:flutter/material.dart';
// import 'package:flutter_test/flutter_test.dart';
//
// import 'package:duolingo/main.dart';
//
// void main() {
// testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// // Build our app and trigger a frame.
// await tester.pumpWidget(const MyApp());
//
// // Verify that our counter starts at 0.
// expect(find.text('0'), findsOneWidget);
// expect(find.text('1'), findsNothing);
//
// // Tap the '+' icon and trigger a frame.
// await tester.tap(find.byIcon(Icons.add));
// await tester.pump();
//
// // Verify that our counter has incremented.
// expect(find.text('0'), findsNothing);
// expect(find.text('1'), findsOneWidget);
// });
// }