Updated README, added GIF, added Github Actions, fixed overflow bug when opening a keyboard on mobile devices.

This commit is contained in:
Thomas Klein Langenhorst 2022-11-25 11:41:44 +01:00
parent 92a1af6d72
commit 503d826718
5 changed files with 198 additions and 143 deletions

32
.github/workflows/flutter.yml vendored Normal file
View file

@ -0,0 +1,32 @@
name: CI
on:
push:
branches: [ master ]
pull_request:
branches:
- master
- feature/*
- bugfix/*
- hotfix/*
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: |
~/.gradle/wrapper
/opt/hostedtoolcache/flutter
key: ${{ runner.OS }}-flutter-install-cache
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
- name: Flutter pub get
run: flutter pub get
- name: Flutter format
run: flutter format -o none --set-exit-if-changed .
- name: Flutter analyze
run: flutter analyze

View file

@ -1,21 +1,15 @@
[![pub package](https://img.shields.io/pub/v/flutter_introduction_widget.svg)](https://github.com/Iconica-Development) [![Build status](https://img.shields.io/github/workflow/status/Iconica-Development/flutter_login_widget/CI)](https://github.com/Iconica-Development/flutter_login_widget/actions/new) [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://github.com/tenhobi/effective_dart)
# Login Widget
A package facilitating the basic ingredients for creating functional yet customizable login pages
## Features
[Login GIF](flutter_login.gif)
Create a login screen for email and password logins
Create a forgot password screen by passing in the email from the login
## Setup
## Getting started
To use this package, add `flutter_login_widget` as a dependency in your pubspec.yaml file.
1. install the package by adding the following to your pubspec.yaml
```
flutter_login:
git:
url: https://github.com/Iconica-Development/flutter_login.git
ref: 1.0.0
```
## Usage
## How to use
```dart
final loginOptions = LoginOptions(
@ -93,3 +87,17 @@ class ForgotPasswordScreen extends StatelessWidget {
}
```
See the [Example Code](example/lib/main.dart) for an example on how to use this package.
## Issues
Please file any issues, bugs or feature request as an issue on our [GitHub](https://github.com/Iconica-Development/flutter_login_widget) page. Commercial support is available if you need help with integration with your app or services. You can contact us at [support@iconica.nl](mailto:support@iconica.nl).
## Want to contribute
If you would like to contribute to the plugin (e.g. by improving the documentation, solving a bug or adding a cool new feature), please carefully review our [contribution guide](./CONTRIBUTING.md) and send us your [pull request](https://github.com/Iconica-Development/flutter_login_widget/pulls).
## Author
This `flutter_login_widget` for Flutter is developed by [Iconica](https://iconica.nl). You can contact us at <support@iconica.nl>

View file

@ -9,8 +9,10 @@ final loginOptions = LoginOptions(
),
emailInputPrefix: const Icon(Icons.email),
passwordInputPrefix: const Icon(Icons.password),
title: const Text('Login'),
image: const FlutterLogo(),
title: const Text('Login Demo'),
image: const FlutterLogo(
size: 200,
),
requestForgotPasswordButtonBuilder: (
context,
onPressed,

BIN
flutter_login.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 MiB

View file

@ -65,140 +65,153 @@ class _EmailPasswordLoginFormState extends State<EmailPasswordLoginForm> {
Widget build(BuildContext context) {
var theme = Theme.of(context);
var options = widget.options;
return Column(
children: [
if (options.title != null) ...[
const SizedBox(
height: 60,
),
Align(
alignment: Alignment.topCenter,
child: _wrapWithDefaultStyle(
options.title,
theme.textTheme.headline6,
),
)
],
if (options.subtitle != null) ...[
const SizedBox(
height: 10,
),
Align(
alignment: Alignment.topCenter,
child: _wrapWithDefaultStyle(
options.subtitle,
theme.textTheme.subtitle1,
),
)
],
if (options.image != null) ...[
Padding(
padding: const EdgeInsets.all(16),
child: options.image,
),
],
Expanded(
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 300,
),
child: Form(
key: _formKey,
child: Align(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
options.emailInputContainerBuilder(
TextFormField(
onChanged: _updateCurrentEmail,
validator: widget.options.validations.validateEmail,
initialValue: options.initialEmail,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
decoration: options.decoration.copyWith(
hintText: options.emailHintText,
prefixIcon: options.emailInputPrefix,
label: options.emailLabel,
),
),
),
const SizedBox(height: 24),
options.passwordInputContainerBuilder(
TextFormField(
obscureText: _obscurePassword,
onChanged: _updateCurrentPassword,
validator: widget.options.validations.validatePassword,
initialValue: options.initialPassword,
keyboardType: TextInputType.visiblePassword,
textInputAction: TextInputAction.done,
onFieldSubmitted: (_) => _handleLogin(),
decoration: options.decoration.copyWith(
hintText: options.passwordHintText,
label: options.passwordLabel,
prefixIcon: options.passwordInputPrefix,
suffixIcon: IconButton(
onPressed: () {
setState(() {
_obscurePassword = !_obscurePassword;
});
},
icon: Icon(
_obscurePassword
? Icons.visibility
: Icons.visibility_off,
return CustomScrollView(
physics: MediaQuery.of(context).viewInsets.bottom == 0
? const NeverScrollableScrollPhysics()
: null,
slivers: [
SliverFillRemaining(
fillOverscroll: true,
hasScrollBody: false,
child: Column(
children: [
if (options.title != null) ...[
const SizedBox(
height: 60,
),
Align(
alignment: Alignment.topCenter,
child: _wrapWithDefaultStyle(
options.title,
theme.textTheme.headline6,
),
)
],
if (options.subtitle != null) ...[
const SizedBox(
height: 10,
),
Align(
alignment: Alignment.topCenter,
child: _wrapWithDefaultStyle(
options.subtitle,
theme.textTheme.subtitle1,
),
)
],
if (options.image != null) ...[
Padding(
padding: const EdgeInsets.all(16),
child: options.image,
),
],
Expanded(
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 300,
),
child: Form(
key: _formKey,
child: Align(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
options.emailInputContainerBuilder(
TextFormField(
onChanged: _updateCurrentEmail,
validator:
widget.options.validations.validateEmail,
initialValue: options.initialEmail,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
decoration: options.decoration.copyWith(
hintText: options.emailHintText,
prefixIcon: options.emailInputPrefix,
label: options.emailLabel,
),
),
),
),
const SizedBox(height: 24),
options.passwordInputContainerBuilder(
TextFormField(
obscureText: _obscurePassword,
onChanged: _updateCurrentPassword,
validator:
widget.options.validations.validatePassword,
initialValue: options.initialPassword,
keyboardType: TextInputType.visiblePassword,
textInputAction: TextInputAction.done,
onFieldSubmitted: (_) => _handleLogin(),
decoration: options.decoration.copyWith(
hintText: options.passwordHintText,
label: options.passwordLabel,
prefixIcon: options.passwordInputPrefix,
suffixIcon: IconButton(
onPressed: () {
setState(() {
_obscurePassword = !_obscurePassword;
});
},
icon: Icon(
_obscurePassword
? Icons.visibility
: Icons.visibility_off,
),
),
),
),
),
const SizedBox(height: 24),
if (widget.onForgotPassword != null) ...[
Align(
alignment: Alignment.topRight,
child: options.forgotPasswordButtonBuilder(
context,
() {
widget.onForgotPassword?.call(_currentEmail);
},
false,
() {},
options,
),
),
],
const SizedBox(height: 8),
AnimatedBuilder(
animation: _formValid,
builder: (context, _) {
return options.loginButtonBuilder(
context,
_handleLogin,
!_formValid.value,
() {
_formKey.currentState?.validate();
},
options,
);
},
),
if (widget.onRegister != null) ...[
options.registrationButtonBuilder(
context,
() {
widget.onRegister?.call(
_currentEmail,
_currentPassword,
);
},
false,
() {},
options,
),
]
],
),
),
const SizedBox(height: 24),
if (widget.onForgotPassword != null) ...[
Align(
alignment: Alignment.topRight,
child: options.forgotPasswordButtonBuilder(
context,
() {
widget.onForgotPassword?.call(_currentEmail);
},
false,
() {},
options,
),
),
],
const SizedBox(height: 8),
AnimatedBuilder(
animation: _formValid,
builder: (context, _) {
return options.loginButtonBuilder(
context,
_handleLogin,
!_formValid.value,
() {
_formKey.currentState?.validate();
},
options,
);
},
),
if (widget.onRegister != null) ...[
options.registrationButtonBuilder(
context,
() {
widget.onRegister?.call(
_currentEmail,
_currentPassword,
);
},
false,
() {},
options,
),
]
],
),
),
),
),
],
),
),
],