From 1a11692b5b0ad29627ee4dd96f7c66f0f141eacc Mon Sep 17 00:00:00 2001 From: Vick Top Date: Mon, 19 Feb 2024 16:03:18 +0100 Subject: [PATCH] doc: create documentation for files --- CONTRIBUTING.md | 194 ++++++++++++++++++++++ example/pubspec.lock | 68 +++++--- lib/src/config/login_options.dart | 34 ++++ lib/src/widgets/email_password_login.dart | 7 + lib/src/widgets/forgot_password_form.dart | 7 + lib/src/widgets/mfa_widget.dart | 46 +++++ 6 files changed, 334 insertions(+), 22 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..840680a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,194 @@ +# 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/example/pubspec.lock b/example/pubspec.lock index ebf3226..6e5a4c3 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -58,17 +58,17 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.3" flutter_login: dependency: "direct main" description: path: ".." relative: true source: path - version: "5.1.1" + version: "5.1.4" flutter_test: dependency: "direct dev" description: flutter @@ -79,54 +79,78 @@ packages: description: flutter source: sdk version: "0.0.0" + 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: name: lints - sha256: "5cfd6509652ff5e7fe149b6df4859e687fca9048437857cb2e65c8d780f396e3" + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.1.1" matcher: 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" path: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" pinput: dependency: transitive description: name: pinput - sha256: "1773743c188cdd2f8d0398ea708ec72645bb41ac9311755c4f7bb03a4184bdcf" + sha256: "543da5bfdefd9e06914a12100f8c9156f84cef3efc14bca507c49e966c5b813b" url: "https://pub.dev" source: hosted - version: "2.2.31" + version: "2.3.0" sky_engine: dependency: transitive description: flutter @@ -136,10 +160,10 @@ packages: dependency: transitive description: name: smart_auth - sha256: "8cfaec55b77d5930ed1666bb7ae70db5bade099bb1422401386853b400962113" + sha256: a25229b38c02f733d0a4e98d941b42bed91a976cb589e934895e60ccfa674cf6 url: "https://pub.dev" source: hosted - version: "1.0.8" + version: "1.1.1" source_span: dependency: transitive description: @@ -204,14 +228,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" sdks: - dart: ">=3.2.0-194.0.dev <4.0.0" + dart: ">=3.2.0-0 <4.0.0" flutter: ">=3.7.0" diff --git a/lib/src/config/login_options.dart b/lib/src/config/login_options.dart index cc94779..dfdbe74 100644 --- a/lib/src/config/login_options.dart +++ b/lib/src/config/login_options.dart @@ -31,15 +31,31 @@ class LoginOptions { this.showObscurePassword = true, }); + /// Builds the login button. final ButtonBuilder loginButtonBuilder; + + /// Builds the registration button. final ButtonBuilder registrationButtonBuilder; + + /// Builds the forgot password button. final ButtonBuilder forgotPasswordButtonBuilder; + + /// Builds the request forgot password button. final ButtonBuilder requestForgotPasswordButtonBuilder; + + /// Builds the email input container. final InputContainerBuilder emailInputContainerBuilder; + + /// Builds the password input container. final InputContainerBuilder passwordInputContainerBuilder; + /// The image to display on the login screen. final Widget? image; + + /// The title widget to display on the login screen. final Widget? title; + + /// The subtitle widget to display on the login screen. final Widget? subtitle; /// Option to modify the spacing between the title, subtitle, image, form, @@ -49,16 +65,34 @@ class LoginOptions { /// Maximum width of the form. Defaults to 400. final double? maxFormWidth; + /// Decoration for the email input field. final InputDecoration emailDecoration; + + /// Decoration for the password input field. final InputDecoration passwordDecoration; + + /// The initial email value for the email input field. final String initialEmail; + + /// The initial password value for the password input field. final String initialPassword; + + /// The text style for the email input field. final TextStyle? emailTextStyle; + + /// The text style for the password input field. final TextStyle? passwordTextStyle; + + /// Translations for various texts on the login screen. final LoginTranslations translations; + + /// The validation service used for validating email and password inputs. final ValidationService? validationService; + + /// Determines whether the password field should be obscured. final bool showObscurePassword; + /// Get validations. ValidationService get validations => validationService ?? LoginValidationService(this); } diff --git a/lib/src/widgets/email_password_login.dart b/lib/src/widgets/email_password_login.dart index 4213f9b..96ef072 100644 --- a/lib/src/widgets/email_password_login.dart +++ b/lib/src/widgets/email_password_login.dart @@ -4,6 +4,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_login/flutter_login.dart'; class EmailPasswordLoginForm extends StatefulWidget { + /// Constructs an [EmailPasswordLoginForm] widget. + /// + /// [onLogin]: Callback function for user login. + /// [onForgotPassword]: Callback function for when the user + /// forgets their password. + /// [onRegister]: Callback function for user registration. + /// [options]: The options for configuring the login form. const EmailPasswordLoginForm({ required this.onLogin, super.key, diff --git a/lib/src/widgets/forgot_password_form.dart b/lib/src/widgets/forgot_password_form.dart index 177376a..201cc65 100644 --- a/lib/src/widgets/forgot_password_form.dart +++ b/lib/src/widgets/forgot_password_form.dart @@ -4,6 +4,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_login/flutter_login.dart'; class ForgotPasswordForm extends StatefulWidget { + /// Constructs a [ForgotPasswordForm] widget. + /// + /// [options]: The options for configuring the forgot password form. + /// [description]: Widget to display description. + /// [onRequestForgotPassword]: Callback function for requesting + /// password reset. + /// [title]: Widget to display title. const ForgotPasswordForm({ required this.options, required this.description, diff --git a/lib/src/widgets/mfa_widget.dart b/lib/src/widgets/mfa_widget.dart index 38341d1..62eb00b 100644 --- a/lib/src/widgets/mfa_widget.dart +++ b/lib/src/widgets/mfa_widget.dart @@ -2,6 +2,23 @@ import 'package:flutter/material.dart'; import 'package:pinput/pinput.dart'; class MFAWidget extends StatefulWidget { + /// Constructs an [MFAWidget]. + /// + /// [onCompleted]: Callback function triggered when the MFA code is completed. + /// [onSubmitted]: Callback function triggered when the MFA code is submitted. + /// [length]: The length of the MFA code. + /// [defaultPinTheme]: The theme for the default state of the input pins. + /// [focusedPinTheme]: The theme for the focused state of the input pins. + /// [submittedPinTheme]: The theme for the submitted state of the input pins. + /// [followingPinTheme]: The theme for the pins following the submitted pin. + /// [disabledPinTheme]: The theme for disabled input pins. + /// [errorPinTheme]: The theme for input pins in error state. + /// [seperatorPositions]: Positions for separators between input pins. + /// [errorText]: Text to display when there's an error. + /// [validator]: Validator function to validate the input. + /// [errorBuilder]: Builder function to customize the error display. + /// [errorTextStyle]: Style for the error text. + /// [submitButtonBuilder]: Builder function to customize the submit button. const MFAWidget({ required this.onCompleted, this.onSubmitted, @@ -26,20 +43,49 @@ class MFAWidget extends StatefulWidget { ' not null', ); + /// Callback function triggered when the MFA code is completed. final Function(String code) onCompleted; + + /// Callback function triggered when the MFA code is submitted. final Function(String code)? onSubmitted; + + /// The length of the MFA code. final int length; + + /// The theme for the default state of the input pins. final PinTheme? defaultPinTheme; + + /// The theme for the focused state of the input pins. final PinTheme? focusedPinTheme; + + /// The theme for the submitted state of the input pins. final PinTheme? submittedPinTheme; + + /// The theme for the pins following the submitted pin. final PinTheme? followingPinTheme; + + /// The theme for disabled input pins. final PinTheme? disabledPinTheme; + + /// The theme for input pins in error state. final PinTheme? errorPinTheme; + + /// Positions for separators between input pins. final List? seperatorPositions; + + /// Text to display when there's an error. final String? errorText; + + /// Validator function to validate the input. final String? Function(String?)? validator; + + /// Builder function to customize the error display. final Widget Function(String?, String)? errorBuilder; + + /// Style for the error text. final TextStyle? errorTextStyle; + + /// Builder function to customize the submit button. final Widget Function(Function onTap)? submitButtonBuilder; @override