Skip to content

Commit

Permalink
[#6] Create LoginScreen with LoginForm
Browse files Browse the repository at this point in the history
  • Loading branch information
Thieurom committed Aug 7, 2023
1 parent 047f556 commit d25e885
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 99 deletions.
20 changes: 0 additions & 20 deletions integration_test/my_home_page_test.dart

This file was deleted.

84 changes: 5 additions & 79 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,47 +1,32 @@
import 'package:flutter/material.dart';
import 'package:flutter_config/flutter_config.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:survey_flutter/gen/assets.gen.dart';
import 'package:go_router/go_router.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:survey_flutter/screens/login/login_screen.dart';
import 'package:survey_flutter/theme/app_theme.dart';

void main() async {
WidgetsFlutterBinding.ensureInitialized();
await FlutterConfig.loadEnvVariables();
runApp(MyApp());
}

const routePathRootScreen = '/';
const routePathSecondScreen = 'second';

class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);

final GoRouter _router = GoRouter(
routes: <GoRoute>[
GoRoute(
path: routePathRootScreen,
builder: (BuildContext context, GoRouterState state) =>
const HomeScreen(),
routes: [
GoRoute(
path: routePathSecondScreen,
builder: (BuildContext context, GoRouterState state) =>
const SecondScreen(),
),
],
path: routePathLoginScreen,
builder: (context, state) => const LoginScreen(),
),
],
);

@override
Widget build(BuildContext context) {
return MaterialApp.router(
theme: ThemeData(
primarySwatch: Colors.blue,
brightness: Brightness.light,
fontFamily: Assets.fonts.neuzeit,
),
theme: AppTheme.light,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
routeInformationProvider: _router.routeInformationProvider,
Expand All @@ -50,62 +35,3 @@ class MyApp extends StatelessWidget {
);
}
}

class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: FutureBuilder<PackageInfo>(
future: PackageInfo.fromPlatform(),
builder: (context, snapshot) {
return snapshot.hasData
? Text(snapshot.data?.appName ?? "")
: const SizedBox.shrink();
}),
),
body: Center(
child: Column(
children: [
const SizedBox(height: 24),
FractionallySizedBox(
widthFactor: 0.5,
child: Image.asset(
Assets.images.nimbleLogo.path,
fit: BoxFit.fitWidth,
),
),
const SizedBox(height: 24),
Text(AppLocalizations.of(context)!.hello),
Text(
FlutterConfig.get('SECRET'),
style: const TextStyle(color: Colors.black, fontSize: 24),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () => context.go('/$routePathSecondScreen'),
child: const Text("Navigate to Second Screen"),
),
],
),
),
);
}
}

class SecondScreen extends StatelessWidget {
const SecondScreen({
Key? key,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Second Screen"),
),
);
}
}
71 changes: 71 additions & 0 deletions lib/screens/login/login_form.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import 'package:flutter/material.dart';
import 'package:survey_flutter/screens/widgets/primary_button_style.dart';
import 'package:survey_flutter/screens/widgets/primary_text_field_decoration.dart';

class LoginForm extends StatefulWidget {
const LoginForm({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _LoginFormState();
}

class _LoginFormState extends State<LoginForm> {
final _formKey = GlobalKey<FormState>();

TextTheme get _textTheme => Theme.of(context).textTheme;

TextFormField get _emailTextField => TextFormField(
keyboardType: TextInputType.emailAddress,
autocorrect: false,
decoration: PrimaryTextFieldDecoration(
hintText: 'Email',
hintTextStyle: _textTheme.bodyMedium,
),
style: _textTheme.bodyMedium,
);

TextFormField get _passwordTextField => TextFormField(
autocorrect: false,
obscureText: true,
decoration: PrimaryTextFieldDecoration(
hintText: 'Password',
hintTextStyle: _textTheme.bodyMedium,
),
style: _textTheme.bodyMedium,
);

ElevatedButton get _loginButton => ElevatedButton(
style: PrimaryButtonStyle(hintTextStyle: _textTheme.labelMedium),
onPressed: _submit,
child: const Text('Log in'),
);

void _submit() {
// TODO: Integrate with API
}

@override
Widget build(BuildContext context) {
const fieldSpacing = 20.0;
return Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_emailTextField,
const SizedBox(
height: fieldSpacing,
),
_passwordTextField,
const SizedBox(
height: fieldSpacing,
),
SizedBox(
height: 56,
width: double.infinity,
child: _loginButton,
),
],
),
);
}
}
48 changes: 48 additions & 0 deletions lib/screens/login/login_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import 'package:flutter/material.dart';
import 'package:survey_flutter/screens/login/login_form.dart';

// TODO: Update to `/login`
const routePathLoginScreen = '/';

class LoginScreen extends StatefulWidget {
const LoginScreen({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _LoginSrceenState();
}

class _LoginSrceenState extends State<LoginScreen> {
late final _gradientOverlay = Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.black.withOpacity(0.2),
Colors.black,
],
),
),
);

late final _loginForm = const Padding(
padding: EdgeInsets.symmetric(
horizontal: 24.0,
),
child: LoginForm(),
);

@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
alignment: AlignmentDirectional.center,
fit: StackFit.expand,
children: [
_gradientOverlay,
_loginForm,
],
),
);
}
}
18 changes: 18 additions & 0 deletions lib/screens/widgets/primary_button_style.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'package:flutter/material.dart';

class PrimaryButtonStyle extends ButtonStyle {
PrimaryButtonStyle({required TextStyle? hintTextStyle})
: super(
textStyle: MaterialStateProperty.all(
hintTextStyle,
),
backgroundColor: MaterialStateProperty.all(Colors.white),
foregroundColor: MaterialStateProperty.all(Colors.black),
overlayColor: MaterialStateProperty.all(Colors.black12),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
),
);
}
17 changes: 17 additions & 0 deletions lib/screens/widgets/primary_text_field_decoration.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:flutter/material.dart';

class PrimaryTextFieldDecoration extends InputDecoration {
PrimaryTextFieldDecoration(
{required String hintText, required TextStyle? hintTextStyle})
: super(
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(12.0),
),
fillColor: Colors.white24,
filled: true,
hintText: hintText,
hintStyle: hintTextStyle?.copyWith(color: Colors.white24),
errorMaxLines: 2,
);
}
20 changes: 20 additions & 0 deletions lib/theme/app_theme.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:flutter/material.dart';
import 'package:survey_flutter/gen/fonts.gen.dart';

class AppTheme {
static ThemeData get light => ThemeData(
fontFamily: FontFamily.neuzeit,
textTheme: const TextTheme(
bodyMedium: TextStyle(
color: Colors.white,
fontSize: 17,
fontWeight: FontWeight.normal,
),
labelMedium: TextStyle(
color: Colors.white,
fontSize: 17,
fontWeight: FontWeight.bold,
),
),
);
}

0 comments on commit d25e885

Please sign in to comment.