From e98fb1bdd8f3d5baa933bac25149dbdd0ffd5d5e Mon Sep 17 00:00:00 2001 From: Jacques Date: Thu, 1 Feb 2024 11:40:49 +0100 Subject: [PATCH] feat(password): Add the abiltity for the user to change its password --- CHANGELOG.md | 4 + example/lib/main.dart | 106 +++++++------- .../lib/utils/example_profile_service.dart | 5 + example/pubspec.lock | 83 +++++------ lib/flutter_profile.dart | 1 + lib/src/models/change_password_config.dart | 44 ++++++ lib/src/services/profile_service.dart | 2 + .../widgets/item_builder/item_builder.dart | 24 ++- .../profile/change_password_widget.dart | 135 +++++++++++++++++ lib/src/widgets/profile/profile_page.dart | 7 + lib/src/widgets/profile/profile_wrapper.dart | 137 +++++++++++------- pubspec.yaml | 14 +- test/test_classes/test_profile_service.dart | 3 + 13 files changed, 410 insertions(+), 155 deletions(-) create mode 100644 lib/src/models/change_password_config.dart create mode 100644 lib/src/widgets/profile/change_password_widget.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index a0f991f..4364257 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.2.0 + +- Added the posibilty to enable the user to change it's password. + ## 1.1.6 - Fixed avatar image zooming when constrained beyond it's size diff --git a/example/lib/main.dart b/example/lib/main.dart index 6a29d83..2ff9bc9 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -2,8 +2,6 @@ // // SPDX-License-Identifier: BSD-3-Clause -import 'dart:typed_data'; - import 'package:example/utils/example_profile_service.dart'; import 'package:flutter/material.dart'; @@ -44,9 +42,6 @@ class _ProfileExampleState extends State { _user = User( firstName: 'Firstname', lastName: 'Lastname', - image: Uint8List.fromList( - [], - ), profileData: profileData, ); } @@ -58,57 +53,62 @@ class _ProfileExampleState extends State { return Scaffold( body: Center( - child: Column( - children: [ - SizedBox( - height: 400, - width: 800, - child: ProfilePage( - showItems: false, - prioritizedItems: const ['remarks', 'about'], - wrapViewOptions: WrapViewOptions( - direction: Axis.horizontal, - spacing: 16, - ), - bottomActionText: 'Log out', - itemBuilderOptions: ItemBuilderOptions( - //no label for email - validators: { - 'first_name': (String? value) { - if (value == null || value.isEmpty) { - return 'Field empty'; - } - return null; - }, - 'last_name': (String? value) { - if (value == null || value.isEmpty) { - return 'Field empty'; - } - return null; - }, - 'email': (String? value) { - if (value == null || value.isEmpty) { - return 'Field empty'; - } - return null; - }, - }, - ), - user: _user, - service: ExampleProfileService(), - style: ProfileStyle( - avatarTextStyle: const TextStyle(fontSize: 20), - pagePadding: EdgeInsets.only( - top: 50, - bottom: 50, - left: width * 0.1, - right: width * 0.1, - ), + child: ProfilePage( + changePasswordConfig: + const ChangePasswordConfig(enablePasswordChange: true), + wrapViewOptions: WrapViewOptions( + direction: Axis.horizontal, + spacing: 16, + ), + bottomActionText: 'Log out', + itemBuilderOptions: ItemBuilderOptions( + //no label for email + validators: { + 'first_name': (String? value) { + if (value == null || value.isEmpty) { + return 'Field empty'; + } + return null; + }, + 'last_name': (String? value) { + if (value == null || value.isEmpty) { + return 'Field empty'; + } + return null; + }, + 'email': (String? value) { + if (value == null || value.isEmpty) { + return 'Field empty'; + } + return null; + }, + }, + inputDecorationField: { + 'password_1': const InputDecoration( + constraints: BoxConstraints( + maxHeight: 60, + maxWidth: 200, ), ), + 'password_2': const InputDecoration( + constraints: BoxConstraints( + maxHeight: 60, + maxWidth: 200, + ), + ), + }, + ), + user: _user, + service: ExampleProfileService(), + style: ProfileStyle( + avatarTextStyle: const TextStyle(fontSize: 20), + pagePadding: EdgeInsets.only( + top: 50, + bottom: 50, + left: width * 0.1, + right: width * 0.1, ), - const Text('test') - ], + ), ), ), ); diff --git a/example/lib/utils/example_profile_service.dart b/example/lib/utils/example_profile_service.dart index 9e505ce..d0ea9f7 100644 --- a/example/lib/utils/example_profile_service.dart +++ b/example/lib/utils/example_profile_service.dart @@ -28,4 +28,9 @@ class ExampleProfileService extends ProfileService { {required Function(bool isUploading) onUploadStateChanged}) { debugPrint('Updating avatar'); } + + @override + FutureOr changePassword(String password) { + debugPrint(password); + } } diff --git a/example/pubspec.lock b/example/pubspec.lock index e737ecf..b943d24 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -21,26 +21,26 @@ packages: dependency: transitive description: name: cached_network_image - sha256: be69fd8b429d48807102cee6ab4106a55e1f2f3e79a1b83abb8572bc06c64f26 + sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" url: "https://pub.dev" source: hosted - version: "3.2.2" + version: "3.3.1" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - sha256: bb2b8403b4ccdc60ef5f25c70dead1f3d32d24b9d6117cfc087f496b178594a7 + sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "4.0.0" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - sha256: b8eb814ebfcb4dea049680f8c1ffb2df399e4d03bf7a352c775e26fa06e02fa0 + sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.1" characters: dependency: transitive description: @@ -61,10 +61,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" crypto: dependency: transitive description: @@ -110,22 +110,23 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_blurhash: - dependency: transitive - description: - name: flutter_blurhash - sha256: "05001537bd3fac7644fa6558b09ec8c0a3f2eba78c0765f88912882b1331a5c6" - url: "https://pub.dev" - source: hosted - version: "0.7.0" flutter_cache_manager: dependency: transitive description: name: flutter_cache_manager - sha256: "32cd900555219333326a2d0653aaaf8671264c29befa65bbd9856d204a4c9fb3" + sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.3.1" + flutter_input_library: + dependency: transitive + description: + path: "." + ref: "2.7.0" + resolved-ref: "8eb1d80a9f08be0b7fe70078104d1a8851083edd" + url: "https://github.com/Iconica-Development/flutter_input_library" + source: git + version: "2.7.0" flutter_lints: dependency: "direct dev" description: @@ -140,7 +141,7 @@ packages: path: ".." relative: true source: path - version: "1.0.5" + version: "1.1.6" flutter_test: dependency: "direct dev" description: flutter @@ -162,6 +163,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + intl: + dependency: transitive + description: + name: intl + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + url: "https://pub.dev" + source: hosted + version: "0.18.1" lints: dependency: transitive description: @@ -190,18 +199,18 @@ packages: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" octo_image: dependency: transitive description: name: octo_image - sha256: "107f3ed1330006a3bea63615e81cf637433f5135a52466c7caa0e7152bca9143" + sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "2.0.0" path: dependency: transitive description: @@ -266,14 +275,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" - pedantic: - dependency: transitive - description: - name: pedantic - sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" - url: "https://pub.dev" - source: hosted - version: "1.11.1" platform: dependency: transitive description: @@ -339,18 +340,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -379,10 +380,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.6.1" typed_data: dependency: transitive description: @@ -411,10 +412,10 @@ packages: dependency: transitive description: name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "0.3.0" win32: dependency: transitive description: @@ -432,5 +433,5 @@ packages: source: hosted version: "0.2.0+2" sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" - flutter: ">=3.3.0" + dart: ">=3.2.0-194.0.dev <4.0.0" + flutter: ">=3.10.0" diff --git a/lib/flutter_profile.dart b/lib/flutter_profile.dart index da72eb5..106dc42 100644 --- a/lib/flutter_profile.dart +++ b/lib/flutter_profile.dart @@ -11,4 +11,5 @@ export 'src/widgets/avatar/avatar.dart'; export 'src/services/profile_service.dart'; export 'src/widgets/item_builder/item_builder.dart'; export 'src/models/user.dart'; +export 'src/models/change_password_config.dart'; export 'src/widgets/item_builder/item_builder_options.dart'; diff --git a/lib/src/models/change_password_config.dart b/lib/src/models/change_password_config.dart new file mode 100644 index 0000000..6816698 --- /dev/null +++ b/lib/src/models/change_password_config.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; + +/// Configuration to enable to user to change his password in the profilescreen. +class ChangePasswordConfig { + const ChangePasswordConfig({ + required this.enablePasswordChange, + this.title = 'Change password', + this.titleStyle, + this.underTitle = + 'You van make the password more secure using upper and lower case ' + 'letter, numbers and special characters.', + this.underTitleStyle, + this.saveButtonBuilder, + this.fieldRequiredErrorText = 'Field required', + this.notEqualErrorText = 'Password have to be equal', + }); + + /// Enables the textfields for the user to provide a new password. + final bool enablePasswordChange; + + /// Text for the title above the textfields. + final String title; + + /// Textstyle of the title. + final TextStyle? titleStyle; + + /// Text for the undertitle just above the textfields. + final String underTitle; + + /// Textstyle for the undertitle + final TextStyle? underTitleStyle; + + /// Ability to override the standard 'save password' button. + final Widget Function( + BuildContext context, + void Function() onTap, + )? saveButtonBuilder; + + /// Error text to be shown when either of the textfields is empty. + final String fieldRequiredErrorText; + + /// Error text to be shown when the second password isn't equal to the first password. + final String notEqualErrorText; +} diff --git a/lib/src/services/profile_service.dart b/lib/src/services/profile_service.dart index ed95f4e..b3726d4 100644 --- a/lib/src/services/profile_service.dart +++ b/lib/src/services/profile_service.dart @@ -24,4 +24,6 @@ abstract class ProfileService { BuildContext context, { required Function(bool isUploading) onUploadStateChanged, }); + + FutureOr changePassword(String password); } diff --git a/lib/src/widgets/item_builder/item_builder.dart b/lib/src/widgets/item_builder/item_builder.dart index bad0bb1..d9c4f92 100644 --- a/lib/src/widgets/item_builder/item_builder.dart +++ b/lib/src/widgets/item_builder/item_builder.dart @@ -3,6 +3,7 @@ // SPDX-License-Identifier: BSD-3-Clause import 'package:flutter/material.dart'; +import 'package:flutter_input_library/flutter_input_library.dart'; import 'package:flutter_profile/src/widgets/item_builder/item_builder_options.dart'; /// ItemBuilder is used to set the standard textfield for each undefined users data item. @@ -22,10 +23,9 @@ class ItemBuilder { text: '${value ?? ''}', ); - late InputDecoration inputDecoration; - - inputDecoration = + var inputDecoration = options.inputDecorationField?[key] ?? options.inputDecoration; + var formFieldKey = GlobalKey(); return TextFormField( style: options.inputTextStyle, @@ -47,4 +47,22 @@ class ItemBuilder { } return widget; } + + Widget buildPassword( + String key, + Function(String?) onChanged, + String? Function(String?) validator, + ) { + var inputDecoration = + options.inputDecorationField?[key] ?? options.inputDecoration; + + return FlutterFormInputPassword( + style: options.inputTextStyle, + decoration: inputDecoration, + onChanged: onChanged, + enabled: !options.readOnly, + validator: (value) => + validator(value) ?? options.validators?[key]?.call(value), + ); + } } diff --git a/lib/src/widgets/profile/change_password_widget.dart b/lib/src/widgets/profile/change_password_widget.dart new file mode 100644 index 0000000..71459f8 --- /dev/null +++ b/lib/src/widgets/profile/change_password_widget.dart @@ -0,0 +1,135 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_profile/flutter_profile.dart'; + +class ChangePassword extends StatefulWidget { + const ChangePassword({ + required this.config, + required this.service, + this.wrapViewOptions, + this.wrapItemsBuilder, + this.itemBuilder, + this.itemBuilderOptions, + this.style = const ProfileStyle(), + super.key, + }); + + final ChangePasswordConfig config; + final WrapViewOptions? wrapViewOptions; + final ItemBuilder? itemBuilder; + final ItemBuilderOptions? itemBuilderOptions; + final Widget Function(BuildContext context, Widget child)? wrapItemsBuilder; + final ProfileStyle style; + final ProfileService service; + + @override + State createState() => _ChangePasswordState(); +} + +class _ChangePasswordState extends State { + late var config = widget.config; + + late final GlobalKey _formKey = GlobalKey(); + + late final Widget? changePasswordChild; + + String? password1; + String? password2; + + late var builder = widget.itemBuilder ?? + ItemBuilder( + options: widget.itemBuilderOptions ?? ItemBuilderOptions(), + ); + + @override + void initState() { + super.initState(); + + var changePasswordItems = Wrap( + alignment: widget.wrapViewOptions?.wrapAlignment ?? WrapAlignment.start, + direction: widget.wrapViewOptions?.direction ?? Axis.vertical, + spacing: widget.wrapViewOptions?.spacing ?? 0, + runSpacing: widget.wrapViewOptions?.runSpacing ?? 0, + clipBehavior: widget.wrapViewOptions?.clipBehavior ?? Clip.none, + children: [ + builder.buildPassword( + 'password_1', + (value) => password1 = value, + (value) { + if (password1?.isEmpty ?? true) { + return config.fieldRequiredErrorText; + } + + return null; + }, + ), + builder.buildPassword( + 'password_2', + (value) => password2 = value, + (value) { + if (password2?.isEmpty ?? true) { + return config.fieldRequiredErrorText; + } + + if (password2 != password1) { + return config.notEqualErrorText; + } + + return null; + }, + ), + ], + ); + + changePasswordChild = + widget.wrapItemsBuilder?.call(context, changePasswordItems) ?? + changePasswordItems; + } + + @override + Widget build(BuildContext context) { + var theme = Theme.of(context); + + void onTapSave() { + if ((_formKey.currentState?.validate() ?? false) && password2 != null) { + widget.service.changePassword(password2!); + } + } + + return Form( + key: _formKey, + child: Column( + children: [ + SizedBox( + height: widget.style.betweenDefaultItemPadding * 2.5, + ), + Text( + config.title, + style: config.titleStyle ?? theme.textTheme.titleMedium, + textAlign: TextAlign.center, + ), + Text( + config.underTitle, + style: config.underTitleStyle ?? theme.textTheme.bodyMedium, + textAlign: TextAlign.center, + ), + SizedBox( + height: widget.style.betweenDefaultItemPadding, + ), + changePasswordChild!, + SizedBox( + height: widget.style.betweenDefaultItemPadding * 2, + ), + config.saveButtonBuilder?.call( + context, + () => onTapSave(), + ) ?? + FilledButton( + onPressed: () => onTapSave(), + child: const Text('Save password'), + ), + const Spacer(), + ], + ), + ); + } +} diff --git a/lib/src/widgets/profile/profile_page.dart b/lib/src/widgets/profile/profile_page.dart index 9dda43f..83e2afb 100644 --- a/lib/src/widgets/profile/profile_page.dart +++ b/lib/src/widgets/profile/profile_page.dart @@ -3,6 +3,7 @@ // SPDX-License-Identifier: BSD-3-Clause import 'package:flutter/material.dart'; +import 'package:flutter_profile/src/models/change_password_config.dart'; import 'package:flutter_profile/src/models/user.dart'; import 'package:flutter_profile/src/services/profile_service.dart'; import 'package:flutter_profile/src/widgets/item_builder/item_builder.dart'; @@ -46,6 +47,8 @@ class ProfilePage extends StatefulWidget { this.wrapViewOptions, this.extraWidgets, this.formKey, + this.changePasswordConfig = + const ChangePasswordConfig(enablePasswordChange: false), }) : super(key: key); /// User containing all the user data. @@ -96,6 +99,9 @@ class ProfilePage extends StatefulWidget { /// Use the form key to save on any custom callback final GlobalKey? formKey; + /// Configuration to give the user the option to change his/her password. + final ChangePasswordConfig changePasswordConfig; + @override State createState() => _ProfilePageState(); } @@ -123,6 +129,7 @@ class _ProfilePageState extends State { extraWidgets: widget.extraWidgets, formKey: widget.formKey, avatarBackgroundColor: widget.avatarBackgroundColor, + changePasswordConfig: widget.changePasswordConfig, ); } } diff --git a/lib/src/widgets/profile/profile_wrapper.dart b/lib/src/widgets/profile/profile_wrapper.dart index 869765c..07c9f63 100644 --- a/lib/src/widgets/profile/profile_wrapper.dart +++ b/lib/src/widgets/profile/profile_wrapper.dart @@ -3,12 +3,14 @@ // SPDX-License-Identifier: BSD-3-Clause import 'package:flutter/material.dart'; +import 'package:flutter_profile/src/models/change_password_config.dart'; import 'package:flutter_profile/src/models/user.dart'; import 'package:flutter_profile/src/services/profile_service.dart'; import 'package:flutter_profile/src/widgets/avatar/avatar_wrapper.dart'; import 'package:flutter_profile/src/widgets/item_builder/item_builder.dart'; import 'package:flutter_profile/src/widgets/item_builder/item_builder_options.dart'; import 'package:flutter_profile/src/widgets/item_builder/item_list.dart'; +import 'package:flutter_profile/src/widgets/profile/change_password_widget.dart'; import 'package:flutter_profile/src/widgets/profile/profile_page.dart'; import 'package:flutter_profile/src/widgets/profile/profile_style.dart'; @@ -31,6 +33,8 @@ class ProfileWrapper extends StatefulWidget { this.wrapItemsBuilder, this.formKey, this.extraWidgets, + this.changePasswordConfig = + const ChangePasswordConfig(enablePasswordChange: false), super.key, }); @@ -50,6 +54,7 @@ class ProfileWrapper extends StatefulWidget { final Widget Function(BuildContext context, Widget child)? wrapItemsBuilder; final Map? extraWidgets; final GlobalKey? formKey; + final ChangePasswordConfig changePasswordConfig; /// Map keys of items that should be shown first before the default items and the rest of the items. final List prioritizedItems; @@ -193,63 +198,85 @@ class _ProfileWrapperState extends State { Widget build(BuildContext context) { return Material( color: Colors.transparent, - child: Padding( - padding: widget.style.pagePadding, - child: Column( - children: [ - if (widget.showAvatar) ...[ - InkWell( - onTap: () => widget.service.uploadImage( - context, - onUploadStateChanged: (isUploading) => setState( - () { - _isUploadingImage = isUploading; + child: SingleChildScrollView( + child: SizedBox( + height: MediaQuery.of(context).size.height, + child: Padding( + padding: widget.style.pagePadding, + child: Column( + children: [ + if (widget.showAvatar) ...[ + InkWell( + onTap: () => widget.service.uploadImage( + context, + onUploadStateChanged: (isUploading) => setState( + () { + _isUploadingImage = isUploading; + }, + ), + ), + child: AvatarWrapper( + avatarBackgroundColor: widget.avatarBackgroundColor, + user: widget.user, + textStyle: widget.style.avatarTextStyle, + customAvatar: _isUploadingImage + ? Container( + width: 100, + height: 100, + decoration: const BoxDecoration( + color: Colors.black, + shape: BoxShape.circle, + ), + child: const CircularProgressIndicator(), + ) + : widget.customAvatar, + ), + ), + SizedBox( + height: widget.style.betweenDefaultItemPadding, + ), + ], + if (widget.showItems) Form(key: _formKey, child: child), + if (widget.changePasswordConfig.enablePasswordChange) ...[ + Expanded( + child: ChangePassword( + config: widget.changePasswordConfig, + service: widget.service, + wrapViewOptions: widget.wrapViewOptions, + wrapItemsBuilder: widget.wrapItemsBuilder, + itemBuilder: widget.itemBuilder, + itemBuilderOptions: widget.itemBuilderOptions, + style: widget.style, + ), + ), + ], + if (widget.bottomActionText != null) ...[ + SizedBox( + height: widget.style.betweenDefaultItemPadding, + ), + if (!widget.changePasswordConfig.enablePasswordChange) ...[ + const Spacer(), + ], + InkWell( + onTap: () { + widget.service.pageBottomAction(); }, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + widget.bottomActionText!, + style: widget.style.bottomActionTextStyle, + ), + ), ), - ), - child: AvatarWrapper( - avatarBackgroundColor: widget.avatarBackgroundColor, - user: widget.user, - textStyle: widget.style.avatarTextStyle, - customAvatar: _isUploadingImage - ? Container( - width: 100, - height: 100, - decoration: const BoxDecoration( - color: Colors.black, - shape: BoxShape.circle, - ), - child: const CircularProgressIndicator(), - ) - : widget.customAvatar, - ), - ), - SizedBox( - height: widget.style.betweenDefaultItemPadding, - ), - ], - if (widget.showItems) Form(key: _formKey, child: child), - if (widget.bottomActionText != null) ...[ - SizedBox( - height: widget.style.betweenDefaultItemPadding, - ), - const Spacer(), - InkWell( - onTap: () { - widget.service.pageBottomAction(); - }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - widget.bottomActionText!, - style: widget.style.bottomActionTextStyle, - ), - ), - ), - ] else ...[ - const Spacer(), - ], - ], + ], + if (widget.bottomActionText == null && + !widget.changePasswordConfig.enablePasswordChange) ...[ + const Spacer(), + ] + ], + ), + ), ), ), ); diff --git a/pubspec.yaml b/pubspec.yaml index 711b548..0fb9f71 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,14 +1,22 @@ name: flutter_profile description: Flutter profile package -version: 1.1.6 +version: 1.2.0 repository: https://github.com/Iconica-Development/flutter_profile +publish_to: none + environment: - sdk: ">=2.17.6 <3.0.0" + sdk: ^3.0.0 flutter: ">=1.17.0" dependencies: - cached_network_image: ^3.2.2 + cached_network_image: ^3.3.0 + + flutter_input_library: + git: + url: https://github.com/Iconica-Development/flutter_input_library + ref: 2.7.0 + flutter: sdk: flutter diff --git a/test/test_classes/test_profile_service.dart b/test/test_classes/test_profile_service.dart index 32cc46f..101e502 100644 --- a/test/test_classes/test_profile_service.dart +++ b/test/test_classes/test_profile_service.dart @@ -25,4 +25,7 @@ class TestProfileService extends ProfileService { BuildContext context, { required Function(bool isUploading) onUploadStateChanged, }) {} + + @override + FutureOr changePassword(String password) {} }