From 2c7f7f9dfe4c8ed00597defb9dcc6585d444dc9f Mon Sep 17 00:00:00 2001 From: Thiago Carvalho Date: Tue, 29 Aug 2023 10:35:13 -0300 Subject: [PATCH] refactor: enhance the documentation of the codes and improves the modal example on storybook --- lib/src/components/modal.dart | 34 +++- storybook/lib/src/modals.dart | 365 ++++++++++++++-------------------- 2 files changed, 187 insertions(+), 212 deletions(-) diff --git a/lib/src/components/modal.dart b/lib/src/components/modal.dart index dfdbfc4..3aa0a4b 100644 --- a/lib/src/components/modal.dart +++ b/lib/src/components/modal.dart @@ -289,7 +289,26 @@ class _ModalCloseButton extends StatelessWidget { } } +/// ArDriveStandardModal Class +/// +/// [ArDriveStandardModal] is a stateless widget that renders a standard modal dialog. +/// It serves as a reusable component and offers flexibility by allowing various configurations. +/// +/// Example: +/// ```dart +/// ArDriveStandardModal( +/// title: "My Title", +/// description: "Description", +/// actions: [/* ... */], +/// content: /* ... */, +/// hasCloseButton: true, +/// ) +/// ``` class ArDriveStandardModal extends StatelessWidget { + /// Creates an instance of [ArDriveStandardModal]. + /// + /// The [actions] should not exceed 3 in number. + /// If [hasCloseButton] is set to true, a close button appears in the title area. const ArDriveStandardModal({ super.key, this.title, @@ -298,13 +317,26 @@ class ArDriveStandardModal extends StatelessWidget { this.actions, this.width, this.hasCloseButton = false, - }); + }) : assert(actions == null || actions.length <= 3); + /// Optional title displayed at the top of the modal. final String? title; + + /// Optional description text. + /// Displayed only if [content] is null. final String? description; + + /// A list of custom modal actions, usually an `ArDriveButton`. final List? actions; + + /// Optional widget content. + /// Takes precedence over [description]. final Widget? content; + + /// Optional width for the modal. final double? width; + + /// Flag to show or hide the close button. final bool hasCloseButton; @override diff --git a/storybook/lib/src/modals.dart b/storybook/lib/src/modals.dart index eeb96c6..0585866 100644 --- a/storybook/lib/src/modals.dart +++ b/storybook/lib/src/modals.dart @@ -5,112 +5,95 @@ import 'package:flutter/material.dart'; import 'package:storybook/src/ardrive_app_base.dart'; import 'package:widgetbook/widgetbook.dart'; +Widget buildModalWidget(Widget modal, BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + modal, + const SizedBox(height: 16), + ArDriveButton( + text: 'Open modal', + onPressed: () => showAnimatedDialog( + context, + content: SizedBox( + width: MediaQuery.of(context).size.width * 0.8, + height: MediaQuery.of(context).size.height * 0.8, + child: ArDriveStorybookAppBase( + builder: (context) => modal, + ), + ), + ), + ), + ], + ); +} + +WidgetbookUseCase buildUseCase( + String name, + Widget Function(BuildContext) modalBuilder, +) { + return WidgetbookUseCase( + name: name, + builder: (context) { + final modal = modalBuilder(context); + return ArDriveStorybookAppBase( + builder: (context) => Scaffold( + body: Center( + child: buildModalWidget( + modal, + context, + ), + ), + ), + ); + }, + ); +} + WidgetbookCategory modals() { - return WidgetbookCategory(name: 'Modals', children: [ - WidgetbookComponent(name: 'Modals', useCases: [ - WidgetbookUseCase( - name: 'Standard', - builder: (context) { - return ArDriveStorybookAppBase(builder: (context) { - final modal = ArDriveStandardModal( + return WidgetbookCategory( + name: 'Modals', + children: [ + WidgetbookComponent( + name: 'Modals', + useCases: [ + buildUseCase( + 'Standard', + (context) { + return ArDriveStandardModal( title: context.knobs.text( label: 'Title', initialValue: 'Warning', ), description: context.knobs.text( - label: 'content', - initialValue: - 'The file you have selected is too large to download from the mobile app.'), + label: 'Content', + initialValue: + 'The file you have selected is too large to download from the mobile app.', + ), actions: context.knobs.options( - label: 'Actions', - labelBuilder: (option) => option!.isEmpty - ? 'None' - : option.length == 1 - ? 'One' - : option.length == 2 - ? 'Two' - : 'Three', - options: [ - [], - [ - ModalAction( - action: () { - print('action 1'); - }, - title: 'Action 1', - ), - ], - [ - ModalAction( - action: () { - print('action 1'); - }, - title: 'Action 1', - ), - ModalAction( - action: () { - print('action 2'); - }, - title: 'Action 2', - ), - ], - [ - ModalAction( - action: () { - print('action 1'); - }, - title: 'Action 1', - ), - ModalAction( - action: () { - print('action 2'); - }, - title: 'Action 2', - ), - ModalAction( - action: () { - print('action 3'); - }, - title: 'Action 3', - ), - ] - ]), - ); - return Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - modal, - const SizedBox( - height: 16, - ), - ArDriveButton( - text: 'Open modal', - onPressed: () { - showAnimatedDialog(context, content: modal); - }, - ) - ], - ), + label: 'Actions', + labelBuilder: getActionLabel, + options: createActionOptions(3), ), ); - }); - }), - WidgetbookUseCase( - name: 'Mini', - builder: (context) { - return ArDriveStorybookAppBase(builder: (context) { - final modal = ArDriveMiniModal( + }, + ), + buildUseCase( + 'Mini', + (context) { + return ArDriveMiniModal( title: context.knobs.text( label: 'Title', initialValue: 'Warning', ), content: context.knobs.text( - label: 'content', initialValue: 'You created a new drive.'), + label: 'content', + initialValue: 'You created a new drive.', + ), leading: context.knobs.options( label: 'leading', labelBuilder: (value) => value == null ? 'null' : 'Icon', + // ArDriveMiniModal accepts custom widgets as options options: [ null, const ArDriveIcon( @@ -120,131 +103,91 @@ WidgetbookCategory modals() { ], ), ); - return Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - modal, - const SizedBox( - height: 16, - ), - ArDriveButton( - text: 'Open modal', - onPressed: () { - showAnimatedDialog(context, content: modal); - }, - ) - ], - ), + }, + ), + buildUseCase( + 'Long', + (context) { + return ArDriveLongModal( + title: context.knobs.text( + label: 'Title', + initialValue: 'Warning', ), - ); - }); - }), - WidgetbookUseCase( - name: 'Long', - builder: (context) { - return ArDriveStorybookAppBase(builder: (context) { - final modal = ArDriveLongModal( - title: context.knobs.text( - label: 'Title', - initialValue: 'Warning', - ), - content: context.knobs.text( - label: 'content', - initialValue: 'You created a new drive.', - ), - action: context.knobs.options(label: 'Action', options: [ - null, - ModalAction(action: () {}, title: 'Action'), - ])); - - return Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - modal, - const SizedBox( - height: 16, - ), - ArDriveButton( - text: 'Open modal', - onPressed: () { - showAnimatedDialog(context, content: modal); - }, - ) - ], - ), + content: context.knobs.text( + label: 'content', + initialValue: 'You created a new drive.', ), - ); - }); - }), - WidgetbookUseCase( - name: 'Modal Icon', - builder: (context) { - final modal = ArDriveIconModal( - title: context.knobs - .text(label: 'Title', initialValue: 'Settings saved!'), - content: context.knobs.text( - label: 'Content', - initialValue: - 'Your profile settings have been updated. Now you can go ahead and jump on into the ArDrive app, have some fun, enjoy yourself, and upload some really awesome stuff.'), - icon: ArDriveIcon( - icon: ArDriveIconsData.check_cirle, - size: 88, - color: ArDriveTheme.of(context) - .themeData - .colors - .themeSuccessDefault, - ), - actions: context.knobs.options(label: 'Actions', options: [ - [], - [ - ModalAction( - action: () { - print('action 1'); - }, - title: 'Action 1', - ), - ], - [ - ModalAction( - action: () { - print('action 1'); - }, - title: 'Action 1', - ), - ModalAction( - action: () { - print('action 2'); - }, - title: 'Action 2', - ), - ], - ]), - ); - return ArDriveStorybookAppBase(builder: (context) { - return Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - modal, - const SizedBox( - height: 16, - ), - ArDriveButton( - text: 'Open modal', - onPressed: () { - showAnimatedDialog(context, content: modal); - }, + action: context.knobs.options( + label: 'Action', + labelBuilder: (value) => value == null ? 'None' : 'Action', + options: [ + null, + ModalAction( + action: () {}, + title: 'Action', ) ], - )), + ), + ); + }, + ), + buildUseCase( + 'Modal Icon', + (context) { + return ArDriveIconModal( + title: context.knobs + .text(label: 'Title', initialValue: 'Settings saved!'), + content: context.knobs.text( + label: 'Content', + initialValue: + 'Your profile settings have been updated. Now you can go ahead and jump on into the ArDrive app, have some fun, enjoy yourself, and upload some really awesome stuff.'), + icon: ArDriveIcon( + icon: ArDriveIconsData.check_cirle, + size: 88, + color: ArDriveTheme.of(context) + .themeData + .colors + .themeSuccessDefault, + ), + actions: context.knobs.options( + labelBuilder: getActionLabel, + label: 'Actions', + options: createActionOptions(1), + ), ); - }); - }) - ]) - ]); + }, + ), + ], + ), + ], + ); +} + +String getActionLabel(List? option) { + if (option == null || option.isEmpty) return 'None'; + switch (option.length) { + case 1: + return 'One'; + case 2: + return 'Two'; + default: + return 'Three'; + } +} + +List?> createActionOptions(int numberOfOptions) { + return List.generate( + numberOfOptions, + (index) => List.generate( + index + 1, + (actionNumber) => createModalAction(actionNumber), + ), + )..insert(0, null); +} + +ModalAction createModalAction(int actionNumber) { + return ModalAction( + action: () => print('action $actionNumber'), + title: 'Action $actionNumber', + ); }