mirror of
https://github.com/Iconica-Development/flutter_profile.git
synced 2025-05-19 01:03:45 +02:00
Merge pull request #28 from Iconica-Development/feat/change_password_current_password
feat: Add password field for authentication
This commit is contained in:
commit
802265e43c
13 changed files with 194 additions and 140 deletions
|
@ -1,3 +1,7 @@
|
|||
## 1.3.0
|
||||
|
||||
- Field has been added so the user can provide it's current password for reauthentication.
|
||||
|
||||
## 1.2.1
|
||||
|
||||
- Added Iconica CI and Iconica Linter
|
||||
|
|
|
@ -52,13 +52,12 @@ class _ProfileExampleState extends State<ProfileExample> {
|
|||
var width = MediaQuery.of(context).size.width;
|
||||
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: ProfilePage(
|
||||
body: ProfilePage(
|
||||
changePasswordConfig:
|
||||
const ChangePasswordConfig(enablePasswordChange: true),
|
||||
wrapViewOptions: WrapViewOptions(
|
||||
direction: Axis.horizontal,
|
||||
spacing: 16,
|
||||
spacing: 8,
|
||||
direction: Axis.vertical,
|
||||
),
|
||||
bottomActionText: 'Log out',
|
||||
itemBuilderOptions: ItemBuilderOptions(
|
||||
|
@ -83,19 +82,26 @@ class _ProfileExampleState extends State<ProfileExample> {
|
|||
return null;
|
||||
},
|
||||
},
|
||||
|
||||
inputDecorationField: {
|
||||
'current_password': const InputDecoration(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: 60,
|
||||
maxWidth: 250,
|
||||
),
|
||||
hintText: 'Current password'),
|
||||
'password_1': const InputDecoration(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: 60,
|
||||
maxWidth: 200,
|
||||
),
|
||||
maxWidth: 250,
|
||||
),
|
||||
hintText: 'New password'),
|
||||
'password_2': const InputDecoration(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: 60,
|
||||
maxWidth: 200,
|
||||
),
|
||||
maxWidth: 250,
|
||||
),
|
||||
hintText: 'Repeat new password'),
|
||||
},
|
||||
),
|
||||
user: _user,
|
||||
|
@ -110,7 +116,6 @@ class _ProfileExampleState extends State<ProfileExample> {
|
|||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,10 @@ class ExampleProfileService extends ProfileService {
|
|||
}
|
||||
|
||||
@override
|
||||
FutureOr<void> changePassword(String password) {
|
||||
debugPrint(password);
|
||||
FutureOr<bool> changePassword(
|
||||
BuildContext context, String currentPassword, String newPassword) {
|
||||
debugPrint('$currentPassword -> $newPassword');
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,11 +122,11 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: "2.7.0"
|
||||
resolved-ref: "8eb1d80a9f08be0b7fe70078104d1a8851083edd"
|
||||
ref: "3.1.0"
|
||||
resolved-ref: "5fca291c5e79c9ad6dad500e4ea5d9b628ee0f5d"
|
||||
url: "https://github.com/Iconica-Development/flutter_input_library"
|
||||
source: git
|
||||
version: "2.7.0"
|
||||
version: "3.1.0"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
|
|
@ -15,6 +15,9 @@ import 'package:flutter_profile/src/models/user.dart';
|
|||
/// EditProfile is called when a user changes and submits a standard textfields.
|
||||
///
|
||||
/// UploadImage is called when te user presses the avatar.
|
||||
///
|
||||
/// changePassword is called when the user requests to change his password.
|
||||
/// Return true to clear the inputfields.
|
||||
abstract class ProfileService {
|
||||
const ProfileService();
|
||||
|
||||
|
@ -28,5 +31,9 @@ abstract class ProfileService {
|
|||
required Function(bool isUploading) onUploadStateChanged,
|
||||
});
|
||||
|
||||
FutureOr<void> changePassword(String password);
|
||||
FutureOr<bool> changePassword(
|
||||
BuildContext context,
|
||||
String currentPassword,
|
||||
String newPassword,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ class ItemBuilder {
|
|||
|
||||
Widget buildPassword(
|
||||
String key,
|
||||
TextEditingController controller,
|
||||
Function(String?) onChanged,
|
||||
String? Function(String?) validator,
|
||||
) {
|
||||
|
@ -61,6 +62,7 @@ class ItemBuilder {
|
|||
options.inputDecorationField?[key] ?? options.inputDecoration;
|
||||
|
||||
return FlutterFormInputPassword(
|
||||
controller: controller,
|
||||
style: options.inputTextStyle,
|
||||
decoration: inputDecoration,
|
||||
onChanged: onChanged,
|
||||
|
|
|
@ -32,6 +32,11 @@ class _ChangePasswordState extends State<ChangePassword> {
|
|||
|
||||
late final Widget? changePasswordChild;
|
||||
|
||||
late var currentPasswordController = TextEditingController();
|
||||
late var password1Controller = TextEditingController();
|
||||
late var password2Controller = TextEditingController();
|
||||
|
||||
String? currentPassword;
|
||||
String? password1;
|
||||
String? password2;
|
||||
|
||||
|
@ -51,8 +56,21 @@ class _ChangePasswordState extends State<ChangePassword> {
|
|||
runSpacing: widget.wrapViewOptions?.runSpacing ?? 0,
|
||||
clipBehavior: widget.wrapViewOptions?.clipBehavior ?? Clip.none,
|
||||
children: [
|
||||
builder.buildPassword(
|
||||
'current_password',
|
||||
currentPasswordController,
|
||||
(value) => currentPassword = value,
|
||||
(value) {
|
||||
if (currentPassword?.isEmpty ?? true) {
|
||||
return config.fieldRequiredErrorText;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
),
|
||||
builder.buildPassword(
|
||||
'password_1',
|
||||
password1Controller,
|
||||
(value) => password1 = value,
|
||||
(value) {
|
||||
if (password1?.isEmpty ?? true) {
|
||||
|
@ -64,6 +82,7 @@ class _ChangePasswordState extends State<ChangePassword> {
|
|||
),
|
||||
builder.buildPassword(
|
||||
'password_2',
|
||||
password2Controller,
|
||||
(value) => password2 = value,
|
||||
(value) {
|
||||
if (password2?.isEmpty ?? true) {
|
||||
|
@ -90,14 +109,26 @@ class _ChangePasswordState extends State<ChangePassword> {
|
|||
var theme = Theme.of(context);
|
||||
|
||||
Future<void> onTapSave() async {
|
||||
if ((_formKey.currentState?.validate() ?? false) && password2 != null) {
|
||||
widget.service.changePassword(password2!);
|
||||
if ((_formKey.currentState?.validate() ?? false) &&
|
||||
currentPassword != null &&
|
||||
password2 != null) {
|
||||
if (await widget.service
|
||||
.changePassword(context, currentPassword!, password2!)) {
|
||||
currentPasswordController.clear();
|
||||
password1Controller.clear();
|
||||
password2Controller.clear();
|
||||
|
||||
currentPassword = null;
|
||||
password1 = null;
|
||||
password2 = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: widget.style.betweenDefaultItemPadding * 2.5,
|
||||
|
@ -127,7 +158,6 @@ class _ChangePasswordState extends State<ChangePassword> {
|
|||
onPressed: onTapSave,
|
||||
child: const Text('Save password'),
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
@ -74,9 +74,9 @@ class _ProfileWrapperState extends State<ProfileWrapper> {
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_formKey = widget.formKey ?? GlobalKey<FormState>();
|
||||
|
||||
super.initState();
|
||||
if (widget.showDefaultItems) {
|
||||
if (widget.itemBuilder == null) {
|
||||
var builder = ItemBuilder(
|
||||
|
@ -196,11 +196,12 @@ class _ProfileWrapperState extends State<ProfileWrapper> {
|
|||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Material(
|
||||
color: Colors.transparent,
|
||||
child: SingleChildScrollView(
|
||||
child: SizedBox(
|
||||
Widget build(BuildContext context) => Stack(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: widget.style.pagePadding,
|
||||
child: Column(
|
||||
|
@ -209,7 +210,7 @@ class _ProfileWrapperState extends State<ProfileWrapper> {
|
|||
InkWell(
|
||||
onTap: () async => widget.service.uploadImage(
|
||||
context,
|
||||
onUploadStateChanged: (bool isUploading) => setState(
|
||||
onUploadStateChanged: (isUploading) => setState(
|
||||
() {
|
||||
_isUploadingImage = isUploading;
|
||||
},
|
||||
|
@ -236,10 +237,14 @@ class _ProfileWrapperState extends State<ProfileWrapper> {
|
|||
height: widget.style.betweenDefaultItemPadding,
|
||||
),
|
||||
],
|
||||
if (widget.showItems) Form(key: _formKey, child: child),
|
||||
if (widget.showItems) ...[
|
||||
Form(
|
||||
key: _formKey,
|
||||
child: child,
|
||||
),
|
||||
],
|
||||
if (widget.changePasswordConfig.enablePasswordChange) ...[
|
||||
Expanded(
|
||||
child: ChangePassword(
|
||||
ChangePassword(
|
||||
config: widget.changePasswordConfig,
|
||||
service: widget.service,
|
||||
wrapViewOptions: widget.wrapViewOptions,
|
||||
|
@ -248,19 +253,19 @@ class _ProfileWrapperState extends State<ProfileWrapper> {
|
|||
itemBuilderOptions: widget.itemBuilderOptions,
|
||||
style: widget.style,
|
||||
),
|
||||
),
|
||||
],
|
||||
if (widget.bottomActionText != null) ...[
|
||||
SizedBox(
|
||||
height: widget.style.betweenDefaultItemPadding,
|
||||
),
|
||||
if (!widget.changePasswordConfig.enablePasswordChange) ...[
|
||||
const Spacer(),
|
||||
],
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
widget.service.pageBottomAction();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.bottomActionText != null &&
|
||||
MediaQuery.of(Scaffold.of(context).context).viewInsets.bottom ==
|
||||
0.0) ...[
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: InkWell(
|
||||
onTap: () async => await widget.service.pageBottomAction(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
|
@ -269,21 +274,14 @@ class _ProfileWrapperState extends State<ProfileWrapper> {
|
|||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
if (widget.bottomActionText == null &&
|
||||
!widget.changePasswordConfig.enablePasswordChange) ...[
|
||||
const Spacer(),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
/// This calls onSaved on all the fiels which check if they have a new value
|
||||
void submitAllChangedFields() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
if (_formKey.currentState?.validate() ?? false) {
|
||||
_formKey.currentState!.save();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: flutter_profile
|
||||
description: Flutter profile package
|
||||
version: 1.2.1
|
||||
version: 1.3.0
|
||||
repository: https://github.com/Iconica-Development/flutter_profile
|
||||
|
||||
publish_to: none
|
||||
|
@ -15,7 +15,7 @@ dependencies:
|
|||
flutter_input_library:
|
||||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_input_library
|
||||
ref: 2.7.0
|
||||
ref: 3.1.0
|
||||
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
|
|
@ -28,5 +28,10 @@ class TestProfileService extends ProfileService {
|
|||
}) {}
|
||||
|
||||
@override
|
||||
FutureOr<void> changePassword(String password) {}
|
||||
FutureOr<bool> changePassword(
|
||||
BuildContext context,
|
||||
String currentPassword,
|
||||
String newPassword,
|
||||
) =>
|
||||
true;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue