From cdfe8bb40503256118ac8f97b1d043964b5c783f Mon Sep 17 00:00:00 2001 From: Vick Top Date: Thu, 22 Feb 2024 13:41:47 +0100 Subject: [PATCH] doc: create documentation for files --- CHANGELOG.md | 4 + CONTRIBUTING.md | 198 ++++++++++++++++++ README.md | 3 +- example/pubspec.lock | 58 +++-- lib/src/models/user.dart | 19 ++ lib/src/widgets/avatar/avatar.dart | 8 + lib/src/widgets/avatar/avatar_wrapper.dart | 17 +- lib/src/widgets/item_builder/item_list.dart | 20 ++ .../profile/change_password_widget.dart | 17 +- lib/src/widgets/profile/profile_page.dart | 14 +- lib/src/widgets/profile/profile_wrapper.dart | 39 +++- pubspec.yaml | 4 +- 12 files changed, 372 insertions(+), 29 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 5397177..3f23fac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.4.0 + +- Added CONTRIBUTING.md, documentation and updated flutter_input_library to 3.2.1 + ## 1.3.0 - Field has been added so the user can provide it's current password for reauthentication. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e6350b8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,198 @@ +# Contributing + +First off, thanks for taking the time to contribute! ❤️ + +All types of contributions are encouraged and valued. +See the [Table of Contents](#table-of-contents) for different ways to help and details about how we handle them. +Please make sure to read the relevant section before making your contribution. +It will make it a lot easier for us maintainers and smooth out the experience for all involved. +Iconica looks forward to your contributions. 🎉 + +## Table of contents + +- [Code of conduct](#code-of-conduct) +- [I Have a Question](#i-have-a-question) +- [I Want To Contribute](#i-want-to-contribute) + - [Reporting Bugs](#reporting-bugs) + - [Contributing code](#contributing-code) + +## Code of conduct + +### Legal notice + +When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license. +All accepted pull requests and other additions to this project will be considered intellectual property of Iconica. + +All repositories should be kept clean of jokes, easter eggs and other unnecessary additions. + +## I have a question + +If you want to ask a question, we assume that you have read the available documentation found within the code. +Before you ask a question, it is best to search for existing issues that might help you. +In case you have found a suitable issue but still need clarification, you can ask your question +It is also advisable to search the internet for answers first. + +If you then still feel the need to ask a question and need clarification, we recommend the following: + +- Open an issue. +- Provide as much context as you can about what you're running into. + +We will then take care of the issue as soon as possible. + +## I want to contribute + +### Reporting bugs + + + +**Before submitting a bug report** + +A good bug report shouldn't leave others needing to chase you up for more information. +Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. +Please complete the following steps in advance to help us fix any potential bug as fast as possible. + +- Make sure that you are using the latest version. +- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (If you are looking for support, you might want to check [this section](#i-have-a-question)). +- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error. +- Also make sure to search the internet (including Stack Overflow) to see if users outside of Iconica have discussed the issue. +- Collect information about the bug: +- Stack trace (Traceback) +- OS, Platform and Version (Windows, Linux, macOS, x86, ARM) +- Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant. +- Time and date of occurance +- Describe the expected result and actual result +- Can you reliably reproduce the issue? And can you also reproduce it with older versions? Describe all steps that lead to the bug. + +Once it's filed: + +- The project team will label the issue accordingly. +- A team member will try to reproduce the issue with your provided steps. + If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for additional information. +- If the team is able to reproduce the issue, it will be moved into the backlog, as well as marked with a priority, and the issue will be left to be [implemented by someone](#contributing-code). + +### Contributing code + +When you start working on your contribution, make sure you are aware of the relevant documentation and the functionality of the component you are working on. + +When writing code, follow the style guidelines set by Dart: [Effective Dart](https://Dart.dev/guides/language/effective-Dart). This contains most information you will need to write clean Dart code that is well documented. + +**Documentation** + +As Effective Dart indicates, documenting your public methods with Dart doc comments is recommended. +Aside from Effective Dart, we require specific information in the documentation of a method: + +At the very least, your documentation should first name what the code does, then followed below by requirements for calling the method, the result of the method. +Any references to internal variables or other methods should be done through [var] to indicate a reference. + +If the method or class is complex enough (determined by the reviewers) an example is required. +If unsure, add an example in the docs using code blocks. + +For classes and methods, document the individual parameters with their implications. + +> Tip: Remember that the shortest documentation can be written by having good descriptive names in the first place. + +An example: + +````Dart +library iconica_utilities.bidirectional_sorter; + +part 'sorter.Dart'; +part 'enum.Dart'; + +/// Generic sort method, allow sorting of list with primitives or complex types. +/// Uses [SortDirection] to determine the direction, either Ascending or Descending, +/// Gets called on [List] toSort of type [T] which cannot be shorter than 2. +/// Optionally for complex types a [Comparable] [Function] can be given to compare complex types. +/// ``` +/// List objects = []; +/// for (int i = 0; i < 10; i++) { +/// objects.add(TestObject(name: "name", id: i)); +/// } +/// +/// sort( +/// SortDirection.descending, objects, (object) => object.id); +/// +/// ``` +/// In the above example a list of TestObjects is created, and then sorted in descending order. +/// If the implementation of TestObject is as following: +/// ``` +/// class TestObject { +/// final String name; +/// final int id; +/// +/// TestObject({required this.name, required this.id}); +/// } +/// ``` +/// And the list is logged to the console, the following will appear: +/// ``` +/// [name9, name8, name7, name6, name5, name4, name3, name2, name1, name0] +/// ``` + +void sort( + /// Determines the sorting direction, can be either Ascending or Descending + SortDirection sortDirection, + + /// Incoming list, which gets sorted + List toSort, [ + + /// Optional comparable, which is only necessary for complex types + SortFieldGetter? sortValueCallback, +]) { + if (toSort.length < 2) return; + assert( + toSort.whereType().isNotEmpty || sortValueCallback != null); + BidirectionalSorter( + sortInstructions: >[ + SortInstruction( + sortValueCallback ?? (t) => t as Comparable, sortDirection), + ], + ).sort(toSort); +} + +/// same functionality as [sort] but with the added functionality +/// of sorting multiple values +void sortMulti( + /// Incoming list, which gets sorted + List toSort, + + /// list of comparables to sort multiple values at once, + /// priority based on index + List> sortValueCallbacks, +) { + if (toSort.length < 2) return; + assert(sortValueCallbacks.isNotEmpty); + BidirectionalSorter( + sortInstructions: sortValueCallbacks, + ).sort(toSort); +} + +```` + +**Tests** + +For each public method that was created, excluding widgets, which contains any form of logic (e.g. Calculations, predicates or major side-effects) tests are required. + +A set of tests is written for each method, covering at least each path within the method. For example: + +```Dart +void foo() { + try { + var bar = doSomething(); + if (bar) { + doSomethingElse(); + } else { + doSomethingCool(); + } + } catch (_) { + displayError(); + } +} +``` + +The method above should result in 3 tests: + +1. A test for the path leading to displayError by the cause of an exception +2. A test for if bar is true, resulting in doSomethingElse() +3. A test for if bar is false, resulting in the doSomethingCool() method being called. + +This means that we require 100% coverage of each method you test. diff --git a/README.md b/README.md index 8c4eba0..e71f74c 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Underneath are all paramters, of the 'ProfilePage' widget, listed with an explan | itemBuilderOptions | The options used by the standard itemBuilder to alter the function and style of the textfields | | prioritizedItems | The items that are displayed at the top of the page. Before all the other items in the list and the default items | +By default input fields are saved after pressing 'enter' inside of the input field. ## Issues @@ -38,7 +39,7 @@ Please file any issues, bugs or feature request as an issue on our [GitHub](http ## 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_profile/pulls). +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_profile/pulls). ## Author diff --git a/example/pubspec.lock b/example/pubspec.lock index d235b58..983fd23 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -122,11 +122,11 @@ packages: dependency: transitive description: path: "." - ref: "3.1.0" - resolved-ref: "5fca291c5e79c9ad6dad500e4ea5d9b628ee0f5d" + ref: "3.2.1" + resolved-ref: fddf100fb0aaeff3d6171f58c403d811fab80346 url: "https://github.com/Iconica-Development/flutter_input_library" source: git - version: "3.1.0" + version: "3.2.1" flutter_lints: dependency: "direct dev" description: @@ -141,7 +141,7 @@ packages: path: ".." relative: true source: path - version: "1.2.0" + version: "1.4.0" flutter_test: dependency: "direct dev" description: flutter @@ -171,6 +171,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.18.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" lints: dependency: transitive description: @@ -183,26 +207,26 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" octo_image: dependency: transitive description: @@ -215,10 +239,10 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_provider: dependency: transitive description: @@ -408,14 +432,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - web: + vm_service: dependency: transitive description: - name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "13.0.0" win32: dependency: transitive description: @@ -433,5 +457,5 @@ packages: source: hosted version: "0.2.0+2" sdks: - dart: ">=3.2.0-194.0.dev <4.0.0" + dart: ">=3.2.0-0 <4.0.0" flutter: ">=3.10.0" diff --git a/lib/src/models/user.dart b/lib/src/models/user.dart index be9eba0..b2eee7b 100644 --- a/lib/src/models/user.dart +++ b/lib/src/models/user.dart @@ -25,13 +25,32 @@ class User { imageUrl: data['image_url'], profileData: data['profile_data'], ); + + /// The first name of the user. String? firstName; + + /// The last name of the user. String? lastName; + + /// The image of the user, stored as Uint8List. Uint8List? image; + + /// The URL of the user's image. String? imageUrl; + + /// Additional profile data for the user. ProfileData? profileData; + /// The display name of the user, which is a combination of + /// the first name and the last name. + /// If the first name or the last name is null, + /// an empty string is used instead. String get displayName => '${firstName ?? ''} ${lastName ?? ''}'; + + /// The initials of the user, which are the first characters + /// of the first name and the last name. + /// If the first name or the last name is null or empty, + /// an empty string is used instead. String get initials => '${(firstName?.isNotEmpty ?? false) ? firstName![0] : ''}' '${(lastName?.isNotEmpty ?? false) ? lastName![0] : ''}'; diff --git a/lib/src/widgets/avatar/avatar.dart b/lib/src/widgets/avatar/avatar.dart index 55e7db8..7c1cafd 100644 --- a/lib/src/widgets/avatar/avatar.dart +++ b/lib/src/widgets/avatar/avatar.dart @@ -14,8 +14,13 @@ class Avatar extends StatelessWidget { this.avatarBackgroundColor, }); + /// The user object containing user information. final User? user; + + /// Size of the avatar. final double size; + + /// Background color of the avatar. final Color? avatarBackgroundColor; @override @@ -54,6 +59,7 @@ class Avatar extends StatelessWidget { ); } + /// Returns the image provider based on user's image or image URL. ImageProvider? _getImageProvider(User? user) { if (user?.image != null) { return MemoryImage(user!.image!); @@ -63,6 +69,8 @@ class Avatar extends StatelessWidget { return null; } + /// Generates a color based on the initials of the user's + /// first name and last name. Color _generateColorWithIntials(String? firstName, String? lastName) { var idFirstName = 0; var idLastName = 0; diff --git a/lib/src/widgets/avatar/avatar_wrapper.dart b/lib/src/widgets/avatar/avatar_wrapper.dart index 0a81962..28798c4 100644 --- a/lib/src/widgets/avatar/avatar_wrapper.dart +++ b/lib/src/widgets/avatar/avatar_wrapper.dart @@ -18,14 +18,27 @@ class AvatarWrapper extends StatelessWidget { this.avatarBackgroundColor, }); + /// The user object containing user information. final User user; + + /// Custom widget to be used as an avatar. final Widget? customAvatar; + + /// Background color of the avatar. final Color? avatarBackgroundColor; + + /// Whether to show the user's name beneath the avatar. final bool showName; + + /// Padding around the avatar and the name. final EdgeInsets padding; - final TextStyle? textStyle; + + /// Size of the avatar. final double size; + /// Style for the user's name. + final TextStyle? textStyle; + @override Widget build(BuildContext context) { var avatar = customAvatar ?? @@ -43,8 +56,8 @@ class AvatarWrapper extends StatelessWidget { padding: padding, child: Flexible( child: Text( - style: textStyle, user.displayName, + style: textStyle, ), ), ), diff --git a/lib/src/widgets/item_builder/item_list.dart b/lib/src/widgets/item_builder/item_list.dart index fd9277d..73e5339 100644 --- a/lib/src/widgets/item_builder/item_list.dart +++ b/lib/src/widgets/item_builder/item_list.dart @@ -44,18 +44,38 @@ class ItemList { }); } } + + /// Gets the map of item keys and their corresponding widgets. Map getItemList() => widgets; + /// Map containing item keys and their values. final Map items; + + /// Map containing item keys and their types. final Map typeMap; + + /// Function to update the profile with a specific item's value. final Function(String, String?) updateProfile; + + /// Function to save the profile after an item value is updated. final Function() saveProfile; + + /// Builder for custom item widgets. final ItemBuilder? itemBuilder; + + /// Options for the item builder. final ItemBuilderOptions? itemBuilderOptions; + + /// Global key for the form associated with the item list. final GlobalKey formKey; + /// Map containing item keys and their corresponding widgets. Map widgets = {}; + /// `builder` is an instance of `ItemBuilder` which is used + /// to build the items in the list. + /// If `itemBuilderOptions` is not provided, a default + /// `ItemBuilderOptions` instance is used. late ItemBuilder builder = ItemBuilder( options: itemBuilderOptions ?? ItemBuilderOptions(), ); diff --git a/lib/src/widgets/profile/change_password_widget.dart b/lib/src/widgets/profile/change_password_widget.dart index 0eb53f7..f5f4cd8 100644 --- a/lib/src/widgets/profile/change_password_widget.dart +++ b/lib/src/widgets/profile/change_password_widget.dart @@ -13,12 +13,25 @@ class ChangePassword extends StatefulWidget { super.key, }); + /// Configuration for changing password. final ChangePasswordConfig config; + + /// Options for wrapping the items. final WrapViewOptions? wrapViewOptions; - final ItemBuilder? itemBuilder; - final ItemBuilderOptions? itemBuilderOptions; + + /// Builder for wrapping items. final Widget Function(BuildContext context, Widget child)? wrapItemsBuilder; + + /// Builder for creating items. + final ItemBuilder? itemBuilder; + + /// Options for item builder. + final ItemBuilderOptions? itemBuilderOptions; + + /// Styling options for the widget. final ProfileStyle style; + + /// Profile service for managing user profile. final ProfileService service; @override diff --git a/lib/src/widgets/profile/profile_page.dart b/lib/src/widgets/profile/profile_page.dart index 683a884..511a2e1 100644 --- a/lib/src/widgets/profile/profile_page.dart +++ b/lib/src/widgets/profile/profile_page.dart @@ -153,9 +153,19 @@ class WrapViewOptions { this.runSpacing, this.clipBehavior, }); + + /// The direction to use as the main axis. Axis? direction; + + /// The distance between adjacent children in the cross axis. double? spacing; - double? runSpacing; - Clip? clipBehavior; + + /// How the children should be placed along the main axis. WrapAlignment? wrapAlignment; + + /// The distance between adjacent children in the main axis. + double? runSpacing; + + /// Determines how visual overflow should be handled. + Clip? clipBehavior; } diff --git a/lib/src/widgets/profile/profile_wrapper.dart b/lib/src/widgets/profile/profile_wrapper.dart index 121c4eb..4e0d1e1 100644 --- a/lib/src/widgets/profile/profile_wrapper.dart +++ b/lib/src/widgets/profile/profile_wrapper.dart @@ -38,22 +38,55 @@ class ProfileWrapper extends StatefulWidget { super.key, }); + /// The user object containing user information. final User user; + + /// The service for managing user profile. final ProfileService service; + + /// The styling options for the profile. final ProfileStyle style; + + /// Custom avatar widget. final Widget? customAvatar; + + /// Flag to show or hide the avatar. final bool showAvatar; + + /// Background color for the avatar. final Color? avatarBackgroundColor; + + /// Text for the bottom action. final String? bottomActionText; + + /// Builder for creating items. final ItemBuilder? itemBuilder; - final WrapViewOptions? wrapViewOptions; - final Function() rebuild; + + /// Options for item builder. final ItemBuilderOptions? itemBuilderOptions; + + /// Options for wrapping the view. + final WrapViewOptions? wrapViewOptions; + + /// Callback to rebuild the widget. + final Function() rebuild; + + /// Flag to show default items. final bool showDefaultItems; + + /// Flag to show items. final bool showItems; + + /// Builder for wrapping items. final Widget Function(BuildContext context, Widget child)? wrapItemsBuilder; - final Map? extraWidgets; + + /// Key for the form. final GlobalKey? formKey; + + /// Additional widgets to be displayed. + final Map? extraWidgets; + + /// Configuration for changing password. final ChangePasswordConfig changePasswordConfig; /// Map keys of items that should be shown first before the default items and diff --git a/pubspec.yaml b/pubspec.yaml index da4caed..8abe34a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_profile description: Flutter profile package -version: 1.3.0 +version: 1.4.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: 3.0.1 + ref: 3.2.1 flutter: sdk: flutter