From f01fdc43f440e952461d817e057e50a051bae3a1 Mon Sep 17 00:00:00 2001 From: Nayuta403 <40540394+Nayuta403@users.noreply.github.com> Date: Tue, 7 Dec 2021 21:32:17 +0800 Subject: [PATCH 01/24] =?UTF-8?q?=F0=9F=9A=80=20merge=20master=20to=202.2.?= =?UTF-8?q?x=20(#1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ fix typo * setting pubspec.yaml and modify CHANGELOG.md * fix typo Co-authored-by: zhoujuanjuan001 Co-authored-by: zhoujuanjuan <15143015732@163.com> --- CHANGELOG.md | 4 ++-- README.md | 16 ++++++++-------- pubspec.yaml | 17 ++++++++--------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac071598..63530156 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,3 @@ -## [0.0.1] - TODO: Add release date. +## [1.0.0] - first publish adapter flutter sdk 1.22.4. + -* TODO: Describe initial release. diff --git a/README.md b/README.md index f710fc7d..f7e67442 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@

Bruno

-一套企业级移动端Flutter组件库 +一套企业级移动端 Flutter 组件库 [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/LianjiaTech/bruno/blob/master/LICENSE) @@ -17,7 +17,7 @@
-简体中文| [English](./README.en-US.md) +简体中文 | [English](./README.en-US.md)
@@ -27,11 +27,11 @@ ## ✨ 特性 - 提炼自企业级移动端产品的交互和视觉风格 -- 开箱即用的高质量Flutter组件 +- 开箱即用的高质量 Flutter 组件 - 提供满足业务差异的主题定制能力 - 设计工具赋能开发全链路 -### Demo下载 +### Demo 下载 [Bruno for Android]() @@ -40,7 +40,7 @@ -## 适配Flutter版本 +## 适配 Flutter 版本 @@ -53,7 +53,7 @@ ## 接入 -Flutter 工程中pubspec.yaml文件里加入以下依赖: +Flutter 工程中 pubspec.yaml 文件里加入以下依赖: ```dart dependencies: @@ -82,7 +82,7 @@ BrnBubbleText( 贡献之前请先阅读 [贡献指南]()。 -感谢所有为Bruno做出贡献的开发者! +感谢所有为 Bruno 做出贡献的开发者!
@@ -165,7 +165,7 @@ BrnBubbleText( ## 致谢 -bruno作为整套标准组件,参考和引用部分开源库如下: +Bruno 作为整套标准组件,参考和引用部分开源库如下: - [flutter_gifimage](https://github.com/peng8350/flutter_gifimage) - [expansion_tile_card.dart](https://gist.github.com/Skylled/7ac0f2f99881f7df2a0a850e60ef2df0) diff --git a/pubspec.yaml b/pubspec.yaml index 357c5025..79717056 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,8 +1,7 @@ name: bruno -description: A new Flutter package project. -version: 0.0.1 -author: -homepage: +description: An enterprise-class package of Flutter components for mobile applications. +version: 1.0.0 +homepage: https://github.com/LianjiaTech/bruno environment: sdk: ">=2.1.0 <3.0.0" @@ -13,11 +12,11 @@ dependencies: xml: ^3.5.0 lpinyin: ^1.0.7 path_drawing: ^0.4.1 - flutter_easyrefresh: 2.1.1 - intl: 0.16.1 - photo_view: 0.13.0 - provider: 3.2.0 - badges: 1.2.0 + flutter_easyrefresh: ^2.1.1 + intl: ^0.16.1 + photo_view: ^0.13.0 + provider: ^3.2.0 + badges: ^1.2.0 dev_dependencies: flutter_test: From b96a55199a535e8fce727819389770d15d71c16d Mon Sep 17 00:00:00 2001 From: violinday Date: Wed, 8 Dec 2021 10:56:59 +0800 Subject: [PATCH 02/24] perf: pass puv.dev static analysis --- lib/bruno.dart | 1 - .../brn_selected_list_action_sheet.dart | 1 + .../actionsheet/brn_share_action_sheet.dart | 18 +- lib/src/components/appraise/brn_appraise.dart | 18 +- .../appraise/brn_appraise_bottom_picker.dart | 11 +- .../appraise/brn_appraise_emoji_item.dart | 8 +- .../brn_appraise_emoji_list_view.dart | 10 +- .../appraise/brn_appraise_header.dart | 67 ++++--- .../appraise/brn_appraise_star_list_view.dart | 15 +- .../appraise/brn_flutter_gif_image.dart | 7 +- .../appraise/brn_mulit_select_tags.dart | 37 ++-- .../button/brn_big_ghost_button.dart | 4 +- .../button/brn_big_outline_button.dart | 8 +- .../button/brn_small_main_button.dart | 5 +- .../button/brn_small_outline_button.dart | 9 +- .../collection/brn_bottom_button_panel.dart | 16 +- .../button/collection/brn_button_panel.dart | 3 +- .../brn_multiple_bottom_button.dart | 81 ++++++--- .../collection/brn_text_button_panel.dart | 22 +-- .../card/bubble_card/brn_bubble_text.dart | 8 +- .../card/bubble_card/brn_insert_info.dart | 8 +- .../content_card/brn_enhance_number_card.dart | 14 +- .../content_card/brn_pair_info_rich_grid.dart | 26 ++- .../card/shadow_card/brn_shadow_card.dart | 5 +- .../card_title/brn_action_card_title.dart | 4 +- .../brn_doughnut_chart.dart | 57 ++++-- .../brn_doughnut_chart_legend.dart | 3 +- .../brn_progress_bar_chart.dart | 27 ++- .../brn_progress_bar_chart_painter.dart | 3 + .../brn_progress_chart.dart | 10 +- .../brn_progress_chart_painter.dart | 11 +- .../charts/broken_line/brn_broken_line.dart | 29 ++- .../charts/broken_line/brn_line_data.dart | 7 +- .../charts/broken_line/brn_line_painter.dart | 127 ++++++++----- .../broken_line/brn_line_y_painter.dart | 38 ++-- .../charts/broken_line/monotone_x.dart | 18 +- lib/src/components/charts/funnel_chart.dart | 114 ++++++++---- lib/src/components/charts/radar_chart.dart | 46 +++-- lib/src/components/dialog/brn_dialog.dart | 98 ++++++---- .../dialog/brn_enhance_operation_dialog.dart | 3 +- .../dialog/brn_middle_input_diaolg.dart | 23 ++- .../dialog/brn_multi_select_dialog.dart | 29 ++- .../dialog/brn_scrollable_text_dialog.dart | 13 +- .../components/dialog/brn_share_dialog.dart | 5 +- .../components/dialog/brn_single_select.dart | 60 +++--- .../components/empty/brn_empty_status.dart | 30 +-- .../form/base/brn_form_item_type.dart | 10 +- .../form/base/input_item_interface.dart | 11 +- .../general/brn_multi_choice_input_item.dart | 66 ++++--- .../brn_multi_choice_portrait_input_item.dart | 28 +-- .../general/brn_quick_select_input_item.dart | 39 ++-- .../items/general/brn_radio_input_item.dart | 76 ++++---- .../brn_radio_portrait_input_item.dart | 27 +-- .../items/general/brn_range_input_item.dart | 63 ++++--- .../items/general/brn_ratio_input_item.dart | 45 +++-- .../items/general/brn_star_input_item.dart | 25 +-- .../items/general/brn_step_input_item.dart | 79 ++++---- .../general/brn_text_block_input_item.dart | 30 +-- .../items/general/brn_text_input_item.dart | 38 ++-- .../items/general/brn_text_select_item.dart | 54 ++++-- .../general/brn_title_select_input_item.dart | 52 +++--- .../form/items/group/brn_expand_group.dart | 8 - .../form/items/group/brn_normal_group.dart | 10 +- .../items/group/element_expand_widget.dart | 30 +-- .../form/items/misc/brn_add_label_item.dart | 16 +- .../form/items/misc/brn_title_item.dart | 19 +- .../form/items/title/brn_base_title_item.dart | 7 +- .../undetermined/brn_expandable_group.dart | 40 ++-- .../brn_portrait_radio_group.dart | 15 +- .../components/form/utils/brn_form_util.dart | 96 ++++++---- .../config/brn_basic_gallery_config.dart | 8 +- .../gallery/config/brn_bottom_card.dart | 22 ++- .../config/brn_photo_gallery_config.dart | 14 +- .../gallery/page/brn_gallery_detail_page.dart | 40 ++-- .../page/brn_gallery_summary_page.dart | 16 +- .../guide/brn_delay_rendered_widget.dart | 3 +- .../components/guide/brn_flutter_guide.dart | 19 +- .../components/guide/brn_pulse_widget.dart | 18 +- .../guide/brn_step_widget_builder.dart | 10 +- lib/src/components/guide/brn_tip_widget.dart | 56 ++++-- lib/src/components/input/brn_input_text.dart | 23 ++- lib/src/components/line/brn_dashed_line.dart | 18 +- lib/src/components/line/brn_line.dart | 7 +- lib/src/components/loading/brn_loading.dart | 15 +- lib/src/components/navbar/brn_search_bar.dart | 30 ++- .../noticebar/brn_marquee_text.dart | 25 ++- .../components/noticebar/brn_notice_bar.dart | 19 +- .../components/picker/base/brn_picker.dart | 54 ++++-- .../picker/base/brn_picker_constants.dart | 3 +- .../components/picker/brn_bottom_picker.dart | 31 +++- .../picker/brn_bottom_write_picker.dart | 37 +++- .../picker/brn_mulit_select_tags_picker.dart | 61 +++++-- .../components/picker/brn_multi_picker.dart | 44 +++-- .../brn_select_tags_with_input_picker.dart | 1 - .../picker/brn_tags_common_picker.dart | 19 +- .../picker/brn_tags_picker_config.dart | 16 +- .../bean/brn_multi_column_picker_entity.dart | 33 ++-- .../brn_multi_column_converter.dart | 18 +- .../brn_multi_column_list.dart | 29 ++- .../brn_multi_column_picker.dart | 57 ++++-- .../brn_multi_column_picker_util.dart | 17 +- .../btn_multi_column_picker_item.dart | 29 +-- .../brn_multi_select_data.dart | 3 +- .../brn_multi_select_list_picker.dart | 55 +++--- .../brn_date_picker_constants.dart | 3 +- .../time_picker/brn_date_time_formatter.dart | 37 ++-- .../date_picker/brn_date_picker.dart | 14 +- .../date_picker/brn_date_widget.dart | 53 ++++-- .../date_picker/brn_datetime_widget.dart | 151 +++++++++++----- .../date_picker/brn_time_widget.dart | 75 +++++--- .../brn_date_range_picker.dart | 21 ++- .../brn_date_range_side_widget.dart | 50 +++-- .../brn_date_range_widget.dart | 57 +++--- .../brn_time_range_side_widget.dart | 66 ++++--- .../brn_time_range_widget.dart | 57 +++--- .../components/popup/brn_overlay_window.dart | 12 +- .../components/popup/brn_popup_window.dart | 99 ++++++---- lib/src/components/radio/brn_checkbox.dart | 9 +- .../components/radio/brn_radio_button.dart | 9 +- lib/src/components/radio/brn_radio_core.dart | 4 +- .../components/rating/brn_rating_star.dart | 7 +- .../scroll_anchor/brn_scroll_anchor_tab.dart | 40 ++-- .../selectcity/brn_az_listview.dart | 11 +- .../selectcity/brn_base_azlistview_page.dart | 3 +- .../components/selectcity/brn_index_bar.dart | 9 +- .../brn_single_select_city_page.dart | 15 +- .../selectcity/brn_suspension_view.dart | 3 +- .../bean/brn_selection_common_entity.dart | 58 +++--- .../selection/brn_flat_selection.dart | 9 +- .../selection/brn_more_selection.dart | 17 +- .../selection/brn_selection_list_entity.dart | 3 +- .../selection/brn_selection_util.dart | 25 ++- .../selection/brn_selection_view.dart | 63 ++++--- .../selection/brn_simple_selection.dart | 10 +- .../converter/brn_selection_converter.dart | 31 ++-- .../widget/brn_flat_selection_item.dart | 86 ++++++--- .../widget/brn_layer_more_selection_page.dart | 35 ++-- .../widget/brn_selection_animate_widget.dart | 32 ++-- .../brn_selection_common_item_widget.dart | 18 +- .../brn_selection_date_range_item_widget.dart | 54 +++--- ...n_selection_datepicker_animate_widget.dart | 14 +- .../widget/brn_selection_list_widget.dart | 50 +++-- .../brn_selection_menu_item_widget.dart | 13 +- .../widget/brn_selection_menu_widget.dart | 123 ++++++++----- .../brn_selection_more_item_widget.dart | 107 +++++++---- ...brn_selection_range_input_item_widget.dart | 17 +- .../brn_selection_range_tag_widget.dart | 20 +- .../widget/brn_selection_range_widget.dart | 105 +++++++---- .../brn_selection_single_list_widget.dart | 41 +++-- .../components/step/brn_horizontal_steps.dart | 30 ++- lib/src/components/step/brn_step_line.dart | 10 +- .../components/sugsearch/brn_search_text.dart | 66 ++++--- .../bottom/brn_bottom_tab_bar_main.dart | 54 ++++-- .../indicator/brn_custom_width_indicator.dart | 7 +- .../brn_fixed_underline_decoration.dart | 3 +- .../indicator/brn_triangle_decoration.dart | 29 ++- .../tabbar/normal/brn_sub_switch_title.dart | 6 +- .../components/tabbar/normal/brn_tab_bar.dart | 81 ++++++--- .../tabbar/normal/brn_tabbar_controller.dart | 3 +- lib/src/components/tag/brn_state_tag.dart | 3 +- lib/src/components/tag/brn_tag_custom.dart | 29 ++- .../tag/tagview/brn_delete_tag.dart | 22 ++- .../tag/tagview/brn_select_tag.dart | 17 +- .../components/text/brn_expandable_text.dart | 24 ++- lib/src/components/toast/brn_toast.dart | 27 ++- lib/src/constants/brn_asset_constants.dart | 104 +++++++---- lib/src/theme/base/brn_base_config.dart | 6 +- .../theme/base/brn_default_config_utils.dart | 171 +++++++++++------- lib/src/theme/brn_initializer.dart | 1 + lib/src/theme/brn_theme_configurator.dart | 3 +- .../configs/brn_abnormal_state_config.dart | 55 ++++-- .../configs/brn_action_sheet_config.dart | 76 +++++--- lib/src/theme/configs/brn_all_config.dart | 46 +++-- lib/src/theme/configs/brn_appbar_config.dart | 20 +- lib/src/theme/configs/brn_button_config.dart | 11 +- .../theme/configs/brn_card_title_config.dart | 45 +++-- lib/src/theme/configs/brn_common_config.dart | 5 +- lib/src/theme/configs/brn_dialog_config.dart | 62 ++++--- .../brn_enhance_number_card_config.dart | 27 ++- lib/src/theme/configs/brn_form_config.dart | 101 +++++++---- .../configs/brn_gallery_detail_config.dart | 68 ++++--- .../theme/configs/brn_pair_info_config.dart | 70 ++++--- lib/src/theme/configs/brn_picker_config.dart | 62 ++++--- .../theme/configs/brn_selection_config.dart | 167 ++++++++++------- lib/src/theme/configs/brn_tabbar_config.dart | 43 +++-- lib/src/theme/configs/brn_tag_config.dart | 32 ++-- .../theme/img/brn_theme_default_utils.dart | 6 +- lib/src/utils/brn_event_bus.dart | 6 +- lib/src/utils/brn_rich_text.dart | 19 +- lib/src/utils/brn_text_util.dart | 4 +- lib/src/utils/brn_tools.dart | 15 +- lib/src/utils/css/brn_core_funtion.dart | 28 ++- lib/src/utils/css/brn_css_2_text.dart | 6 +- lib/src/utils/css/brn_util.dart | 6 +- lib/src/utils/i18n/brn_date_picker_i18n.dart | 28 ++- lib/src/utils/i18n/brn_strings_zh_cn.dart | 15 +- 196 files changed, 4068 insertions(+), 2278 deletions(-) diff --git a/lib/bruno.dart b/lib/bruno.dart index 82e0e0a1..b2b13bea 100644 --- a/lib/bruno.dart +++ b/lib/bruno.dart @@ -161,7 +161,6 @@ export 'src/components/gallery/config/brn_bottom_card.dart'; export 'src/components/gallery/config/brn_basic_gallery_config.dart'; export 'src/components/gallery/config/brn_controller.dart'; - // 红点组件 export 'src/components/input/brn_input_text.dart'; diff --git a/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart b/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart index a4a9ca46..2b0dd36e 100644 --- a/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart +++ b/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart @@ -32,6 +32,7 @@ class BrnSelectedListActionSheetController extends ChangeNotifier { _isHidden = true; notifyListeners(); } + bool get isHidden { return _isHidden; } diff --git a/lib/src/components/actionsheet/brn_share_action_sheet.dart b/lib/src/components/actionsheet/brn_share_action_sheet.dart index 9c657f3b..d547ebf4 100644 --- a/lib/src/components/actionsheet/brn_share_action_sheet.dart +++ b/lib/src/components/actionsheet/brn_share_action_sheet.dart @@ -5,7 +5,8 @@ import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; /// section为所在行数(0或1),index是在第几位(从0开始记), shareItem为渠道相关信息 -typedef void BrnShareActionSheetItemClickCallBack(int section, int index, BrnShareItem shareItem); +typedef void BrnShareActionSheetItemClickCallBack( + int section, int index, BrnShareItem shareItem); /// 点击事件拦截回调(如果配置了此项,返回值为是否拦截,如果为true,则进行拦截,不进行默认回调) /// section为所在行数(0或1),index是在第几位(从0开始记),shareItem为渠道相关信息 @@ -125,8 +126,8 @@ class BrnShareActionSheet extends StatelessWidget { : (channel.canClick ? BrunoTools.getAssetImage( BrnShareItemConstants.shareItemImagePathList[channel.shareType]) - : BrunoTools.getAssetImage( - BrnShareItemConstants.disableShareItemImagePathList[channel.shareType])); + : BrunoTools.getAssetImage(BrnShareItemConstants + .disableShareItemImagePathList[channel.shareType])); //如果没图或没文字则不显示 if (title == null || image == null) { return null; @@ -158,7 +159,8 @@ class BrnShareActionSheet extends StatelessWidget { ), ), onTap: () { - if (clickInterceptor == null || !clickInterceptor(section, index, channel)) { + if (clickInterceptor == null || + !clickInterceptor(section, index, channel)) { // 推荐使用回调方法处理点击事件!!!!!!!!!! if (clickCallBack != null && channel.canClick) { clickCallBack(section, index, channel); @@ -212,7 +214,10 @@ class BrnShareActionSheet extends StatelessWidget { style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase), + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase), ), )); @@ -264,7 +269,8 @@ class BrnShareActionSheet extends StatelessWidget { child: Center( child: Text( (cancelTitle != null) ? cancelTitle : "取消", - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: textColor), + style: TextStyle( + fontSize: 16, fontWeight: FontWeight.w600, color: textColor), ), ), ), diff --git a/lib/src/components/appraise/brn_appraise.dart b/lib/src/components/appraise/brn_appraise.dart index e0d2c452..c396c807 100644 --- a/lib/src/components/appraise/brn_appraise.dart +++ b/lib/src/components/appraise/brn_appraise.dart @@ -19,7 +19,8 @@ typedef BrnAppraiseTagClick = void Function(List selectedTags); /// index 选中的表情或者星星的index /// selectedTags 所有选中标签的集合 /// input 自定义输入的内容 -typedef BrnAppraiseConfirmClick = void Function(int index, List selectedTags, String input); +typedef BrnAppraiseConfirmClick = void Function( + int index, List selectedTags, String input); /// 点击关闭的回掉 typedef BrnAppraiseCloseClickCallBack = void Function(BuildContext context); @@ -68,7 +69,13 @@ class BrnAppraise extends StatefulWidget { final BrnAppraiseConfig config; /// 评价组建每个评分对应的默认文案 - static const List _defaultIconDescriptions = ['不好', '还行', '满意', '很棒', '超惊喜']; + static const List _defaultIconDescriptions = [ + '不好', + '还行', + '满意', + '很棒', + '超惊喜' + ]; BrnAppraise({ this.title, @@ -137,9 +144,10 @@ class _BrnAppraiseState extends State { /// header Widget _headerArea(BuildContext context) { - EdgeInsets defaultPadding = (widget.headerType == BrnAppraiseHeaderType.center) - ? EdgeInsets.only(top: 20, bottom: 20) - : EdgeInsets.only(left: 20, top: 16, right: 16, bottom: 20); + EdgeInsets defaultPadding = + (widget.headerType == BrnAppraiseHeaderType.center) + ? EdgeInsets.only(top: 20, bottom: 20) + : EdgeInsets.only(left: 20, top: 16, right: 16, bottom: 20); return BrnAppraiseHeader( showHeader: widget.config?.showHeader ?? true, headerType: widget.headerType ?? BrnAppraiseHeaderType.spaceBetween, diff --git a/lib/src/components/appraise/brn_appraise_bottom_picker.dart b/lib/src/components/appraise/brn_appraise_bottom_picker.dart index bae702dc..2701efef 100644 --- a/lib/src/components/appraise/brn_appraise_bottom_picker.dart +++ b/lib/src/components/appraise/brn_appraise_bottom_picker.dart @@ -33,7 +33,13 @@ class BrnAppraiseBottomPicker extends StatefulWidget { final BrnAppraiseConfig config; /// 评价组建每个评分对应的默认文案 - static const List _defaultIconDescriptions = ['不好', '还行', '满意', '很棒', '超惊喜']; + static const List _defaultIconDescriptions = [ + '不好', + '还行', + '满意', + '很棒', + '超惊喜' + ]; BrnAppraiseBottomPicker({ this.title, @@ -47,7 +53,8 @@ class BrnAppraiseBottomPicker extends StatefulWidget { }); @override - _BrnAppraiseBottomPickerState createState() => _BrnAppraiseBottomPickerState(); + _BrnAppraiseBottomPickerState createState() => + _BrnAppraiseBottomPickerState(); } class _BrnAppraiseBottomPickerState extends State { diff --git a/lib/src/components/appraise/brn_appraise_emoji_item.dart b/lib/src/components/appraise/brn_appraise_emoji_item.dart index 630fd7bb..b3867c82 100644 --- a/lib/src/components/appraise/brn_appraise_emoji_item.dart +++ b/lib/src/components/appraise/brn_appraise_emoji_item.dart @@ -69,7 +69,8 @@ class _BrnAppraiseEmojiItemState extends State ); _gif = GifImage( controller: _controller, - image: AssetImage(widget.selectedName, package: BrnStrings.flutterPackageName), + image: AssetImage(widget.selectedName, + package: BrnStrings.flutterPackageName), width: 34, height: 34, defaultImage: Image.asset( @@ -103,8 +104,9 @@ class _BrnAppraiseEmojiItemState extends State child: Text( widget.title ?? '', style: TextStyle( - color: - widget.index == widget.selectedIndex ? Color(0xffffc300) : Color(0xff999999), + color: widget.index == widget.selectedIndex + ? Color(0xffffc300) + : Color(0xff999999), fontSize: 12.0, fontWeight: FontWeight.w600, ), diff --git a/lib/src/components/appraise/brn_appraise_emoji_list_view.dart b/lib/src/components/appraise/brn_appraise_emoji_list_view.dart index 1826feb1..52c1cf75 100644 --- a/lib/src/components/appraise/brn_appraise_emoji_list_view.dart +++ b/lib/src/components/appraise/brn_appraise_emoji_list_view.dart @@ -20,12 +20,15 @@ class BrnAppraiseEmojiListView extends StatefulWidget { static const List _defaultTitles = ['不好', '还行', '满意', '很棒', '超惊喜']; BrnAppraiseEmojiListView( - {this.indexes = const [0, 1, 2, 3, 4], this.titles = _defaultTitles, this.onTap}) + {this.indexes = const [0, 1, 2, 3, 4], + this.titles = _defaultTitles, + this.onTap}) : assert((indexes?.length ?? 0) > 0), assert(titles?.length == 5); @override - _BrnAppraiseEmojiListViewState createState() => _BrnAppraiseEmojiListViewState(); + _BrnAppraiseEmojiListViewState createState() => + _BrnAppraiseEmojiListViewState(); } class _BrnAppraiseEmojiListViewState extends State { @@ -71,7 +74,8 @@ class _BrnAppraiseEmojiListViewState extends State { unselectedName: _unselectedIcons[widget.indexes[i]], defaultName: _defaultIcons[widget.indexes[i]], index: i, - padding: EdgeInsets.symmetric(horizontal: 7.0 * (6 - widget.indexes.length)), + padding: + EdgeInsets.symmetric(horizontal: 7.0 * (6 - widget.indexes.length)), selectedIndex: _selectedIndex, title: widget.titles[widget.indexes[i]], onTap: (index) { diff --git a/lib/src/components/appraise/brn_appraise_header.dart b/lib/src/components/appraise/brn_appraise_header.dart index 8768d5c2..065962a4 100644 --- a/lib/src/components/appraise/brn_appraise_header.dart +++ b/lib/src/components/appraise/brn_appraise_header.dart @@ -53,7 +53,10 @@ class BrnAppraiseHeader extends StatelessWidget { title ?? '', maxLines: maxLines ?? 1, style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, fontSize: 18.0, fontWeight: FontWeight.w600, ), @@ -66,38 +69,42 @@ class BrnAppraiseHeader extends StatelessWidget { color: Colors.white, height: 38 + (maxLines ?? 1) * 22.0, child: Padding( - padding: headPadding ?? EdgeInsets.only(left: 20, top: 16, right: 16, bottom: 20), - child: Row( - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Padding( - padding: EdgeInsets.only(top: 4, right: 12), - child: Text( - title ?? '', - maxLines: maxLines ?? 1, - style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, - fontSize: 18.0, - height: 1, - fontWeight: FontWeight.w600, - ), - ), + padding: headPadding ?? + EdgeInsets.only(left: 20, top: 16, right: 16, bottom: 20), + child: Row( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Padding( + padding: EdgeInsets.only(top: 4, right: 12), + child: Text( + title ?? '', + maxLines: maxLines ?? 1, + style: TextStyle( + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, + fontSize: 18.0, + height: 1, + fontWeight: FontWeight.w600, ), ), - InkWell( - onTap: () { - if (cancelCallBack != null) { - cancelCallBack(context); - } - Navigator.of(context).pop(); - }, - child: BrunoTools.getAssetImage(BrnAsset.ICON_PICKER_CLOSE), - ), - ], + ), + ), + InkWell( + onTap: () { + if (cancelCallBack != null) { + cancelCallBack(context); + } + Navigator.of(context).pop(); + }, + child: BrunoTools.getAssetImage(BrnAsset.ICON_PICKER_CLOSE), ), - ), + ], + ), + ), ); } } diff --git a/lib/src/components/appraise/brn_appraise_star_list_view.dart b/lib/src/components/appraise/brn_appraise_star_list_view.dart index 5e3fb693..c4aef940 100644 --- a/lib/src/components/appraise/brn_appraise_star_list_view.dart +++ b/lib/src/components/appraise/brn_appraise_star_list_view.dart @@ -24,14 +24,16 @@ class BrnAppraiseStarListView extends StatefulWidget { assert(titles == null || titles.length >= count); @override - _BrnAppraiseStarListViewState createState() => _BrnAppraiseStarListViewState(); + _BrnAppraiseStarListViewState createState() => + _BrnAppraiseStarListViewState(); } class _BrnAppraiseStarListViewState extends State { - Image _star = BrunoTools.getAssetImage(BrnAsset.iconStarSize, gaplessPlayback: true); + Image _star = + BrunoTools.getAssetImage(BrnAsset.iconStarSize, gaplessPlayback: true); - Image _selectedStar = - BrunoTools.getAssetImage(BrnAsset.iconStarSizeSelected, gaplessPlayback: true); + Image _selectedStar = BrunoTools.getAssetImage(BrnAsset.iconStarSizeSelected, + gaplessPlayback: true); int _selectedIndex = -1; @@ -52,7 +54,10 @@ class _BrnAppraiseStarListViewState extends State { subTitle ?? '', style: TextStyle( fontSize: 12.0, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextSecondary, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextSecondary, fontWeight: FontWeight.w600), ), ); diff --git a/lib/src/components/appraise/brn_flutter_gif_image.dart b/lib/src/components/appraise/brn_flutter_gif_image.dart index 45fae960..efa21010 100644 --- a/lib/src/components/appraise/brn_flutter_gif_image.dart +++ b/lib/src/components/appraise/brn_flutter_gif_image.dart @@ -50,7 +50,8 @@ class GifImage extends StatefulWidget { } class GifImageState extends State { - ValueNotifier> _images = ValueNotifier>(List()); + ValueNotifier> _images = + ValueNotifier>(List()); double _curValue = 0.0; @override @@ -129,8 +130,8 @@ class GifImageState extends State { AssetBundleImageKey key = await provider.obtainKey(ImageConfiguration()); data = await key.bundle.load(key.name); - ui.Codec codec = - await PaintingBinding.instance.instantiateImageCodec(data.buffer.asUint8List()); + ui.Codec codec = await PaintingBinding.instance + .instantiateImageCodec(data.buffer.asUint8List()); for (int i = 0; i < codec.frameCount; i++) { FrameInfo frameInfo = await codec.getNextFrame(); infos.add(ImageInfo(image: frameInfo.image)); diff --git a/lib/src/components/appraise/brn_mulit_select_tags.dart b/lib/src/components/appraise/brn_mulit_select_tags.dart index 538ed4c8..3d463c82 100644 --- a/lib/src/components/appraise/brn_mulit_select_tags.dart +++ b/lib/src/components/appraise/brn_mulit_select_tags.dart @@ -18,7 +18,8 @@ enum BrnMultiSelectStyle { typedef BrnMultiSelectTagText = String Function(V data); ///提交按钮事件回调 -typedef BrnMultiSelectedTagsCallback = void Function(List selectedTags); +typedef BrnMultiSelectedTagsCallback = void Function( + List selectedTags); class BrnMultiSelectTags extends StatefulWidget { ///当点击到最大数目时的点击事件 @@ -113,13 +114,16 @@ class _BrnMultiSelectTagsState extends State { ///等宽度的布局 Widget _buildGridViewWidget(BuildContext context) { int brnCrossAxisCount = widget.brnCrossAxisCount ?? 2; - double width = - (MediaQuery.of(context).size.width - (brnCrossAxisCount - 1) * 12 - 40) / brnCrossAxisCount; + double width = (MediaQuery.of(context).size.width - + (brnCrossAxisCount - 1) * 12 - + 40) / + brnCrossAxisCount; //计算宽高比 double brnChildAspectRatio = width / 34.0; return Container( - padding: widget.padding ?? EdgeInsets.only(top: 0.0, left: 20.0, right: 20.0, bottom: 0.0), + padding: widget.padding ?? + EdgeInsets.only(top: 0.0, left: 20.0, right: 20.0, bottom: 0.0), constraints: BoxConstraints(maxHeight: 322, minHeight: 120), child: GridView.count( shrinkWrap: true, @@ -132,7 +136,8 @@ class _BrnMultiSelectTagsState extends State { //宽高比 childAspectRatio: brnChildAspectRatio, children: _sourceTags.map((choice) { - return _getItem(choice, EdgeInsets.only(left: 8, right: 8, bottom: 1)); + return _getItem( + choice, EdgeInsets.only(left: 8, right: 8, bottom: 1)); }).toList(), ), ); @@ -146,7 +151,8 @@ class _BrnMultiSelectTagsState extends State { spacing: 12, runSpacing: 12, children: _sourceTags.map((choice) { - return _getItem(choice, EdgeInsets.only(left: 8, right: 8, top: 10.5, bottom: 11)); + return _getItem(choice, + EdgeInsets.only(left: 8, right: 8, top: 10.5, bottom: 11)); }).toList(), )); } @@ -199,9 +205,15 @@ class _BrnMultiSelectTagsState extends State { BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary; Color tagTitleColor = widget.tagPickerBean.tagTitleColor ?? BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; - Color tagBackgroundColor = widget.tagPickerBean.tagBackgroudColor ?? Color(0xFFF8F8F8); - Color selectedTagBackgroundColor = widget.tagPickerBean.selectedTagBackgroudColor ?? - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary.withAlpha(0x14); + Color tagBackgroundColor = + widget.tagPickerBean.tagBackgroudColor ?? Color(0xFFF8F8F8); + Color selectedTagBackgroundColor = + widget.tagPickerBean.selectedTagBackgroudColor ?? + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary + .withAlpha(0x14); bool selected = choice.isSelect; Color titleColor = selected ? selectedTagTitleColor : tagTitleColor; @@ -215,9 +227,12 @@ class _BrnMultiSelectTagsState extends State { }, child: Container( constraints: BoxConstraints(minWidth: widget.minWidth ?? 75), - decoration: BoxDecoration(color: bgColor, borderRadius: BorderRadius.circular(3.0)), + decoration: BoxDecoration( + color: bgColor, borderRadius: BorderRadius.circular(3.0)), padding: padding, - alignment: widget.tagStyle == BrnMultiSelectStyle.average ? Alignment.center : null, + alignment: widget.tagStyle == BrnMultiSelectStyle.average + ? Alignment.center + : null, child: Text( textToDisplay, textAlign: TextAlign.center, diff --git a/lib/src/components/button/brn_big_ghost_button.dart b/lib/src/components/button/brn_big_ghost_button.dart index ca345bce..9722e302 100644 --- a/lib/src/components/button/brn_big_ghost_button.dart +++ b/lib/src/components/button/brn_big_ghost_button.dart @@ -63,8 +63,8 @@ class BrnBigGhostButton extends StatelessWidget { constraints: BoxConstraints.tightFor( width: width ?? double.infinity, height: defaultThemeConfig.bigButtonHeight), - backgroundColor: - bgColor ?? defaultThemeConfig.commonConfig.brandPrimary.withOpacity(0.05), + backgroundColor: bgColor ?? + defaultThemeConfig.commonConfig.brandPrimary.withOpacity(0.05), onTap: onTap, alignment: Alignment.center, text: title ?? '确认', diff --git a/lib/src/components/button/brn_big_outline_button.dart b/lib/src/components/button/brn_big_outline_button.dart index 883d0bdb..9940fe9d 100644 --- a/lib/src/components/button/brn_big_outline_button.dart +++ b/lib/src/components/button/brn_big_outline_button.dart @@ -29,8 +29,10 @@ import 'package:flutter/material.dart'; /// 默认水平间距 const double _BHorizontalPadding = 16; + /// 默认垂直间距 const double _BVerticalPadding = 8; + /// 默认线宽 const double _BBorderWith = 1; @@ -74,7 +76,8 @@ class BrnBigOutlineButton extends StatelessWidget { .buttonConfig .merge(defaultThemeConfig); - Color _lineColor = lineColor ?? defaultThemeConfig.commonConfig.borderColorBase; + Color _lineColor = + lineColor ?? defaultThemeConfig.commonConfig.borderColorBase; return BrnNormalButton.outline( borderWith: _BBorderWith, @@ -92,7 +95,8 @@ class BrnBigOutlineButton extends StatelessWidget { width: width ?? double.infinity, height: defaultThemeConfig.bigButtonHeight), onTap: onTap, - insertPadding: EdgeInsets.symmetric(vertical: _BVerticalPadding, horizontal: _BHorizontalPadding), + insertPadding: EdgeInsets.symmetric( + vertical: _BVerticalPadding, horizontal: _BHorizontalPadding), backgroundColor: Colors.white, disableBackgroundColor: Color(0xffcccccc).withOpacity(0.1), ); diff --git a/lib/src/components/button/brn_small_main_button.dart b/lib/src/components/button/brn_small_main_button.dart index df8c50b8..93801488 100644 --- a/lib/src/components/button/brn_small_main_button.dart +++ b/lib/src/components/button/brn_small_main_button.dart @@ -68,8 +68,7 @@ class BrnSmallMainButton extends StatelessWidget { Widget build(BuildContext context) { BrnButtonConfig defaultThemeConfig = themeData ?? BrnButtonConfig(); defaultThemeConfig = defaultThemeConfig.merge(BrnButtonConfig( - smallButtonFontSize: fontSize, - smallButtonRadius: radius)); + smallButtonFontSize: fontSize, smallButtonRadius: radius)); defaultThemeConfig = BrnThemeConfigurator.instance .getConfig(configId: defaultThemeConfig.configId) @@ -92,7 +91,7 @@ class BrnSmallMainButton extends StatelessWidget { double textWidth = textPainter.width; //按钮本身大小 double _maxWidth = textWidth + _BHorizontalPadding * 2; - double _minWidth = min(_BMinWidth,con.maxWidth); + double _minWidth = min(_BMinWidth, con.maxWidth); //保证最小宽度是 (84、可用空间)的最小值 if (_maxWidth <= _minWidth) { diff --git a/lib/src/components/button/brn_small_outline_button.dart b/lib/src/components/button/brn_small_outline_button.dart index 65fcd5fb..bfda7d0b 100644 --- a/lib/src/components/button/brn_small_outline_button.dart +++ b/lib/src/components/button/brn_small_outline_button.dart @@ -19,13 +19,15 @@ Color normalColor = Color(0xffF0F0F0); /// 其他按钮如下: /// * [BrnSmallMainButton], 小主色调按钮 - /// 默认水平间距 const double _BHorizontalPadding = 6; + /// 默认垂直间距 const double _BVerticalPadding = 8; + /// 默认最小宽度 const double _BMinWidth = 84; + /// 默认线宽 const double _BBorderWith = 1; @@ -79,8 +81,9 @@ class BrnSmallOutlineButton extends StatelessWidget { BrnButtonConfig defaultThemeConfig = themeData ?? BrnButtonConfig(); defaultThemeConfig = defaultThemeConfig.merge(BrnButtonConfig( - smallButtonFontSize: fontSize, - smallButtonRadius: radius,)); + smallButtonFontSize: fontSize, + smallButtonRadius: radius, + )); defaultThemeConfig = BrnThemeConfigurator.instance .getConfig(configId: defaultThemeConfig.configId) .buttonConfig diff --git a/lib/src/components/button/collection/brn_bottom_button_panel.dart b/lib/src/components/button/collection/brn_bottom_button_panel.dart index 182349f0..05f9486a 100644 --- a/lib/src/components/button/collection/brn_bottom_button_panel.dart +++ b/lib/src/components/button/collection/brn_bottom_button_panel.dart @@ -106,7 +106,8 @@ class BrnBottomButtonPanel extends StatelessWidget { VoidCallback secondaryButtonOnTap, bool enableMainButton = true, List iconButtonList}) { - if ((buttonTitleList == null || buttonTitleList.isEmpty) && iconButtonList == null) { + if ((buttonTitleList == null || buttonTitleList.isEmpty) && + iconButtonList == null) { return Container( height: 0, width: 0, @@ -210,7 +211,10 @@ class BrnBottomButtonPanel extends StatelessWidget { padding: EdgeInsets.only(left: 8, right: 8, top: 6, bottom: 6), decoration: BoxDecoration( color: enableSecondaryButton - ? BrnThemeConfigurator.instance.getConfig().commonConfig.brandAuxiliary + ? BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandAuxiliary : Color(0xFFCCCCCC), borderRadius: BorderRadius.all(Radius.circular(6.0)), ), @@ -250,7 +254,10 @@ class BrnBottomButtonPanel extends StatelessWidget { padding: EdgeInsets.only(left: 8, right: 8, top: 6, bottom: 6), decoration: BoxDecoration( color: enableMainButton - ? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary + ? BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary : Color(0xFFCCCCCC), borderRadius: BorderRadius.all(Radius.circular(6.0)), ), @@ -277,7 +284,8 @@ class BrnBottomButtonPanel extends StatelessWidget { return Expanded( child: Padding( - padding: EdgeInsets.only(left: (_isEmptyIcon() && _isEmptySecondary()) ? 12 : 8), + padding: EdgeInsets.only( + left: (_isEmptyIcon() && _isEmptySecondary()) ? 12 : 8), child: mainWidget, ), ); diff --git a/lib/src/components/button/collection/brn_button_panel.dart b/lib/src/components/button/collection/brn_button_panel.dart index 9b3e4ce8..3ec50256 100644 --- a/lib/src/components/button/collection/brn_button_panel.dart +++ b/lib/src/components/button/collection/brn_button_panel.dart @@ -191,8 +191,7 @@ class _BrnButtonPanelState extends State { ), key: _popWindowKey, onTap: () { - BrnPopupListWindow.showButtonPanelPopList( - context, _popWindowKey, + BrnPopupListWindow.showButtonPanelPopList(context, _popWindowKey, data: list, itemBuilder: (int index, String item) { return Text(item, diff --git a/lib/src/components/button/collection/brn_multiple_bottom_button.dart b/lib/src/components/button/collection/brn_multiple_bottom_button.dart index 7ce68d0a..61ca51b7 100644 --- a/lib/src/components/button/collection/brn_multiple_bottom_button.dart +++ b/lib/src/components/button/collection/brn_multiple_bottom_button.dart @@ -47,20 +47,21 @@ class BrnMultipleBottomButton extends StatefulWidget { /// 暴露给外界设置多选状态的控制器 final BrnMultipleBottomController bottomController; -const BrnMultipleBottomButton( - {Key key, - this.mainButton, - this.subButton, - this.onMainButtonTap, - this.onSubButtonTap, - this.onSelectedButtonTap, - this.onSelectAll, - this.hasArrow = false, - this.bottomController}) + const BrnMultipleBottomButton( + {Key key, + this.mainButton, + this.subButton, + this.onMainButtonTap, + this.onSubButtonTap, + this.onSelectedButtonTap, + this.onSelectAll, + this.hasArrow = false, + this.bottomController}) : super(key: key); @override - _BrnMultipleBottomButtonState createState() => _BrnMultipleBottomButtonState(); + _BrnMultipleBottomButtonState createState() => + _BrnMultipleBottomButtonState(); } class _BrnMultipleBottomButtonState extends State { @@ -95,7 +96,8 @@ class _BrnMultipleBottomButtonState extends State { ? GestureDetector( onTap: () { //点击全选将当前状态置反,回调到外界,行为与单独点击圆圈保持一致 - bool currentState = !_controller.valueNotifier.value.selectAllState; + bool currentState = + !_controller.valueNotifier.value.selectAllState; _controller.setState(selectAllState: currentState); if (widget.onSelectAll != null) widget.onSelectAll(currentState); }, @@ -115,7 +117,8 @@ class _BrnMultipleBottomButtonState extends State { onValueChangedAtIndex: (index, value) { //同步到外界的当前的全选状态 _controller.setState(selectAllState: value); - if (widget.onSelectAll != null) widget.onSelectAll(value); + if (widget.onSelectAll != null) + widget.onSelectAll(value); }, key: Key(DateTime.now().toString()), ); @@ -136,13 +139,15 @@ class _BrnMultipleBottomButtonState extends State { } Widget _selectedCountWidget() { - Image unfoldWidget = BrunoTools.getAssetImageWithColor(BrnAsset.ICON_SELECTED_UP_TRIANGLE, + Image unfoldWidget = BrunoTools.getAssetImageWithColor( + BrnAsset.ICON_SELECTED_UP_TRIANGLE, BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary); - Image foldWidget = BrunoTools.getAssetImage(BrnAsset.ICON_UNSELECT_DOWN_TRIANGLE); + Image foldWidget = + BrunoTools.getAssetImage(BrnAsset.ICON_UNSELECT_DOWN_TRIANGLE); - Image cantFoldWidget = - BrunoTools.getAssetImageWithColor(BrnAsset.ICON_UNSELECT_DOWN_TRIANGLE, Color(0XCCCCCCCC)); + Image cantFoldWidget = BrunoTools.getAssetImageWithColor( + BrnAsset.ICON_UNSELECT_DOWN_TRIANGLE, Color(0XCCCCCCCC)); return GestureDetector( onTap: () { @@ -150,7 +155,8 @@ class _BrnMultipleBottomButtonState extends State { if (widget.onSelectedButtonTap != null) { if (_controller.valueNotifier.value.selectedCount == 0) { _unfoldState = false; - widget.onSelectedButtonTap(BrnMultipleButtonArrowState.cantUnfold); + widget + .onSelectedButtonTap(BrnMultipleButtonArrowState.cantUnfold); return; } _unfoldState = !_unfoldState; @@ -178,13 +184,17 @@ class _BrnMultipleBottomButtonState extends State { '(${value.selectedCount})', style: TextStyle( color: value.selectedCount != 0 - ? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary + ? BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary : Color(0x99999999), fontSize: 16), )); if (value.selectedCount == 0) _unfoldState = false; if (widget.hasArrow) { - if (value.arrowStatus != BrnMultipleButtonArrowState.defaultStatus) { + if (value.arrowStatus != + BrnMultipleButtonArrowState.defaultStatus) { //使用方主动设置箭头状态的时候 Widget arrow; switch (value.arrowStatus) { @@ -201,8 +211,10 @@ class _BrnMultipleBottomButtonState extends State { break; } //重置unfold的状态,避免主动设置箭头方向后,影响原本逻辑 - _unfoldState = value.arrowStatus == BrnMultipleButtonArrowState.fold; - value.arrowStatus = BrnMultipleButtonArrowState.defaultStatus; + _unfoldState = + value.arrowStatus == BrnMultipleButtonArrowState.fold; + value.arrowStatus = + BrnMultipleButtonArrowState.defaultStatus; rowChildren.add(Container( margin: EdgeInsets.only(left: 2, top: 2), @@ -214,7 +226,9 @@ class _BrnMultipleBottomButtonState extends State { rowChildren.add(Container( margin: EdgeInsets.only(left: 2, top: 2), width: 6, - child: value.selectedCount == 0 ? cantFoldWidget : foldWidget, + child: value.selectedCount == 0 + ? cantFoldWidget + : foldWidget, )); } else { rowChildren.add(Container( @@ -261,14 +275,19 @@ class _BrnMultipleBottomButtonState extends State { decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(4)), color: value.mainButtonState - ? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary + ? BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary : Color(0xFFCCCCCC)), child: widget.mainButton is String ? Center( child: Text( widget.mainButton, style: TextStyle( - color: value.mainButtonState ? Colors.white : Color(0xAAFFFFFF), + color: value.mainButtonState + ? Colors.white + : Color(0xAAFFFFFF), fontSize: 16, fontWeight: FontWeight.w600), overflow: TextOverflow.ellipsis, @@ -299,14 +318,19 @@ class _BrnMultipleBottomButtonState extends State { decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(4)), color: value.subButtonState - ? BrnThemeConfigurator.instance.getConfig().commonConfig.brandAuxiliary + ? BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandAuxiliary : Color(0xFFCCCCCC)), child: widget.subButton is String ? Center( child: Text( widget.subButton, style: TextStyle( - color: value.subButtonState ? Colors.white : Color(0xAAFFFFFF), + color: value.subButtonState + ? Colors.white + : Color(0xAAFFFFFF), fontSize: 16, fontWeight: FontWeight.w600), overflow: TextOverflow.ellipsis, @@ -347,7 +371,8 @@ class BrnMultipleBottomController { MultiSelectState data = MultiSelectState( selectedCount: selectedCount ?? valueNotifier?.value?.selectedCount, selectAllState: selectAllState ?? valueNotifier?.value?.selectAllState, - mainButtonState: mainButtonState ?? valueNotifier?.value?.mainButtonState, + mainButtonState: + mainButtonState ?? valueNotifier?.value?.mainButtonState, subButtonState: subButtonState ?? valueNotifier?.value?.subButtonState, arrowStatus: arrowStatus ?? valueNotifier?.value?.arrowStatus); valueNotifier.value = data; diff --git a/lib/src/components/button/collection/brn_text_button_panel.dart b/lib/src/components/button/collection/brn_text_button_panel.dart index 9b1b43b0..64b324d1 100644 --- a/lib/src/components/button/collection/brn_text_button_panel.dart +++ b/lib/src/components/button/collection/brn_text_button_panel.dart @@ -172,19 +172,15 @@ class _BrnTextButtonPanelState extends State { BrnPopupListWindow.showPopListWindow(context, _popWindowKey, offset: 10, popDirection: widget.popDirection, - - data: list, - onItemClick: (index, item) { - if (widget.onTap != null) { - widget.onTap(index + 3); - } - }, - - onDismiss: () { - setState(() { - _isExpanded = false; - }); - }); + data: list, onItemClick: (index, item) { + if (widget.onTap != null) { + widget.onTap(index + 3); + } + }, onDismiss: () { + setState(() { + _isExpanded = false; + }); + }); setState(() { _isExpanded = true; }); diff --git a/lib/src/components/card/bubble_card/brn_bubble_text.dart b/lib/src/components/card/bubble_card/brn_bubble_text.dart index eaa6b6d7..0af90b23 100644 --- a/lib/src/components/card/bubble_card/brn_bubble_text.dart +++ b/lib/src/components/card/bubble_card/brn_bubble_text.dart @@ -40,7 +40,8 @@ class BrnBubbleText extends StatelessWidget { ///气泡的圆角 默认是4 final double radius; - const BrnBubbleText({Key key, this.text, this.maxLines, this.onExpanded, this.radius = 4}) + const BrnBubbleText( + {Key key, this.text, this.maxLines, this.onExpanded, this.radius = 4}) : super(key: key); @override @@ -81,7 +82,10 @@ class BrnBubbleText extends StatelessWidget { textStyle: TextStyle( fontWeight: FontWeight.w500, fontSize: 14, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, ), ), ), diff --git a/lib/src/components/card/bubble_card/brn_insert_info.dart b/lib/src/components/card/bubble_card/brn_insert_info.dart index e5ffbb9d..2a402468 100644 --- a/lib/src/components/card/bubble_card/brn_insert_info.dart +++ b/lib/src/components/card/bubble_card/brn_insert_info.dart @@ -26,7 +26,8 @@ class BrnInsertInfo extends StatelessWidget { final String infoText; final int maxLines; - const BrnInsertInfo({Key key, @required this.infoText, this.maxLines = 2}) : super(key: key); + const BrnInsertInfo({Key key, @required this.infoText, this.maxLines = 2}) + : super(key: key); @override Widget build(BuildContext context) { @@ -37,7 +38,10 @@ class BrnInsertInfo extends StatelessWidget { style: TextStyle( fontWeight: FontWeight.w500, fontSize: 14, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, ), ); diff --git a/lib/src/components/card/content_card/brn_enhance_number_card.dart b/lib/src/components/card/content_card/brn_enhance_number_card.dart index 79a1b4fa..7e60a8bc 100644 --- a/lib/src/components/card/content_card/brn_enhance_number_card.dart +++ b/lib/src/components/card/content_card/brn_enhance_number_card.dart @@ -82,7 +82,8 @@ class BrnEnhanceNumberCard extends StatelessWidget { this.rowCount = 3, this.runningSpace, this.itemRunningSpace, - this.padding = const EdgeInsets.only(left: 20, right: 20), this.backgroundColor = Colors.white, + this.padding = const EdgeInsets.only(left: 20, right: 20), + this.backgroundColor = Colors.white, this.itemTextAlign = TextAlign.left, this.themeData, }) : super(key: key); @@ -107,7 +108,6 @@ class BrnEnhanceNumberCard extends StatelessWidget { } return LayoutBuilder( builder: (context, constraints) { - Widget contentWidget = Container( height: 0, width: 0, @@ -143,11 +143,11 @@ class BrnEnhanceNumberCard extends StatelessWidget { // 每行的最后一个的 右边距,使用的是rightPadding的功能 Expanded( child: Padding( - padding: EdgeInsets.only( - left: isFirst ? 0 : 20, right: condition1 ? 0 : 20), - child: _buildItemWidget(data, defaultConfig, - width: singleWidth), - )), + padding: EdgeInsets.only( + left: isFirst ? 0 : 20, right: condition1 ? 0 : 20), + child: _buildItemWidget(data, defaultConfig, + width: singleWidth), + )), //分割线的显示规则是:固定高度47 // item之间显示,最后一个不显示 Visibility( diff --git a/lib/src/components/card/content_card/brn_pair_info_rich_grid.dart b/lib/src/components/card/content_card/brn_pair_info_rich_grid.dart index 8eb009b6..f9c9d7fd 100644 --- a/lib/src/components/card/content_card/brn_pair_info_rich_grid.dart +++ b/lib/src/components/card/content_card/brn_pair_info_rich_grid.dart @@ -80,7 +80,8 @@ class BrnRichInfoGrid extends StatelessWidget { } Widget _buildGridView(context) { - BrnPairRichInfoGridConfig defaultConfig = themeData ?? BrnPairRichInfoGridConfig(); + BrnPairRichInfoGridConfig defaultConfig = + themeData ?? BrnPairRichInfoGridConfig(); defaultConfig = defaultConfig.merge(BrnPairRichInfoGridConfig( itemSpacing: space, rowSpacing: rowSpace, itemHeight: itemHeight)); @@ -95,7 +96,8 @@ class BrnRichInfoGrid extends StatelessWidget { if (gridWidth == double.infinity) { gridWidth = MediaQuery.of(context).size.width; } - double itemHeight = defaultConfig.itemHeight * (MediaQuery.textScaleFactorOf(context)); + double itemHeight = + defaultConfig.itemHeight * (MediaQuery.textScaleFactorOf(context)); double itemWidth = (gridWidth - defaultConfig.itemSpacing) / 2; var gridView = GridView.builder( @@ -144,7 +146,9 @@ class BrnRichInfoGrid extends StatelessWidget { return Container( constraints: BoxConstraints(maxWidth: width / 4), child: Text(info.keyPart, - maxLines: 1, overflow: TextOverflow.ellipsis, style: _getKeyStyle(themeData: config)), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: _getKeyStyle(themeData: config)), ); } if (info.keyPart is Widget) { @@ -157,7 +161,8 @@ class BrnRichInfoGrid extends StatelessWidget { ); } - Widget _getValueWidget(BrnRichGridInfo info, BrnPairRichInfoGridConfig config) { + Widget _getValueWidget( + BrnRichGridInfo info, BrnPairRichInfoGridConfig config) { if (info == null) { return Container( height: 0, @@ -213,8 +218,8 @@ class BrnRichGridInfo { BrnPairRichInfoGridConfig themeData, }) { themeData ??= BrnPairRichInfoGridConfig(); - themeData = themeData - .merge(BrnPairRichInfoGridConfig(linkTextStyle: BrnTextStyle(color: clickColor))); + themeData = themeData.merge(BrnPairRichInfoGridConfig( + linkTextStyle: BrnTextStyle(color: clickColor))); themeData = BrnThemeConfigurator.instance .getConfig(configId: themeData.configId) .pairRichInfoGridConfig @@ -231,7 +236,8 @@ class BrnRichGridInfo { }, child: Padding( padding: EdgeInsets.only(left: isKey ? 0 : 4), - child: BrunoTools.getAssetSizeImage(BrnAsset.ICON_PAIR_INFO_QUESTION, 14, 14), + child: BrunoTools.getAssetSizeImage( + BrnAsset.ICON_PAIR_INFO_QUESTION, 14, 14), )); } @@ -249,7 +255,8 @@ class BrnRichGridInfo { child: Text(clickTitle, maxLines: 1, overflow: TextOverflow.ellipsis, - style: _getClickStyle(clickTitle, clickColor, themeData: themeData)), + style: _getClickStyle(clickTitle, clickColor, + themeData: themeData)), ), ), ); @@ -334,5 +341,6 @@ TextStyle _getClickStyle(String content, Color clickColor, {BrnPairRichInfoGridConfig themeData}) => themeData.linkTextStyle?.generateTextStyle(); -TextStyle _getValueStyle(String content, {BrnPairRichInfoGridConfig themeData}) => +TextStyle _getValueStyle(String content, + {BrnPairRichInfoGridConfig themeData}) => themeData?.valueTextStyle?.generateTextStyle(); diff --git a/lib/src/components/card/shadow_card/brn_shadow_card.dart b/lib/src/components/card/shadow_card/brn_shadow_card.dart index a85dee19..c68fda31 100644 --- a/lib/src/components/card/shadow_card/brn_shadow_card.dart +++ b/lib/src/components/card/shadow_card/brn_shadow_card.dart @@ -64,7 +64,10 @@ class BrnShadowCard extends StatelessWidget { borderRadius: BorderRadius.all(Radius.circular(circular)), border: tempBorderWidth != 0 ? Border.all( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.dividerColorBase, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .dividerColorBase, width: tempBorderWidth) : Border.all(style: BorderStyle.none), boxShadow: [ diff --git a/lib/src/components/card_title/brn_action_card_title.dart b/lib/src/components/card_title/brn_action_card_title.dart index 1a4564cf..f483e641 100644 --- a/lib/src/components/card_title/brn_action_card_title.dart +++ b/lib/src/components/card_title/brn_action_card_title.dart @@ -130,7 +130,9 @@ class BrnActionCardTitle extends StatelessWidget { return Container( constraints: BoxConstraints(maxWidth: 84), child: Text(this.subTitle, - maxLines: 1, overflow: TextOverflow.ellipsis, style: subTextStyle(defaultConfig)), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: subTextStyle(defaultConfig)), ); } diff --git a/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart.dart b/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart.dart index ad3fa4d0..e27cc652 100644 --- a/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart.dart +++ b/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart.dart @@ -34,7 +34,8 @@ class BrnDoughnutDataItem { } /// 选中扇形区域后执行的回调 -typedef BrnDoughnutSelectCallback = void Function(BrnDoughnutDataItem selectedItem); +typedef BrnDoughnutSelectCallback = void Function( + BrnDoughnutDataItem selectedItem); class BrnDoughnut extends CustomPainter { ///圆心位置 @@ -96,8 +97,9 @@ class BrnDoughnut extends CustomPainter { void paint(Canvas canvas, Size size) { double minLength = size.width < size.height ? size.width : size.height; double outterCircleRadius = minLength / 2; - double innerCircleRadius = - outterCircleRadius - this.ringWidth >= 0 ? outterCircleRadius - this.ringWidth : 30.0; + double innerCircleRadius = outterCircleRadius - this.ringWidth >= 0 + ? outterCircleRadius - this.ringWidth + : 30.0; double indicatorLCircleRadius = outterCircleRadius - 5; double indicatorRCircleRadius = outterCircleRadius + 8; @@ -123,10 +125,13 @@ class BrnDoughnut extends CustomPainter { // 画文本 if (item.title != null && - (this.showTitleWhenSelected == false || item.startRadius == selectedItem?.startRadius)) { + (this.showTitleWhenSelected == false || + item.startRadius == selectedItem?.startRadius)) { // 画引线 - Offset indicarorLPoint = calcOffsetWith(item.middleRadius, indicatorLCircleRadius); - Offset indicatorRPoint = calcOffsetWith(item.middleRadius, indicatorRCircleRadius); + Offset indicarorLPoint = + calcOffsetWith(item.middleRadius, indicatorLCircleRadius); + Offset indicatorRPoint = + calcOffsetWith(item.middleRadius, indicatorRCircleRadius); Offset revisedIndicarorLPoint = Offset( indicarorLPoint.dx + center.dx.roundToDouble(), indicarorLPoint.dy + center.dy.roundToDouble(), @@ -142,17 +147,21 @@ class BrnDoughnut extends CustomPainter { ..isAntiAlias = true ..strokeWidth = 1 ..style = PaintingStyle.fill; - canvas.drawLine(revisedIndicarorLPoint, revisedIndicatorRPoint, _paintIndicator); + canvas.drawLine( + revisedIndicarorLPoint, revisedIndicatorRPoint, _paintIndicator); /// 画水平线 - Offset indicatorEndOffset = - calcHorizontalOffset(revisedIndicarorLPoint, revisedIndicatorRPoint); - canvas.drawLine(revisedIndicatorRPoint, indicatorEndOffset, _paintIndicator); + Offset indicatorEndOffset = calcHorizontalOffset( + revisedIndicarorLPoint, revisedIndicatorRPoint); + canvas.drawLine( + revisedIndicatorRPoint, indicatorEndOffset, _paintIndicator); - TextStyle textStyle = TextStyle(fontSize: this.fontSize, color: this.fontColor); + TextStyle textStyle = + TextStyle(fontSize: this.fontSize, color: this.fontColor); TextPainter textPainter = TextPainter( - text: TextSpan(text: item.title, style: textStyle), textDirection: TextDirection.ltr) + text: TextSpan(text: item.title, style: textStyle), + textDirection: TextDirection.ltr) ..layout(maxWidth: double.infinity, minWidth: 0); double textWidth = textPainter.size.width; @@ -161,15 +170,20 @@ class BrnDoughnut extends CustomPainter { //画背景 Offset baseRectCenter = Offset( indicatorEndOffset.dx > revisedIndicatorRPoint.dx - ? indicatorEndOffset.dx + textWidth / 2 + this.textHorizontalPadding - : indicatorEndOffset.dx - textWidth / 2 - this.textHorizontalPadding, + ? indicatorEndOffset.dx + + textWidth / 2 + + this.textHorizontalPadding + : indicatorEndOffset.dx - + textWidth / 2 - + this.textHorizontalPadding, indicatorEndOffset.dy); Rect baseRect = Rect.fromCenter( center: baseRectCenter, width: textWidth + this.textHorizontalPadding * 2, height: textHeight + this.textVerticalPadding * 2); RRect rRect = RRect.fromRectAndRadius(baseRect, Radius.circular(2)); - Paint textBackgroundPaint = Paint()..color = Colors.black.withOpacity(0.7); + Paint textBackgroundPaint = Paint() + ..color = Colors.black.withOpacity(0.7); canvas.drawRRect(rRect, textBackgroundPaint); textPainter.paint( @@ -219,9 +233,11 @@ class BrnDoughnut extends CustomPainter { for (int i = 0; i < length; i++) { BrnDoughnutDataItem item = data[i]; double radain = pointRadianInSector(position); - if (item.startRadius < radain && radain < (item.startRadius + item.radius)) { + if (item.startRadius < radain && + radain < (item.startRadius + item.radius)) { if (null != brnDoughnutSelectCallback) - brnDoughnutSelectCallback(item.startRadius == selectedItem?.startRadius ? null : item); + brnDoughnutSelectCallback( + item.startRadius == selectedItem?.startRadius ? null : item); break; } } @@ -230,9 +246,10 @@ class BrnDoughnut extends CustomPainter { } double pointRadianInSector(Offset position) { - Offset relativePosition = Offset(position.dx - circleCenter.dx, position.dy - circleCenter.dy); - double round = - acos(relativePosition.dx / sqrt(pow(relativePosition.dx, 2) + pow(relativePosition.dy, 2))); + Offset relativePosition = + Offset(position.dx - circleCenter.dx, position.dy - circleCenter.dy); + double round = acos(relativePosition.dx / + sqrt(pow(relativePosition.dx, 2) + pow(relativePosition.dy, 2))); double revisedRadian = round; if (relativePosition.dy < 0) { revisedRadian = 2 * pi - round; diff --git a/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart_legend.dart b/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart_legend.dart index 9d69fa11..a5c4c8fa 100644 --- a/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart_legend.dart +++ b/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart_legend.dart @@ -23,7 +23,8 @@ class DoughnutChartLegend extends StatelessWidget { /// 图例展示所用数据 final List data; - DoughnutChartLegend({this.legendStyle = BrnDoughnutChartLegendStyle.wrap, this.data}); + DoughnutChartLegend( + {this.legendStyle = BrnDoughnutChartLegendStyle.wrap, this.data}); @override Widget build(BuildContext context) { diff --git a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart index 0ce54cd7..df33b1ee 100644 --- a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart +++ b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart @@ -100,23 +100,28 @@ class BrnProgressBarChartState extends State { int numberOfBars = widget.barBundleList[0].barList.length; if (BarChartStyle.horizontal == widget.barChartStyle) { double height = widget.yAxis.leadingSpace + - (widget.singleBarWidth * barBundleCount + widget.barGroupSpace) * numberOfBars; + (widget.singleBarWidth * barBundleCount + widget.barGroupSpace) * + numberOfBars; ///有 x 轴 需要加上 x 轴占用的高度 - if (null != widget.xAxis?.axisItemList && 0 < widget.xAxis.axisItemList.length) { + if (null != widget.xAxis?.axisItemList && + 0 < widget.xAxis.axisItemList.length) { height += 22; } double width = MediaQuery.of(context).size.width; return Size(width, height); } else if (BarChartStyle.vertical == widget.barChartStyle) { double width = widget.xAxis.leadingSpace + - (widget.singleBarWidth * barBundleCount + widget.barGroupSpace) * numberOfBars; + (widget.singleBarWidth * barBundleCount + widget.barGroupSpace) * + numberOfBars; /// 有 y 轴需要加上 y 轴占用的宽度 - if (null != widget.yAxis?.axisItemList && 0 < widget.yAxis.axisItemList.length) { + if (null != widget.yAxis?.axisItemList && + 0 < widget.yAxis.axisItemList.length) { width += BrnProgressBarChartPainter.maxYAxisWidth(widget.yAxis); } - return Size(widget.minWidth > width ? widget.minWidth : width, widget.height ?? 300); + return Size(widget.minWidth > width ? widget.minWidth : width, + widget.height ?? 300); } else { return Size.zero; } @@ -169,7 +174,8 @@ class BrnProgressBarChartState extends State { return Container(); } if (BarChartStyle.vertical == widget.barChartStyle) { - double yAxisWidth = BrnProgressBarChartPainter.maxYAxisWidth(widget.yAxis); + double yAxisWidth = + BrnProgressBarChartPainter.maxYAxisWidth(widget.yAxis); return Padding( padding: widget.padding, child: Stack( @@ -203,11 +209,14 @@ class BrnProgressBarChartState extends State { barMaxValue: widget.barMaxValue, barGroupSpace: widget.barGroupSpace, barBundleList: widget.barBundleList, - onBarItemClickInterceptor: widget.onBarItemClickInterceptor, + onBarItemClickInterceptor: + widget.onBarItemClickInterceptor, selectedBarItem: _selectedBarItem, selectedHintTextColor: widget.selectedHintTextColor, - selectedHintTextBackgroundColor: widget.selectedHintTextBackgroundColor, - brnProgressBarChartSelectCallback: (BrnProgressBarItem item) { + selectedHintTextBackgroundColor: + widget.selectedHintTextBackgroundColor, + brnProgressBarChartSelectCallback: + (BrnProgressBarItem item) { if (null != widget.barChartSelectCallback) widget.barChartSelectCallback(item); setState(() { diff --git a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart index 2823ae28..d1f52385 100644 --- a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart +++ b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart @@ -58,12 +58,15 @@ class ChartAxis { /// 是否有刻度 final bool hasMark; + /// 实线/虚线/无 final AxisStyle axisStyle; + /// 两个刻度间距 double space; double maxTextHeight = 0; double maxTextWidth = 0; + /// 0/刻度偏移量 double leadingSpace = 30; TextStyle textStyle = TextStyle(color: Color(0x999999), fontSize: 12); diff --git a/lib/src/components/charts/brn_progress_chart/brn_progress_chart.dart b/lib/src/components/charts/brn_progress_chart/brn_progress_chart.dart index 034c48f1..d1a9ca59 100644 --- a/lib/src/components/charts/brn_progress_chart/brn_progress_chart.dart +++ b/lib/src/components/charts/brn_progress_chart/brn_progress_chart.dart @@ -2,7 +2,8 @@ import 'package:bruno/src/components/charts/brn_progress_chart/brn_progress_char import 'package:flutter/material.dart'; /// 在进度条上展示的 Widget -typedef BrnProgressIndicatorBuilder = Widget Function(BuildContext context, double value); +typedef BrnProgressIndicatorBuilder = Widget Function( + BuildContext context, double value); /// 一个简单的进度条 Widget,支持数据变化时的动画 class BrnProgressChart extends StatefulWidget { @@ -53,7 +54,8 @@ class BrnProgressChart extends StatefulWidget { } } -class BrnProgressChartState extends State with SingleTickerProviderStateMixin { +class BrnProgressChartState extends State + with SingleTickerProviderStateMixin { Animation _animation; AnimationController _animationController; double _value = 0; @@ -62,8 +64,8 @@ class BrnProgressChartState extends State with SingleTickerPro void initState() { super.initState(); if (widget.showAnimation) { - _animationController = - AnimationController(vsync: this, duration: Duration(milliseconds: 250)); + _animationController = AnimationController( + vsync: this, duration: Duration(milliseconds: 250)); Tween tween = Tween(begin: 0, end: widget.value); _animation = tween.animate(_animationController); _animation.addListener(() { diff --git a/lib/src/components/charts/brn_progress_chart/brn_progress_chart_painter.dart b/lib/src/components/charts/brn_progress_chart/brn_progress_chart_painter.dart index 75f84da0..de391f0d 100644 --- a/lib/src/components/charts/brn_progress_chart/brn_progress_chart_painter.dart +++ b/lib/src/components/charts/brn_progress_chart/brn_progress_chart_painter.dart @@ -42,15 +42,18 @@ class BrnProgressChartPainter extends CustomPainter { Rect progressBarRect = Rect.fromLTWH(0, 0, size.width * value, size.height); RRect progressBarRRect = RRect.fromRectAndCorners(progressBarRect, - bottomRight: - Radius.circular(1 == value && false == this.alwaysShowRadius ? 0 : this.radius), - topRight: Radius.circular(1 == value && false == this.alwaysShowRadius ? 0 : this.radius)); + bottomRight: Radius.circular( + 1 == value && false == this.alwaysShowRadius ? 0 : this.radius), + topRight: Radius.circular( + 1 == value && false == this.alwaysShowRadius ? 0 : this.radius)); Shader progressBarShader = LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, tileMode: TileMode.clamp, - colors: (this.colors.length > 1) ? this.colors : [this.colors[0], this.colors[0]]) + colors: (this.colors.length > 1) + ? this.colors + : [this.colors[0], this.colors[0]]) .createShader(progressBarRect); Paint progressBarPaint = Paint()..shader = progressBarShader; diff --git a/lib/src/components/charts/broken_line/brn_broken_line.dart b/lib/src/components/charts/broken_line/brn_broken_line.dart index fc152640..c8ddbc0e 100644 --- a/lib/src/components/charts/broken_line/brn_broken_line.dart +++ b/lib/src/components/charts/broken_line/brn_broken_line.dart @@ -184,14 +184,16 @@ class BrnBrokenLineState extends State { child: GestureDetector( onPanDown: (DragDownDetails e) { for (var i = 0; i < widget.lines[0].points.length; i++) { - int lineIndex = _lineWithXPainter.lineIndexCompute(e.localPosition, i); + int lineIndex = + _lineWithXPainter.lineIndexCompute(e.localPosition, i); if (lineIndex >= 0) { lineSelectIndex = lineIndex; pointSelectIndex = i; - Point selectedPoint = - _lineWithXPainter.selectedPoint(lineSelectIndex, pointSelectIndex); + Point selectedPoint = _lineWithXPainter.selectedPoint( + lineSelectIndex, pointSelectIndex); _fillLeftTopPoint( - widget.lines[lineSelectIndex].points[pointSelectIndex].lineTouchData, + widget.lines[lineSelectIndex].points[pointSelectIndex] + .lineTouchData, _lineWithXPainter.startX, _lineWithXPainter.endX, _lineWithXPainter.startY, @@ -219,8 +221,10 @@ class BrnBrokenLineState extends State { child: Stack(children: [ CustomPaint( size: widget.size, - painter: widget.backgroundColor == null ? _lineWithXPainter : null, - foregroundPainter: widget.backgroundColor != null ? _lineWithXPainter : null, + painter: + widget.backgroundColor == null ? _lineWithXPainter : null, + foregroundPainter: + widget.backgroundColor != null ? _lineWithXPainter : null, child: widget.backgroundColor != null ? Container( width: widget.size.width, @@ -230,7 +234,8 @@ class BrnBrokenLineState extends State { : null, ), (lineSelectIndex >= 0 && pointSelectIndex >= 0) - ? _buildTouchTipWidget(widget.lines[lineSelectIndex].points[pointSelectIndex]) + ? _buildTouchTipWidget( + widget.lines[lineSelectIndex].points[pointSelectIndex]) : Container(), ]), ), @@ -295,8 +300,14 @@ class BrnBrokenLineState extends State { return touchTipWidget; } - void _fillLeftTopPoint(BrnLineTouchData lineTouchData, double startX, double endX, double startY, - double endY, double fixedHeight, Point selectedPoint) { + void _fillLeftTopPoint( + BrnLineTouchData lineTouchData, + double startX, + double endX, + double startY, + double endY, + double fixedHeight, + Point selectedPoint) { if (selectedPoint == null || lineTouchData == null) return; if (pointSelectIndex < 0 && lineSelectIndex < 0) { diff --git a/lib/src/components/charts/broken_line/brn_line_data.dart b/lib/src/components/charts/broken_line/brn_line_data.dart index 7ce333b4..caa6bd33 100644 --- a/lib/src/components/charts/broken_line/brn_line_data.dart +++ b/lib/src/components/charts/broken_line/brn_line_data.dart @@ -47,7 +47,10 @@ class BrnPointData { pointTextStyle ??= TextStyle( fontWeight: FontWeight.w500, fontSize: 12, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase); + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase); } } @@ -73,7 +76,6 @@ class BrnLineTouchData { /// 每条线的定义 class BrnPointsLine { - /// 点集合 List points; @@ -110,7 +112,6 @@ class BrnPointsLine { /// 是否展示节点的文本 bool isShowPointText; - BrnPointsLine( {this.isShowXDial = false, this.lineWidth = 2, diff --git a/lib/src/components/charts/broken_line/brn_line_painter.dart b/lib/src/components/charts/broken_line/brn_line_painter.dart index 74e26a9a..6bae7ec4 100644 --- a/lib/src/components/charts/broken_line/brn_line_painter.dart +++ b/lib/src/components/charts/broken_line/brn_line_painter.dart @@ -63,7 +63,12 @@ class BrnLinePainter extends BrnBasePainter { double selectX; double selectY; - double _startX = 0.0, _endX = 0.0, _startY = 0.0, _endY = 0.0, _fixedHeight, _fixedWidth; + double _startX = 0.0, + _endX = 0.0, + _startY = 0.0, + _endY = 0.0, + _fixedHeight, + _fixedWidth; List _lineCanvasModels; List> _linePointPositions = List(); @@ -100,7 +105,8 @@ class BrnLinePainter extends BrnBasePainter { }) { if (xDialValues == null) { for (var i = 1; i < lines.length; i++) { - assert(lines[i - 1].points.length == lines[i].points.length, '折线${i - 1}和$i条线的节点数不一致'); + assert(lines[i - 1].points.length == lines[i].points.length, + '折线${i - 1}和$i条线的节点数不一致'); } } } @@ -150,9 +156,14 @@ class BrnLinePainter extends BrnBasePainter { } void _initValue() { - xDialColor ??= BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; - yDialColor ??= BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextSecondary; - hintLineColor ??= BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; + xDialColor ??= + BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; + yDialColor ??= BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextSecondary; + hintLineColor ??= + BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; hintLineSolid ??= true; xyLineWidth ??= 0.5; xDialMin ??= 0; @@ -189,19 +200,26 @@ class BrnLinePainter extends BrnBasePainter { if (xDialValues != null && xDialValues.isNotEmpty) { for (var i = 0; i < item.points.length; i++) { - var xPosition = - _startX + ((item.points[i].x - xDialMin) / (xDialMax - xDialMin) * _fixedWidth); - var yPosition = - _startY - ((item.points[i].y - yDialMin) / (yDialMax - yDialMin) * _fixedHeight); + var xPosition = _startX + + ((item.points[i].x - xDialMin) / + (xDialMax - xDialMin) * + _fixedWidth); + var yPosition = _startY - + ((item.points[i].y - yDialMin) / + (yDialMax - yDialMin) * + _fixedHeight); pointArr.add(Point(xPosition, yPosition)); } } else { var xScaleCount = item.points?.length ?? 0; - var W = _fixedWidth / (xScaleCount > 1 ? (xScaleCount - 1) : 1); //两个点之间的x方向距离 + var W = _fixedWidth / + (xScaleCount > 1 ? (xScaleCount - 1) : 1); //两个点之间的x方向距离 for (var i = 0; i < item.points.length; i++) { var xPosition = _startX + W * i; - var yPosition = - _startY - ((item.points[i].y - yDialMin) / (yDialMax - yDialMin) * _fixedHeight); + var yPosition = _startY - + ((item.points[i].y - yDialMin) / + (yDialMax - yDialMin) * + _fixedHeight); pointArr.add(Point(xPosition, yPosition)); } } @@ -253,7 +271,8 @@ class BrnLinePainter extends BrnBasePainter { Path _getSmoothLinePath(List points) { var targetPoints = List(); targetPoints.addAll(points); - targetPoints.add(Point(points[points.length - 1].x * 2, points[points.length - 1].y * 2)); + targetPoints.add(Point( + points[points.length - 1].x * 2, points[points.length - 1].y * 2)); var x0, y0, x1, y1, t0, path = Path(); for (int i = 0; i < targetPoints.length; i++) { var t1; @@ -268,7 +287,8 @@ class BrnLinePainter extends BrnBasePainter { break; case 2: t1 = MonotoneX.slope3(x0, y0, x1, y1, x, y); - MonotoneX.point(path, x0, y0, x1, y1, MonotoneX.slope2(x0, y0, x1, y1, t1), t1); + MonotoneX.point( + path, x0, y0, x1, y1, MonotoneX.slope2(x0, y0, x1, y1, t1), t1); break; default: t1 = MonotoneX.slope3(x0, y0, x1, y1, x, y); @@ -286,8 +306,8 @@ class BrnLinePainter extends BrnBasePainter { ///x,y轴 void _drawXy(Canvas canvas, Paint paint) { if (isShowHintY) { - canvas.drawLine(Offset(_startX, _startY), Offset(_startX, _endY - basePadding), - paint..color = yDialColor); //y轴 + canvas.drawLine(Offset(_startX, _startY), + Offset(_startX, _endY - basePadding), paint..color = yDialColor); //y轴 } if (lines != null && lines.isNotEmpty) { @@ -309,20 +329,26 @@ class BrnLinePainter extends BrnBasePainter { var tpX = TextPainter( textAlign: TextAlign.center, ellipsis: '.', - text: TextSpan(text: xDialValues[i].dialText, style: xDialValues[i].dialTextStyle), + text: TextSpan( + text: xDialValues[i].dialText, + style: xDialValues[i].dialTextStyle), textDirection: TextDirection.ltr) ..layout(); // 开始绘制刻度 _drawXRuleByPointPosition( tpX, canvas, - _startX + (xDialValues[i].value - xDialMin) / (xDialMax - xDialMin) * _fixedWidth, + _startX + + (xDialValues[i].value - xDialMin) / + (xDialMax - xDialMin) * + _fixedWidth, paint); } } } - void _drawXRuleByPointPosition(TextPainter tpX, Canvas canvas, double xPosition, Paint paint) { + void _drawXRuleByPointPosition( + TextPainter tpX, Canvas canvas, double xPosition, Paint paint) { tpX.paint(canvas, Offset(xPosition - tpX.width / 2, _startY + textPadding)); // 绘制与 X 轴对应的垂直辅助线 @@ -345,8 +371,8 @@ class BrnLinePainter extends BrnBasePainter { // 绘制 x轴刻度 if (isShowHintX) { - canvas.drawLine(Offset(xPosition, _startY), Offset(xPosition, _startY + rulerWidth), - paint..color = xDialColor); + canvas.drawLine(Offset(xPosition, _startY), + Offset(xPosition, _startY + rulerWidth), paint..color = xDialColor); } } @@ -361,7 +387,8 @@ class BrnLinePainter extends BrnBasePainter { end: Alignment.bottomCenter, tileMode: TileMode.clamp, colors: element.shaderColors) - .createShader(Rect.fromLTWH(_startX, _endY, _fixedWidth, _fixedHeight)); + .createShader( + Rect.fromLTWH(_startX, _endY, _fixedWidth, _fixedHeight)); canvas ..drawPath( shadowPathElement, @@ -398,7 +425,8 @@ class BrnLinePainter extends BrnBasePainter { ..style = PaintingStyle.stroke; //描边为居中描边 canvas.drawCircle( Offset(pointElement.x, pointElement.y), - (element.pointRadius - element.pointInnerRadius) / 2 + element.pointInnerRadius, + (element.pointRadius - element.pointInnerRadius) / 2 + + element.pointInnerRadius, pointPaint); }); @@ -414,10 +442,11 @@ class BrnLinePainter extends BrnBasePainter { ..strokeCap = StrokeCap.round ..color = color ..style = PaintingStyle.fill; - canvas.drawCircle( - Offset(pointElement.x, pointElement.y), element.pointInnerRadius, pointPaintBg); + canvas.drawCircle(Offset(pointElement.x, pointElement.y), + element.pointInnerRadius, pointPaintBg); - if (currentLineIndex == lineSelectIndex && currentPointIndex == pointSelectIndex) { + if (currentLineIndex == lineSelectIndex && + currentPointIndex == pointSelectIndex) { color = element.pointInnerColor; } var pointPaint = Paint() @@ -425,8 +454,8 @@ class BrnLinePainter extends BrnBasePainter { ..strokeCap = StrokeCap.round ..color = color ..style = PaintingStyle.fill; - canvas.drawCircle( - Offset(pointElement.x, pointElement.y), element.pointInnerRadius, pointPaint); + canvas.drawCircle(Offset(pointElement.x, pointElement.y), + element.pointInnerRadius, pointPaint); }); } }); @@ -452,7 +481,10 @@ class BrnLinePainter extends BrnBasePainter { dashArray: CircularIntervalList([4.0, 4.0]), ), paint - ..color = BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase + ..color = BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase ..strokeWidth = 1.0, ); @@ -462,7 +494,10 @@ class BrnLinePainter extends BrnBasePainter { dashArray: CircularIntervalList([4.0, 4.0]), ), paint - ..color = BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase + ..color = BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase ..strokeWidth = 1.0, ); } @@ -470,25 +505,31 @@ class BrnLinePainter extends BrnBasePainter { void _drawPointDisplayText(Canvas canvas) { if (_linePointPositions != null && _linePointPositions.isNotEmpty) { - for (int lineIndex = 0; lineIndex < _linePointPositions.length; lineIndex++) { + for (int lineIndex = 0; + lineIndex < _linePointPositions.length; + lineIndex++) { BrnPointsLine item = lines[lineIndex]; - if (item.isShowPointText && item.points != null && item.points.isNotEmpty) { + if (item.isShowPointText && + item.points != null && + item.points.isNotEmpty) { var length = item.points.length; for (var i = 0; i < length; i++) { - if (item.points[i].pointText == null || item.points[i].pointText.length == 0) { + if (item.points[i].pointText == null || + item.points[i].pointText.length == 0) { continue; } var tpX = TextPainter( textAlign: TextAlign.center, ellipsis: '.', text: TextSpan( - text: '${item.points[i].pointText}', style: item.points[i].pointTextStyle), + text: '${item.points[i].pointText}', + style: item.points[i].pointTextStyle), textDirection: TextDirection.ltr) ..layout(); - double adjustOffset = - isAdjustPosition(lineIndex, _linePointPositions[lineIndex][i], _linePointPositions) - ? (20 - tpX.height) - : -20; + double adjustOffset = isAdjustPosition(lineIndex, + _linePointPositions[lineIndex][i], _linePointPositions) + ? (20 - tpX.height) + : -20; tpX.paint( canvas, Offset( @@ -504,7 +545,8 @@ class BrnLinePainter extends BrnBasePainter { } } - bool isAdjustPosition(int lineIndex, Point currentPoint, List>> lines) { + bool isAdjustPosition( + int lineIndex, Point currentPoint, List>> lines) { List> sameXPoints = getSameXValuePoints(currentPoint, lines); if (sameXPoints.length > 0) { if (currentPoint.distanceTo(sameXPoints[0]) == 0) { @@ -516,13 +558,16 @@ class BrnLinePainter extends BrnBasePainter { return false; } - List> getSameXValuePoints(Point currentPoint, List>> lines) { + List> getSameXValuePoints( + Point currentPoint, List>> lines) { List> sameXPoints = List(); if (lines != null) { for (int lineIndex = 0; lineIndex < lines.length; lineIndex++) { List> linePoints = lines[lineIndex]; if (linePoints != null) { - for (int pointIndex = 0; pointIndex < linePoints.length; pointIndex++) { + for (int pointIndex = 0; + pointIndex < linePoints.length; + pointIndex++) { if (currentPoint.x == linePoints[pointIndex].x && currentPoint != linePoints[pointIndex]) { sameXPoints.add(linePoints[pointIndex]); diff --git a/lib/src/components/charts/broken_line/brn_line_y_painter.dart b/lib/src/components/charts/broken_line/brn_line_y_painter.dart index 1b7d0301..9a8e9d8f 100644 --- a/lib/src/components/charts/broken_line/brn_line_y_painter.dart +++ b/lib/src/components/charts/broken_line/brn_line_y_painter.dart @@ -97,9 +97,14 @@ class BrnLineYPainter extends BrnBasePainter { } void _initValue() { - xColor ??= BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; - yColor ??= BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextSecondary; - hintLineColor ??= BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; + xColor ??= + BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; + yColor ??= BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextSecondary; + hintLineColor ??= + BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; isHintLineSolid ??= true; xyLineWidth ??= 0.5; @@ -127,12 +132,12 @@ class BrnLineYPainter extends BrnBasePainter { /// x,y轴 void _drawXy(Canvas canvas, Paint paint) { if (isShowXHintLine) { - canvas.drawLine(Offset(_startX, _startY), Offset(_endX + _basePadding, _startY), - paint..color = xColor); //x轴 + canvas.drawLine(Offset(_startX, _startY), + Offset(_endX + _basePadding, _startY), paint..color = xColor); //x轴 } if (isShowYHintLine) { - canvas.drawLine(Offset(_startX, _startY), Offset(_startX, _endY - _basePadding), - paint..color = yColor); //y轴 + canvas.drawLine(Offset(_startX, _startY), + Offset(_startX, _endY - _basePadding), paint..color = yColor); //y轴 } _drawYRuler(canvas, paint); } @@ -151,12 +156,18 @@ class BrnLineYPainter extends BrnBasePainter { textAlign: TextAlign.right, ellipsis: '.', maxLines: 1, - text: TextSpan(text: '${ydialValue.dialText}', style: ydialValue.dialTextStyle), + text: TextSpan( + text: '${ydialValue.dialText}', style: ydialValue.dialTextStyle), textDirection: TextDirection.rtl) ..layout(); textY.paint( canvas, - Offset(_startX - (textY.width > yHintLineOffset ? yHintLineOffset : textY.width) - 6, + Offset( + _startX - + (textY.width > yHintLineOffset + ? yHintLineOffset + : textY.width) - + 6, _startY - yLength - textY.height / 2)); if (isShowXHintLine && yLength != 0) { @@ -171,7 +182,8 @@ class BrnLineYPainter extends BrnBasePainter { canvas.drawPath( dashPath( hitXPath, - dashArray: CircularIntervalList([4.0, 4.0]), //虚线和间隔 + dashArray: + CircularIntervalList([4.0, 4.0]), //虚线和间隔 ), paint..color = hintLineColor, ); @@ -180,8 +192,10 @@ class BrnLineYPainter extends BrnBasePainter { // y轴刻度 if (isShowYHintLine) { - canvas.drawLine(Offset(_startX, _startY - yLength), - Offset(_startX + rulerWidth, _startY - yLength), paint..color = yColor); + canvas.drawLine( + Offset(_startX, _startY - yLength), + Offset(_startX + rulerWidth, _startY - yLength), + paint..color = yColor); } } } diff --git a/lib/src/components/charts/broken_line/monotone_x.dart b/lib/src/components/charts/broken_line/monotone_x.dart index 11f86e62..930d7091 100644 --- a/lib/src/components/charts/broken_line/monotone_x.dart +++ b/lib/src/components/charts/broken_line/monotone_x.dart @@ -12,11 +12,14 @@ class MonotoneX { return h != 0 ? (3 * (y1 - y0) / h - t) / 2 : t; } - static double slope3(double x0, double y0, double x1, double y1, double x2, double y2) { + static double slope3( + double x0, double y0, double x1, double y1, double x2, double y2) { double h0 = x1 - x0; double h1 = x2 - x1; - double s0 = (y1 - y0) / (h0 != 0 ? h0 : (h1 < 0 ? -double.infinity : double.infinity)); - double s1 = (y2 - y1) / (h1 != 0 ? h1 : (h0 < 0 ? -double.infinity : double.infinity)); + double s0 = (y1 - y0) / + (h0 != 0 ? h0 : (h1 < 0 ? -double.infinity : double.infinity)); + double s1 = (y2 - y1) / + (h1 != 0 ? h1 : (h0 < 0 ? -double.infinity : double.infinity)); double p = (s0 * h1 + s1 * h0) / (h0 + h1); var source = [s0.abs(), s1.abs(), 0.5 * p.abs()]; source.sort(); @@ -26,16 +29,19 @@ class MonotoneX { // According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations // "you can express cubic Hermite interpolation in terms of cubic Bézier curves // with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1". - static Path point(Path path, double x0, double y0, double x1, double y1, double t0, double t1) { + static Path point(Path path, double x0, double y0, double x1, double y1, + double t0, double t1) { var dx = (x1 - x0) / 3; path.cubicTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1); return path; } - static Path addCurve(Path path, List points, {bool reversed = false, int endIndex = -1}) { + static Path addCurve(Path path, List points, + {bool reversed = false, int endIndex = -1}) { var targetPoints = List(); targetPoints.addAll(points); - targetPoints.add(Point(points[points.length - 1].x * 2, points[points.length - 1].y * 2)); + targetPoints.add(Point( + points[points.length - 1].x * 2, points[points.length - 1].y * 2)); double x0, y0, x1, y1, t0; if (path == null) { path = Path(); diff --git a/lib/src/components/charts/funnel_chart.dart b/lib/src/components/charts/funnel_chart.dart index 2d69b744..da5955bd 100644 --- a/lib/src/components/charts/funnel_chart.dart +++ b/lib/src/components/charts/funnel_chart.dart @@ -76,8 +76,10 @@ class BrnFunnelChart extends MultiChildRenderObjectWidget { assert(maxLayerWidth >= minLayerWidth), assert(layerCount - markerCount == 0 || layerCount - markerCount == 1), assert(() { - if (shape == FunnelShape.LeftOrRight && alignment == MarkerAlignment.center) { - debugPrint('当shape为FunnelShape.LeftOrRight时,alignment为MarkerAlignment.center无效'); + if (shape == FunnelShape.LeftOrRight && + alignment == MarkerAlignment.center) { + debugPrint( + '当shape为FunnelShape.LeftOrRight时,alignment为MarkerAlignment.center无效'); } return true; }()), @@ -105,7 +107,9 @@ class BrnFunnelChart extends MultiChildRenderObjectWidget { }) : this.layerPainter = BrnDefaultFunnelLayerPainter(), this.shape = FunnelShape.LeftAndRight, this.alignment = MarkerAlignment.right, - assert(layerCount != null && layerCount <= defaultLayerColors.length && layerCount >= 0), + assert(layerCount != null && + layerCount <= defaultLayerColors.length && + layerCount >= 0), assert(maxLayerWidth >= minLayerWidth), assert(layerCount - markerCount == 0 || layerCount - markerCount == 1), super( @@ -134,7 +138,8 @@ class BrnFunnelChart extends MultiChildRenderObjectWidget { } @override - void updateRenderObject(BuildContext context, RenderFunnelChart renderObject) { + void updateRenderObject( + BuildContext context, RenderFunnelChart renderObject) { renderObject ..childOffset = childOffset ..maxLayerWidth = maxLayerWidth @@ -306,7 +311,8 @@ abstract class RenderFunnelChart extends RenderBox double getIntrinsicDimensionHorizontal( double height, double mainChildSizeGetter(RenderBox child)); - double getIntrinsicDimensionVertical(double width, double mainChildSizeGetter(RenderBox child)); + double getIntrinsicDimensionVertical( + double width, double mainChildSizeGetter(RenderBox child)); void paintFunnel(PaintingContext context, Offset offset); } @@ -365,7 +371,9 @@ class BrnFunnelRender extends RenderFunnelChart { while (child != null) { top = (num + 0.5) * layerHeight + num * layerMargin + childOffset.dy; bottom = top + layerMargin + layerHeight; - left = (intrinsicHeight - bottom) * (maxLayerWidth - minLayerWidth) / intrinsicHeight + + left = (intrinsicHeight - bottom) * + (maxLayerWidth - minLayerWidth) / + intrinsicHeight + minLayerWidth + childOffset.dx; @@ -381,7 +389,8 @@ class BrnFunnelRender extends RenderFunnelChart { } @override - double getIntrinsicDimensionVertical(double width, double mainChildSizeGetter(RenderBox child)) { + double getIntrinsicDimensionVertical( + double width, double mainChildSizeGetter(RenderBox child)) { return layerCount * layerHeight + (layerCount - 1) * layerMargin; } @@ -390,7 +399,9 @@ class BrnFunnelRender extends RenderFunnelChart { _hasVisualOverflow = false; double intrinsicWidth = maxLayerWidth; double intrinsicHeight = layerHeight * layerCount + - (childCount >= layerCount ? layerMargin * childCount : layerMargin * (layerCount - 1)); + (childCount >= layerCount + ? layerMargin * childCount + : layerMargin * (layerCount - 1)); RenderBox child = firstChild; double top, bottom, left, right; @@ -412,10 +423,11 @@ class BrnFunnelRender extends RenderFunnelChart { left = 0 + childOffset.dx; right = constraints.maxWidth; } else if (alignment == MarkerAlignment.right) { - left = - (intrinsicHeight - bottom) * (maxLayerWidth - minLayerWidth) / (2 * intrinsicHeight) + - (minLayerWidth + maxLayerWidth) / 2 + - childOffset.dx; + left = (intrinsicHeight - bottom) * + (maxLayerWidth - minLayerWidth) / + (2 * intrinsicHeight) + + (minLayerWidth + maxLayerWidth) / 2 + + childOffset.dx; right = constraints.maxWidth; } else if (alignment == MarkerAlignment.left) { left = 0; @@ -429,7 +441,10 @@ class BrnFunnelRender extends RenderFunnelChart { BoxConstraints childConstraints; if (alignment == MarkerAlignment.center) { childConstraints = BoxConstraints( - minWidth: 0, maxWidth: constraints.maxWidth, minHeight: 0, maxHeight: layerMargin); + minWidth: 0, + maxWidth: constraints.maxWidth, + minHeight: 0, + maxHeight: layerMargin); } else if (alignment == MarkerAlignment.right) { childConstraints = BoxConstraints( minWidth: 0, @@ -454,7 +469,9 @@ class BrnFunnelRender extends RenderFunnelChart { intrinsicWidth, maxLayerWidth + childSize.width - - bottom * (maxLayerWidth - minLayerWidth) / (2 * intrinsicHeight)); + bottom * + (maxLayerWidth - minLayerWidth) / + (2 * intrinsicHeight)); } num++; child = childParentData.nextSibling; @@ -477,22 +494,28 @@ class BrnFunnelRender extends RenderFunnelChart { _centerOffset = Offset.zero; } _overflowOffset = Offset( - intrinsicSize.width - size.width > 0 ? intrinsicSize.width - size.width : 0, - intrinsicSize.height - size.height > 0 ? intrinsicSize.height - size.height : 0); + intrinsicSize.width - size.width > 0 + ? intrinsicSize.width - size.width + : 0, + intrinsicSize.height - size.height > 0 + ? intrinsicSize.height - size.height + : 0); num = 0; child = firstChild; while (child != null) { final BrnFunnelChartParentData childParentData = child.parentData; if (alignment == MarkerAlignment.center) { childParentData.offset = - Offset(0, ((num * layerMargin) + (num + 1) * layerHeight)) + _centerOffset; + Offset(0, ((num * layerMargin) + (num + 1) * layerHeight)) + + _centerOffset; } else if (alignment == MarkerAlignment.right) { top = (num + 0.5) * layerHeight + num * layerMargin + childOffset.dy; bottom = top + layerMargin + layerHeight; - left = - (intrinsicHeight - bottom) * (maxLayerWidth - minLayerWidth) / (2 * intrinsicHeight) + - (minLayerWidth + maxLayerWidth) / 2 + - childOffset.dx; + left = (intrinsicHeight - bottom) * + (maxLayerWidth - minLayerWidth) / + (2 * intrinsicHeight) + + (minLayerWidth + maxLayerWidth) / 2 + + childOffset.dx; childParentData.offset = Offset(left, top) + _centerOffset; } else if (alignment == MarkerAlignment.left) { top = (num + 0.5) * layerHeight + num * layerMargin + childOffset.dy; @@ -523,16 +546,20 @@ class BrnFunnelRender extends RenderFunnelChart { for (int i = 0; i < layerCount; i++) { Offset topLeft, bottomRight; if (alignment == MarkerAlignment.center) { - topLeft = Offset((size.width - maxLayerWidth) / 2, i * layerHeight + i * layerMargin); - bottomRight = - Offset((size.width + maxLayerWidth) / 2, (i + 1) * layerHeight + i * layerMargin); + topLeft = Offset((size.width - maxLayerWidth) / 2, + i * layerHeight + i * layerMargin); + bottomRight = Offset((size.width + maxLayerWidth) / 2, + (i + 1) * layerHeight + i * layerMargin); //绘制背景 } else if (alignment == MarkerAlignment.right) { topLeft = Offset(0, i * layerHeight + i * layerMargin); - bottomRight = Offset(maxLayerWidth, (i + 1) * layerHeight + i * layerMargin); + bottomRight = + Offset(maxLayerWidth, (i + 1) * layerHeight + i * layerMargin); } else if (alignment == MarkerAlignment.left) { - topLeft = Offset(size.width - maxLayerWidth, i * layerHeight + i * layerMargin); - bottomRight = Offset(size.width, (i + 1) * layerHeight + i * layerMargin); + topLeft = Offset( + size.width - maxLayerWidth, i * layerHeight + i * layerMargin); + bottomRight = + Offset(size.width, (i + 1) * layerHeight + i * layerMargin); } //绘制layer背景色 if (!layerPainter.isGradient(i)) { @@ -544,8 +571,8 @@ class BrnFunnelRender extends RenderFunnelChart { } else { //渐变背景 if (layerPainter.getLayerColors(i) != null) { - ui.Gradient gradient = - ui.Gradient.linear(topLeft, bottomRight, layerPainter.getLayerColors(i)); + ui.Gradient gradient = ui.Gradient.linear( + topLeft, bottomRight, layerPainter.getLayerColors(i)); _paint.shader = gradient; canvas.drawRect(Rect.fromPoints(topLeft, bottomRight), _paint); } @@ -606,7 +633,8 @@ class BrnFunnelRender extends RenderFunnelChart { safeRight = maxLayerWidth; } } - layerPainter.paintLayer(canvas, safeLeft, safeTop, safeRight, safeBottom, i); + layerPainter.paintLayer( + canvas, safeLeft, safeTop, safeRight, safeBottom, i); } _paint ..blendMode = BlendMode.dstOut @@ -622,7 +650,8 @@ class BrnFunnelRender extends RenderFunnelChart { } Path path; - if (_shape == FunnelShape.LeftAndRight || alignment == MarkerAlignment.left) { + if (_shape == FunnelShape.LeftAndRight || + alignment == MarkerAlignment.left) { path = Path(); //这里为什么都加了HALF_PIXEL,是因为裁剪的时候边缘会留下一定像素的误差。 //这里的解决方式就是提高半个像素的裁剪范围 @@ -630,16 +659,20 @@ class BrnFunnelRender extends RenderFunnelChart { //高版本flutter无此问题 path.moveTo(topLeftX - HALF_PIXEL, -HALF_PIXEL); path.lineTo(topLeftX - HALF_PIXEL, size.height + HALF_PIXEL); - path.lineTo((maxLayerWidth - minLayerWidth) / 2 + topLeftX, size.height + HALF_PIXEL); + path.lineTo((maxLayerWidth - minLayerWidth) / 2 + topLeftX, + size.height + HALF_PIXEL); path.close(); canvas.drawPath(path, _paint); } - if (_shape == FunnelShape.LeftAndRight || alignment == MarkerAlignment.right) { + if (_shape == FunnelShape.LeftAndRight || + alignment == MarkerAlignment.right) { path = Path(); path.moveTo(maxLayerWidth + topLeftX + HALF_PIXEL, -HALF_PIXEL); - path.lineTo(maxLayerWidth + topLeftX + HALF_PIXEL, size.height + HALF_PIXEL); - path.lineTo((maxLayerWidth + minLayerWidth) / 2 + topLeftX, size.height + HALF_PIXEL); + path.lineTo( + maxLayerWidth + topLeftX + HALF_PIXEL, size.height + HALF_PIXEL); + path.lineTo((maxLayerWidth + minLayerWidth) / 2 + topLeftX, + size.height + HALF_PIXEL); path.close(); canvas.drawPath(path, _paint); } @@ -689,8 +722,8 @@ abstract class BrnFunnelLayerPainter { ///[canvas] 提供的画布,对画布进行旋转裁剪等特殊操作,一定要调用[canvas.save()]操作。 ///[left],[top],[right],[bottom]是提供给调用者绘制的一个安全区域,超过这个区域限制,可能会被截断 ///[layerIndex] 漏斗的layer index。 - void paintLayer( - Canvas canvas, double left, double top, double right, double bottom, int layerIndex); + void paintLayer(Canvas canvas, double left, double top, double right, + double bottom, int layerIndex); } ///漏斗图默认LayerPainter,在漏斗每层layer中间绘制文案,每层的颜色值使用Bruno预设的颜色。 @@ -709,8 +742,8 @@ class BrnDefaultFunnelLayerPainter extends BrnFunnelLayerPainter { }) : _textPainter = TextPainter()..textDirection = TextDirection.ltr; @override - void paintLayer( - Canvas canvas, double left, double top, double right, double bottom, int layerIndex) { + void paintLayer(Canvas canvas, double left, double top, double right, + double bottom, int layerIndex) { if (layerIndex >= titles.length) { return; } @@ -721,7 +754,8 @@ class BrnDefaultFunnelLayerPainter extends BrnFunnelLayerPainter { ..layout(); _textPainter.paint( canvas, - Offset((left + right - _textPainter.width) / 2, (top + bottom - _textPainter.height) / 2), + Offset((left + right - _textPainter.width) / 2, + (top + bottom - _textPainter.height) / 2), ); } diff --git a/lib/src/components/charts/radar_chart.dart b/lib/src/components/charts/radar_chart.dart index ac431888..1c6550bb 100644 --- a/lib/src/components/charts/radar_chart.dart +++ b/lib/src/components/charts/radar_chart.dart @@ -155,7 +155,9 @@ class BrnRadarChart extends MultiChildRenderObjectWidget { maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle( - color: Color(0xFF222222), fontSize: 12, fontWeight: FontWeight.w600), + color: Color(0xFF222222), + fontSize: 12, + fontWeight: FontWeight.w600), ), )); } @@ -341,10 +343,12 @@ class RenderRadarChart extends RenderBox @override void setupParentData(RenderBox child) { - if (child.parentData is! BrnRadarChartParentData) child.parentData = BrnRadarChartParentData(); + if (child.parentData is! BrnRadarChartParentData) + child.parentData = BrnRadarChartParentData(); } - double _getIntrinsicDimensionHorizontal(double mainChildSizeGetter(RenderBox child)) { + double _getIntrinsicDimensionHorizontal( + double mainChildSizeGetter(RenderBox child)) { double x; double maxX = 0, minX = 0; RenderBox child = firstChild; @@ -377,7 +381,8 @@ class RenderRadarChart extends RenderBox return maxX - minX; } - double _getIntrinsicDimensionVertical(double mainChildSizeGetter(RenderBox child)) { + double _getIntrinsicDimensionVertical( + double mainChildSizeGetter(RenderBox child)) { double y; double maxY = 0, minY = 0; RenderBox child = firstChild; @@ -427,12 +432,14 @@ class RenderRadarChart extends RenderBox @override double computeMinIntrinsicHeight(double width) { - return _getIntrinsicDimensionVertical((RenderBox child) => child.getMinIntrinsicHeight(width)); + return _getIntrinsicDimensionVertical( + (RenderBox child) => child.getMinIntrinsicHeight(width)); } @override double computeMaxIntrinsicHeight(double width) { - return _getIntrinsicDimensionVertical((RenderBox child) => child.getMaxIntrinsicHeight(width)); + return _getIntrinsicDimensionVertical( + (RenderBox child) => child.getMaxIntrinsicHeight(width)); } @override @@ -506,8 +513,12 @@ class RenderRadarChart extends RenderBox _hasVisualOverflow = true; } _overflowOffset = Offset( - intrinsicSize.width - size.width > 0 ? intrinsicSize.width - size.width : 0, - intrinsicSize.height - size.height > 0 ? intrinsicSize.height - size.height : 0); + intrinsicSize.width - size.width > 0 + ? intrinsicSize.width - size.width + : 0, + intrinsicSize.height - size.height > 0 + ? intrinsicSize.height - size.height + : 0); _centerOffset = Offset(-(maxX + minX) / 2, (maxY + minY) / 2); child = firstChild; i = 0; @@ -524,7 +535,10 @@ class RenderRadarChart extends RenderBox } else if (angle == pi / 2) { y = size.height / 2 - y - child.size.height / 2; } else { - y = size.height / 2 - y - child.size.height - _markerMargin * cos(angle); + y = size.height / 2 - + y - + child.size.height - + _markerMargin * cos(angle); } } else { if (angle == pi) { @@ -548,7 +562,10 @@ class RenderRadarChart extends RenderBox if (angle == pi * 3 / 2) { x = size.width / 2 + x - _markerMargin - child.size.width; } else { - x = size.width / 2 + x - child.size.width + _markerMargin * sin(angle); + x = size.width / 2 + + x - + child.size.width + + _markerMargin * sin(angle); } } childParentData.offset = Offset(x, y) + _offset[i] + _centerOffset; @@ -575,7 +592,8 @@ class RenderRadarChart extends RenderBox double translateX = rect.width / 2; double translateY = rect.height / 2; //translate the canvas's top left to widget'center since flutter canvas rotate pivot can only be the top left. - canvas.translate(translateX + _centerOffset?.dx ?? 0, translateY + _centerOffset?.dy ?? 0); + canvas.translate(translateX + _centerOffset?.dx ?? 0, + translateY + _centerOffset?.dy ?? 0); canvas.rotate(_rotateAngle); _drawBackground(canvas, rect.size, translateX, translateY); _drawRadar(canvas); @@ -689,9 +707,11 @@ class RenderRadarChart extends RenderBox if (radarStyle.dotted) { for (int i = 0; i < dotPosition.length; i++) { _radarPainter.color = Colors.white; - canvas.drawCircle(dotPosition[i], radarStyle.dotRadius + 2 ?? 2, _radarPainter); + canvas.drawCircle( + dotPosition[i], radarStyle.dotRadius + 2 ?? 2, _radarPainter); _radarPainter.color = radarStyle.dotColor ?? radarStyle.strokeColor; - canvas.drawCircle(dotPosition[i], radarStyle.dotRadius ?? 2, _radarPainter); + canvas.drawCircle( + dotPosition[i], radarStyle.dotRadius ?? 2, _radarPainter); } } } diff --git a/lib/src/components/dialog/brn_dialog.dart b/lib/src/components/dialog/brn_dialog.dart index 53d06273..cdfefe63 100644 --- a/lib/src/components/dialog/brn_dialog.dart +++ b/lib/src/components/dialog/brn_dialog.dart @@ -14,7 +14,10 @@ const EdgeInsetsGeometry cIconPadding = const EdgeInsets.only(top: 28.0); /// title的文字样式 const TextStyle cTitleTextStyle = const TextStyle( - fontWeight: FontWeight.w600, inherit: true, fontSize: 18.0, color: Color(0xFF222222)); + fontWeight: FontWeight.w600, + inherit: true, + fontSize: 18.0, + color: Color(0xFF222222)); /// title的文字的对齐 const int cTitleMaxLines = 3; @@ -27,11 +30,17 @@ const TextAlign cContentTextAlign = TextAlign.center; /// 内容部分的文字的样式 const TextStyle cContentTextStyle = const TextStyle( - inherit: true, fontSize: 14.0, color: Color(0xFF666666), decoration: TextDecoration.none); + inherit: true, + fontSize: 14.0, + color: Color(0xFF666666), + decoration: TextDecoration.none); /// 警示文案样式 const TextStyle cWarningTextStyle = TextStyle( - inherit: true, fontSize: 14.0, color: Color(0xFFFA3F3F), decoration: TextDecoration.none); + inherit: true, + fontSize: 14.0, + color: Color(0xFFFA3F3F), + decoration: TextDecoration.none); /// 警示文案的文字对齐 const TextAlign cWarningTextAlign = TextAlign.center; @@ -40,22 +49,22 @@ const TextAlign cWarningTextAlign = TextAlign.center; const Color cBackgroundColor = Colors.white; /// 对话框的边框----》默认圆角5 -const ShapeBorder cShape = - const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5.0))); +const ShapeBorder cShape = const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(5.0))); /// 主题按钮的背景颜色---》白色 const Color cMainBackgroundColor = Colors.white; /// 主题按钮的文字样式---》主色调 -const TextStyle cMainTextStyle = - const TextStyle(color: Color(0xFF00AE66), fontWeight: FontWeight.w600, fontSize: 16); +const TextStyle cMainTextStyle = const TextStyle( + color: Color(0xFF00AE66), fontWeight: FontWeight.w600, fontSize: 16); /// 灰色按钮的背景颜色---》白色 const Color cGreyBackgroundColor = Colors.white; /// 非按钮的文字样式---》灰色 -const TextStyle cGreyActionsTextStyle = - const TextStyle(color: Color(0xFF222222), fontWeight: FontWeight.w600, fontSize: 16); +const TextStyle cGreyActionsTextStyle = const TextStyle( + color: Color(0xFF222222), fontWeight: FontWeight.w600, fontSize: 16); /// 底部按钮的高度 const double cBottomHeight = 44.0; @@ -73,10 +82,13 @@ const Divider cDividerLine = const Divider( enum ButtonType { /// 单按钮 Single, + /// 多按钮 Multi, + /// 左按钮 Left, + /// 右按钮 Right, } @@ -288,12 +300,14 @@ class BrnDialog extends AlertDialog { } if (_isShowContent()) { - Widget generateContentWidget = _generateContentWidget(context, defaultConfig); + Widget generateContentWidget = + _generateContentWidget(context, defaultConfig); children.add(generateContentWidget); } if (_isShowWarning()) { - Widget generateWarningWidget = _generateWarningWidget(context, defaultConfig); + Widget generateWarningWidget = + _generateWarningWidget(context, defaultConfig); children.add(generateWarningWidget); } @@ -321,14 +335,15 @@ class BrnDialog extends AlertDialog { width: defaultConfig?.dialogWidth, child: Material( shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(BrnDialogUtils.getDialogRadius(defaultConfig)))), + borderRadius: BorderRadius.all(Radius.circular( + BrnDialogUtils.getDialogRadius(defaultConfig)))), child: dialogChild, color: defaultConfig?.backgroundColor, ))); } - Widget _generateIconWidget(BuildContext context, BrnDialogConfig dialogConfig) { + Widget _generateIconWidget( + BuildContext context, BrnDialogConfig dialogConfig) { Widget _createWidget(Widget widget) { return Center( child: Padding( @@ -346,7 +361,8 @@ class BrnDialog extends AlertDialog { return _createWidget(iconImage); } if (showIcon) { - return _createWidget(BrunoTools.getAssetImageWithBandColor("icons/icon_alter.png")); + return _createWidget( + BrunoTools.getAssetImageWithBandColor("icons/icon_alter.png")); } return SizedBox( @@ -356,7 +372,8 @@ class BrnDialog extends AlertDialog { } /// 标题widget:以titleWidget为准,辅以title生成的Text。 - Widget _generateTitleWidget(BuildContext context, BrnDialogConfig dialogConfig) { + Widget _generateTitleWidget( + BuildContext context, BrnDialogConfig dialogConfig) { if (titleWidget != null) { return DefaultTextStyle( textAlign: dialogConfig?.titleTextAlign, @@ -378,7 +395,8 @@ class BrnDialog extends AlertDialog { } /// 内容widget:以contentWidget为准,辅以message生成的Text - Widget _generateContentWidget(BuildContext context, BrnDialogConfig dialogConfig) { + Widget _generateContentWidget( + BuildContext context, BrnDialogConfig dialogConfig) { if (contentWidget != null) return Flexible( child: DefaultTextStyle( @@ -400,7 +418,8 @@ class BrnDialog extends AlertDialog { } /// 警示widget:以warningWidget为准,辅以warning生成的Text - Widget _generateWarningWidget(BuildContext context, BrnDialogConfig dialogConfig) { + Widget _generateWarningWidget( + BuildContext context, BrnDialogConfig dialogConfig) { if (warningWidget != null) return Flexible( child: DefaultTextStyle( @@ -423,8 +442,8 @@ class BrnDialog extends AlertDialog { /// 单个button 左右有圆角 /// 两个button 左button有左圆角&右直角 右button有右圆角&左直角 /// 多个button 最后一个左右圆角 其他均直角 - Widget _generateMainWidget( - Widget widget, Color background, ButtonType type, int index, BrnDialogConfig dialogConfig) { + Widget _generateMainWidget(Widget widget, Color background, ButtonType type, + int index, BrnDialogConfig dialogConfig) { return Container( decoration: ShapeDecoration( color: background, @@ -458,8 +477,8 @@ class BrnDialog extends AlertDialog { /// 单个button 左右有圆角 /// 两个button 左button有左圆角&右直角 右button有右圆角&左直角 /// 多个button 最后一个左右圆角 其他均直角 - Widget _generateGreyWidget( - Widget widget, Color background, ButtonType type, int index, BrnDialogConfig dialogConfig) { + Widget _generateGreyWidget(Widget widget, Color background, ButtonType type, + int index, BrnDialogConfig dialogConfig) { return Container( constraints: BoxConstraints.tightFor(height: cBottomHeight), decoration: ShapeDecoration( @@ -489,7 +508,8 @@ class BrnDialog extends AlertDialog { ); } - Widget _generateActionsWidget(BuildContext context, BrnDialogConfig defaultConfig) { + Widget _generateActionsWidget( + BuildContext context, BrnDialogConfig defaultConfig) { bool showTextActions = _isEmptyActionsWidget(); int length = showTextActions ? actionsText.length : actionsWidget.length; if (length == 1) { @@ -510,7 +530,8 @@ class BrnDialog extends AlertDialog { children: [ Expanded( child: showTextActions - ? _mapTextToGesWidget(context, actionsText[0], 0, false, defaultConfig, + ? _mapTextToGesWidget( + context, actionsText[0], 0, false, defaultConfig, type: ButtonType.Left) : actionsWidget[0], ), @@ -520,7 +541,8 @@ class BrnDialog extends AlertDialog { ), Expanded( child: showTextActions - ? _mapTextToGesWidget(context, actionsText[1], 1, true, defaultConfig, + ? _mapTextToGesWidget( + context, actionsText[1], 1, true, defaultConfig, type: ButtonType.Right) : actionsWidget[1], ) @@ -535,7 +557,8 @@ class BrnDialog extends AlertDialog { physics: length > 3 ? null : NeverScrollableScrollPhysics(), itemBuilder: (context, i) { return showTextActions - ? _mapTextToGesWidget(context, actionsText[i], i, true, defaultConfig, + ? _mapTextToGesWidget( + context, actionsText[i], i, true, defaultConfig, type: ButtonType.Multi) : actionsWidget[i]; }, @@ -547,21 +570,25 @@ class BrnDialog extends AlertDialog { } } - Widget _mapTextToGesWidget( - BuildContext context, String label, int index, bool main, BrnDialogConfig dialogConfig, + Widget _mapTextToGesWidget(BuildContext context, String label, int index, + bool main, BrnDialogConfig dialogConfig, {ButtonType type = ButtonType.Single}) { Text text = Text(label); Widget ges = GestureDetector( child: main - ? _generateMainWidget( - text, dialogConfig?.mainActionBackgroundColor, type, index, dialogConfig) + ? _generateMainWidget(text, dialogConfig?.mainActionBackgroundColor, + type, index, dialogConfig) : _generateGreyWidget( - text, dialogConfig?.assistActionsBackgroundColor, type, index, dialogConfig), + text, + dialogConfig?.assistActionsBackgroundColor, + type, + index, + dialogConfig), onTap: () { if (indexedActionCallback != null) { //点击的监听 indexedActionCallback(index); - }else{ + } else { Navigator.pop(context); } }, @@ -608,7 +635,8 @@ class BrnDialog extends AlertDialog { defaultConfig = defaultConfig.merge(BrnDialogConfig( mainActionTextStyle: BrnTextStyle.withStyle(brnDialogStyle.mainTextStyle), mainActionBackgroundColor: brnDialogStyle.mainBackgroundColor, - assistActionsTextStyle: BrnTextStyle.withStyle(brnDialogStyle.greyActionsTextStyle), + assistActionsTextStyle: + BrnTextStyle.withStyle(brnDialogStyle.greyActionsTextStyle), assistActionsBackgroundColor: brnDialogStyle.greyActionsBackgroundColor, radius: brnDialogStyle.radius, iconPadding: brnDialogStyle.iconPadding, @@ -632,7 +660,9 @@ class BrnDialog extends AlertDialog { /// 主题配置的标题间距 EdgeInsetsGeometry _configTitlePadding(BrnDialogConfig dialogConfig) { - return _isShowIcon() ? dialogConfig?.titlePaddingSm : dialogConfig?.titlePaddingLg; + return _isShowIcon() + ? dialogConfig?.titlePaddingSm + : dialogConfig?.titlePaddingLg; } /// 主题配置的内容间距 diff --git a/lib/src/components/dialog/brn_enhance_operation_dialog.dart b/lib/src/components/dialog/brn_enhance_operation_dialog.dart index ec24288f..2215d39a 100644 --- a/lib/src/components/dialog/brn_enhance_operation_dialog.dart +++ b/lib/src/components/dialog/brn_enhance_operation_dialog.dart @@ -88,7 +88,8 @@ class BrnEnhanceOperationDialog extends StatelessWidget { themeData: themeData, iconImage: (iconType == BrnDialogConstants.ICON_CUSTOM) ? customIconWidget - : BrunoTools.getAssetImage(BrnDialogConstants.shareItemImagePathList[iconType]), + : BrunoTools.getAssetImage( + BrnDialogConstants.shareItemImagePathList[iconType]), titleText: titleText, messageText: descText, warningWidget: Container( diff --git a/lib/src/components/dialog/brn_middle_input_diaolg.dart b/lib/src/components/dialog/brn_middle_input_diaolg.dart index c4876b3e..2416da11 100644 --- a/lib/src/components/dialog/brn_middle_input_diaolg.dart +++ b/lib/src/components/dialog/brn_middle_input_diaolg.dart @@ -112,13 +112,17 @@ class BrnMiddleInputDialog { maxLines: maxLines ?? minLines, minLines: minLines, //光标颜色 - cursorColor: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + cursorColor: + BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, autofocus: autoFocus ?? false, //光标圆角弧度 cursorRadius: Radius.circular(2.0), style: TextStyle( fontSize: 14, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase), + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase), maxLengthEnforced: true, onChanged: (value) { _value = value; @@ -129,18 +133,27 @@ class BrnMiddleInputDialog { hintText: hintText, hintStyle: TextStyle( fontSize: 14, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextHint), + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextHint), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(4.0), borderSide: BorderSide( width: 0.5, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextHint, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextHint, )), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(4.0), borderSide: BorderSide( width: 0.5, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextHint, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextHint, )), ), )); diff --git a/lib/src/components/dialog/brn_multi_select_dialog.dart b/lib/src/components/dialog/brn_multi_select_dialog.dart index 72427991..4e00e0d6 100644 --- a/lib/src/components/dialog/brn_multi_select_dialog.dart +++ b/lib/src/components/dialog/brn_multi_select_dialog.dart @@ -6,7 +6,8 @@ import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -typedef BrnMultiSelectDialogClickSubmitCallback = bool Function(List data); +typedef BrnMultiSelectDialogClickSubmitCallback = bool Function( + List data); typedef BrnMultiSelectDialogOnItemClickCallback = void Function( BuildContext dialogContext, int index); @@ -92,8 +93,8 @@ class BrnMultiSelectDialog extends Dialog { submitText: submitText, onSubmitClick: onSubmitClick, onItemClick: onItemClick, - submitBgColor: - submitBgColor ?? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + submitBgColor: submitBgColor ?? + BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, isShowOperateWidget: isShowOperateWidget); } } @@ -172,12 +173,14 @@ class MultiSelectPickerWidgetState extends State { ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => _buildItem(context, index), + itemBuilder: (context, index) => + _buildItem(context, index), itemCount: widget.conditions?.length), widget.customWidget != null ? Container( child: widget.customWidget, - padding: EdgeInsets.only(left: 20, right: 20, top: 12), + padding: EdgeInsets.only( + left: 20, right: 20, top: 12), ) : Container( width: 0, @@ -190,13 +193,15 @@ class MultiSelectPickerWidgetState extends State { children: [ Expanded( child: ListView.builder( - itemBuilder: (context, index) => _buildItem(context, index), + itemBuilder: (context, index) => + _buildItem(context, index), itemCount: widget.conditions?.length), ), widget.customWidget != null ? Container( child: widget.customWidget, - padding: EdgeInsets.only(left: 20, right: 20, top: 12), + padding: + EdgeInsets.only(left: 20, right: 20, top: 12), ) : Container( width: 0, @@ -258,7 +263,8 @@ class MultiSelectPickerWidgetState extends State { behavior: HitTestBehavior.opaque, onTap: () { setState(() { - widget.conditions[index].isChecked = !widget.conditions[index].isChecked; + widget.conditions[index].isChecked = + !widget.conditions[index].isChecked; }); if (widget.onItemClick != null) { widget.onItemClick(context, index); @@ -290,13 +296,16 @@ class MultiSelectPickerWidgetState extends State { alignment: Alignment.center, height: 44, child: widget.conditions[index].isChecked - ? BrunoTools.getAssetImageWithBandColor(BrnAsset.iconMultiSelected) + ? BrunoTools.getAssetImageWithBandColor( + BrnAsset.iconMultiSelected) : BrunoTools.getAssetImage(BrnAsset.iconUnSelect)), ], ), ), index != widget.conditions.length - 1 - ? Padding(padding: EdgeInsets.fromLTRB(20, 0, 20, 0), child: BrnLine()) + ? Padding( + padding: EdgeInsets.fromLTRB(20, 0, 20, 0), + child: BrnLine()) : Container() ], )); diff --git a/lib/src/components/dialog/brn_scrollable_text_dialog.dart b/lib/src/components/dialog/brn_scrollable_text_dialog.dart index 8c301691..61af7496 100644 --- a/lib/src/components/dialog/brn_scrollable_text_dialog.dart +++ b/lib/src/components/dialog/brn_scrollable_text_dialog.dart @@ -117,11 +117,14 @@ class BrnScrollableText extends StatelessWidget { constraints: BoxConstraints(maxHeight: 220), child: Scrollbar( child: SingleChildScrollView( - child: Column(mainAxisSize: MainAxisSize.min, children: [ - BrnCSS2Text.toTextView(contentText, - linksCallback: linksCallback, - defaultStyle: TextStyle(fontSize: textFontSize, color: textColor)) - ])))), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + BrnCSS2Text.toTextView(contentText, + linksCallback: linksCallback, + defaultStyle: + TextStyle(fontSize: textFontSize, color: textColor)) + ])))), ), title: title, isClose: isClose, diff --git a/lib/src/components/dialog/brn_share_dialog.dart b/lib/src/components/dialog/brn_share_dialog.dart index add9dd75..8e58eb68 100644 --- a/lib/src/components/dialog/brn_share_dialog.dart +++ b/lib/src/components/dialog/brn_share_dialog.dart @@ -244,8 +244,9 @@ class BrnShareDialog extends StatelessWidget { ), )); } - double space = - (shareItems.length >= 5) ? 14 : (300 - 39 * shareItems.length) / (shareItems.length + 1); + double space = (shareItems.length >= 5) + ? 14 + : (300 - 39 * shareItems.length) / (shareItems.length + 1); return Container( padding: EdgeInsets.only(bottom: 28), alignment: Alignment.center, diff --git a/lib/src/components/dialog/brn_single_select.dart b/lib/src/components/dialog/brn_single_select.dart index a4668989..e466f6e4 100644 --- a/lib/src/components/dialog/brn_single_select.dart +++ b/lib/src/components/dialog/brn_single_select.dart @@ -7,7 +7,8 @@ import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; typedef BrnSingleSelectOnSubmitCallback = Function(String data); -typedef BrnSingleSelectOnItemClickCallback = void Function(BuildContext dialogContext, int index); +typedef BrnSingleSelectOnItemClickCallback = void Function( + BuildContext dialogContext, int index); /// 单选列表弹框 class BrnSingleSelectDialog extends Dialog { @@ -119,8 +120,8 @@ class BrnSingleSelectDialogWidget extends StatefulWidget { } } -class BrnSingleSelectDialogWidgetState extends State { - +class BrnSingleSelectDialogWidgetState + extends State { @override Widget build(BuildContext context) { return Scaffold( @@ -132,8 +133,9 @@ class BrnSingleSelectDialogWidgetState extends State[ @@ -145,7 +147,8 @@ class BrnSingleSelectDialogWidgetState extends State _buildItem(context, index), - itemCount: widget.conditions?.length ?? 0), + itemBuilder: (context, index) => + _buildItem(context, index), + itemCount: + widget.conditions?.length ?? 0), widget.customWidget != null ? Container( child: widget.customWidget, - padding: EdgeInsets.only(left: 20, right: 20, top: 12), + padding: EdgeInsets.only( + left: 20, right: 20, top: 12), ) : Container( width: 0, @@ -175,13 +181,16 @@ class BrnSingleSelectDialogWidgetState extends State[ Expanded( child: ListView.builder( - itemBuilder: (context, index) => _buildItem(context, index), - itemCount: widget.conditions?.length ?? 0), + itemBuilder: (context, index) => + _buildItem(context, index), + itemCount: + widget.conditions?.length ?? 0), ), widget.customWidget != null ? Container( child: widget.customWidget, - padding: EdgeInsets.only(left: 20, right: 20, top: 12), + padding: EdgeInsets.only( + left: 20, right: 20, top: 12), ) : Container( width: 0, @@ -200,7 +209,8 @@ class BrnSingleSelectDialogWidgetState extends State[ _buildImageWidget(context), _buildTextWidget(), @@ -163,8 +164,9 @@ class BrnAbnormalStateWidget extends StatelessWidget { final height = size.height; return img != null ? Container( - padding: - isCenterVertical ? null : EdgeInsets.only(top: topOffset ?? height * topPercent), + padding: isCenterVertical + ? null + : EdgeInsets.only(top: topOffset ?? height * topPercent), child: img, ) : Container(); @@ -177,7 +179,8 @@ class BrnAbnormalStateWidget extends StatelessWidget { alignment: Alignment.center, padding: EdgeInsets.fromLTRB(60, 24, 60, 0), child: Text(title, - textAlign: TextAlign.center, style: themeData?.titleTextStyle?.generateTextStyle()), + textAlign: TextAlign.center, + style: themeData?.titleTextStyle?.generateTextStyle()), ) : Container(); } @@ -215,7 +218,8 @@ class BrnAbnormalStateWidget extends StatelessWidget { padding: EdgeInsets.fromLTRB(48, 16, 48, 16), decoration: BoxDecoration( color: themeData.commonConfig.brandPrimary, - borderRadius: BorderRadius.all(Radius.circular(themeData?.btnRadius))), + borderRadius: + BorderRadius.all(Radius.circular(themeData?.btnRadius))), child: Text(operateTexts[0] ?? "", textAlign: TextAlign.center, style: themeData?.singleBrnTextStyle?.generateTextStyle()), @@ -232,7 +236,8 @@ class BrnAbnormalStateWidget extends StatelessWidget { padding: EdgeInsets.fromLTRB(36, 16, 36, 16), decoration: BoxDecoration( color: themeData.commonConfig.brandPrimary.withAlpha(0x14), - borderRadius: BorderRadius.all(Radius.circular(themeData?.btnRadius))), + borderRadius: + BorderRadius.all(Radius.circular(themeData?.btnRadius))), child: Text(operateTexts[0] ?? "", textAlign: TextAlign.center, style: themeData?.doubleBrnTextStyle?.generateTextStyle()), @@ -249,7 +254,8 @@ class BrnAbnormalStateWidget extends StatelessWidget { padding: EdgeInsets.fromLTRB(36, 16, 36, 16), decoration: BoxDecoration( color: themeData.commonConfig.brandPrimary.withAlpha(0x14), - borderRadius: BorderRadius.all(Radius.circular(themeData?.btnRadius))), + borderRadius: + BorderRadius.all(Radius.circular(themeData?.btnRadius))), child: Text(operateTexts[1] ?? "", textAlign: TextAlign.center, style: themeData?.doubleBrnTextStyle?.generateTextStyle()), @@ -260,8 +266,8 @@ class BrnAbnormalStateWidget extends StatelessWidget { } else if (OperateAreaType.TextButton == operateAreaType) { return GestureDetector( onTap: () => action(0), - child: - Text(operateTexts[0] ?? "", style: themeData?.operateTextStyle?.generateTextStyle())); + child: Text(operateTexts[0] ?? "", + style: themeData?.operateTextStyle?.generateTextStyle())); } return Container(); } diff --git a/lib/src/components/form/base/brn_form_item_type.dart b/lib/src/components/form/base/brn_form_item_type.dart index e1122448..1335a8a9 100644 --- a/lib/src/components/form/base/brn_form_item_type.dart +++ b/lib/src/components/form/base/brn_form_item_type.dart @@ -15,13 +15,15 @@ class BrnInputItemType { static const String TEXT_ARRAY_INPUT_TYPE = "text_array_input_type"; static const String TEXT_SELECT_INPUT_TYPE = "text_select_input_type"; static const String TEXT_BLOCK_INPUT_TYPE = "text_block_input_type"; - static const String TEXT_INPUT_TITLE_SELECT_TYPE = "text_input_title_select_type"; + static const String TEXT_INPUT_TITLE_SELECT_TYPE = + "text_input_title_select_type"; static const String TEXT_RANGE_INPUT_TYPE = "text_range_input_type"; static const String TEXT_STEP_INPUT_TYPE = "text_step_input_type"; static const String RADIO_INPUT_TYPE = "radio_input_type"; static const String RADIO_PORTRAIT_INPUT_TYPE = "radio_column_input_type"; static const String MULTI_CHOICE_INPUT_TYPE = "multi_choice_input_type"; - static const String MULTI_CHOICE_PORTRAIT_INPUT_TYPE = "multi_choice_column_input_type"; + static const String MULTI_CHOICE_PORTRAIT_INPUT_TYPE = + "multi_choice_column_input_type"; static const String SWITCH_TYPE = "switch_type"; static const String STAR_INPUT_TYPE = "star_input_type"; @@ -30,7 +32,8 @@ class BrnInputItemType { static const String NORMAL_GROUP_TYPE = "normal_group_type"; static const String TEXT_INPUT_RATIO_TYPE = "text_input_ratio_type"; - static const String TEXT_QUICK_SELECT_INPUT_TYPE = "text_quick_select_input_type"; + static const String TEXT_QUICK_SELECT_INPUT_TYPE = + "text_quick_select_input_type"; /// bottom类型 static const String BOTTOM_BTN_TYPE = "bottom_btn_type"; @@ -41,7 +44,6 @@ class BrnInputItemType { static const String LABEL_TITLE = "label_title"; static const String LABEL_ADD = "label_add"; - } class BrnInputType { diff --git a/lib/src/components/form/base/input_item_interface.dart b/lib/src/components/form/base/input_item_interface.dart index 1a9c78f7..7bfd14e5 100644 --- a/lib/src/components/form/base/input_item_interface.dart +++ b/lib/src/components/form/base/input_item_interface.dart @@ -1,16 +1,17 @@ - /// 用于model兼容回调 /// 主要用于各种点击事件 typedef OnBrnFormSelectAll = void Function(int index, bool isSelect); /// 主要用于各种输入值变化 -typedef OnBrnFormRadioValueChanged = void Function(String oldStr, String newStr); +typedef OnBrnFormRadioValueChanged = void Function( + String oldStr, String newStr); typedef OnBrnFormSwitchChanged = void Function(bool oldValue, bool newValue); typedef OnBrnFormValueChanged = void Function(int oldValue, int newValue); -typedef OnBrnFormMultiChoiceValueChanged = void Function(List oldValue, List newValue); -typedef OnBrnFormBtnSelectChanged = void Function(List oldValue, List newValue); +typedef OnBrnFormMultiChoiceValueChanged = void Function( + List oldValue, List newValue); +typedef OnBrnFormBtnSelectChanged = void Function( + List oldValue, List newValue); /// 用于model兼容回调 定义等同于 form_interface /// 主要用于各种点击事件 typedef OnBrnFormTitleSelected = void Function(String title, int index); - diff --git a/lib/src/components/form/items/general/brn_multi_choice_input_item.dart b/lib/src/components/form/items/general/brn_multi_choice_input_item.dart index 6a431e0d..047176ef 100644 --- a/lib/src/components/form/items/general/brn_multi_choice_input_item.dart +++ b/lib/src/components/form/items/general/brn_multi_choice_input_item.dart @@ -68,28 +68,27 @@ class BrnMultiChoiceInputFormItem extends StatefulWidget { /// 选项选中状态变化回调 final OnBrnFormMultiChoiceValueChanged onChanged; - /// form配置 BrnFormItemConfig themeData; - BrnMultiChoiceInputFormItem({ - Key key, - this.label, - this.title: "", - this.subTitle, - this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, - this.error: "", - this.isEdit: true, - this.isRequire: true, - this.onAddTap, - this.onRemoveTap, - this.onTip, - this.value, - this.options, - this.enableList, - this.onChanged, - this.themeData}) + BrnMultiChoiceInputFormItem( + {Key key, + this.label, + this.title: "", + this.subTitle, + this.tipLabel, + this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.error: "", + this.isEdit: true, + this.isRequire: true, + this.onAddTap, + this.onRemoveTap, + this.onTip, + this.value, + this.options, + this.enableList, + this.onChanged, + this.themeData}) : super() { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance @@ -102,10 +101,10 @@ class BrnMultiChoiceInputFormItem extends StatefulWidget { BrnMultiChoiceInputFormItemState createState() { return BrnMultiChoiceInputFormItemState(); } - } -class BrnMultiChoiceInputFormItemState extends State { +class BrnMultiChoiceInputFormItemState + extends State { // 标记选项的选中状态,内部变量无须初始化。初始化选中状态通过设置value字段设置 List _selectStatus; @@ -132,14 +131,21 @@ class BrnMultiChoiceInputFormItemState extends State[ - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon( + widget.prefixIconType, + widget.isEdit, + context, + widget.onAddTap, + widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), - BrnFormUtil.buildTitleWidget(widget.title, widget.themeData), - BrnFormUtil.buildTipLabelWidget(widget.tipLabel, widget.onTip, widget.themeData), + BrnFormUtil.buildTitleWidget( + widget.title, widget.themeData), + BrnFormUtil.buildTipLabelWidget( + widget.tipLabel, widget.onTip, widget.themeData), ], ), ), @@ -187,9 +193,10 @@ class BrnMultiChoiceInputFormItemState extends State oldValue = List()..addAll(widget.value); @@ -205,7 +212,6 @@ class BrnMultiChoiceInputFormItemState extends State { +class BrnMultiChoicePortraitInputFormItemState + extends State { // 标记选项的选中状态,内部变量无须初始化。初始化选中状态通过设置value字段设置 List _selectStatus; @@ -134,14 +132,21 @@ class BrnMultiChoicePortraitInputFormItemState extends State[ Container( - padding: BrnFormUtil.titleEdgeInsets( - widget.prefixIconType, widget.isRequire, widget.themeData), + padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, + widget.isRequire, widget.themeData), child: Row( children: [ - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon( + widget.prefixIconType, + widget.isEdit, + context, + widget.onAddTap, + widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), - BrnFormUtil.buildTitleWidget(widget.title, widget.themeData), - BrnFormUtil.buildTipLabelWidget(widget.tipLabel, widget.onTip, widget.themeData), + BrnFormUtil.buildTitleWidget( + widget.title, widget.themeData), + BrnFormUtil.buildTipLabelWidget( + widget.tipLabel, widget.onTip, widget.themeData), ], ), ), @@ -175,7 +180,6 @@ class BrnMultiChoicePortraitInputFormItemState extends State { - +class BrnTextQuickSelectFormItemState + extends State { @override Widget build(BuildContext context) { return Container( @@ -138,20 +138,27 @@ class BrnTextQuickSelectFormItemState extends State child: Row( children: [ Container( - padding: BrnFormUtil.titleEdgeInsets( - widget.prefixIconType, widget.isRequire, widget.themeData), + padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, + widget.isRequire, widget.themeData), child: Row( children: [ - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon( + widget.prefixIconType, + widget.isEdit, + context, + widget.onAddTap, + widget.onRemoveTap), // 必填项 BrnFormUtil.buildRequireWidget(widget.isRequire), // 主标题 - BrnFormUtil.buildTitleWidget(widget.title, widget.themeData), + BrnFormUtil.buildTitleWidget( + widget.title, widget.themeData), // 问号提示 - BrnFormUtil.buildTipLabelWidget(widget.tipLabel, widget.onTip, widget.themeData), + BrnFormUtil.buildTipLabelWidget( + widget.tipLabel, widget.onTip, widget.themeData), ], ), ), @@ -197,10 +204,8 @@ class BrnTextQuickSelectFormItemState extends State btns: widget.btns, isBtnsScroll: widget.isBtnsScroll, isEdit: widget.isEdit, - onBtnSelectChanged: widget.onBtnSelectChanged, - ) - ), + )), /// 错误提示 BrnFormUtil.buildErrorWidget(widget.error, widget.themeData) @@ -224,8 +229,6 @@ class BrnTextQuickSelectFormItemState extends State ); } } - - } // ignore: must_be_immutable @@ -345,7 +348,9 @@ class QuickButtonsState extends State { ), ), onPressed: () { - if (!widget.isEdit || (widget.enableBtnList != null && !widget.enableBtnList[index])) { + if (!widget.isEdit || + (widget.enableBtnList != null && + !widget.enableBtnList[index])) { return; } if (widget.onBtnSelectChanged != null) { @@ -353,7 +358,8 @@ class QuickButtonsState extends State { } if (_useInnerStatus) { // 如果是内部维护的状态,需要改变按钮的状态 - widget.selectBtnList[index] = widget.selectBtnList[index] ? false : true; + widget.selectBtnList[index] = + widget.selectBtnList[index] ? false : true; } setState(() {}); /* @@ -410,7 +416,8 @@ class QuickButtonsState extends State { return Color(0xFF999999); } - if (widget.selectBtnList == null || widget.selectBtnList.length != widget.btnsTxt.length) { + if (widget.selectBtnList == null || + widget.selectBtnList.length != widget.btnsTxt.length) { return Color(0xFF222222); } diff --git a/lib/src/components/form/items/general/brn_radio_input_item.dart b/lib/src/components/form/items/general/brn_radio_input_item.dart index 81981c1a..de7bdffc 100644 --- a/lib/src/components/form/items/general/brn_radio_input_item.dart +++ b/lib/src/components/form/items/general/brn_radio_input_item.dart @@ -81,27 +81,26 @@ class BrnRadioInputFormItem extends StatefulWidget { /// form配置 BrnFormItemConfig themeData; - BrnRadioInputFormItem( - {Key key, - this.label, - this.title: "", - this.subTitle, - this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, - this.error: "", - this.isEdit: true, - this.isRequire: false, - this.onAddTap, - this.onRemoveTap, - this.onTip, - this.value, - this.options, - this.enableList, - this.onChanged, - this.themeData, - this.titleMaxLines,}) - : super(key: key) { - + BrnRadioInputFormItem({ + Key key, + this.label, + this.title: "", + this.subTitle, + this.tipLabel, + this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.error: "", + this.isEdit: true, + this.isRequire: false, + this.onAddTap, + this.onRemoveTap, + this.onTip, + this.value, + this.options, + this.enableList, + this.onChanged, + this.themeData, + this.titleMaxLines, + }) : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance .getConfig(configId: this.themeData.configId) @@ -131,7 +130,6 @@ class BrnRadioInputFormItem extends StatefulWidget { this.layoutRatio, this.themeData, }) : super(key: key) { - this._isAutoLayout = true; this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance @@ -144,7 +142,6 @@ class BrnRadioInputFormItem extends StatefulWidget { BrnRadioInputFormItemState createState() { return BrnRadioInputFormItemState(); } - } class BrnRadioInputFormItemState extends State { @@ -183,7 +180,8 @@ class BrnRadioInputFormItemState extends State { } Widget _buildAutoLayoutTitleWidget(BuildContext context) { - return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { double maxWidth = _getTitleMaxWidth(context, constraints); return Row( crossAxisAlignment: CrossAxisAlignment.start, @@ -194,7 +192,12 @@ class BrnRadioInputFormItemState extends State { widget.prefixIconType, widget.isRequire, widget.themeData), child: Row( children: [ - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon( + widget.prefixIconType, + widget.isEdit, + context, + widget.onAddTap, + widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), Flexible(child: _buildTitleTextWidget()), _buildTipWidget() @@ -220,7 +223,7 @@ class BrnRadioInputFormItemState extends State { offstage: (widget.tipLabel == null /*|| widget.tipLabel.isEmpty*/), child: GestureDetector( onTap: () { - if(widget.onTip != null){ + if (widget.onTip != null) { widget.onTip(); } }, @@ -294,12 +297,13 @@ class BrnRadioInputFormItemState extends State { Widget _buildTitleTextWidget() { return Text(widget.title ?? "", - overflow: widget.titleMaxLines == null ? TextOverflow.clip : TextOverflow.ellipsis, + overflow: widget.titleMaxLines == null + ? TextOverflow.clip + : TextOverflow.ellipsis, maxLines: widget.titleMaxLines, style: BrnFormUtil.getTitleTextStyle(widget.themeData)); } - Row _buildTitleWidget(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.start, @@ -314,15 +318,19 @@ class BrnRadioInputFormItemState extends State { child: Row( children: [ // 添加/删除图标 - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon( + widget.prefixIconType, + widget.isEdit, + context, + widget.onAddTap, + widget.onRemoveTap), // 必填项 "*" 图标 BrnFormUtil.buildRequireWidget(widget.isRequire), // 主标题 - Container( - child: _buildTitleTextWidget()), + Container(child: _buildTitleTextWidget()), - // 问号图标 + // 问号图标 _buildTipWidget(), ], ), @@ -422,8 +430,4 @@ class BrnRadioInputFormItemState extends State { return !widget.enableList[index]; } - } - - - diff --git a/lib/src/components/form/items/general/brn_radio_portrait_input_item.dart b/lib/src/components/form/items/general/brn_radio_portrait_input_item.dart index c22dc50f..7d9f2ecb 100644 --- a/lib/src/components/form/items/general/brn_radio_portrait_input_item.dart +++ b/lib/src/components/form/items/general/brn_radio_portrait_input_item.dart @@ -90,7 +90,6 @@ class BrnRadioPortraitInputFormItem extends StatefulWidget { this.onChanged, this.themeData}) : super(key: key) { - this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance .getConfig(configId: this.themeData.configId) @@ -102,12 +101,10 @@ class BrnRadioPortraitInputFormItem extends StatefulWidget { BrnRadioPortraitInputFormItemState createState() { return BrnRadioPortraitInputFormItemState(); } - } -class BrnRadioPortraitInputFormItemState extends State { - - +class BrnRadioPortraitInputFormItemState + extends State { @override Widget build(BuildContext context) { return Container( @@ -124,14 +121,21 @@ class BrnRadioPortraitInputFormItemState extends State[ Container( - padding: BrnFormUtil.titleEdgeInsets( - widget.prefixIconType, widget.isRequire, widget.themeData), + padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, + widget.isRequire, widget.themeData), child: Row( children: [ - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon( + widget.prefixIconType, + widget.isEdit, + context, + widget.onAddTap, + widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), - BrnFormUtil.buildTitleWidget(widget.title, widget.themeData), - BrnFormUtil.buildTipLabelWidget(widget.tipLabel, widget.onTip, widget.themeData), + BrnFormUtil.buildTitleWidget( + widget.title, widget.themeData), + BrnFormUtil.buildTipLabelWidget( + widget.tipLabel, widget.onTip, widget.themeData), ], ), ), @@ -238,7 +242,4 @@ class BrnRadioPortraitInputFormItemState extends State { @@ -155,7 +153,6 @@ class BrnRangeInputFormItemState extends State { super.initState(); } - @override Widget build(BuildContext context) { return Container( @@ -172,14 +169,21 @@ class BrnRangeInputFormItemState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( - padding: BrnFormUtil.titleEdgeInsets( - widget.prefixIconType, widget.isRequire, widget.themeData), + padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, + widget.isRequire, widget.themeData), child: Row( children: [ - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon( + widget.prefixIconType, + widget.isEdit, + context, + widget.onAddTap, + widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), - BrnFormUtil.buildTitleWidget(widget.title, widget.themeData), - BrnFormUtil.buildTipLabelWidget(widget.tipLabel, widget.onTip, widget.themeData), + BrnFormUtil.buildTitleWidget( + widget.title, widget.themeData), + BrnFormUtil.buildTipLabelWidget( + widget.tipLabel, widget.onTip, widget.themeData), ], ), ), @@ -192,29 +196,33 @@ class BrnRangeInputFormItemState extends State { maxWidth: 50, ), child: TextField( - keyboardType: BrnFormUtil.getInputType(widget.inputType), + keyboardType: + BrnFormUtil.getInputType(widget.inputType), enabled: widget.isEdit, maxLines: 1, maxLength: widget.leftMaxCount, - style: BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit), + style: BrnFormUtil.getIsEditTextStyle( + widget.themeData, widget.isEdit), decoration: InputDecoration( border: InputBorder.none, - hintStyle: BrnFormUtil.getHintTextStyle(widget.themeData), + hintStyle: + BrnFormUtil.getHintTextStyle(widget.themeData), hintText: widget.hintMin ?? '最小', - counterText: "", contentPadding: EdgeInsets.all(0), isDense: true, enabledBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), + borderSide: + BorderSide(color: Colors.transparent)), focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), + borderSide: + BorderSide(color: Colors.transparent)), ), textAlign: TextAlign.end, controller: _minController, onChanged: (text) { - - BrnFormUtil.notifyInputChanged(widget.onMinChanged, text); + BrnFormUtil.notifyInputChanged( + widget.onMinChanged, text); }, ), ), @@ -243,28 +251,33 @@ class BrnRangeInputFormItemState extends State { maxWidth: 50, ), child: TextField( - keyboardType: BrnFormUtil.getInputType(widget.inputType), + keyboardType: + BrnFormUtil.getInputType(widget.inputType), enabled: widget.isEdit, maxLines: 1, maxLength: widget.rightMaxCount, - style: BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit), + style: BrnFormUtil.getIsEditTextStyle( + widget.themeData, widget.isEdit), decoration: InputDecoration( border: InputBorder.none, - hintStyle: BrnFormUtil.getHintTextStyle(widget.themeData), + hintStyle: + BrnFormUtil.getHintTextStyle(widget.themeData), hintText: widget.hintMax ?? '最大', - counterText: "", contentPadding: EdgeInsets.all(0), isDense: true, enabledBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), + borderSide: + BorderSide(color: Colors.transparent)), focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), + borderSide: + BorderSide(color: Colors.transparent)), ), textAlign: TextAlign.end, controller: _maxController, onChanged: (text) { - BrnFormUtil.notifyInputChanged(widget.onMaxChanged, text); + BrnFormUtil.notifyInputChanged( + widget.onMaxChanged, text); }, ), ), @@ -304,8 +317,4 @@ class BrnRangeInputFormItemState extends State { _maxController?.dispose(); } } - } - - - diff --git a/lib/src/components/form/items/general/brn_ratio_input_item.dart b/lib/src/components/form/items/general/brn_ratio_input_item.dart index 379ce644..266f70aa 100644 --- a/lib/src/components/form/items/general/brn_ratio_input_item.dart +++ b/lib/src/components/form/items/general/brn_ratio_input_item.dart @@ -95,7 +95,6 @@ class BrnRatioInputFormItem extends StatefulWidget { this.onChanged, this.themeData}) : super(key: key) { - this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance .getConfig(configId: this.themeData.configId) @@ -107,7 +106,6 @@ class BrnRatioInputFormItem extends StatefulWidget { BrnRatioInputFormItemState createState() { return BrnRatioInputFormItemState(); } - } class BrnRatioInputFormItemState extends State { @@ -120,7 +118,6 @@ class BrnRatioInputFormItemState extends State { super.initState(); } - @override Widget build(BuildContext context) { return Container( @@ -137,14 +134,21 @@ class BrnRatioInputFormItemState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( - padding: BrnFormUtil.titleEdgeInsets( - widget.prefixIconType, widget.isRequire, widget.themeData), + padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, + widget.isRequire, widget.themeData), child: Row( children: [ - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon( + widget.prefixIconType, + widget.isEdit, + context, + widget.onAddTap, + widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), - BrnFormUtil.buildTitleWidget(widget.title, widget.themeData), - BrnFormUtil.buildTipLabelWidget(widget.tipLabel, widget.onTip, widget.themeData), + BrnFormUtil.buildTitleWidget( + widget.title, widget.themeData), + BrnFormUtil.buildTipLabelWidget( + widget.tipLabel, widget.onTip, widget.themeData), ], ), ), @@ -154,33 +158,39 @@ class BrnRatioInputFormItemState extends State { padding: EdgeInsets.only(right: 10), child: Text( "1 : ", - style: BrnFormUtil.getTitleTextStyle(widget.themeData), + style: + BrnFormUtil.getTitleTextStyle(widget.themeData), )), Container( width: 60, child: TextField( - keyboardType: BrnFormUtil.getInputType(widget.inputType), + keyboardType: + BrnFormUtil.getInputType(widget.inputType), enabled: widget.isEdit, maxLines: 1, - style: BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit), + style: BrnFormUtil.getIsEditTextStyle( + widget.themeData, widget.isEdit), inputFormatters: widget.inputFormatters, decoration: InputDecoration( border: InputBorder.none, - hintStyle: BrnFormUtil.getHintTextStyle(widget.themeData), + hintStyle: + BrnFormUtil.getHintTextStyle(widget.themeData), hintText: widget.hint ?? '请输入', - counterText: "", contentPadding: EdgeInsets.all(0), isDense: true, enabledBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), + borderSide: + BorderSide(color: Colors.transparent)), focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), + borderSide: + BorderSide(color: Colors.transparent)), ), textAlign: TextAlign.end, controller: _controller, onChanged: (text) { - BrnFormUtil.notifyInputChanged(widget.onChanged, text); + BrnFormUtil.notifyInputChanged( + widget.onChanged, text); }, ), ), @@ -207,7 +217,4 @@ class BrnRatioInputFormItemState extends State { _controller?.dispose(); } } - } - - diff --git a/lib/src/components/form/items/general/brn_star_input_item.dart b/lib/src/components/form/items/general/brn_star_input_item.dart index dd20cee3..6b15bf7d 100644 --- a/lib/src/components/form/items/general/brn_star_input_item.dart +++ b/lib/src/components/form/items/general/brn_star_input_item.dart @@ -81,7 +81,6 @@ class BrnStarsFormItem extends StatefulWidget { this.onAddTap, this.onRemoveTap, this.onTip, - this.sumStar: 5, this.value: 0, this.onChanged, @@ -98,7 +97,6 @@ class BrnStarsFormItem extends StatefulWidget { BrnStarsFormItemState createState() { return BrnStarsFormItemState(); } - } class BrnStarsFormItemState extends State { @@ -116,18 +114,25 @@ class BrnStarsFormItemState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( - padding: BrnFormUtil.titleEdgeInsets( - widget.prefixIconType, widget.isRequire, widget.themeData), + padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, + widget.isRequire, widget.themeData), child: ConstrainedBox( constraints: BoxConstraints( maxHeight: 25, ), child: Row( children: [ - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon( + widget.prefixIconType, + widget.isEdit, + context, + widget.onAddTap, + widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), - BrnFormUtil.buildTitleWidget(widget.title, widget.themeData), - BrnFormUtil.buildTipLabelWidget(widget.tipLabel, widget.onTip, widget.themeData), + BrnFormUtil.buildTitleWidget( + widget.title, widget.themeData), + BrnFormUtil.buildTipLabelWidget( + widget.tipLabel, widget.onTip, widget.themeData), ], ))), Row( @@ -160,7 +165,8 @@ class BrnStarsFormItemState extends State { final int label = index; int oldValue = widget.value; widget.value = label + 1; - BrnFormUtil.notifyValueChanged(widget.onChanged, context, oldValue, widget.value); + BrnFormUtil.notifyValueChanged( + widget.onChanged, context, oldValue, widget.value); setState(() {}); }, child: Container( @@ -194,7 +200,4 @@ class BrnStarsFormItemState extends State { return BrunoTools.getAssetImage(BrnAsset.ICON_STAR_UNSELECT); } - } - - diff --git a/lib/src/components/form/items/general/brn_step_input_item.dart b/lib/src/components/form/items/general/brn_step_input_item.dart index 8e694ea7..8af51c31 100644 --- a/lib/src/components/form/items/general/brn_step_input_item.dart +++ b/lib/src/components/form/items/general/brn_step_input_item.dart @@ -71,26 +71,25 @@ class BrnStepInputFormItem extends StatefulWidget { /// form配置 BrnFormItemConfig themeData; - BrnStepInputFormItem( - {Key key, - this.label, - this.title: "", - this.subTitle, - this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, - this.error: "", - this.isEdit: true, - this.isRequire: false, - this.onAddTap, - this.onRemoveTap, - this.onTip, - this.value: 0, - this.maxLimit: 10, - this.minLimit: 0, - this.onChanged, - this.themeData, }) - : super(key: key) { - + BrnStepInputFormItem({ + Key key, + this.label, + this.title: "", + this.subTitle, + this.tipLabel, + this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.error: "", + this.isEdit: true, + this.isRequire: false, + this.onAddTap, + this.onRemoveTap, + this.onTip, + this.value: 0, + this.maxLimit: 10, + this.minLimit: 0, + this.onChanged, + this.themeData, + }) : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance .getConfig(configId: this.themeData.configId) @@ -98,16 +97,13 @@ class BrnStepInputFormItem extends StatefulWidget { .merge(this.themeData); } - @override BrnStepInputFormItemState createState() { return BrnStepInputFormItemState(); } - } class BrnStepInputFormItemState extends State { - @override Widget build(BuildContext context) { return Container( @@ -124,14 +120,21 @@ class BrnStepInputFormItemState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( - padding: BrnFormUtil.titleEdgeInsets( - widget.prefixIconType, widget.isRequire, widget.themeData), + padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, + widget.isRequire, widget.themeData), child: Row( children: [ - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon( + widget.prefixIconType, + widget.isEdit, + context, + widget.onAddTap, + widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), - BrnFormUtil.buildTitleWidget(widget.title, widget.themeData), - BrnFormUtil.buildTipLabelWidget(widget.tipLabel, widget.onTip, widget.themeData), + BrnFormUtil.buildTitleWidget( + widget.title, widget.themeData), + BrnFormUtil.buildTipLabelWidget( + widget.tipLabel, widget.onTip, widget.themeData), ], ), ), @@ -150,16 +153,16 @@ class BrnStepInputFormItemState extends State { if (widget.value == null) { widget.value = 1; - BrnFormUtil.notifyValueChanged( - widget.onChanged, context, widget.value + 1, widget.value); + BrnFormUtil.notifyValueChanged(widget.onChanged, + context, widget.value + 1, widget.value); setState(() {}); return; } if (!isReachMinLevel()) { widget.value = widget.value - 1; - BrnFormUtil.notifyValueChanged( - widget.onChanged, context, widget.value + 1, widget.value); + BrnFormUtil.notifyValueChanged(widget.onChanged, + context, widget.value + 1, widget.value); setState(() {}); } }, @@ -190,16 +193,16 @@ class BrnStepInputFormItemState extends State { if (widget.value == null) { widget.value = 1; - BrnFormUtil.notifyValueChanged( - widget.onChanged, context, widget.value - 1, widget.value); + BrnFormUtil.notifyValueChanged(widget.onChanged, + context, widget.value - 1, widget.value); setState(() {}); return; } if (!isReachMaxLevel()) { widget.value = widget.value + 1; - BrnFormUtil.notifyValueChanged( - widget.onChanged, context, widget.value - 1, widget.value); + BrnFormUtil.notifyValueChanged(widget.onChanged, + context, widget.value - 1, widget.value); setState(() {}); } }, @@ -281,8 +284,4 @@ class BrnStepInputFormItemState extends State { return false; } - } - - - diff --git a/lib/src/components/form/items/general/brn_text_block_input_item.dart b/lib/src/components/form/items/general/brn_text_block_input_item.dart index 564c9729..c0f85bb4 100644 --- a/lib/src/components/form/items/general/brn_text_block_input_item.dart +++ b/lib/src/components/form/items/general/brn_text_block_input_item.dart @@ -67,6 +67,7 @@ class BrnTextBlockInputFormItem extends StatefulWidget { /// 输入内容类型 final String inputType; + /// 指定对输入数据的格式化要求 List inputFormatters; @@ -109,7 +110,6 @@ class BrnTextBlockInputFormItem extends StatefulWidget { this.maxLines = 20, this.themeData}) : super(key: key) { - this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance .getConfig(configId: this.themeData.configId) @@ -121,7 +121,6 @@ class BrnTextBlockInputFormItem extends StatefulWidget { BrnTextBlockInputFormItemState createState() { return BrnTextBlockInputFormItemState(); } - } class BrnTextBlockInputFormItemState extends State { @@ -151,14 +150,20 @@ class BrnTextBlockInputFormItemState extends State { child: Row( children: [ // 添加/删除 按钮 - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon( + widget.prefixIconType, + widget.isEdit, + context, + widget.onAddTap, + widget.onRemoveTap), // 是否必填图标 BrnFormUtil.buildRequireWidget(widget.isRequire), // title BrnFormUtil.buildTitleWidget(widget.title, widget.themeData), - BrnFormUtil.buildTipLabelWidget(widget.tipLabel, widget.onTip, widget.themeData), + BrnFormUtil.buildTipLabelWidget( + widget.tipLabel, widget.onTip, widget.themeData), ], ), ), @@ -182,7 +187,8 @@ class BrnTextBlockInputFormItemState extends State { minLines: widget.minLines ?? 4, textAlign: TextAlign.left, enabled: widget.isEdit, - style: BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit), + style: BrnFormUtil.getIsEditTextStyle( + widget.themeData, widget.isEdit), inputFormatters: widget.inputFormatters, decoration: InputDecoration( hintText: widget.hint ?? "请输入", @@ -190,13 +196,12 @@ class BrnTextBlockInputFormItemState extends State { contentPadding: EdgeInsets.all(0), border: InputBorder.none, isDense: true, - enabledBorder: - UnderlineInputBorder(borderSide: BorderSide(color: Colors.transparent)), - focusedBorder: - UnderlineInputBorder(borderSide: BorderSide(color: Colors.transparent)), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), ), onChanged: (text) { - BrnFormUtil.notifyInputChanged(widget.onChanged, text); }, ), @@ -206,7 +211,6 @@ class BrnTextBlockInputFormItemState extends State { ); } - @override void dispose() { super.dispose(); @@ -214,8 +218,4 @@ class BrnTextBlockInputFormItemState extends State { _controller?.dispose(); } } - - } - - diff --git a/lib/src/components/form/items/general/brn_text_input_item.dart b/lib/src/components/form/items/general/brn_text_input_item.dart index 5ac1d245..4018cb4d 100644 --- a/lib/src/components/form/items/general/brn_text_input_item.dart +++ b/lib/src/components/form/items/general/brn_text_input_item.dart @@ -110,7 +110,6 @@ class BrnTextInputFormItem extends StatefulWidget { this.controller, this.themeData, }) : super(key: key) { - this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance .getConfig(configId: this.themeData.configId) @@ -122,7 +121,6 @@ class BrnTextInputFormItem extends StatefulWidget { State createState() { return BrnTextInputFormItemState(); } - } class BrnTextInputFormItemState extends State { @@ -134,7 +132,6 @@ class BrnTextInputFormItemState extends State { super.initState(); } - @override Widget build(BuildContext context) { return Container( @@ -150,23 +147,31 @@ class BrnTextInputFormItemState extends State { child: Row( children: [ Container( - padding: BrnFormUtil.titleEdgeInsets( - widget.prefixIconType, widget.isRequire, widget.themeData), + padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, + widget.isRequire, widget.themeData), child: Row( children: [ - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon( + widget.prefixIconType, + widget.isEdit, + context, + widget.onAddTap, + widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), - BrnFormUtil.buildTitleWidget(widget.title, widget.themeData), + BrnFormUtil.buildTitleWidget( + widget.title, widget.themeData), Offstage( offstage: (widget.prefixText == null), child: Container( padding: EdgeInsets.only(left: 10, right: 10), child: Text( widget.prefixText ?? "", - style: BrnFormUtil.getTitleTextStyle(widget.themeData), + style: BrnFormUtil.getTitleTextStyle( + widget.themeData), )), ), - BrnFormUtil.buildTipLabelWidget(widget.tipLabel, widget.onTip, widget.themeData), + BrnFormUtil.buildTipLabelWidget( + widget.tipLabel, widget.onTip, widget.themeData), ], ), ), @@ -176,26 +181,24 @@ class BrnTextInputFormItemState extends State { enabled: widget.isEdit, maxLines: 1, maxLength: widget.maxCharCount, - style: BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit), + style: BrnFormUtil.getIsEditTextStyle( + widget.themeData, widget.isEdit), decoration: InputDecoration( border: InputBorder.none, hintStyle: BrnFormUtil.getHintTextStyle(widget.themeData), hintText: widget.hint ?? '请输入', counterText: "", - contentPadding: EdgeInsets.all(0), isDense: true, - enabledBorder: - UnderlineInputBorder(borderSide: BorderSide(color: Colors.transparent)), - focusedBorder: - UnderlineInputBorder(borderSide: BorderSide(color: Colors.transparent)), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), ), - textAlign: TextAlign.end, controller: _controller, inputFormatters: widget.inputFormatters, onChanged: (text) { - BrnFormUtil.notifyInputChanged(widget.onChanged, text); }, ), @@ -232,4 +235,3 @@ class BrnTextInputFormItemState extends State { } } } - diff --git a/lib/src/components/form/items/general/brn_text_select_item.dart b/lib/src/components/form/items/general/brn_text_select_item.dart index d71430ed..3c400269 100644 --- a/lib/src/components/form/items/general/brn_text_select_item.dart +++ b/lib/src/components/form/items/general/brn_text_select_item.dart @@ -133,7 +133,6 @@ class BrnTextSelectFormItem extends StatefulWidget { this.layoutRatio, this.themeData}) : super(key: key) { - this._isAutoLayout = true; this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance @@ -146,19 +145,19 @@ class BrnTextSelectFormItem extends StatefulWidget { BrnTextSelectFormItemState createState() { return BrnTextSelectFormItemState(); } - } double _fontSize = BrnFont.FONT_16; -StrutStyle _contentStructStyle = - StrutStyle(forceStrutHeight: true, height: 1, leading: 0.5, fontSize: _fontSize); +StrutStyle _contentStructStyle = StrutStyle( + forceStrutHeight: true, height: 1, leading: 0.5, fontSize: _fontSize); class BrnTextSelectFormItemState extends State { @override Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.computeItemEdgeInsets2(widget.prefixIconType, widget.isRequire), + padding: BrnFormUtil.computeItemEdgeInsets2( + widget.prefixIconType, widget.isRequire), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -166,10 +165,10 @@ class BrnTextSelectFormItemState extends State { ? _buildAutoLayoutTitleWidget(context) : _buildTitleWidget(context), - // 副标题 + // 副标题 BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), - // 错误提示 + // 错误提示 BrnFormUtil.buildErrorWidget(widget.error, widget.themeData) ], ), @@ -194,17 +193,24 @@ class BrnTextSelectFormItemState extends State { // 当左侧标题显示不下时折行展示 // 当有用户自定义比例时用用户自定义比例 Widget _buildAutoLayoutTitleWidget(BuildContext context) { - return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { double maxWidth = _getTitleMaxWidth(context, constraints); return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Flexible( child: Container( - padding: BrnFormUtil.computeEdgeInsets2(widget.prefixIconType, widget.isRequire), + padding: BrnFormUtil.computeEdgeInsets2( + widget.prefixIconType, widget.isRequire), child: Row( children: [ - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon( + widget.prefixIconType, + widget.isEdit, + context, + widget.onAddTap, + widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), Flexible(child: _buildTitleTextWidget()), _buildTipWidget(), @@ -243,7 +249,8 @@ class BrnTextSelectFormItemState extends State { children: [ Expanded(child: buildText()), Container( - height: calculateTextHeight(context, getCalculateText(), _fontSize, 1), + height: calculateTextHeight( + context, getCalculateText(), _fontSize, 1), alignment: Alignment.center, child: BrnFormUtil.getRightArrowIcon(), ), @@ -253,7 +260,6 @@ class BrnTextSelectFormItemState extends State { ); } - // 提示语 Widget _buildTipWidget() { return Offstage( @@ -280,7 +286,10 @@ class BrnTextSelectFormItemState extends State { widget.tipLabel ?? "", overflow: TextOverflow.ellipsis, strutStyle: StrutStyle( - forceStrutHeight: true, height: 1, leading: 0.5, fontSize: BrnFont.FONT_14), + forceStrutHeight: true, + height: 1, + leading: 0.5, + fontSize: BrnFont.FONT_14), style: BrnFormUtil.getTipsTextStyle(widget.themeData), ), ), @@ -294,7 +303,9 @@ class BrnTextSelectFormItemState extends State { Widget _buildTitleTextWidget() { return Text( widget.title ?? "", - overflow: widget.titleMaxLines == null ? TextOverflow.clip : TextOverflow.ellipsis, + overflow: widget.titleMaxLines == null + ? TextOverflow.clip + : TextOverflow.ellipsis, maxLines: widget.titleMaxLines, strutStyle: _contentStructStyle, style: BrnFormUtil.getTitleTextStyle(widget.themeData, height: 1), @@ -307,10 +318,12 @@ class BrnTextSelectFormItemState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - padding: BrnFormUtil.computeEdgeInsets2(widget.prefixIconType, widget.isRequire), + padding: BrnFormUtil.computeEdgeInsets2( + widget.prefixIconType, widget.isRequire), child: Row( children: [ - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, + context, widget.onAddTap, widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), _buildTitleTextWidget(), _buildTipWidget(), @@ -337,7 +350,9 @@ class BrnTextSelectFormItemState extends State { strutStyle: _contentStructStyle, text: TextSpan( text: widget.value, - style: BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit, height: 1), + style: BrnFormUtil.getIsEditTextStyle( + widget.themeData, widget.isEdit, + height: 1), )); } else { painter = TextPainter( @@ -364,7 +379,8 @@ class BrnTextSelectFormItemState extends State { maxLines: widget.valueMaxLines ?? 1, textAlign: TextAlign.end, strutStyle: _contentStructStyle, - style: BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit, height: 1), + style: BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit, + height: 1), ); } else { return Text( @@ -410,6 +426,4 @@ class BrnTextSelectFormItemState extends State { // 文字的高度:painter.height return painter.height < fontSize ? fontSize : painter.height; } - } - diff --git a/lib/src/components/form/items/general/brn_title_select_input_item.dart b/lib/src/components/form/items/general/brn_title_select_input_item.dart index c5975d02..ad23341b 100644 --- a/lib/src/components/form/items/general/brn_title_select_input_item.dart +++ b/lib/src/components/form/items/general/brn_title_select_input_item.dart @@ -116,7 +116,6 @@ class BrnTitleSelectInputFormItem extends StatefulWidget { this.controller, this.themeData}) : super(key: key) { - this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance .getConfig(configId: this.themeData.configId) @@ -125,11 +124,12 @@ class BrnTitleSelectInputFormItem extends StatefulWidget { } @override - BrnTitleSelectInputFormItemState createState() => BrnTitleSelectInputFormItemState(); - + BrnTitleSelectInputFormItemState createState() => + BrnTitleSelectInputFormItemState(); } -class BrnTitleSelectInputFormItemState extends State { +class BrnTitleSelectInputFormItemState + extends State { TextEditingController _controller; StreamController _showController; StreamController _textController; @@ -174,18 +174,20 @@ class BrnTitleSelectInputFormItemState extends State[ - BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, widget.onAddTap, widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, + context, widget.onAddTap, widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), //menu _buildMenuWidget(), //小三角 _buildTriangle(), - BrnFormUtil.buildTipLabelWidget(widget.tipLabel, widget.onTip, widget.themeData), + BrnFormUtil.buildTipLabelWidget( + widget.tipLabel, widget.onTip, widget.themeData), ], ), ); @@ -204,7 +206,8 @@ class BrnTitleSelectInputFormItemState extends State snapshot) { return snapshot.data - ? BrunoTools.getAssetImageWithBandColor(BrnAsset.ICON_SELECTED_UP_TRIANGLE) + ? BrunoTools.getAssetImageWithBandColor( + BrnAsset.ICON_SELECTED_UP_TRIANGLE) : BrunoTools.getAssetImage(BrnAsset.ICON_UNSELECT_DOWN_TRIANGLE); }, ), @@ -295,16 +302,14 @@ class BrnTitleSelectInputFormItemState extends State { ), ], color: Colors.white, - border: Border.all(color: widget.themeData.commonConfig.dividerColorBase, width: 0.5), + border: Border.all( + color: widget.themeData.commonConfig.dividerColorBase, width: 0.5), borderRadius: BorderRadius.all(Radius.circular(4)), ), child: Column( @@ -414,4 +417,3 @@ class _TitleSelectPopWidgetState extends State { ); } } - diff --git a/lib/src/components/form/items/group/brn_expand_group.dart b/lib/src/components/form/items/group/brn_expand_group.dart index b1f4584e..770a8191 100644 --- a/lib/src/components/form/items/group/brn_expand_group.dart +++ b/lib/src/components/form/items/group/brn_expand_group.dart @@ -65,10 +65,8 @@ class BrnExpandFormGroup extends StatefulWidget { this.error: "", this.isEdit: true, this.isRequire: false, - this.onRemoveTap, this.onTip, - this.isExpand: true, this.deleteLabel, this.children, @@ -78,11 +76,9 @@ class BrnExpandFormGroup extends StatefulWidget { BrnExpandFormGroupState createState() { return BrnExpandFormGroupState(); } - } class BrnExpandFormGroupState extends State { - @override Widget build(BuildContext context) { return Container( @@ -119,8 +115,4 @@ class BrnExpandFormGroupState extends State { return result; } - - } - - diff --git a/lib/src/components/form/items/group/brn_normal_group.dart b/lib/src/components/form/items/group/brn_normal_group.dart index 5573eab5..59bfcc76 100644 --- a/lib/src/components/form/items/group/brn_normal_group.dart +++ b/lib/src/components/form/items/group/brn_normal_group.dart @@ -71,7 +71,6 @@ class BrnNormalFormGroup extends StatefulWidget { this.deleteLabel, this.children, }) : super() { - this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance .getConfig(configId: this.themeData.configId) @@ -83,7 +82,6 @@ class BrnNormalFormGroup extends StatefulWidget { BrnNormalFormGroupState createState() { return BrnNormalFormGroupState(); } - } class BrnNormalFormGroupState extends State { @@ -113,8 +111,9 @@ class BrnNormalFormGroupState extends State { padding: EdgeInsets.only(left: 20, right: 6), child: Text( widget.title ?? "", - style: - BrnFormUtil.getHeadTitleTextStyle(widget.themeData, isBold: true), + style: BrnFormUtil.getHeadTitleTextStyle( + widget.themeData, + isBold: true), )), ], ), @@ -185,7 +184,4 @@ class BrnNormalFormGroupState extends State { return result; } - } - - diff --git a/lib/src/components/form/items/group/element_expand_widget.dart b/lib/src/components/form/items/group/element_expand_widget.dart index 05a05526..587dbb3a 100644 --- a/lib/src/components/form/items/group/element_expand_widget.dart +++ b/lib/src/components/form/items/group/element_expand_widget.dart @@ -90,9 +90,12 @@ class ExpansionElementWidget extends StatefulWidget { class _ExpansionElementState extends State with SingleTickerProviderStateMixin { - static final Animatable _easeOutTween = CurveTween(curve: Curves.easeOut); - static final Animatable _easeInTween = CurveTween(curve: Curves.easeIn); - static final Animatable _halfTween = Tween(begin: 0.0, end: 0.5); + static final Animatable _easeOutTween = + CurveTween(curve: Curves.easeOut); + static final Animatable _easeInTween = + CurveTween(curve: Curves.easeIn); + static final Animatable _halfTween = + Tween(begin: 0.0, end: 0.5); /// 头部颜色 final ColorTween _borderColorTween = ColorTween(); @@ -111,15 +114,17 @@ class _ExpansionElementState extends State @override void initState() { super.initState(); - _isExpanded = PageStorage.of(context)?.readState(context) ?? widget.initiallyExpanded; + _isExpanded = + PageStorage.of(context)?.readState(context) ?? widget.initiallyExpanded; - _controller = - AnimationController(duration: Duration(milliseconds: 200) /*_kExpand*/, vsync: this); + _controller = AnimationController( + duration: Duration(milliseconds: 200) /*_kExpand*/, vsync: this); _heightFactor = _controller.drive(_easeInTween); if (_isExpanded) { _iconTurns = _controller.drive(_halfTween.chain(_easeInTween)); } else { - _iconTurns = _controller.drive(Tween(begin: 0.5, end: 0.0).chain(_easeInTween)); + _iconTurns = _controller + .drive(Tween(begin: 0.5, end: 0.0).chain(_easeInTween)); } /// 头部颜色 @@ -157,12 +162,14 @@ class _ExpansionElementState extends State } PageStorage.of(context)?.writeState(context, _isExpanded); }); - if (widget.onExpansionChanged != null) widget.onExpansionChanged(_isExpanded); + if (widget.onExpansionChanged != null) + widget.onExpansionChanged(_isExpanded); } Widget _buildHeader(BuildContext context, Widget child) { final Color borderSideColor = /*_borderColor.value ??*/ Colors.transparent; - final Color backgroundColor = /*_backgroundColor.value ??*/ Colors.transparent; + final Color backgroundColor = /*_backgroundColor.value ??*/ Colors + .transparent; return Container( decoration: BoxDecoration( @@ -192,8 +199,9 @@ class _ExpansionElementState extends State padding: EdgeInsets.only(right: 6), child: Text( widget.title ?? "", - style: - BrnFormUtil.getHeadTitleTextStyle(widget.themeData, isBold: true), + style: BrnFormUtil.getHeadTitleTextStyle( + widget.themeData, + isBold: true), )), RotationTransition( turns: _iconTurns, diff --git a/lib/src/components/form/items/misc/brn_add_label_item.dart b/lib/src/components/form/items/misc/brn_add_label_item.dart index f943106a..87981746 100644 --- a/lib/src/components/form/items/misc/brn_add_label_item.dart +++ b/lib/src/components/form/items/misc/brn_add_label_item.dart @@ -9,12 +9,9 @@ import 'package:flutter/widgets.dart'; /// 添加组类型录入项所使用的Widget // ignore: must_be_immutable class BrnAddLabel extends StatefulWidget { - /// 录入项的唯一标识,主要用于录入类型页面框架中 final String label; - - /// 录入项类型,主要用于录入类型页面框架中 String type = BrnInputItemType.LABEL_ADD; @@ -27,7 +24,6 @@ class BrnAddLabel extends StatefulWidget { /// 点击录入区回调 final VoidCallback onTap; - BrnAddLabel({ Key key, this.label, @@ -40,12 +36,9 @@ class BrnAddLabel extends StatefulWidget { BrnAddLabelState createState() { return BrnAddLabelState(); } - } class BrnAddLabelState extends State { - - @override Widget build(BuildContext context) { return GestureDetector( @@ -62,15 +55,14 @@ class BrnAddLabelState extends State { child: Text( widget.title ?? "", style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, fontSize: BrnFont.FONT_18, ), ), ), ); } - - } - - diff --git a/lib/src/components/form/items/misc/brn_title_item.dart b/lib/src/components/form/items/misc/brn_title_item.dart index cab5aa33..fe024075 100644 --- a/lib/src/components/form/items/misc/brn_title_item.dart +++ b/lib/src/components/form/items/misc/brn_title_item.dart @@ -67,7 +67,6 @@ class BrnTitleFormItem extends StatefulWidget { this.onTap, this.themeData}) : super(key: key) { - this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance .getConfig(configId: this.themeData.configId) @@ -79,11 +78,9 @@ class BrnTitleFormItem extends StatefulWidget { BrnTitleFormItemState createState() { return BrnTitleFormItemState(); } - } class BrnTitleFormItemState extends State { - @override Widget build(BuildContext context) { return Container( @@ -100,18 +97,21 @@ class BrnTitleFormItemState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( - padding: BrnFormUtil.titleEdgeInsets( - widget.prefixIconType, widget.isRequire, widget.themeData), + padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, + widget.isRequire, widget.themeData), child: Row( children: [ // 主标题 Container( - child: Text(widget.title ?? "", - style: BrnFormUtil.getHeadTitleTextStyle(widget.themeData), + child: Text( + widget.title ?? "", + style: + BrnFormUtil.getHeadTitleTextStyle(widget.themeData), )), // 问号提示 - BrnFormUtil.buildTipLabelWidget(widget.tipLabel, widget.onTip, widget.themeData), + BrnFormUtil.buildTipLabelWidget( + widget.tipLabel, widget.onTip, widget.themeData), ], ), ), @@ -151,7 +151,4 @@ class BrnTitleFormItemState extends State { ), ); } - } - - diff --git a/lib/src/components/form/items/title/brn_base_title_item.dart b/lib/src/components/form/items/title/brn_base_title_item.dart index 81ba692a..b03187ac 100644 --- a/lib/src/components/form/items/title/brn_base_title_item.dart +++ b/lib/src/components/form/items/title/brn_base_title_item.dart @@ -98,10 +98,10 @@ class BrnTitleState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( - padding: BrnFormUtil.titleEdgeInsetsForHead(widget.isRequire, widget.themeData), + padding: BrnFormUtil.titleEdgeInsetsForHead( + widget.isRequire, widget.themeData), child: Row( children: [ - // 必填项符号 BrnFormUtil.buildRequireWidget(widget.isRequire), @@ -109,7 +109,8 @@ class BrnTitleState extends State { getTitleWidget(), // 问号提示 - BrnFormUtil.buildTipLabelWidget(widget.tipLabel, widget.onTip, widget.themeData), + BrnFormUtil.buildTipLabelWidget( + widget.tipLabel, widget.onTip, widget.themeData), ], ), ), diff --git a/lib/src/components/form/undetermined/brn_expandable_group.dart b/lib/src/components/form/undetermined/brn_expandable_group.dart index 96abc198..4a7ba3fc 100644 --- a/lib/src/components/form/undetermined/brn_expandable_group.dart +++ b/lib/src/components/form/undetermined/brn_expandable_group.dart @@ -10,7 +10,6 @@ import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; - /// A single-line [ListTile] with a trailing button that expands or collapses /// the tile to reveal or hide the [children]. /// @@ -76,7 +75,6 @@ class BrnExpandableGroup extends StatefulWidget { /// The color to display behind the sublist when expanded. final Color backgroundColor; - /// Specifies if the list tile is initially expanded (true) or collapsed (false, the default). final bool initiallyExpanded; @@ -88,8 +86,10 @@ class BrnExpandableGroup extends StatefulWidget { class _BrnExpansionElementState extends State with SingleTickerProviderStateMixin { - static final Animatable _easeInTween = CurveTween(curve: Curves.easeIn); - static final Animatable _halfTween = Tween(begin: 0.0, end: 0.5); + static final Animatable _easeInTween = + CurveTween(curve: Curves.easeIn); + static final Animatable _halfTween = + Tween(begin: 0.0, end: 0.5); /// 头部颜色 final ColorTween _borderColorTween = ColorTween(); @@ -108,15 +108,17 @@ class _BrnExpansionElementState extends State @override void initState() { super.initState(); - _isExpanded = PageStorage.of(context)?.readState(context) ?? widget.initiallyExpanded; + _isExpanded = + PageStorage.of(context)?.readState(context) ?? widget.initiallyExpanded; - _controller = - AnimationController(duration: Duration(milliseconds: 200) /*_kExpand*/, vsync: this); + _controller = AnimationController( + duration: Duration(milliseconds: 200) /*_kExpand*/, vsync: this); _heightFactor = _controller.drive(_easeInTween); if (_isExpanded) { _iconTurns = _controller.drive(_halfTween.chain(_easeInTween)); } else { - _iconTurns = _controller.drive(Tween(begin: 0.5, end: 0.0).chain(_easeInTween)); + _iconTurns = _controller + .drive(Tween(begin: 0.5, end: 0.0).chain(_easeInTween)); } if (_isExpanded) { @@ -124,7 +126,8 @@ class _BrnExpansionElementState extends State } if (_isExpanded) { - arrowIcon = BrunoTools.getAssetSizeImage(BrnAsset.ICON_DOWN_ARROW, 12, 12); + arrowIcon = + BrunoTools.getAssetSizeImage(BrnAsset.ICON_DOWN_ARROW, 12, 12); } else { arrowIcon = BrunoTools.getAssetSizeImage(BrnAsset.ICON_UP_ARROW, 12, 12); } @@ -148,11 +151,12 @@ class _BrnExpansionElementState extends State } PageStorage.of(context)?.writeState(context, _isExpanded); }); - if (widget.onExpansionChanged != null) widget.onExpansionChanged(_isExpanded); + if (widget.onExpansionChanged != null) + widget.onExpansionChanged(_isExpanded); } Widget _buildHeader(BuildContext context, Widget child) { - final Color backgroundColor = Colors.transparent; + final Color backgroundColor = Colors.transparent; return Container( color: backgroundColor, @@ -165,7 +169,8 @@ class _BrnExpansionElementState extends State }, child: Container( color: Colors.white, - padding: EdgeInsets.only(left: 20, top: 14, bottom: 14, right: 20), + padding: + EdgeInsets.only(left: 20, top: 14, bottom: 14, right: 20), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, @@ -177,8 +182,9 @@ class _BrnExpansionElementState extends State padding: EdgeInsets.only(right: 6), child: Text( widget.title ?? "", - style: - BrnFormUtil.getHeadTitleTextStyle(widget.themeData, isBold: true), + style: BrnFormUtil.getHeadTitleTextStyle( + widget.themeData, + isBold: true), )), // 副标题 Container( @@ -187,11 +193,13 @@ class _BrnExpansionElementState extends State padding: EdgeInsets.only(top: 4), child: Offstage( // ignore: deprecated_member_use_from_same_package - offstage: (widget.subtitle == null || widget.subtitle.isEmpty), + offstage: (widget.subtitle == null || + widget.subtitle.isEmpty), child: Text( // ignore: deprecated_member_use_from_same_package widget.subtitle ?? "", - style: BrnFormUtil.getSubTitleTextStyle(widget.themeData), + style: BrnFormUtil.getSubTitleTextStyle( + widget.themeData), ), ), ), diff --git a/lib/src/components/form/undetermined/brn_portrait_radio_group.dart b/lib/src/components/form/undetermined/brn_portrait_radio_group.dart index 82795d5e..36504d9c 100644 --- a/lib/src/components/form/undetermined/brn_portrait_radio_group.dart +++ b/lib/src/components/form/undetermined/brn_portrait_radio_group.dart @@ -51,8 +51,10 @@ class BrnPortraitRadioGroup extends StatefulWidget { this.themeData, this.isCollapseContent = false, }) { - this.options = - options?.map((item) => BrnPortraitRadioGroupOption(title: item))?.toList() ?? List(); + this.options = options + ?.map((item) => BrnPortraitRadioGroupOption(title: item)) + ?.toList() ?? + List(); int selectedIndex = options.indexOf(selectedOption); if (selectedIndex > -1) { this.selectedOption = this.options[selectedIndex]; @@ -131,7 +133,8 @@ class BrnPortraitRadioGroupState extends State { fit: FlexFit.tight, child: Text( option.title ?? '', - overflow: widget.isCollapseContent ? TextOverflow.ellipsis : null, + overflow: + widget.isCollapseContent ? TextOverflow.ellipsis : null, maxLines: widget.isCollapseContent ? 1 : null, style: getOptionTextStyle(option, index), ), @@ -160,7 +163,8 @@ class BrnPortraitRadioGroupState extends State { padding: EdgeInsets.only(top: 4, right: 20), child: Text( option.subTitle ?? '', - overflow: widget.isCollapseContent ? TextOverflow.ellipsis : null, + overflow: + widget.isCollapseContent ? TextOverflow.ellipsis : null, maxLines: widget.isCollapseContent ? 1 : null, style: BrnFormUtil.getSubTitleTextStyle(widget.themeData), ), @@ -191,7 +195,8 @@ class BrnPortraitRadioGroupState extends State { return selectedIndex; } - bool isSameOption(BrnPortraitRadioGroupOption src, BrnPortraitRadioGroupOption dst) { + bool isSameOption( + BrnPortraitRadioGroupOption src, BrnPortraitRadioGroupOption dst) { if (src == null || dst == null) return false; return src.title == dst.title && src.subTitle == dst.subTitle; } diff --git a/lib/src/components/form/utils/brn_form_util.dart b/lib/src/components/form/utils/brn_form_util.dart index b6481e93..b15c7c33 100644 --- a/lib/src/components/form/utils/brn_form_util.dart +++ b/lib/src/components/form/utils/brn_form_util.dart @@ -11,8 +11,8 @@ class BrnFormUtil { /// /// 获取添加、删除图标 - static Widget buildPrefixIcon(String prefixIconType, bool isEdit, BuildContext context, - VoidCallback onAddTap, VoidCallback onRemoveTap) { + static Widget buildPrefixIcon(String prefixIconType, bool isEdit, + BuildContext context, VoidCallback onAddTap, VoidCallback onRemoveTap) { return Offstage( offstage: prefixIconType == BrnPrefixIconType.TYPE_NORMAL, child: Container( @@ -23,7 +23,8 @@ class BrnFormUtil { return; } - BrnFormUtil.notifyAddRemoveTap(context, prefixIconType, onAddTap, onRemoveTap); + BrnFormUtil.notifyAddRemoveTap( + context, prefixIconType, onAddTap, onRemoveTap); }, child: BrnFormUtil.getPrefixIcon(prefixIconType), ), @@ -45,7 +46,8 @@ class BrnFormUtil { } /// 获取子标题Widget - static Widget buildSubTitleWidget(String subTitle, BrnFormItemConfig themeData) { + static Widget buildSubTitleWidget( + String subTitle, BrnFormItemConfig themeData) { return Offstage( offstage: (subTitle == null || subTitle.isEmpty), child: Container( @@ -58,7 +60,7 @@ class BrnFormUtil { } /// 获取必填项 - static Widget buildRequireWidget(bool isRequire){ + static Widget buildRequireWidget(bool isRequire) { return Offstage( offstage: (isRequire == null || !isRequire), child: BrnFormUtil.getRequireIcon(isRequire), @@ -66,7 +68,8 @@ class BrnFormUtil { } /// 获取问号 - static Widget buildTipLabelWidget(String tipLabel,VoidCallback onTip,BrnFormItemConfig themeData){ + static Widget buildTipLabelWidget( + String tipLabel, VoidCallback onTip, BrnFormItemConfig themeData) { return Offstage( offstage: (tipLabel == null), child: GestureDetector( @@ -97,9 +100,9 @@ class BrnFormUtil { static Widget buildTitleWidget(String title, BrnFormItemConfig themeData) { return Container( child: Text( - title ?? "", - style: BrnFormUtil.getTitleTextStyle(themeData), - )); + title ?? "", + style: BrnFormUtil.getTitleTextStyle(themeData), + )); } /// 录入项是否可编辑 @@ -110,9 +113,6 @@ class BrnFormUtil { return isEdit; } - - - static Widget getPrefixIcon(String type) { if (type == BrnPrefixIconType.TYPE_ADD) { return BrunoTools.getAssetImageWithBandColor(BrnAsset.ICON_ADD_FORM_ITEM); @@ -128,7 +128,10 @@ class BrnFormUtil { ? BrnFormUtil.getPrefixIcon(type) : ColorFiltered( colorFilter: ColorFilter.mode( - BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextHint, + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextHint, BlendMode.srcIn), child: BrnFormUtil.getPrefixIcon(type), ); @@ -138,16 +141,19 @@ class BrnFormUtil { isRequire ??= false; return Container( - padding: isRequire ? EdgeInsets.only(right: 2) : EdgeInsets.only(right: 0), + padding: + isRequire ? EdgeInsets.only(right: 2) : EdgeInsets.only(right: 0), child: isRequire - ? BrunoTools.getAssetSizeImage(BrnAsset.ICON_REQUIRE_RED, 8, 8, color: Color(0xFFFA3F3F)) + ? BrunoTools.getAssetSizeImage(BrnAsset.ICON_REQUIRE_RED, 8, 8, + color: Color(0xFFFA3F3F)) : null, ); } /// 视觉同学要求修改右箭头图标 static Image getRightArrowIcon() { - return BrunoTools.getAssetSizeImage(BrnAsset.ICON_RIGHT_ARROW, rightArrowSize, rightArrowSize); + return BrunoTools.getAssetSizeImage( + BrnAsset.ICON_RIGHT_ARROW, rightArrowSize, rightArrowSize); } static Image getQuestionMarkIcon() { @@ -225,8 +231,8 @@ class BrnFormUtil { /// /// 处理点击"添加/删除"按钮动作 - static void notifyAddRemoveTap(BuildContext context, String prefixIconType, VoidCallback onAddTap, - VoidCallback onRemoveTap) { + static void notifyAddRemoveTap(BuildContext context, String prefixIconType, + VoidCallback onAddTap, VoidCallback onRemoveTap) { if (BrnPrefixIconType.TYPE_ADD == prefixIconType) { if (onAddTap != null) { onAddTap(); @@ -260,23 +266,24 @@ class BrnFormUtil { } /// 处理 输入状态 变化 - static void notifyInputChanged(ValueChanged onTextChanged, String newStr) { + static void notifyInputChanged( + ValueChanged onTextChanged, String newStr) { if (onTextChanged != null) { onTextChanged(/*oldStr, */ newStr); } } /// 处理 开关 变化 - static void notifySwitchChanged( - OnBrnFormSwitchChanged onSwitchChanged, BuildContext context, bool oldValue, bool newValue) { + static void notifySwitchChanged(OnBrnFormSwitchChanged onSwitchChanged, + BuildContext context, bool oldValue, bool newValue) { if (onSwitchChanged != null) { onSwitchChanged(oldValue, newValue); } } /// 处理 数字值 变化 - static void notifyValueChanged( - OnBrnFormValueChanged onValueChanged, BuildContext context, int oldVal, int newVal) { + static void notifyValueChanged(OnBrnFormValueChanged onValueChanged, + BuildContext context, int oldVal, int newVal) { if (onValueChanged != null) { onValueChanged(oldVal, newVal); } @@ -317,7 +324,8 @@ class BrnFormUtil { } /// 标题行的左间距 - static EdgeInsets titleEdgeInsets(String type, bool isRequire, BrnFormItemConfig themeData) { + static EdgeInsets titleEdgeInsets( + String type, bool isRequire, BrnFormItemConfig themeData) { isRequire ??= false; if (isRequire && type == BrnPrefixIconType.TYPE_NORMAL) { return themeData?.titlePaddingSm; @@ -326,7 +334,8 @@ class BrnFormUtil { } /// 标题行的左间距 - static EdgeInsets titleEdgeInsetsForHead(bool isRequire, BrnFormItemConfig themeData) { + static EdgeInsets titleEdgeInsetsForHead( + bool isRequire, BrnFormItemConfig themeData) { isRequire ??= false; return isRequire ? themeData?.titlePaddingSm : themeData?.titlePaddingLg; } @@ -347,9 +356,12 @@ class BrnFormUtil { } /// 获取 右侧 输入、选择默认文本样式 - static TextStyle getHintTextStyle(BrnFormItemConfig themeData, {double height = 0}) { + static TextStyle getHintTextStyle(BrnFormItemConfig themeData, + {double height = 0}) { if (height > 0) { - return BrnTextStyle(height: height).merge(themeData?.hintTextStyle)?.generateTextStyle(); + return BrnTextStyle(height: height) + .merge(themeData?.hintTextStyle) + ?.generateTextStyle(); } return themeData?.hintTextStyle?.generateTextStyle(); } @@ -360,8 +372,12 @@ class BrnFormUtil { isEdit ??= true; if (height > 0) { return isEdit - ? BrnTextStyle(height: height).merge(themeData?.contentTextStyle)?.generateTextStyle() - : BrnTextStyle(height: height).merge(themeData?.disableTextStyle)?.generateTextStyle(); + ? BrnTextStyle(height: height) + .merge(themeData?.contentTextStyle) + ?.generateTextStyle() + : BrnTextStyle(height: height) + .merge(themeData?.disableTextStyle) + ?.generateTextStyle(); } return isEdit ? themeData?.contentTextStyle?.generateTextStyle() @@ -369,15 +385,19 @@ class BrnFormUtil { } /// 获取标题文本样式 - static TextStyle getTitleTextStyle(BrnFormItemConfig themeData, {double height = 0}) { + static TextStyle getTitleTextStyle(BrnFormItemConfig themeData, + {double height = 0}) { if (height > 0) { - return BrnTextStyle(height: height).merge(themeData?.titleTextStyle)?.generateTextStyle(); + return BrnTextStyle(height: height) + .merge(themeData?.titleTextStyle) + ?.generateTextStyle(); } return themeData?.titleTextStyle?.generateTextStyle(); } /// 获取标题文本样式 - static TextStyle getHeadTitleTextStyle(BrnFormItemConfig themeData, {bool isBold = false}) { + static TextStyle getHeadTitleTextStyle(BrnFormItemConfig themeData, + {bool isBold = false}) { if (isBold) { return themeData?.headTitleTextStyle ?.merge(BrnTextStyle(fontWeight: FontWeight.w600)) @@ -422,10 +442,14 @@ class BrnFormUtil { /// 当左右内容超出默认比例且「有」提示语,则按比例 6:4 布局 /// 当左右内容超出默认比例且「无」提示语,则按比例 4:6 布局 /// 有用户自定义比例时用用户自定义比例 - static double getAutoLayoutContentRatio({bool tipLabelHidden, double layoutRatio}) { - double defaultRatio = tipLabelHidden ? BrnFormUtil.contentRatio : 1 - BrnFormUtil.contentRatio; - double contentRatio = - layoutRatio != null && layoutRatio > 0 ? 1 / (layoutRatio + 1) : defaultRatio; + static double getAutoLayoutContentRatio( + {bool tipLabelHidden, double layoutRatio}) { + double defaultRatio = tipLabelHidden + ? BrnFormUtil.contentRatio + : 1 - BrnFormUtil.contentRatio; + double contentRatio = layoutRatio != null && layoutRatio > 0 + ? 1 / (layoutRatio + 1) + : defaultRatio; return contentRatio; } } diff --git a/lib/src/components/gallery/config/brn_basic_gallery_config.dart b/lib/src/components/gallery/config/brn_basic_gallery_config.dart index c11122d5..73e00487 100644 --- a/lib/src/components/gallery/config/brn_basic_gallery_config.dart +++ b/lib/src/components/gallery/config/brn_basic_gallery_config.dart @@ -18,10 +18,10 @@ abstract class BrnBasicItemConfig { String type; //构建查看详情页的widget - Widget buildDetailWidget( - BuildContext context, List allConfig, int groupId, int index); + Widget buildDetailWidget(BuildContext context, + List allConfig, int groupId, int index); //构建简略页的widget - Widget buildSummaryWidget( - BuildContext context, List allConfig, int groupId, int index); + Widget buildSummaryWidget(BuildContext context, + List allConfig, int groupId, int index); } diff --git a/lib/src/components/gallery/config/brn_bottom_card.dart b/lib/src/components/gallery/config/brn_bottom_card.dart index 79e1ae4c..ca8ff2ea 100644 --- a/lib/src/components/gallery/config/brn_bottom_card.dart +++ b/lib/src/components/gallery/config/brn_bottom_card.dart @@ -31,7 +31,8 @@ class BrnPhotoBottomCard extends StatefulWidget { _BrnPhotoBottomCardState createState() => _BrnPhotoBottomCardState(); } -class _BrnPhotoBottomCardState extends State with TickerProviderStateMixin { +class _BrnPhotoBottomCardState extends State + with TickerProviderStateMixin { PhotoBottomCardState state; @override @@ -45,7 +46,9 @@ class _BrnPhotoBottomCardState extends State with TickerProv return Container( width: double.infinity, color: widget.themeData.bottomBackgroundColor, - child: state == PhotoBottomCardState.cantFold ? buildCantFoldWidget() : buildFoldableWidget(), + child: state == PhotoBottomCardState.cantFold + ? buildCantFoldWidget() + : buildFoldableWidget(), ); } @@ -58,7 +61,8 @@ class _BrnPhotoBottomCardState extends State with TickerProv child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text(widget.name ?? "", style: widget.themeData.titleStyle?.generateTextStyle()), + Text(widget.name ?? "", + style: widget.themeData.titleStyle?.generateTextStyle()), GestureDetector( onTap: () { setState(() { @@ -70,7 +74,9 @@ class _BrnPhotoBottomCardState extends State with TickerProv children: [ Padding( padding: EdgeInsets.only(right: 4), - child: Text('展开', style: widget.themeData.actionStyle?.generateTextStyle()), + child: Text('展开', + style: + widget.themeData.actionStyle?.generateTextStyle()), ), Transform.rotate( angle: pi, @@ -93,7 +99,8 @@ class _BrnPhotoBottomCardState extends State with TickerProv child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text(widget.name ?? "", style: widget.themeData.titleStyle?.generateTextStyle()), + Text(widget.name ?? "", + style: widget.themeData.titleStyle?.generateTextStyle()), GestureDetector( onTap: () { setState(() { @@ -105,8 +112,9 @@ class _BrnPhotoBottomCardState extends State with TickerProv children: [ Padding( padding: EdgeInsets.only(right: 4), - child: - Text('收起', style: widget.themeData.actionStyle?.generateTextStyle()), + child: Text('收起', + style: widget.themeData.actionStyle + ?.generateTextStyle()), ), BrunoTools.getAssetImageWithColor( BrnAsset.ICON_UPARROW, widget.themeData.iconColor) diff --git a/lib/src/components/gallery/config/brn_photo_gallery_config.dart b/lib/src/components/gallery/config/brn_photo_gallery_config.dart index 92bb611a..e7c1542f 100644 --- a/lib/src/components/gallery/config/brn_photo_gallery_config.dart +++ b/lib/src/components/gallery/config/brn_photo_gallery_config.dart @@ -16,7 +16,8 @@ class BrnPhotoGroupConfig extends BrnBasicGroupConfig { //通过url列表生成配置 BrnPhotoGroupConfig.url({this.title, @required this.urls, this.themeData}) { configList = List(); - urls.forEach((item) => configList.add(BrnPhotoItemConfig(url: item, themeData: themeData))); + urls.forEach((item) => + configList.add(BrnPhotoItemConfig(url: item, themeData: themeData))); } //自定义配置列表 @@ -83,8 +84,8 @@ class BrnPhotoItemConfig extends BrnBasicItemConfig { } @override - Widget buildSummaryWidget( - BuildContext context, List allConfig, int groupId, int index) { + Widget buildSummaryWidget(BuildContext context, + List allConfig, int groupId, int index) { return Container( decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(2.0)), @@ -101,8 +102,8 @@ class BrnPhotoItemConfig extends BrnBasicItemConfig { } @override - Widget buildDetailWidget( - BuildContext context, List allConfig, int groupId, int index) { + Widget buildDetailWidget(BuildContext context, + List allConfig, int groupId, int index) { return Container( color: Colors.white, child: Stack( @@ -125,7 +126,8 @@ class BrnPhotoItemConfig extends BrnBasicItemConfig { child: Container( color: Colors.white, child: PhotoView( - backgroundDecoration: BoxDecoration(color: themeData.pageBackgroundColor), + backgroundDecoration: + BoxDecoration(color: themeData.pageBackgroundColor), loadingBuilder: (context, event) { return Container( child: BrnLoadingDialog(), diff --git a/lib/src/components/gallery/page/brn_gallery_detail_page.dart b/lib/src/components/gallery/page/brn_gallery_detail_page.dart index 48352abf..78701edf 100644 --- a/lib/src/components/gallery/page/brn_gallery_detail_page.dart +++ b/lib/src/components/gallery/page/brn_gallery_detail_page.dart @@ -60,7 +60,8 @@ class BrnGalleryDetailPage extends StatefulWidget { _BrnGalleryDetailPageState createState() => _BrnGalleryDetailPageState(); } -class _BrnGalleryDetailPageState extends State with TickerProviderStateMixin { +class _BrnGalleryDetailPageState extends State + with TickerProviderStateMixin { /// title 关联的通知,因为 title 与图片所处的位置关联 ValueNotifier _titleNotifier; TabController _tabController; @@ -114,7 +115,8 @@ class _BrnGalleryDetailPageState extends State with Ticker @override void didUpdateWidget(BrnGalleryDetailPage oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.controller != null && oldWidget.controller != widget.controller) { + if (widget.controller != null && + oldWidget.controller != widget.controller) { oldWidget.controller?.removeListener(_refreshByController); widget.controller.addListener(_refreshByController); } @@ -167,7 +169,8 @@ class _BrnGalleryDetailPageState extends State with Ticker void _buildViews() { _reset(); _titleNotifier = ValueNotifier(null); - _tabController = TabController(length: _allConfig.length, vsync: this, initialIndex: _curTab) + _tabController = TabController( + length: _allConfig.length, vsync: this, initialIndex: _curTab) ..addListener(() { _curTab = _tabController.index; }); @@ -181,16 +184,18 @@ class _BrnGalleryDetailPageState extends State with Ticker } _groupStartPosition[i] = _allCount; } - _pageController = PageController(initialPage: _getPagePosition(_curTab, _curIndex)); + _pageController = + PageController(initialPage: _getPagePosition(_curTab, _curIndex)); if (_allConfig != null) { _assorted = _allConfig.length > 1; - _allConfig.forEach( - (item) => _tabs.add(BadgeTab(text: '${item.title ?? ""}(${item.configList.length})'))); + _allConfig.forEach((item) => _tabs.add( + BadgeTab(text: '${item.title ?? ""}(${item.configList.length})'))); if (_allConfig.length > 1) _columnViews.add(BrnTabBar( backgroundcolor: _tabBarConfig.backgroundColor, - unselectedLabelStyle: _tabBarConfig.unselectedLabelStyle?.generateTextStyle(), + unselectedLabelStyle: + _tabBarConfig.unselectedLabelStyle?.generateTextStyle(), unselectedLabelColor: _tabBarConfig.unselectedLabelStyle?.color, labelColor: _tabBarConfig.labelStyle?.color, indicatorColor: _tabBarConfig.labelStyle?.color, @@ -205,13 +210,16 @@ class _BrnGalleryDetailPageState extends State with Ticker for (int i = 0; i < _allConfig.length; i++) { for (int j = 0; j < _allConfig[i].configList.length; j++) { - _pageViews.add(_allConfig[i].configList[j].buildDetailWidget(context, _allConfig, i, j)); + _pageViews.add(_allConfig[i] + .configList[j] + .buildDetailWidget(context, _allConfig, i, j)); } } } _groupTitle = _allConfig[_curTab].title ?? ""; _indexTitle = "${_curIndex + 1}/${_allConfig[_curTab].configList.length}"; - _titleNotifier.value = _assorted ? "$_groupTitle($_indexTitle)" : "$_indexTitle"; + _titleNotifier.value = + _assorted ? "$_groupTitle($_indexTitle)" : "$_indexTitle"; _columnViews.add(Expanded( child: PageView( @@ -236,7 +244,8 @@ class _BrnGalleryDetailPageState extends State with Ticker _curTab = pos[0]; _tabController.animateTo(pos[0]); } - _titleNotifier.value = _assorted ? "$_groupTitle($_indexTitle)" : "$_indexTitle"; + _titleNotifier.value = + _assorted ? "$_groupTitle($_indexTitle)" : "$_indexTitle"; return null; } @@ -261,17 +270,19 @@ class _BrnGalleryDetailPageState extends State with Ticker ), actions: widget.detailRightAction != null ? ValueListenableBuilder( - builder: (c, v, _) => widget.detailRightAction(_curTab, _curIndex), + builder: (c, v, _) => + widget.detailRightAction(_curTab, _curIndex), valueListenable: _titleNotifier, ) : BrnTextAction( - '全部图片', + '全部图片', themeData: _appBarConfig, iconPressed: () { if (widget.fromSummary) { Navigator.of(context).pop(); } else { - Navigator.of(context).push(CupertinoPageRoute(builder: (context) { + Navigator.of(context) + .push(CupertinoPageRoute(builder: (context) { return BrnGallerySummaryPage( controller: widget.controller, allConfig: _allConfig, @@ -280,7 +291,8 @@ class _BrnGalleryDetailPageState extends State with Ticker })).then((result) { if (result is List && result != null) { _tabController.animateTo(result[0]); - _pageController.jumpToPage(_getPagePosition(result[0], result[1])); + _pageController + .jumpToPage(_getPagePosition(result[0], result[1])); } }); } diff --git a/lib/src/components/gallery/page/brn_gallery_summary_page.dart b/lib/src/components/gallery/page/brn_gallery_summary_page.dart index 5eced6ea..bc81ebe0 100644 --- a/lib/src/components/gallery/page/brn_gallery_summary_page.dart +++ b/lib/src/components/gallery/page/brn_gallery_summary_page.dart @@ -54,7 +54,8 @@ class _BrnGallerySummaryPageState extends State { @override void didUpdateWidget(BrnGallerySummaryPage oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.controller != null && oldWidget.controller != widget.controller) { + if (widget.controller != null && + oldWidget.controller != widget.controller) { widget.controller.addListener(() { if (mounted) { setState(() {}); @@ -87,7 +88,9 @@ class _BrnGallerySummaryPageState extends State { return _buildItem(allConfig[i], i); }, tabIndexedBuilder: (c, i) { - return BadgeTab(text: '${allConfig[i].title}(${allConfig[i].configList.length})'); + return BadgeTab( + text: + '${allConfig[i].title}(${allConfig[i].configList.length})'); }, itemCount: allConfig.length), ); @@ -107,7 +110,10 @@ class _BrnGallerySummaryPageState extends State { padding: EdgeInsets.only(top: 16, bottom: 12, left: 20, right: 20), child: Text( '${groupConfig.title}(${groupConfig.configList.length})', - style: TextStyle(color: Color(0xFF222222), fontSize: 18, fontWeight: FontWeight.w600), + style: TextStyle( + color: Color(0xFF222222), + fontSize: 18, + fontWeight: FontWeight.w600), ), ), )); @@ -131,8 +137,8 @@ class _BrnGallerySummaryPageState extends State { ); })); }, - child: - groupConfig.configList[i].buildSummaryWidget(context, widget.allConfig, groupId, i), + child: groupConfig.configList[i] + .buildSummaryWidget(context, widget.allConfig, groupId, i), )); columnViews.add(GridView.count( physics: NeverScrollableScrollPhysics(), diff --git a/lib/src/components/guide/brn_delay_rendered_widget.dart b/lib/src/components/guide/brn_delay_rendered_widget.dart index b7148c78..364b8cae 100644 --- a/lib/src/components/guide/brn_delay_rendered_widget.dart +++ b/lib/src/components/guide/brn_delay_rendered_widget.dart @@ -74,7 +74,8 @@ class _DelayRenderedWidgetState extends State<_DelayRenderedWidget> { }); Timer( Duration( - milliseconds: duration.inMilliseconds + durationInterval.inMilliseconds, + milliseconds: + duration.inMilliseconds + durationInterval.inMilliseconds, ), () { setState(() { diff --git a/lib/src/components/guide/brn_flutter_guide.dart b/lib/src/components/guide/brn_flutter_guide.dart index d4854402..672cd925 100644 --- a/lib/src/components/guide/brn_flutter_guide.dart +++ b/lib/src/components/guide/brn_flutter_guide.dart @@ -109,7 +109,8 @@ class BrnGuide { EdgeInsets padding, BorderRadiusGeometry borderRadius, }) { - assert(stepsIndex.every((stepIndex) => stepIndex >= 0 && stepIndex < stepCount)); + assert(stepsIndex + .every((stepIndex) => stepIndex >= 0 && stepIndex < stepCount)); stepsIndex.forEach((index) { setStepConfig( index, @@ -124,11 +125,15 @@ class BrnGuide { EdgeInsets currentConfig = _configMap[_currentStepIndex]['padding']; RenderBox renderBox; renderBox = globalKey.currentContext.findRenderObject(); - _widgetWidth = renderBox.size.width + (currentConfig?.horizontal ?? padding.horizontal); - _widgetHeight = renderBox.size.height + (currentConfig?.vertical ?? padding.vertical); + _widgetWidth = renderBox.size.width + + (currentConfig?.horizontal ?? padding.horizontal); + _widgetHeight = + renderBox.size.height + (currentConfig?.vertical ?? padding.vertical); _widgetOffset = Offset( - renderBox.localToGlobal(Offset.zero).dx - (currentConfig?.left ?? padding.left), - renderBox.localToGlobal(Offset.zero).dy - (currentConfig?.top ?? padding.top), + renderBox.localToGlobal(Offset.zero).dx - + (currentConfig?.left ?? padding.left), + renderBox.localToGlobal(Offset.zero).dy - + (currentConfig?.top ?? padding.top), ); } on Exception catch (e) { _widgetWidth = 0; @@ -217,7 +222,9 @@ class BrnGuide { left: _widgetOffset.dx, top: _widgetOffset.dy, borderRadiusGeometry: - _configMap[_currentStepIndex]['borderRadius'] ?? borderRadius, + _configMap[_currentStepIndex] + ['borderRadius'] ?? + borderRadius, ), ], ), diff --git a/lib/src/components/guide/brn_pulse_widget.dart b/lib/src/components/guide/brn_pulse_widget.dart index bac8f7c9..b03d9581 100644 --- a/lib/src/components/guide/brn_pulse_widget.dart +++ b/lib/src/components/guide/brn_pulse_widget.dart @@ -12,7 +12,8 @@ class PulseWidget extends StatefulWidget { _PulseWidgetState createState() => _PulseWidgetState(); } -class _PulseWidgetState extends State with TickerProviderStateMixin { +class _PulseWidgetState extends State + with TickerProviderStateMixin { AnimationController _scaleController; AnimationController _fadeController; Animation _alphaAnimation; @@ -54,8 +55,10 @@ class _PulseWidgetState extends State with TickerProviderStateMixin child: ScaleTransition( scale: _scaleController, child: CustomPaint( - painter: CirclePainter( - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary), + painter: CirclePainter(BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary), size: Size(widget.width, widget.height), ), ), @@ -67,8 +70,10 @@ class _PulseWidgetState extends State with TickerProviderStateMixin bottom: widget.width / 4, right: widget.width / 4, child: CustomPaint( - painter: CirclePainter( - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary), + painter: CirclePainter(BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary), size: Size(widget.width / 2, widget.height / 2), ), ) @@ -95,7 +100,8 @@ class CirclePainter extends CustomPainter { Paint paint = Paint() ..style = PaintingStyle.fill ..color = color; - canvas.drawCircle(Offset(size.width / 2, size.height / 2), size.width / 2, paint); + canvas.drawCircle( + Offset(size.width / 2, size.height / 2), size.width / 2, paint); } @override diff --git a/lib/src/components/guide/brn_step_widget_builder.dart b/lib/src/components/guide/brn_step_widget_builder.dart index 9365d96c..a6a25747 100644 --- a/lib/src/components/guide/brn_step_widget_builder.dart +++ b/lib/src/components/guide/brn_step_widget_builder.dart @@ -5,7 +5,8 @@ enum GuideDirection { left, right, topLeft, bottomLeft, topRight, bottomRight } /// 单步引导组件 class StepWidgetBuilder { - static Map _smartGetPosition({Size size, Size screenSize, Offset offset, GuideMode introMode}) { + static Map _smartGetPosition( + {Size size, Size screenSize, Offset offset, GuideMode introMode}) { double height = size.height; double width = size.width; double screenWidth = screenSize.width; @@ -81,7 +82,8 @@ class StepWidgetBuilder { alignTop = false; } if (leftArea > rightArea) { - position['right'] = rightArea + width / 2 - 20 <= 0 ? 16.0 : rightArea + width / 2 - 20; + position['right'] = + rightArea + width / 2 - 20 <= 0 ? 16.0 : rightArea + width / 2 - 20; position['crossAxisAlignment'] = CrossAxisAlignment.end; position['width'] = min(leftArea + width - 16, screenWidth * 0.618); @@ -91,7 +93,9 @@ class StepWidgetBuilder { position['direction'] = GuideDirection.bottomLeft; } } else { - position['left'] = offset.dx + width / 2 - 20 <= 0 ? 16.0 : offset.dx + size.width / 2 - 20; + position['left'] = offset.dx + width / 2 - 20 <= 0 + ? 16.0 + : offset.dx + size.width / 2 - 20; position['width'] = min(rightArea + width - 16, screenWidth * 0.618); if (alignTop) { diff --git a/lib/src/components/guide/brn_tip_widget.dart b/lib/src/components/guide/brn_tip_widget.dart index 9bc68e96..6fa23b68 100644 --- a/lib/src/components/guide/brn_tip_widget.dart +++ b/lib/src/components/guide/brn_tip_widget.dart @@ -45,8 +45,10 @@ class BrnTipInfoWidget extends StatelessWidget { @override Widget build(BuildContext context) { - Color borderColor = mode == GuideMode.force ? Colors.transparent : Color(0xFFCCCCCC); - if (direction == GuideDirection.bottomLeft || direction == GuideDirection.bottomRight) + Color borderColor = + mode == GuideMode.force ? Colors.transparent : Color(0xFFCCCCCC); + if (direction == GuideDirection.bottomLeft || + direction == GuideDirection.bottomRight) return Column( verticalDirection: VerticalDirection.up, children: [ @@ -68,18 +70,22 @@ class BrnTipInfoWidget extends StatelessWidget { ), ], ); - if (direction == GuideDirection.topLeft || direction == GuideDirection.topRight) + if (direction == GuideDirection.topLeft || + direction == GuideDirection.topRight) return Column( children: [ buildContent(), Container( - alignment: direction == GuideDirection.topLeft ? Alignment.topRight : Alignment.topLeft, + alignment: direction == GuideDirection.topLeft + ? Alignment.topRight + : Alignment.topLeft, padding: direction == GuideDirection.topLeft ? EdgeInsets.only(right: arrowPadding ?? 12) : EdgeInsets.only(left: arrowPadding ?? 12), child: CustomPaint( size: Size(14.0, 6.0), - painter: CustomTrianglePainter(borderColor: borderColor, direction: Direction.bottom), + painter: CustomTrianglePainter( + borderColor: borderColor, direction: Direction.bottom), ), ), ], @@ -95,7 +101,8 @@ class BrnTipInfoWidget extends StatelessWidget { padding: EdgeInsets.only(top: 12), child: CustomPaint( size: Size(6.0, 14.0), - painter: CustomTrianglePainter(borderColor: borderColor, direction: Direction.right), + painter: CustomTrianglePainter( + borderColor: borderColor, direction: Direction.right), ), ), ], @@ -134,7 +141,9 @@ class BrnTipInfoWidget extends StatelessWidget { ], borderRadius: BorderRadius.circular(4), color: Colors.white, - border: mode == GuideMode.force ? null : Border.all(color: Color(0xFFCCCCCC), width: 0.5), + border: mode == GuideMode.force + ? null + : Border.all(color: Color(0xFFCCCCCC), width: 0.5), ), width: width, padding: EdgeInsets.only(left: 16, right: 16, bottom: 14), @@ -155,7 +164,8 @@ class BrnTipInfoWidget extends StatelessWidget { double imageSize = width - 16; return Padding( padding: EdgeInsets.only(top: 14), - child: Image.network(info.imgUrl, width: imageSize, height: imageSize, fit: BoxFit.cover), + child: Image.network(info.imgUrl, + width: imageSize, height: imageSize, fit: BoxFit.cover), ); } @@ -171,7 +181,10 @@ class BrnTipInfoWidget extends StatelessWidget { bottom: 0, child: Text( "${info.title}", - style: TextStyle(fontSize: 14, color: Color(0XFF222222), fontWeight: FontWeight.w600), + style: TextStyle( + fontSize: 14, + color: Color(0XFF222222), + fontWeight: FontWeight.w600), ), ), Positioned( @@ -184,7 +197,8 @@ class BrnTipInfoWidget extends StatelessWidget { onTap: () { onClose(); }, - child: BrunoTools.getAssetImageWithColor(BrnAsset.ICON_CLOSE, Colors.black), + child: BrunoTools.getAssetImageWithColor( + BrnAsset.ICON_CLOSE, Colors.black), ), ), ], @@ -197,7 +211,8 @@ class BrnTipInfoWidget extends StatelessWidget { return Padding( padding: EdgeInsets.only(top: 6), child: Text('${info.message}', - style: TextStyle(fontSize: 14, color: Color(0xFF999999), height: 1.3), maxLines: 3), + style: TextStyle(fontSize: 14, color: Color(0xFF999999), height: 1.3), + maxLines: 3), ); } @@ -223,7 +238,8 @@ class BrnTipInfoWidget extends StatelessWidget { }, child: Text( '跳过 (${currentStepIndex + 1}/$stepCount)', - style: TextStyle(color: Color(0xFF999999), fontSize: 14), + style: + TextStyle(color: Color(0xFF999999), fontSize: 14), ), ), )) @@ -240,7 +256,10 @@ class BrnTipInfoWidget extends StatelessWidget { padding: EdgeInsets.only(left: 14, right: 14), alignment: Alignment.centerLeft, decoration: BoxDecoration( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, borderRadius: BorderRadius.circular(2), ), child: GestureDetector( @@ -248,7 +267,9 @@ class BrnTipInfoWidget extends StatelessWidget { onNext(); }, child: Text( - nextTip ?? stepCount == currentStepIndex + 1 ? '我知道了' : '下一步', + nextTip ?? stepCount == currentStepIndex + 1 + ? '我知道了' + : '下一步', style: TextStyle(color: Colors.white, fontSize: 14), ), ), @@ -283,7 +304,8 @@ class BrnTipInfoWidget extends StatelessWidget { }, child: Text( '跳过 (${currentStepIndex + 1}/$stepCount)', - style: TextStyle(color: Color(0xFF999999), fontSize: 14), + style: + TextStyle(color: Color(0xFF999999), fontSize: 14), ), ), )) @@ -303,7 +325,9 @@ class BrnTipInfoWidget extends StatelessWidget { onNext(); }, child: Text( - nextTip ?? stepCount == currentStepIndex + 1 ? '我知道了' : '下一步', + nextTip ?? stepCount == currentStepIndex + 1 + ? '我知道了' + : '下一步', style: TextStyle( color: BrnThemeConfigurator.instance .getConfig() diff --git a/lib/src/components/input/brn_input_text.dart b/lib/src/components/input/brn_input_text.dart index 331c076c..f1e2b352 100644 --- a/lib/src/components/input/brn_input_text.dart +++ b/lib/src/components/input/brn_input_text.dart @@ -105,8 +105,8 @@ class BrnInputText extends StatelessWidget { if (textData != null && textData.length > 0) { _controller = TextEditingController.fromValue(TextEditingValue( text: textData, - selection: TextSelection.fromPosition( - TextPosition(affinity: TextAffinity.downstream, offset: textData.length)))); + selection: TextSelection.fromPosition(TextPosition( + affinity: TextAffinity.downstream, offset: textData.length)))); } else { _controller = TextEditingController(); } @@ -137,8 +137,12 @@ class BrnInputText extends StatelessWidget { textInputAction: textInputAction, style: TextStyle( fontSize: 16, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase), - buildCounter: (BuildContext context, {int currentLength, int maxLength, bool isFocused}) { + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase), + buildCounter: (BuildContext context, + {int currentLength, int maxLength, bool isFocused}) { return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ @@ -147,7 +151,10 @@ class BrnInputText extends StatelessWidget { style: TextStyle( color: (currentLength == 0 ? Color(0xffcccccc) - : BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextSecondary), + : BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextSecondary), fontSize: 16, ), ), @@ -168,8 +175,10 @@ class BrnInputText extends StatelessWidget { contentPadding: EdgeInsets.all(0), border: InputBorder.none, isDense: true, - enabledBorder: UnderlineInputBorder(borderSide: BorderSide(color: Colors.transparent)), - focusedBorder: UnderlineInputBorder(borderSide: BorderSide(color: Colors.transparent)), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), ), onSubmitted: (text) { if (onSubmit != null) { diff --git a/lib/src/components/line/brn_dashed_line.dart b/lib/src/components/line/brn_dashed_line.dart index 841568e6..c952f449 100644 --- a/lib/src/components/line/brn_dashed_line.dart +++ b/lib/src/components/line/brn_dashed_line.dart @@ -36,7 +36,8 @@ class BrnDashedLine extends StatelessWidget { BrnThemeConfigurator.instance.getConfig().commonConfig.dividerColorBase; /// 默认位置,头部 - static const BrnDashedLinePosition _normalPosition = BrnDashedLinePosition.DashedLineLeading; + static const BrnDashedLinePosition _normalPosition = + BrnDashedLinePosition.DashedLineLeading; /// 虚线方向,默认值[_normalAxis] final Axis axis; @@ -145,11 +146,11 @@ class BrnDashedPainter extends CustomPainter { } while (startX < maxWidth) { if ((maxWidth - startX) < this.dashedLength) { - canvas.drawLine( - Offset(startX, height), Offset(startX + (maxWidth - startX), height), paint); + canvas.drawLine(Offset(startX, height), + Offset(startX + (maxWidth - startX), height), paint); } else { - canvas.drawLine( - Offset(startX, height), Offset(startX + this.dashedLength, height), paint); + canvas.drawLine(Offset(startX, height), + Offset(startX + this.dashedLength, height), paint); } startX += space; } @@ -167,10 +168,11 @@ class BrnDashedPainter extends CustomPainter { } while (startY < maxHeight) { if ((maxHeight - startY) < this.dashedLength) { - canvas.drawLine( - Offset(width, startY), Offset(width, startY + (maxHeight - startY)), paint); + canvas.drawLine(Offset(width, startY), + Offset(width, startY + (maxHeight - startY)), paint); } else { - canvas.drawLine(Offset(width, startY), Offset(width, startY + this.dashedLength), paint); + canvas.drawLine(Offset(width, startY), + Offset(width, startY + this.dashedLength), paint); } startY += space; } diff --git a/lib/src/components/line/brn_line.dart b/lib/src/components/line/brn_line.dart index 1444419d..b1573a41 100644 --- a/lib/src/components/line/brn_line.dart +++ b/lib/src/components/line/brn_line.dart @@ -45,8 +45,11 @@ class BrnLine extends StatelessWidget { child: Divider( thickness: this.height, height: this.height, - color: - this.color ?? BrnThemeConfigurator.instance.getConfig().commonConfig.dividerColorBase, + color: this.color ?? + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .dividerColorBase, ), ); } diff --git a/lib/src/components/loading/brn_loading.dart b/lib/src/components/loading/brn_loading.dart index 4eedd60f..5bfca09e 100644 --- a/lib/src/components/loading/brn_loading.dart +++ b/lib/src/components/loading/brn_loading.dart @@ -38,7 +38,9 @@ class BrnPageLoading extends StatelessWidget { height: 50, width: 130, decoration: BoxDecoration( - color: Color(0xff222222), border: null, borderRadius: BorderRadius.circular(5)), + color: Color(0xff222222), + border: null, + borderRadius: BorderRadius.circular(5)), child: Center( child: Row( mainAxisSize: MainAxisSize.min, @@ -70,7 +72,6 @@ class BrnPageLoading extends StatelessWidget { } } - /// 通过 [BrnPageLoading] 构建出的加载状态的弹窗,加载动画和加载文字并排展示,且在屏幕中间。可通 /// 过 [BrnLoadingDialog.show] 和 [BrnLoadingDialog.dismiss] 控制弹窗的显示和关闭。不会自动关闭。 class BrnLoadingDialog extends Dialog { @@ -92,11 +93,11 @@ class BrnLoadingDialog extends Dialog { /// * [useRootNavigator] 把弹窗添加到 [context] 中的 rootNavigator 还是最近的 [Navigator],默认为 true,添加到 /// rootNavigator,详见 [showDialog] 中的 [useRootNavigator]。 static void show( - BuildContext context, { - String content, - bool barrierDismissible = true, - bool useRootNavigator = true, - }) { + BuildContext context, { + String content, + bool barrierDismissible = true, + bool useRootNavigator = true, + }) { showDialog( context: context, barrierDismissible: barrierDismissible, diff --git a/lib/src/components/navbar/brn_search_bar.dart b/lib/src/components/navbar/brn_search_bar.dart index 4c3faddb..06cec3f3 100644 --- a/lib/src/components/navbar/brn_search_bar.dart +++ b/lib/src/components/navbar/brn_search_bar.dart @@ -206,14 +206,20 @@ class __SearchInputWidgetState extends State<_SearchInputWidget> { _defaultCancelTextColor = Colors.white; _defaultClearIconColor = Colors.white.withOpacity(0.4); } else { - _defaultDividerColor = - BrnThemeConfigurator.instance.getConfig().commonConfig.dividerColorBase; - _defaultHintTextColor = BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextHint; - _defaultInputTextColor = - BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextSecondary; + _defaultDividerColor = BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .dividerColorBase; + _defaultHintTextColor = + BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextHint; + _defaultInputTextColor = BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextSecondary; _defaultCancelTextColor = BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; - _defaultClearIconColor = BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextHint; + _defaultClearIconColor = + BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextHint; } } @@ -261,7 +267,8 @@ class __SearchInputWidgetState extends State<_SearchInputWidget> { children: [ Padding( padding: EdgeInsets.only(right: 8.0), - child: BrunoTools.getAssetSizeImage(BrnAsset.ICON_SEARCH, 16, 16), + child: + BrunoTools.getAssetSizeImage(BrnAsset.ICON_SEARCH, 16, 16), ), Expanded( child: TextField( @@ -270,8 +277,10 @@ class __SearchInputWidgetState extends State<_SearchInputWidget> { // 控制器属性,控制正在编辑的文本。 controller: _controller, // 光标颜色属性,绘制光标时使用的颜色。 - cursorColor: - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + cursorColor: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, // 光标宽度属性,光标的厚度,默认是2.0。 cursorWidth: 2.0, // 样式属性,用于正在编辑的文本的样式。 @@ -329,7 +338,8 @@ class __SearchInputWidgetState extends State<_SearchInputWidget> { visible: _controller.text.isNotEmpty, child: Padding( padding: EdgeInsets.only( - right: valueNotifier.value ? 24 : 20, left: valueNotifier.value ? 24 : 20), + right: valueNotifier.value ? 24 : 20, + left: valueNotifier.value ? 24 : 20), child: Image.asset( 'assets/${BrnAsset.ICON_DELETE_TEXT}', color: _defaultClearIconColor, diff --git a/lib/src/components/noticebar/brn_marquee_text.dart b/lib/src/components/noticebar/brn_marquee_text.dart index 13fcff96..0dc6a9f6 100644 --- a/lib/src/components/noticebar/brn_marquee_text.dart +++ b/lib/src/components/noticebar/brn_marquee_text.dart @@ -42,7 +42,8 @@ class BrnMarqueeText extends StatefulWidget { } } -class BrnMarqueeTextState extends State with SingleTickerProviderStateMixin { +class BrnMarqueeTextState extends State + with SingleTickerProviderStateMixin { ScrollController scroController; double blankWidth = 1; double blankHeight = 1; @@ -61,8 +62,8 @@ class BrnMarqueeTextState extends State with SingleTickerProvide widget.height = (widget.height) > 0 ? widget.height : size.height; _key = GlobalKey(); - if (calculateTextWith(widget.text, widget.textStyle.fontSize, widget.textStyle.fontWeight, - double.infinity, 1, context) > + if (calculateTextWith(widget.text, widget.textStyle.fontSize, + widget.textStyle.fontWeight, double.infinity, 1, context) > widget.width) { blankWidth = widget.width * widget.ratioOfBlankToScreen; blankHeight = widget.height * widget.ratioOfBlankToScreen; @@ -78,21 +79,27 @@ class BrnMarqueeTextState extends State with SingleTickerProvide } void startTimer() { - timer = Timer.periodic(new Duration(milliseconds: widget.timerRest), (timer) { + timer = + Timer.periodic(new Duration(milliseconds: widget.timerRest), (timer) { double maxScrollExtent = scroController.position.maxScrollExtent; double pixels = scroController.position.pixels; //当animateTo的距离大于最大滑动距离时,则要返回第一个child的特定位置,让末尾正好处于最右侧,然后继续滚动,造成跑马灯的假象 if (pixels + _moveDistance >= maxScrollExtent) { if (widget.scrollAxis == Axis.horizontal) { - position = (maxScrollExtent - blankWidth - widget.width) / 2 + pixels - maxScrollExtent; + position = (maxScrollExtent - blankWidth - widget.width) / 2 + + pixels - + maxScrollExtent; } else { - position = (maxScrollExtent - blankHeight - widget.height) / 2 + pixels - maxScrollExtent; + position = (maxScrollExtent - blankHeight - widget.height) / 2 + + pixels - + maxScrollExtent; } scroController.jumpTo(position); } position += _moveDistance; scroController.animateTo(position, - duration: new Duration(milliseconds: widget.timerRest), curve: Curves.linear); + duration: new Duration(milliseconds: widget.timerRest), + curve: Curves.linear); }); } @@ -155,8 +162,8 @@ class BrnMarqueeTextState extends State with SingleTickerProvide ); } - double calculateTextWith(String value, double fontSize, FontWeight fontWeight, double maxWidth, - int maxLines, BuildContext context) { + double calculateTextWith(String value, double fontSize, FontWeight fontWeight, + double maxWidth, int maxLines, BuildContext context) { TextPainter painter = TextPainter( ///AUTO:华为手机如果不指定locale的时候,该方法算出来的文字高度是比系统计算偏小的。 diff --git a/lib/src/components/noticebar/brn_notice_bar.dart b/lib/src/components/noticebar/brn_notice_bar.dart index 34824c56..78e0e1fe 100644 --- a/lib/src/components/noticebar/brn_notice_bar.dart +++ b/lib/src/components/noticebar/brn_notice_bar.dart @@ -74,7 +74,8 @@ class BrnNoticeBar extends StatelessWidget { Widget build(BuildContext context) { NoticeStyle defaultStyle = NoticeStyles.runningWithArrow; - Widget tempRightWidget = rightWidget ?? (noticeStyle?.rightIcon ?? defaultStyle.leftIcon); + Widget tempRightWidget = + rightWidget ?? (noticeStyle?.rightIcon ?? defaultStyle.leftIcon); if (onRightIconTap != null) { tempRightWidget = GestureDetector( child: tempRightWidget, @@ -90,7 +91,8 @@ class BrnNoticeBar extends StatelessWidget { height: 36, text: content ?? '', textStyle: TextStyle( - color: textColor ?? (noticeStyle?.textColor ?? defaultStyle.textColor), + color: + textColor ?? (noticeStyle?.textColor ?? defaultStyle.textColor), fontSize: 14, ), ); @@ -99,7 +101,8 @@ class BrnNoticeBar extends StatelessWidget { content ?? '', overflow: TextOverflow.ellipsis, style: TextStyle( - color: textColor ?? (noticeStyle?.textColor ?? defaultStyle.textColor), + color: + textColor ?? (noticeStyle?.textColor ?? defaultStyle.textColor), fontSize: 14, ), ); @@ -107,7 +110,9 @@ class BrnNoticeBar extends StatelessWidget { return Container( color: backgroundColor ?? - (noticeStyle != null ? noticeStyle.backgroundColor : defaultStyle.backgroundColor), + (noticeStyle != null + ? noticeStyle.backgroundColor + : defaultStyle.backgroundColor), padding: this.padding ?? EdgeInsets.symmetric(horizontal: 20), constraints: BoxConstraints(minHeight: this.minHeight), child: GestureDetector( @@ -122,7 +127,8 @@ class BrnNoticeBar extends StatelessWidget { offstage: !showLeftIcon, child: Padding( padding: EdgeInsets.only(right: 8), - child: leftWidget ?? (noticeStyle?.leftIcon ?? defaultStyle.leftIcon), + child: leftWidget ?? + (noticeStyle?.leftIcon ?? defaultStyle.leftIcon), ), ), Expanded( @@ -229,5 +235,6 @@ class NoticeStyle { ///右边的图标 final Widget rightIcon; - NoticeStyle(this.leftIcon, this.textColor, this.backgroundColor, this.rightIcon); + NoticeStyle( + this.leftIcon, this.textColor, this.backgroundColor, this.rightIcon); } diff --git a/lib/src/components/picker/base/brn_picker.dart b/lib/src/components/picker/base/brn_picker.dart index 88ab0085..d23a3d10 100644 --- a/lib/src/components/picker/base/brn_picker.dart +++ b/lib/src/components/picker/base/brn_picker.dart @@ -74,7 +74,8 @@ class BrnPicker extends StatefulWidget { bool looping = false, }) : assert(children != null), assert(diameterRatio != null), - assert(diameterRatio > 0.0, RenderListWheelViewport.diameterRatioZeroMessage), + assert(diameterRatio > 0.0, + RenderListWheelViewport.diameterRatioZeroMessage), assert(magnification > 0), assert(itemExtent != null), assert(itemExtent > 0), @@ -118,13 +119,15 @@ class BrnPicker extends StatefulWidget { int childCount, }) : assert(itemBuilder != null), assert(diameterRatio != null), - assert(diameterRatio > 0.0, RenderListWheelViewport.diameterRatioZeroMessage), + assert(diameterRatio > 0.0, + RenderListWheelViewport.diameterRatioZeroMessage), assert(magnification > 0), assert(itemExtent != null), assert(itemExtent > 0), assert(squeeze != null), assert(squeeze > 0), - childDelegate = ListWheelChildBuilderDelegate(builder: itemBuilder, childCount: childCount), + childDelegate = ListWheelChildBuilderDelegate( + builder: itemBuilder, childCount: childCount), super(key: key); /// Relative ratio between this picker's height and the simulated cylinder's diameter. @@ -207,7 +210,8 @@ class _CupertinoPickerState extends State { void didUpdateWidget(BrnPicker oldWidget) { if (widget.scrollController != null && oldWidget.scrollController == null) { _controller = null; - } else if (widget.scrollController == null && oldWidget.scrollController != null) { + } else if (widget.scrollController == null && + oldWidget.scrollController != null) { assert(_controller == null); _controller = FixedExtentScrollController(); } @@ -223,7 +227,8 @@ class _CupertinoPickerState extends State { void _handleSelectedItemChanged(int index) { // Only the haptic engine hardware on iOS devices would produce the // intended effects. - if (defaultTargetPlatform == TargetPlatform.iOS && index != _lastHapticIndex) { + if (defaultTargetPlatform == TargetPlatform.iOS && + index != _lastHapticIndex) { _lastHapticIndex = index; HapticFeedback.selectionClick(); } @@ -239,9 +244,11 @@ class _CupertinoPickerState extends State { // have to just do a color blend. And a due to the way we are layering // the magnifier and the gradient on the background, using a transparent // background color makes the picker look odd. - if (widget.backgroundColor != null && widget.backgroundColor.alpha < 255) return Container(); + if (widget.backgroundColor != null && widget.backgroundColor.alpha < 255) + return Container(); - final Color widgetBackgroundColor = widget.backgroundColor ?? const Color(0xFFFFFFFF); + final Color widgetBackgroundColor = + widget.backgroundColor ?? const Color(0xFFFFFFFF); return Positioned.fill( child: IgnorePointer( child: Container( @@ -279,8 +286,9 @@ class _CupertinoPickerState extends State { /// Makes the magnifier lens look so that the colors are normal through /// the lens and partially grayed out around it. Widget _buildMagnifierScreen() { - final Color foreground = widget.backgroundColor - ?.withAlpha((widget.backgroundColor.alpha * _kForegroundScreenOpacityFraction).toInt()); + final Color foreground = widget.backgroundColor?.withAlpha( + (widget.backgroundColor.alpha * _kForegroundScreenOpacityFraction) + .toInt()); return IgnorePointer( child: Column( @@ -295,8 +303,10 @@ class _CupertinoPickerState extends State { border: Border( left: BorderSide.none, right: BorderSide.none, - top: BorderSide(width: 0.5, color: widget.lineColor ?? _kHighlighterBorder), - bottom: BorderSide(width: 0.5, color: widget.lineColor ?? _kHighlighterBorder), + top: BorderSide( + width: 0.5, color: widget.lineColor ?? _kHighlighterBorder), + bottom: BorderSide( + width: 0.5, color: widget.lineColor ?? _kHighlighterBorder), ), ), constraints: BoxConstraints.expand( @@ -314,8 +324,9 @@ class _CupertinoPickerState extends State { } Widget _buildUnderMagnifierScreen() { - final Color foreground = widget.backgroundColor - ?.withAlpha((widget.backgroundColor.alpha * _kForegroundScreenOpacityFraction).toInt()); + final Color foreground = widget.backgroundColor?.withAlpha( + (widget.backgroundColor.alpha * _kForegroundScreenOpacityFraction) + .toInt()); return Column( children: [ @@ -402,11 +413,12 @@ class _CupertinoPickerSemantics extends SingleChildRenderObjectWidget { @override RenderObject createRenderObject(BuildContext context) => - _RenderCupertinoPickerSemantics(scrollController, Directionality.of(context)); + _RenderCupertinoPickerSemantics( + scrollController, Directionality.of(context)); @override - void updateRenderObject( - BuildContext context, covariant _RenderCupertinoPickerSemantics renderObject) { + void updateRenderObject(BuildContext context, + covariant _RenderCupertinoPickerSemantics renderObject) { renderObject ..textDirection = Directionality.of(context) ..controller = scrollController; @@ -414,7 +426,8 @@ class _CupertinoPickerSemantics extends SingleChildRenderObjectWidget { } class _RenderCupertinoPickerSemantics extends RenderProxyBox { - _RenderCupertinoPickerSemantics(FixedExtentScrollController controller, this._textDirection) { + _RenderCupertinoPickerSemantics( + FixedExtentScrollController controller, this._textDirection) { this.controller = controller; } @@ -465,9 +478,10 @@ class _RenderCupertinoPickerSemantics extends RenderProxyBox { } @override - void assembleSemanticsNode( - SemanticsNode node, SemanticsConfiguration config, Iterable children) { - if (children.isEmpty) return super.assembleSemanticsNode(node, config, children); + void assembleSemanticsNode(SemanticsNode node, SemanticsConfiguration config, + Iterable children) { + if (children.isEmpty) + return super.assembleSemanticsNode(node, config, children); final SemanticsNode scrollable = children.first; final Map indexedChildren = {}; scrollable.visitChildren((SemanticsNode child) { diff --git a/lib/src/components/picker/base/brn_picker_constants.dart b/lib/src/components/picker/base/brn_picker_constants.dart index ee27a803..bbc22b4d 100755 --- a/lib/src/components/picker/base/brn_picker_constants.dart +++ b/lib/src/components/picker/base/brn_picker_constants.dart @@ -22,4 +22,5 @@ const double PICKER_TITLE_HEIGHT = 48.0; const double PICKER_ITEM_HEIGHT = 48.0; /// Default value of DatePicker's item [TextStyle]. -const TextStyle PICKER_ITEM_TEXT_STYLE = const TextStyle(color: Color(0xFF222222), fontSize: 18.0); +const TextStyle PICKER_ITEM_TEXT_STYLE = + const TextStyle(color: Color(0xFF222222), fontSize: 18.0); diff --git a/lib/src/components/picker/brn_bottom_picker.dart b/lib/src/components/picker/brn_bottom_picker.dart index 642d6d3f..05fd0d8e 100644 --- a/lib/src/components/picker/brn_bottom_picker.dart +++ b/lib/src/components/picker/brn_bottom_picker.dart @@ -45,7 +45,8 @@ class BrnBottomPicker { onConfirmPressed: onConfirm, onCancelPressed: onCancel, barrierDismissible: barrierDismissible, - pickerTitleConfig: BrnPickerTitleConfig(titleContent: title, showTitle: showTitle), + pickerTitleConfig: + BrnPickerTitleConfig(titleContent: title, showTitle: showTitle), ); return theme != null ? Theme(data: theme, child: pageChild) : pageChild; }, @@ -103,8 +104,10 @@ class BrnBottomPickerWidgetState extends State void initState() { super.initState(); //用于动画 - _controller = AnimationController(duration: Duration(milliseconds: 300), vsync: this); - _animation = Tween(end: Offset.zero, begin: Offset(0.0, 1.0)).animate(_controller); + _controller = + AnimationController(duration: Duration(milliseconds: 300), vsync: this); + _animation = + Tween(end: Offset.zero, begin: Offset(0.0, 1.0)).animate(_controller); _controller.forward(); } @@ -139,10 +142,14 @@ class BrnBottomPickerWidgetState extends State position: _animation, child: BrnPickerClipRRect( borderRadius: BorderRadius.only( - topLeft: - Radius.circular(BrnThemeConfigurator.instance.getConfig().pickerConfig.cornerRadius), - topRight: - Radius.circular(BrnThemeConfigurator.instance.getConfig().pickerConfig.cornerRadius), + topLeft: Radius.circular(BrnThemeConfigurator.instance + .getConfig() + .pickerConfig + .cornerRadius), + topRight: Radius.circular(BrnThemeConfigurator.instance + .getConfig() + .pickerConfig + .cornerRadius), ), child: Container( color: Colors.white, @@ -213,7 +220,10 @@ class BrnBottomPickerWidgetState extends State return Text( string, style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, fontSize: 16.0), textAlign: TextAlign.right, ); @@ -223,7 +233,10 @@ class BrnBottomPickerWidgetState extends State return Text( string ?? '取消', style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, fontSize: 16.0), textAlign: TextAlign.right, ); diff --git a/lib/src/components/picker/brn_bottom_write_picker.dart b/lib/src/components/picker/brn_bottom_write_picker.dart index 4cf079b8..cbd9bbd3 100644 --- a/lib/src/components/picker/brn_bottom_write_picker.dart +++ b/lib/src/components/picker/brn_bottom_write_picker.dart @@ -4,7 +4,8 @@ import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:flutter/material.dart'; ///取消输入事件回调 -typedef BrnBottomWritePickerClickCallback = Future Function(String content); +typedef BrnBottomWritePickerClickCallback = Future Function( + String content); ///确认输入事件回调 typedef BrnBottomWritePickerConfirmClickCallback = Future Function( @@ -90,13 +91,21 @@ class BrnBottomWritePicker extends StatefulWidget { onConfirm: onConfirm, onCancel: onCancel, rightTextColor: rightTextColor ?? - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, - cursorColor: - cursorColor ?? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, + cursorColor: cursorColor ?? + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, defaultText: defaultText, textEditingController: textEditingController, ); - return theme != null ? Theme(data: theme, child: pageChild) : pageChild; + return theme != null + ? Theme(data: theme, child: pageChild) + : pageChild; }); } } @@ -112,7 +121,8 @@ class _BottomWritePickerState extends State { _controller = TextEditingController.fromValue(TextEditingValue( text: widget.defaultText, selection: TextSelection.fromPosition(TextPosition( - affinity: TextAffinity.downstream, offset: widget.defaultText.length)))); + affinity: TextAffinity.downstream, + offset: widget.defaultText.length)))); } else { _controller = TextEditingController(); } @@ -128,7 +138,10 @@ class _BottomWritePickerState extends State { child: TextField( style: TextStyle( fontSize: 16, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase), + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase), controller: _controller, autofocus: true, maxLines: 8, @@ -138,10 +151,16 @@ class _BottomWritePickerState extends State { border: InputBorder.none, hintStyle: TextStyle( fontSize: 16, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextHint), + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextHint), counterStyle: TextStyle( fontSize: 16, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextHint), + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextHint), hintText: widget.hintText, )), ), diff --git a/lib/src/components/picker/brn_mulit_select_tags_picker.dart b/lib/src/components/picker/brn_mulit_select_tags_picker.dart index a32cd561..7326c839 100644 --- a/lib/src/components/picker/brn_mulit_select_tags_picker.dart +++ b/lib/src/components/picker/brn_mulit_select_tags_picker.dart @@ -17,7 +17,8 @@ enum BrnMultiSelectTagsLayoutStyle { } typedef BrnMultiSelectTagStringBuilder = String Function(V data); -typedef BrnMultiSelectTagOnItemClick = void Function(BrnTagItemBean onTapTag, bool isSelect); +typedef BrnMultiSelectTagOnItemClick = void Function( + BrnTagItemBean onTapTag, bool isSelect); /// 多选标签弹框,适用于底部弹出 Picker,且选择样式为 Tag 的场景。 /// 功能:多选标签弹框,适用于从底部弹出的情况,属于 Picker; @@ -77,7 +78,7 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { /// 是等分样式还是流式布局样式,[BrnMultiSelectTagsLayoutStyle],默认等分 final BrnMultiSelectTagsLayoutStyle layoutStyle; - /// item的高度, 默认数值是34 + /// item的高度, 默认数值是34 final double itemHeight; /// 操作类型属性 @@ -123,20 +124,32 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { } ///等宽度的布局 - Widget _buildGridViewWidget(BuildContext context, VoidCallback onUpdate, double maxWidth) { - int brnCrossAxisCount = (this.crossAxisCount == 0 || this.crossAxisCount == null) - ? 4 - : this.crossAxisCount; - double width = (maxWidth - (brnCrossAxisCount - 1) * 12 - 40) / brnCrossAxisCount; + Widget _buildGridViewWidget( + BuildContext context, VoidCallback onUpdate, double maxWidth) { + int brnCrossAxisCount = + (this.crossAxisCount == 0 || this.crossAxisCount == null) + ? 4 + : this.crossAxisCount; + double width = + (maxWidth - (brnCrossAxisCount - 1) * 12 - 40) / brnCrossAxisCount; //计算宽高比 double brnChildAspectRatio = width / this.itemHeight; Color selectedTagTitleColor = this.tagPickerConfig.selectedTagTitleColor ?? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary; Color tagTitleColor = this.tagPickerConfig.tagTitleColor ?? - BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextImportant; - Color tagBackgroudColor = this.tagPickerConfig.tagBackgroudColor ?? Color(0xffF8F8F8); - Color selectedTagBackgroudColor = this.tagPickerConfig.selectedTagBackgroudColor ?? - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary.withAlpha(0x14); + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextImportant; + Color tagBackgroudColor = + this.tagPickerConfig.tagBackgroudColor ?? Color(0xffF8F8F8); + Color selectedTagBackgroudColor = + this.tagPickerConfig.selectedTagBackgroudColor ?? + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary + .withAlpha(0x14); return Container( padding: EdgeInsets.only(top: 0.0, left: 20.0, right: 20.0, bottom: 0.0), constraints: BoxConstraints(maxHeight: 322, minHeight: 120), @@ -150,7 +163,8 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { //宽高比 childAspectRatio: brnChildAspectRatio, //GridView内边距 - padding: EdgeInsets.only(top: 20.0, left: 0.0, right: 0.0, bottom: 20.0), + padding: + EdgeInsets.only(top: 20.0, left: 0.0, right: 0.0, bottom: 20.0), primary: true, children: this._sourceTags.map((choice) { bool selected = choice.isSelect; @@ -163,7 +177,8 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { pressElevation: 0, backgroundColor: tagBackgroudColor, selectedColor: selectedTagBackgroudColor, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(2.0)), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(2.0)), label: Container( width: width, child: Text( @@ -202,10 +217,19 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { Color selectedTagTitleColor = this.tagPickerConfig.selectedTagTitleColor ?? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary; Color tagTitleColor = this.tagPickerConfig.tagTitleColor ?? - BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextImportant; - Color tagBackgroudColor = this.tagPickerConfig.tagBackgroudColor ?? Color(0xffF8F8F8); - Color selectedTagBackgroudColor = this.tagPickerConfig.selectedTagBackgroudColor ?? - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary.withAlpha(0x14); + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextImportant; + Color tagBackgroudColor = + this.tagPickerConfig.tagBackgroudColor ?? Color(0xffF8F8F8); + Color selectedTagBackgroudColor = + this.tagPickerConfig.selectedTagBackgroudColor ?? + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary + .withAlpha(0x14); return Container( padding: EdgeInsets.symmetric(vertical: 16, horizontal: 16), @@ -223,7 +247,8 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { pressElevation: 0, backgroundColor: tagBackgroudColor, selectedColor: selectedTagBackgroudColor, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(2.0)), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(2.0)), label: Text( onTagValueGetter(choice), textAlign: TextAlign.center, diff --git a/lib/src/components/picker/brn_multi_picker.dart b/lib/src/components/picker/brn_multi_picker.dart index c08c462a..06ff4bec 100644 --- a/lib/src/components/picker/brn_multi_picker.dart +++ b/lib/src/components/picker/brn_multi_picker.dart @@ -125,7 +125,8 @@ class BrnMultiDataPicker extends StatefulWidget { confirmTextStyle: BrnTextStyle.withStyle(confirmTextStyle), titleTextStyle: BrnTextStyle.withStyle(titleTextStyle), itemTextStyle: BrnTextStyle(color: textColor, fontSize: textFontSize), - itemTextSelectedStyle: BrnTextStyle(color: textSelectedColor, fontSize: textFontSize), + itemTextSelectedStyle: + BrnTextStyle(color: textSelectedColor, fontSize: textFontSize), )); this.themeData = BrnThemeConfigurator.instance @@ -209,14 +210,17 @@ class _BrnMultiDataPickerState extends State { color: widget.themeData?.backgroundColor, child: Row( mainAxisSize: MainAxisSize.max, - children: widget.pickerTitles != null ? _pickersWithTitle() : _pickers())); + children: widget.pickerTitles != null + ? _pickersWithTitle() + : _pickers())); } List _pickersWithTitle() { List pickersWithTitle = List(); for (int i = 0; i < widget.delegate.numberOfComponent(); i++) { int initRow = widget.delegate.initSelectedRowForComponent(i); - FixedExtentScrollController controller = FixedExtentScrollController(initialItem: initRow); + FixedExtentScrollController controller = + FixedExtentScrollController(initialItem: initRow); widget.controllers.add(controller); if (i >= _selectedIndexList.length) _selectedIndexList.add(0); Widget picker = _configSinglePicker(i); @@ -232,7 +236,8 @@ class _BrnMultiDataPickerState extends State { child: Text( widget.pickerTitles[i], style: TextStyle( - fontSize: widget.pickerTitleFontSize, color: widget.pickerTitleColor), + fontSize: widget.pickerTitleFontSize, + color: widget.pickerTitleColor), ), ), ), @@ -248,7 +253,8 @@ class _BrnMultiDataPickerState extends State { List pickers = List(); for (int i = 0; i < widget.delegate.numberOfComponent(); i++) { int initRow = widget.delegate.initSelectedRowForComponent(i); - FixedExtentScrollController controller = FixedExtentScrollController(initialItem: initRow); + FixedExtentScrollController controller = + FixedExtentScrollController(initialItem: initRow); widget.controllers.add(controller); if (i >= _selectedIndexList.length) _selectedIndexList.add(0); Widget picker = _configSinglePicker(i); @@ -267,16 +273,21 @@ class _BrnMultiDataPickerState extends State { createWidgetList: () { if (widget.createItemWidget != null) { List widgetList = List(); - for (int i = 0; i < widget.delegate.numberOfRowsInComponent(component); i++) { + for (int i = 0; + i < widget.delegate.numberOfRowsInComponent(component); + i++) { bool isSelect = _selectedIndexList[component] == i; widgetList.add(widget.createItemWidget != null - ? widget.createItemWidget(isSelect, component, i, _selectedIndexList) + ? widget.createItemWidget( + isSelect, component, i, _selectedIndexList) : Container()); } return widgetList; } else { List list = List(); - for (int i = 0; i < widget.delegate.numberOfRowsInComponent(component); i++) { + for (int i = 0; + i < widget.delegate.numberOfRowsInComponent(component); + i++) { list.add(Center( child: Text( widget.delegate.titleForRowInComponent(component, i), @@ -289,15 +300,21 @@ class _BrnMultiDataPickerState extends State { return list; } }, - itemExtent: widget.delegate.rowHeightForComponent(component) ?? widget.themeData.itemHeight, + itemExtent: widget.delegate.rowHeightForComponent(component) ?? + widget.themeData.itemHeight, changed: (int index) { widget.delegate.selectRowInComponent(component, index); _selectedIndexList[component] = index; setState(() { - for (int i = component + 1; i < widget.delegate.numberOfComponent(); i++) { + for (int i = component + 1; + i < widget.delegate.numberOfComponent(); + i++) { List list = List(); - for (int j = 0; j < widget.delegate.numberOfRowsInComponent(component); j++) { - list.add(widget.delegate.titleForRowInComponent(component, index)); + for (int j = 0; + j < widget.delegate.numberOfRowsInComponent(component); + j++) { + list.add( + widget.delegate.titleForRowInComponent(component, index)); } FixedExtentScrollController controller = widget.controllers[i]; if (widget.sync) { @@ -381,7 +398,8 @@ class _MyPickerState extends State { ///默认的选择轮盘滚动行为,Android去除默认的水波纹动画效果 class _DefaultScrollBehavior extends ScrollBehavior { @override - Widget buildViewportChrome(BuildContext context, Widget child, AxisDirection axisDirection) { + Widget buildViewportChrome( + BuildContext context, Widget child, AxisDirection axisDirection) { return child; } } diff --git a/lib/src/components/picker/brn_select_tags_with_input_picker.dart b/lib/src/components/picker/brn_select_tags_with_input_picker.dart index e797bece..a3f9474e 100644 --- a/lib/src/components/picker/brn_select_tags_with_input_picker.dart +++ b/lib/src/components/picker/brn_select_tags_with_input_picker.dart @@ -5,7 +5,6 @@ import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; - ///传入的泛型数据转换为值 以填充Widget typedef SelectTagWithInputValueGetter = String Function(V data); diff --git a/lib/src/components/picker/brn_tags_common_picker.dart b/lib/src/components/picker/brn_tags_common_picker.dart index bfdae226..7a1fef20 100644 --- a/lib/src/components/picker/brn_tags_common_picker.dart +++ b/lib/src/components/picker/brn_tags_common_picker.dart @@ -10,7 +10,8 @@ enum BrnCommonPickBackType { confirm, } -typedef TagsPickerContentBuilder = Widget Function(BuildContext context, VoidCallback onUpdate); +typedef TagsPickerContentBuilder = Widget Function( + BuildContext context, VoidCallback onUpdate); /// 创建时传入Builder 或者 子类实现 createBuilder 函数 class CommonTagsPicker extends StatefulWidget { @@ -32,7 +33,9 @@ class CommonTagsPicker extends StatefulWidget { this.themeData}) : super(key: key) { this.themeData ??= BrnPickerConfig(); - this.themeData = this.themeData.merge(BrnThemeConfigurator.instance.getConfig().pickerConfig); + this.themeData = this + .themeData + .merge(BrnThemeConfigurator.instance.getConfig().pickerConfig); } void show() { @@ -91,10 +94,14 @@ class _CommonPickerState extends State { Widget build(BuildContext context) { return BrnPickerClipRRect( borderRadius: BorderRadius.only( - topLeft: - Radius.circular(BrnThemeConfigurator.instance.getConfig().pickerConfig.cornerRadius), - topRight: - Radius.circular(BrnThemeConfigurator.instance.getConfig().pickerConfig.cornerRadius), + topLeft: Radius.circular(BrnThemeConfigurator.instance + .getConfig() + .pickerConfig + .cornerRadius), + topRight: Radius.circular(BrnThemeConfigurator.instance + .getConfig() + .pickerConfig + .cornerRadius), ), child: Container( color: Colors.white, diff --git a/lib/src/components/picker/brn_tags_picker_config.dart b/lib/src/components/picker/brn_tags_picker_config.dart index ec250329..76f82a7d 100644 --- a/lib/src/components/picker/brn_tags_picker_config.dart +++ b/lib/src/components/picker/brn_tags_picker_config.dart @@ -15,8 +15,10 @@ class BrnTagsPickerHeaderConfig { this.cancelFontSize = 18, this.dividingLineColor, }) { - this.titleColor = BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; - this.cancelColor = BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; + this.titleColor = + BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; + this.cancelColor = + BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; } final double headerHeight; @@ -46,7 +48,8 @@ class BrnTagsPickerConfig { this.selectedTagBackgroudColor, this.chipPadding, this.tagItemSource = const []}) { - this.tagTitleColor = BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; + this.tagTitleColor = + BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; } ///tag 文字大小 @@ -87,5 +90,10 @@ class BrnTagItemBean { ///自己添加的扩展 Map ext; - BrnTagItemBean({this.name = '', this.code = '', this.index, this.isSelect = false, this.ext}); + BrnTagItemBean( + {this.name = '', + this.code = '', + this.index, + this.isSelect = false, + this.ext}); } diff --git a/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart b/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart index 08a38a00..c6368103 100644 --- a/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart +++ b/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart @@ -16,7 +16,8 @@ enum PickerWindowType { class BrnPickerEntity { String uniqueId; //唯一的id - String type; //类型 目前支持的类型有不限(unlimit)、单选(radio)、复选(checkbox), 最终被解析成 PickerFilterType 类型 + String + type; //类型 目前支持的类型有不限(unlimit)、单选(radio)、复选(checkbox), 最终被解析成 PickerFilterType 类型 String key; //回传给服务器 String value; //回传给服务器 String name; //显示的文案 @@ -43,7 +44,8 @@ class BrnPickerEntity { this.filterType = this.parserFilterTypeWithType(this.type); /// 默认支持最大选中个数为 65535 - this.maxSelectedCount = maxSelectedCount ?? BrnSelectionConstant.MAX_SELECT_COUNT; + this.maxSelectedCount = + maxSelectedCount ?? BrnSelectionConstant.MAX_SELECT_COUNT; } static BrnPickerEntity fromMap(Map map) { @@ -57,7 +59,8 @@ class BrnPickerEntity { entity.isSelected = map['isSelected'] ?? false; entity.defaultValue = map['defaultValue'] ?? ""; entity.value = map['value'] ?? ""; - if (map['maxSelectedCount'] != null && int.tryParse(map['maxSelectedCount']) != null) { + if (map['maxSelectedCount'] != null && + int.tryParse(map['maxSelectedCount']) != null) { entity.maxSelectedCount = int.tryParse(map['maxSelectedCount']); } else { entity.maxSelectedCount = BrnSelectionConstant.MAX_SELECT_COUNT; @@ -65,7 +68,8 @@ class BrnPickerEntity { entity.extMap = map['ext'] ?? {}; // entity.children = map['children'] ?? []; entity.children = List() - ..addAll((map['children'] as List ?? []).map((o) => BrnPickerEntity.fromMap(o))); + ..addAll((map['children'] as List ?? []) + .map((o) => BrnPickerEntity.fromMap(o))); return entity; } @@ -88,7 +92,6 @@ class BrnPickerEntity { } } - void configRelationship() { if (this.children != null && this.children.length > 0) { for (BrnPickerEntity entity in this.children) { @@ -140,7 +143,8 @@ class BrnPickerEntity { if (secondEntity != null && secondEntity.children != null && secondEntity.children.length > 0) { - List thirds = this.currentSelectListForEntity(secondEntity); + List thirds = + this.currentSelectListForEntity(secondEntity); if (thirds.length > 0) { list.addAll(thirds); } else if (secondEntity.isSelected) { @@ -172,11 +176,13 @@ class BrnPickerEntity { if (firstColumn != null && firstColumn.length > 0) { for (BrnPickerEntity firstEntity in firstColumn) { if (firstEntity != null) { - List secondColumn = this.currentSelectListForEntity(firstEntity); + List secondColumn = + this.currentSelectListForEntity(firstEntity); results.addAll(secondColumn); if (secondColumn != null && secondColumn.length > 0) { for (BrnPickerEntity secondEntity in secondColumn) { - List thirdColumn = this.currentSelectListForEntity(secondEntity); + List thirdColumn = + this.currentSelectListForEntity(secondEntity); results.addAll(thirdColumn); } } @@ -215,7 +221,9 @@ class BrnPickerEntity { /// 判断当前的筛选 Item 是否为当前层次中第一个被选中的 Item。 /// 用于展开筛选弹窗时显示选中效果。 int getIndexInCurrentLevel() { - if (parent == null || parent.children == null || parent.children.length == 0) return -1; + if (parent == null || + parent.children == null || + parent.children.length == 0) return -1; for (BrnPickerEntity entity in parent.children) { if (entity == this) { @@ -226,7 +234,9 @@ class BrnPickerEntity { } bool isInLastLevel() { - if (parent == null || parent.children == null || parent.children.length == 0) return true; + if (parent == null || + parent.children == null || + parent.children.length == 0) return true; for (BrnPickerEntity entity in parent.children) { if (entity.children != null && entity.children.length > 0) { @@ -238,7 +248,8 @@ class BrnPickerEntity { /// 在这里简单认为 value 为空【null 或 ''】时为 unLimit. bool isUnLimit() { - return filterType == PickerFilterType.UnLimit || (BrunoTools.isEmpty(value) && filterType == PickerFilterType.Radio); + return filterType == PickerFilterType.UnLimit || + (BrunoTools.isEmpty(value) && filterType == PickerFilterType.Radio); } void clearSelectedEntity() { diff --git a/lib/src/components/picker/multi_range_picker/brn_multi_column_converter.dart b/lib/src/components/picker/multi_range_picker/brn_multi_column_converter.dart index e940e9fd..b29bcbaa 100644 --- a/lib/src/components/picker/multi_range_picker/brn_multi_column_converter.dart +++ b/lib/src/components/picker/multi_range_picker/brn_multi_column_converter.dart @@ -5,17 +5,21 @@ import 'package:bruno/src/utils/brn_tools.dart'; class BrnMultiRangeSelConverter { const BrnMultiRangeSelConverter(); - Map> convertPickedData(List selectedResults, + Map> convertPickedData( + List selectedResults, {bool includeUnlimitSelection = false}) { - return getSelectionParams(selectedResults, includeUnlimitSelection: includeUnlimitSelection); + return getSelectionParams(selectedResults, + includeUnlimitSelection: includeUnlimitSelection); } - Map> getSelectionParams(List selectedResults, + Map> getSelectionParams( + List selectedResults, {bool includeUnlimitSelection = false}) { Map> params = Map(); if (selectedResults == null) return params; for (BrnPickerEntity menuItemEntity in selectedResults) { - int levelCount = BrnMultiColumnPickerUtil.getTotalColumnCount(menuItemEntity); + int levelCount = + BrnMultiColumnPickerUtil.getTotalColumnCount(menuItemEntity); if (levelCount == 1) { params.addAll(getCurrentSelectionEntityParams(menuItemEntity, includeUnlimitSelection: includeUnlimitSelection)); @@ -46,7 +50,8 @@ class BrnMultiRangeSelConverter { return params; } - Map> mergeParams(Map> params, + Map> mergeParams( + Map> params, Map> selectedParams) { selectedParams?.forEach((String key, List value) { if (params != null && params.containsKey(key)) { @@ -74,7 +79,8 @@ class BrnMultiRangeSelConverter { }) ?.map((BrnPickerEntity f) => f) ?.toList(); - List selectedParams = selectedEntity == null ? [] : selectedEntity; + List selectedParams = + selectedEntity == null ? [] : selectedEntity; if (!BrunoTools.isEmpty(selectedParams) && !BrunoTools.isEmpty(parentKey)) { params[parentKey] = selectedParams; } diff --git a/lib/src/components/picker/multi_range_picker/brn_multi_column_list.dart b/lib/src/components/picker/multi_range_picker/brn_multi_column_list.dart index 762c840a..1a4c6b83 100644 --- a/lib/src/components/picker/multi_range_picker/brn_multi_column_list.dart +++ b/lib/src/components/picker/multi_range_picker/brn_multi_column_list.dart @@ -9,7 +9,8 @@ import 'package:flutter/material.dart'; /// [listIndex] 点击位置处于第几列 /// [index] 点击位置处于当前列的位置 /// [entity] 被点击位置的数据 -typedef bool BrnOnSelectEntityInterceptor(int listIndex, int index, BrnPickerEntity entity); +typedef bool BrnOnSelectEntityInterceptor( + int listIndex, int index, BrnPickerEntity entity); // ignore: must_be_immutable class BrnMultiColumnListWidget extends StatefulWidget { @@ -44,8 +45,9 @@ class BrnMultiColumnListWidget extends StatefulWidget { items.forEach((element) { element.configRelationship(); }); - - currentListIndex = BrnMultiColumnPickerUtil.getCurrentColumnIndex(items.length > 0 ? items[0] : null); + + currentListIndex = BrnMultiColumnPickerUtil.getCurrentColumnIndex( + items.length > 0 ? items[0] : null); _selectedItems = items?.where((f) => f.isSelected)?.toList(); if (_selectedItems == null) { @@ -54,7 +56,8 @@ class BrnMultiColumnListWidget extends StatefulWidget { } @override - _BrnMultiColumnListWidgetState createState() => _BrnMultiColumnListWidgetState(); + _BrnMultiColumnListWidgetState createState() => + _BrnMultiColumnListWidgetState(); List getSelectedItems() { return _selectedItems; @@ -94,12 +97,14 @@ class _BrnMultiColumnListWidgetState extends State { isFirstLevel: (1 == widget.currentListIndex) ? true : false, itemSelectFunction: (BrnPickerEntity entity) { if (widget.onSelectEntityInterceptor != null && - widget.onSelectEntityInterceptor(widget.currentListIndex, index, entity) == + widget.onSelectEntityInterceptor( + widget.currentListIndex, index, entity) == false) { return; } _processFilterData(entity); - widget.singleListItemPick(widget.currentListIndex, index, entity); + widget.singleListItemPick( + widget.currentListIndex, index, entity); }, ); }, @@ -122,14 +127,16 @@ class _BrnMultiColumnListWidgetState extends State { return; } - if (selectedEntity.filterType == PickerFilterType.Checkbox && !selectedEntity.isSelected) { + if (selectedEntity.filterType == PickerFilterType.Checkbox && + !selectedEntity.isSelected) { if (!BrnMultiColumnPickerUtil.isSelectedCountExceed(selectedEntity)) { BrnToast.show("您选择的数量已达上限", context); return; } } - int totalLevel = BrnMultiColumnPickerUtil.getTotalColumnCount(selectedEntity); + int totalLevel = + BrnMultiColumnPickerUtil.getTotalColumnCount(selectedEntity); if (selectedEntity.isUnLimit()) { selectedEntity.parent.clearChildSelection(); } @@ -149,8 +156,10 @@ class _BrnMultiColumnListWidgetState extends State { /// (两列、三列时)第一列节点是否被选中取决于它的子节点是否被选中, /// 只有当它子节点被选中时才会认为第一列的节点相应被选中。 if (widget.items != null && widget.items.length > 0) { - widget.items[0].parent?.isSelected = - widget.items[0].parent.children.where((BrnPickerEntity f) => f.isSelected).length > 0; + widget.items[0].parent?.isSelected = widget.items[0].parent.children + .where((BrnPickerEntity f) => f.isSelected) + .length > + 0; } for (BrnPickerEntity item in widget.items) { diff --git a/lib/src/components/picker/multi_range_picker/brn_multi_column_picker.dart b/lib/src/components/picker/multi_range_picker/brn_multi_column_picker.dart index 8d694f2c..22bfd61e 100644 --- a/lib/src/components/picker/multi_range_picker/brn_multi_column_picker.dart +++ b/lib/src/components/picker/multi_range_picker/brn_multi_column_picker.dart @@ -14,15 +14,16 @@ import 'package:flutter/material.dart'; /// [columnIndex] 数据项所在列 /// [rowIndex] 数据项所在列中的位置 /// [entity] 被点击的数据项 -typedef void BrnOnEntityTap(int columnIndex, int rowIndex, BrnPickerEntity entity); +typedef void BrnOnEntityTap( + int columnIndex, int rowIndex, BrnPickerEntity entity); /// 单个数据项被点击的回调, /// [results] 选中的数据项 /// [firstIndex] 第一列被选中数据的位置 /// [secondIndex] 第二列被选中数据的位置 /// [thirdIndex] 第三列被选中数据的位置 -typedef void BrnOnPickerConfirm( - Map> results, int firstIndex, int secondIndex, int thirdIndex); +typedef void BrnOnPickerConfirm(Map> results, + int firstIndex, int secondIndex, int thirdIndex); /// 从屏幕下方弹起的多级筛选选择器 /// 可设置筛项的层级、多选、单选等筛选相关功能 @@ -73,7 +74,9 @@ class BrnMultiColumnPicker extends StatefulWidget { this.themeData}) : super(key: key) { this.themeData ??= BrnPickerConfig(); - this.themeData = this.themeData.merge(BrnThemeConfigurator.instance.getConfig().pickerConfig); + this.themeData = this + .themeData + .merge(BrnThemeConfigurator.instance.getConfig().pickerConfig); } @override @@ -81,7 +84,8 @@ class BrnMultiColumnPicker extends StatefulWidget { } class _BrnSelectionGroupViewState extends State { - static const BrnMultiRangeSelConverter defaultConverter = const BrnMultiRangeSelConverter(); + static const BrnMultiRangeSelConverter defaultConverter = + const BrnMultiRangeSelConverter(); List _firstList = List(); List _secondList = List(); List _thirdList = List(); @@ -102,8 +106,10 @@ class _BrnSelectionGroupViewState extends State { @override void initState() { - _normalColor = BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; - _selectedColor = BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary; + _normalColor = + BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; + _selectedColor = + BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary; _initData(); super.initState(); } @@ -168,9 +174,11 @@ class _BrnSelectionGroupViewState extends State { maxHeight: widget.maxHeight, flex: _getFlexByColumnIndex(1), focusedIndex: _firstIndex, - singleListItemPick: (int listIndex, int index, BrnPickerEntity entity) { + singleListItemPick: + (int listIndex, int index, BrnPickerEntity entity) { _setFirstIndex(index); - if (_columnCount == 1 && widget.entity.filterType == PickerFilterType.Radio) { + if (_columnCount == 1 && + widget.entity.filterType == PickerFilterType.Radio) { _confirmButtonClickEvent(); } if (widget.onEntityTap != null) { @@ -190,7 +198,8 @@ class _BrnSelectionGroupViewState extends State { selectedBackgroundColor: _getSelectBgColorByColumnIndex(1), flex: _getFlexByColumnIndex(1), focusedIndex: _firstIndex, - singleListItemPick: (int listIndex, int index, BrnPickerEntity entity) { + singleListItemPick: + (int listIndex, int index, BrnPickerEntity entity) { _setFirstIndex(index); if (widget.onEntityTap != null) { widget.onEntityTap(0, index, entity); @@ -206,7 +215,8 @@ class _BrnSelectionGroupViewState extends State { selectedBackgroundColor: _getSelectBgColorByColumnIndex(2), flex: _getFlexByColumnIndex(2), focusedIndex: _secondIndex, - singleListItemPick: (int listIndex, int index, BrnPickerEntity entity) { + singleListItemPick: + (int listIndex, int index, BrnPickerEntity entity) { _setSecondIndex(index); if (widget.onEntityTap != null) { widget.onEntityTap(1, index, entity); @@ -225,7 +235,8 @@ class _BrnSelectionGroupViewState extends State { selectedBackgroundColor: _getSelectBgColorByColumnIndex(1), flex: _getFlexByColumnIndex(1), focusedIndex: _firstIndex, - singleListItemPick: (int listIndex, int index, BrnPickerEntity entity) { + singleListItemPick: + (int listIndex, int index, BrnPickerEntity entity) { _setFirstIndex(index); if (widget.onEntityTap != null) { widget.onEntityTap(0, index, entity); @@ -241,7 +252,8 @@ class _BrnSelectionGroupViewState extends State { selectedBackgroundColor: _getSelectBgColorByColumnIndex(2), flex: _getFlexByColumnIndex(2), focusedIndex: _secondIndex, - singleListItemPick: (int listIndex, int index, BrnPickerEntity entity) { + singleListItemPick: + (int listIndex, int index, BrnPickerEntity entity) { _setSecondIndex(index); if (widget.onEntityTap != null) { widget.onEntityTap(1, index, entity); @@ -256,7 +268,8 @@ class _BrnSelectionGroupViewState extends State { selectedBackgroundColor: _getSelectBgColorByColumnIndex(3), flex: _getFlexByColumnIndex(3), focusedIndex: _thirdIndex, - singleListItemPick: (int listIndex, int index, BrnPickerEntity entity) { + singleListItemPick: + (int listIndex, int index, BrnPickerEntity entity) { if (entity.isSelected) { _thirdIndex = index; } else { @@ -287,7 +300,8 @@ class _BrnSelectionGroupViewState extends State { if (widget.onConfirm != null) { //更多和无tips等外部调用的多选需要传递此值selectedLastColumnArray Map> result = defaultConverter - .convertPickedData([widget.entity], includeUnlimitSelection: widget.isIncludeUnLimit); + .convertPickedData([widget.entity], + includeUnlimitSelection: widget.isIncludeUnLimit); widget.onConfirm(result, _firstIndex, _secondIndex, _thirdIndex); } } @@ -356,7 +370,9 @@ class _BrnSelectionGroupViewState extends State { if (_firstIndex == -1) { if (widget.defaultFocusedIndexes != null) { - for (int index = 0; index < widget.defaultFocusedIndexes.length; index++) { + for (int index = 0; + index < widget.defaultFocusedIndexes.length; + index++) { if (index == 0 && widget.defaultFocusedIndexes[index] >= 0) { _firstIndex = widget.defaultFocusedIndexes[index]; } @@ -420,7 +436,8 @@ class _BrnSelectionGroupViewState extends State { _firstIndex = firstIndex; _secondIndex = -1; if (widget.entity.children.length > _firstIndex) { - List seconds = widget.entity.children[_firstIndex].children; + List seconds = + widget.entity.children[_firstIndex].children; if (seconds != null) { _secondIndex = _getInitialSelectIndex(seconds); @@ -437,7 +454,8 @@ class _BrnSelectionGroupViewState extends State { void _setSecondIndex(int secondIndex) { _secondIndex = secondIndex; _thirdIndex = -1; - List seconds = widget.entity.children[_firstIndex].children; + List seconds = + widget.entity.children[_firstIndex].children; if (seconds.length > _secondIndex) { List thirds = seconds[_secondIndex].children; if (thirds != null) { @@ -467,7 +485,8 @@ class _BrnSelectionGroupViewState extends State { // 当上一级为多选时,当前级不应有默认焦点, // 例如1级为多选,不应该默认选中2级的不限 // 否则每选中任意一个1级选项,就默认有了一个2级的不限 - if (entity.isUnLimit() && entity.parent.filterType != PickerFilterType.Checkbox) { + if (entity.isUnLimit() && + entity.parent.filterType != PickerFilterType.Checkbox) { index = levelList.indexOf(entity); break; } diff --git a/lib/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart b/lib/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart index c1adcd04..a719ca04 100644 --- a/lib/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart +++ b/lib/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart @@ -3,7 +3,6 @@ import 'package:bruno/src/utils/brn_tools.dart'; /// BrnMultiColumnPicker相关工具类 class BrnMultiColumnPickerUtil { - /// 筛选项最多不超过三层,故直接写代码判断,本质为深度优先搜索。 static int getTotalColumnCount(BrnPickerEntity entity) { int count = 0; @@ -12,13 +11,17 @@ class BrnMultiColumnPickerUtil { rootEntity = rootEntity.parent; } - if (rootEntity != null && rootEntity.children != null && rootEntity.children.length > 0) { + if (rootEntity != null && + rootEntity.children != null && + rootEntity.children.length > 0) { count = count > 1 ? count : 1; for (BrnPickerEntity firstLevelEntity in rootEntity.children) { - if (firstLevelEntity.children != null && firstLevelEntity.children.length > 0) { + if (firstLevelEntity.children != null && + firstLevelEntity.children.length > 0) { count = count > 2 ? count : 2; for (BrnPickerEntity secondLevelEntity in firstLevelEntity.children) { - if (secondLevelEntity.children != null && secondLevelEntity.children.length > 0) { + if (secondLevelEntity.children != null && + secondLevelEntity.children.length > 0) { count = 3; break; } @@ -49,7 +52,7 @@ class BrnMultiColumnPickerUtil { /// 返回 true 符合条件,false 不符合条件 static bool isSelectedCountExceed(BrnPickerEntity entity) { if (entity == null && entity.parent == null) return false; - return entity.parent.getSelectedChildCount() < entity.parent.maxSelectedCount; + return entity.parent.getSelectedChildCount() < + entity.parent.maxSelectedCount; } - -} \ No newline at end of file +} diff --git a/lib/src/components/picker/multi_range_picker/btn_multi_column_picker_item.dart b/lib/src/components/picker/multi_range_picker/btn_multi_column_picker_item.dart index b064686b..3310c1d0 100644 --- a/lib/src/components/picker/multi_range_picker/btn_multi_column_picker_item.dart +++ b/lib/src/components/picker/multi_range_picker/btn_multi_column_picker_item.dart @@ -34,13 +34,15 @@ class BrnMultiRangePickerCommonItem extends StatelessWidget { @override Widget build(BuildContext context) { var checkbox; - if (!item.isUnLimit() && (item.children == null || item.children.length == 0)) { + if (!item.isUnLimit() && + (item.children == null || item.children.length == 0)) { if (item.isInLastLevel() && _hasCheckBoxBrother(item)) { checkbox = Container( padding: EdgeInsets.only(left: 6), width: 21, child: (item.isSelected) - ? BrunoTools.getAssetImageWithBandColor(BrnAsset.iconMultiSelected) + ? BrunoTools.getAssetImageWithBandColor( + BrnAsset.iconMultiSelected) : BrunoTools.getAssetImage(BrnAsset.iconUnSelect), ); } else { @@ -95,8 +97,9 @@ class BrnMultiRangePickerCommonItem extends StatelessWidget { } Color _getItemTextColor() { - Color itemColor = - (item.isUnLimit() ? isCurrentFocused : item.isSelected) ? selectColor : normalColor; + Color itemColor = (item.isUnLimit() ? isCurrentFocused : item.isSelected) + ? selectColor + : normalColor; if (!item.isInLastLevel()) { itemColor = isCurrentFocused ? selectColor : normalColor; } @@ -104,9 +107,10 @@ class BrnMultiRangePickerCommonItem extends StatelessWidget { } FontWeight _getItemFontWeight() { - FontWeight fontWeight = (item.isUnLimit() ? isCurrentFocused : item.isSelected) - ? FontWeight.w600 - : FontWeight.normal; + FontWeight fontWeight = + (item.isUnLimit() ? isCurrentFocused : item.isSelected) + ? FontWeight.w600 + : FontWeight.normal; if (!item.isInLastLevel()) { fontWeight = isCurrentFocused ? FontWeight.w600 : FontWeight.normal; @@ -116,9 +120,11 @@ class BrnMultiRangePickerCommonItem extends StatelessWidget { String _getSelectedItemCount(BrnPickerEntity item) { String itemCount = ""; - if ((BrnMultiColumnPickerUtil.getTotalColumnCount(item) < 3 || !isFirstLevel) && + if ((BrnMultiColumnPickerUtil.getTotalColumnCount(item) < 3 || + !isFirstLevel) && item.children != null) { - int count = item.children.where((f) => f.isSelected && !f.isUnLimit()).length; + int count = + item.children.where((f) => f.isSelected && !f.isUnLimit()).length; if (count > 1) { return '($count)'; } @@ -127,8 +133,9 @@ class BrnMultiRangePickerCommonItem extends StatelessWidget { } bool _hasCheckBoxBrother(BrnPickerEntity item) { - int count = - item.parent.children?.where((f) => f.filterType == PickerFilterType.Checkbox)?.length; + int count = item.parent.children + ?.where((f) => f.filterType == PickerFilterType.Checkbox) + ?.length; return count == null ? false : count > 0; } } diff --git a/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_data.dart b/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_data.dart index e70d9eda..9d9eebab 100644 --- a/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_data.dart +++ b/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_data.dart @@ -5,5 +5,6 @@ class BrnMultiSelectBottomPickerItem { bool isChecked; //是否选中 - BrnMultiSelectBottomPickerItem(this.code, this.content, {this.isChecked: false}); + BrnMultiSelectBottomPickerItem(this.code, this.content, + {this.isChecked: false}); } diff --git a/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_list_picker.dart b/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_list_picker.dart index 5434f43b..6aee590e 100644 --- a/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_list_picker.dart +++ b/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_list_picker.dart @@ -16,7 +16,8 @@ typedef BrnMultiSelectListPickerSubmit = void Function( /// item 被点击时的回调 /// [index] item 的索引 -typedef BrnMultiSelectListPickerItemClick = void Function(BuildContext context, int index); +typedef BrnMultiSelectListPickerItemClick = void Function( + BuildContext context, int index); /// 多选列表 Picker @@ -29,14 +30,14 @@ class BrnMultiSelectListPicker extends StatefulWidget { final BrnPickerTitleConfig pickerTitleConfig; static void show( - BuildContext context, { - @required List items, - BrnMultiSelectListPickerSubmit onSubmit, - VoidCallback onCancel, - BrnMultiSelectListPickerItemClick onItemClick, - BrnPickerTitleConfig pickerTitleConfig = BrnPickerTitleConfig.Default, - bool isDismissible = true, - }) { + BuildContext context, { + @required List items, + BrnMultiSelectListPickerSubmit onSubmit, + VoidCallback onCancel, + BrnMultiSelectListPickerItemClick onItemClick, + BrnPickerTitleConfig pickerTitleConfig = BrnPickerTitleConfig.Default, + bool isDismissible = true, + }) { showModalBottomSheet( context: context, isDismissible: isDismissible, @@ -52,7 +53,7 @@ class BrnMultiSelectListPicker extends StatefulWidget { }, ); } - + BrnMultiSelectListPicker({ Key key, this.title, @@ -74,10 +75,14 @@ class MultiSelectDialogWidgetState extends State { Widget build(BuildContext context) { return BrnPickerClipRRect( borderRadius: BorderRadius.only( - topLeft: - Radius.circular(BrnThemeConfigurator.instance.getConfig().pickerConfig.cornerRadius), - topRight: - Radius.circular(BrnThemeConfigurator.instance.getConfig().pickerConfig.cornerRadius), + topLeft: Radius.circular(BrnThemeConfigurator.instance + .getConfig() + .pickerConfig + .cornerRadius), + topRight: Radius.circular(BrnThemeConfigurator.instance + .getConfig() + .pickerConfig + .cornerRadius), ), child: Container( color: Colors.white, @@ -92,21 +97,23 @@ class MultiSelectDialogWidgetState extends State { child: BrnPickerTitle( pickerTitleConfig: widget.pickerTitleConfig, onConfirm: () { - List selectedItems = List(); + List selectedItems = + List(); if (widget.onSubmit != null) { for (int i = 0; i < widget.items?.length; i++) { if (widget.items[i].isChecked) { selectedItems.add(widget.items[i]); } } - if(widget.onSubmit != null) { + if (widget.onSubmit != null) { widget.onSubmit(selectedItems); } } }, - onCancel: widget.onCancel ?? () { - Navigator.of(context).pop(); - }, + onCancel: widget.onCancel ?? + () { + Navigator.of(context).pop(); + }, ), ), LimitedBox( @@ -114,7 +121,8 @@ class MultiSelectDialogWidgetState extends State { maxHeight: PICKER_HEIGHT, child: ListView.builder( shrinkWrap: true, - itemBuilder: (context, index) => _buildItem(context, index), + itemBuilder: (context, index) => + _buildItem(context, index), itemCount: widget.items?.length)), ], ), @@ -164,13 +172,16 @@ class MultiSelectDialogWidgetState extends State { alignment: Alignment.center, height: 50, child: widget.items[index].isChecked - ? BrunoTools.getAssetImageWithBandColor(BrnAsset.iconMultiSelected) + ? BrunoTools.getAssetImageWithBandColor( + BrnAsset.iconMultiSelected) : BrunoTools.getAssetImage(BrnAsset.iconUnSelect)), ], ), ), index != widget.items.length - 1 - ? Padding(padding: EdgeInsets.fromLTRB(20, 0, 20, 0), child: BrnLine()) + ? Padding( + padding: EdgeInsets.fromLTRB(20, 0, 20, 0), + child: BrnLine()) : Container() ], )); diff --git a/lib/src/components/picker/time_picker/brn_date_picker_constants.dart b/lib/src/components/picker/time_picker/brn_date_picker_constants.dart index 0fc01f49..04f36245 100755 --- a/lib/src/components/picker/time_picker/brn_date_picker_constants.dart +++ b/lib/src/components/picker/time_picker/brn_date_picker_constants.dart @@ -4,7 +4,8 @@ typedef DateValueCallback(DateTime dateTime, List selectedIndex); typedef DateRangeValueCallback(DateTime startDateTime, DateTime endDateTime, List startSelectedIndex, List endSelectedIndex); -typedef DateRangeSideValueCallback(DateTime selectDateTime, List selectedIndex); +typedef DateRangeSideValueCallback( + DateTime selectDateTime, List selectedIndex); /// Pressed cancel callback. typedef DateVoidCallback(); diff --git a/lib/src/components/picker/time_picker/brn_date_time_formatter.dart b/lib/src/components/picker/time_picker/brn_date_time_formatter.dart index 3ca8e78d..ca584c9e 100755 --- a/lib/src/components/picker/time_picker/brn_date_time_formatter.dart +++ b/lib/src/components/picker/time_picker/brn_date_time_formatter.dart @@ -27,7 +27,8 @@ class DateTimeFormatter { } /// Get default value of date format. - static String generateDateFormat(String dateFormat, BrnDateTimePickerMode pickerMode) { + static String generateDateFormat( + String dateFormat, BrnDateTimePickerMode pickerMode) { if (dateFormat != null && dateFormat.length > 0) { return dateFormat; } @@ -67,7 +68,8 @@ class DateTimeFormatter { } /// Split date format to array. - static List splitDateFormat(String dateFormat, {BrnDateTimePickerMode mode}) { + static List splitDateFormat(String dateFormat, + {BrnDateTimePickerMode mode}) { if (dateFormat == null || dateFormat.length == 0) { return []; } @@ -105,7 +107,8 @@ class DateTimeFormatter { } /// Format datetime string - static String formatDateTime(int value, String format, DateTimePickerLocale locale) { + static String formatDateTime( + int value, String format, DateTimePickerLocale locale) { if (format == null || format.length == 0) { return value.toString(); } @@ -145,7 +148,8 @@ class DateTimeFormatter { } /// Format day display - static String formatDate(DateTime dateTime, String format, DateTimePickerLocale locale) { + static String formatDate( + DateTime dateTime, String format, DateTimePickerLocale locale) { if (format == null || format.length == 0) { return dateTime.toString(); } @@ -173,20 +177,22 @@ class DateTimeFormatter { } /// format year text - static String _formatYear(int value, String format, DateTimePickerLocale locale) { + static String _formatYear( + int value, String format, DateTimePickerLocale locale) { if (format.contains('yyyy')) { // yyyy: the digit count of year is 4, e.g. 2019 return format.replaceAll('yyyy', value.toString()); } else if (format.contains('yy')) { // yy: the digit count of year is 2, e.g. 19 - return format.replaceAll( - 'yy', value.toString().substring(max(0, value.toString().length - 2))); + return format.replaceAll('yy', + value.toString().substring(max(0, value.toString().length - 2))); } return value.toString(); } /// format month text - static String _formatMonth(int value, String format, DateTimePickerLocale locale) { + static String _formatMonth( + int value, String format, DateTimePickerLocale locale) { List months = DatePickerI18n.getLocaleMonths(locale); if (format.contains('MMMM')) { // MMMM: the full name of month, e.g. January @@ -200,12 +206,14 @@ class DateTimeFormatter { } /// format day text - static String _formatDay(int value, String format, DateTimePickerLocale locale) { + static String _formatDay( + int value, String format, DateTimePickerLocale locale) { return _formatNumber(value, format, 'd'); } /// format week text - static String _formatWeek(int value, String format, DateTimePickerLocale locale) { + static String _formatWeek( + int value, String format, DateTimePickerLocale locale) { if (format.contains('EEEE')) { // EEEE: the full name of week, e.g. Monday List weeks = DatePickerI18n.getLocaleWeeks(locale); @@ -217,17 +225,20 @@ class DateTimeFormatter { } /// format hour text - static String _formatHour(int value, String format, DateTimePickerLocale locale) { + static String _formatHour( + int value, String format, DateTimePickerLocale locale) { return _formatNumber(value, format, 'H'); } /// format minute text - static String _formatMinute(int value, String format, DateTimePickerLocale locale) { + static String _formatMinute( + int value, String format, DateTimePickerLocale locale) { return _formatNumber(value, format, 'm'); } /// format second text - static String _formatSecond(int value, String format, DateTimePickerLocale locale) { + static String _formatSecond( + int value, String format, DateTimePickerLocale locale) { return _formatNumber(value, format, 's'); } diff --git a/lib/src/components/picker/time_picker/date_picker/brn_date_picker.dart b/lib/src/components/picker/time_picker/date_picker/brn_date_picker.dart index 19dc3a7f..009af06f 100755 --- a/lib/src/components/picker/time_picker/date_picker/brn_date_picker.dart +++ b/lib/src/components/picker/time_picker/date_picker/brn_date_picker.dart @@ -60,7 +60,6 @@ class BrnDatePicker { /// 分钟间切换的差值 int minuteDivider: 1, - DateTimePickerLocale locale: DATETIME_PICKER_LOCALE_DEFAULT, /// 时间选择组件显示的时间类型 @@ -114,7 +113,8 @@ class BrnDatePicker { onChange: onChange, onConfirm: onConfirm, theme: Theme.of(context), - barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, + barrierLabel: + MaterialLocalizations.of(context).modalBarrierDismissLabel, themeData: themeData, ), ) @@ -178,13 +178,14 @@ class _DatePickerRoute extends PopupRoute { @override AnimationController createAnimationController() { assert(_animationController == null); - _animationController = BottomSheet.createAnimationController(navigator.overlay); + _animationController = + BottomSheet.createAnimationController(navigator.overlay); return _animationController; } @override - Widget buildPage( - BuildContext context, Animation animation, Animation secondaryAnimation) { + Widget buildPage(BuildContext context, Animation animation, + Animation secondaryAnimation) { double height = themeData.pickerHeight; if (pickerTitleConfig.title != null || pickerTitleConfig.showTitle) { height += themeData.titleHeight; @@ -266,7 +267,8 @@ class _DatePickerComponent extends StatelessWidget { builder: (BuildContext context, Widget child) { return ClipRect( child: CustomSingleChildLayout( - delegate: _BottomPickerLayout(route.animation.value, contentHeight: _pickerHeight), + delegate: _BottomPickerLayout(route.animation.value, + contentHeight: _pickerHeight), child: BrnPickerClipRRect( borderRadius: BorderRadius.only( topLeft: Radius.circular(route.themeData.cornerRadius), diff --git a/lib/src/components/picker/time_picker/date_picker/brn_date_widget.dart b/lib/src/components/picker/time_picker/date_picker/brn_date_widget.dart index c0940ad2..3c08e2dd 100755 --- a/lib/src/components/picker/time_picker/date_picker/brn_date_widget.dart +++ b/lib/src/components/picker/time_picker/date_picker/brn_date_widget.dart @@ -53,8 +53,8 @@ class BrnDateWidget extends StatefulWidget { BrnPickerConfig themeData; @override - State createState() => - _BrnDateWidgetState(this.minDateTime, this.maxDateTime, this.initialDateTime); + State createState() => _BrnDateWidgetState( + this.minDateTime, this.maxDateTime, this.initialDateTime); } class _BrnDateWidgetState extends State { @@ -68,7 +68,8 @@ class _BrnDateWidgetState extends State { bool _isChangeDateRange = false; - _BrnDateWidgetState(DateTime minDateTime, DateTime maxDateTime, DateTime initialDateTime) { + _BrnDateWidgetState( + DateTime minDateTime, DateTime maxDateTime, DateTime initialDateTime) { // handle current selected year、month、day DateTime initDateTime = initialDateTime ?? DateTime.now(); this._currYear = initDateTime.year; @@ -92,18 +93,26 @@ class _BrnDateWidgetState extends State { this._currDay = min(max(_dayRange.first, _currDay), _dayRange.last); // create scroll controller - _yearScrollCtrl = FixedExtentScrollController(initialItem: _currYear - _yearRange.first); - _monthScrollCtrl = FixedExtentScrollController(initialItem: _currMonth - _monthRange.first); - _dayScrollCtrl = FixedExtentScrollController(initialItem: _currDay - _dayRange.first); - - _scrollCtrlMap = {'y': _yearScrollCtrl, 'M': _monthScrollCtrl, 'd': _dayScrollCtrl}; + _yearScrollCtrl = + FixedExtentScrollController(initialItem: _currYear - _yearRange.first); + _monthScrollCtrl = FixedExtentScrollController( + initialItem: _currMonth - _monthRange.first); + _dayScrollCtrl = + FixedExtentScrollController(initialItem: _currDay - _dayRange.first); + + _scrollCtrlMap = { + 'y': _yearScrollCtrl, + 'M': _monthScrollCtrl, + 'd': _dayScrollCtrl + }; _valueRangeMap = {'y': _yearRange, 'M': _monthRange, 'd': _dayRange}; } @override Widget build(BuildContext context) { return GestureDetector( - child: Material(color: Colors.transparent, child: _renderPickerView(context)), + child: Material( + color: Colors.transparent, child: _renderPickerView(context)), ); } @@ -112,7 +121,8 @@ class _BrnDateWidgetState extends State { Widget datePickerWidget = _renderDatePickerWidget(); // display the title widget - if (widget.pickerTitleConfig.title != null || widget.pickerTitleConfig.showTitle) { + if (widget.pickerTitleConfig.title != null || + widget.pickerTitleConfig.showTitle) { Widget titleWidget = BrnPickerTitle( pickerTitleConfig: widget.pickerTitleConfig, locale: widget.locale, @@ -120,7 +130,8 @@ class _BrnDateWidgetState extends State { onConfirm: () => _onPressedConfirm(), ); return Column( - mainAxisSize: MainAxisSize.min, children: [titleWidget, datePickerWidget]); + mainAxisSize: MainAxisSize.min, + children: [titleWidget, datePickerWidget]); } return datePickerWidget; } @@ -175,7 +186,8 @@ class _BrnDateWidgetState extends State { /// render the picker widget of year、month and day Widget _renderDatePickerWidget() { List pickers = List(); - List formatArr = DateTimeFormatter.splitDateFormat(widget.dateFormat); + List formatArr = + DateTimeFormatter.splitDateFormat(widget.dateFormat); formatArr.forEach((format) { List valueRange = _findPickerItemRange(format); @@ -195,7 +207,8 @@ class _BrnDateWidgetState extends State { ); pickers.add(pickerColumn); }); - return Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers); + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers); } Widget _renderDatePickerColumnComponent({ @@ -232,14 +245,17 @@ class _BrnDateWidgetState extends State { ColumnType columnType, int index, int value, String format) { TextStyle textStyle = widget.themeData.itemTextStyle.generateTextStyle(); if ((ColumnType.Year == columnType && index == _calcSelectIndexList()[0]) || - (ColumnType.Month == columnType && index == _calcSelectIndexList()[1]) || + (ColumnType.Month == columnType && + index == _calcSelectIndexList()[1]) || (ColumnType.Day == columnType && index == _calcSelectIndexList()[2])) { textStyle = widget.themeData.itemTextSelectedStyle.generateTextStyle(); } return Container( height: widget.themeData.itemHeight, alignment: Alignment.center, - child: Text(DateTimeFormatter.formatDateTime(value, format, widget.locale), style: textStyle), + child: Text( + DateTimeFormatter.formatDateTime(value, format, widget.locale), + style: textStyle), ); } @@ -281,15 +297,16 @@ class _BrnDateWidgetState extends State { _isChangeDateRange = true; List monthRange = _calcMonthRange(); - bool monthRangeChanged = - _monthRange.first != monthRange.first || _monthRange.last != monthRange.last; + bool monthRangeChanged = _monthRange.first != monthRange.first || + _monthRange.last != monthRange.last; if (monthRangeChanged) { // selected year changed _currMonth = max(min(_currMonth, monthRange.last), monthRange.first); } List dayRange = _calcDayRange(); - bool dayRangeChanged = _dayRange.first != dayRange.first || _dayRange.last != dayRange.last; + bool dayRangeChanged = + _dayRange.first != dayRange.first || _dayRange.last != dayRange.last; if (dayRangeChanged) { // day range changed, need limit the value of selected day _currDay = max(min(_currDay, dayRange.last), dayRange.first); diff --git a/lib/src/components/picker/time_picker/date_picker/brn_datetime_widget.dart b/lib/src/components/picker/time_picker/date_picker/brn_datetime_widget.dart index 9afb6ef9..34023ba7 100755 --- a/lib/src/components/picker/time_picker/date_picker/brn_datetime_widget.dart +++ b/lib/src/components/picker/time_picker/date_picker/brn_datetime_widget.dart @@ -49,8 +49,8 @@ class BrnDateTimeWidget extends StatefulWidget { BrnPickerConfig themeData; @override - State createState() => - _BrnDateTimeWidgetState(this.minDateTime, this.maxDateTime, this.initDateTime, minuteDivider); + State createState() => _BrnDateTimeWidgetState( + this.minDateTime, this.maxDateTime, this.initDateTime, minuteDivider); } class _BrnDateTimeWidgetState extends State { @@ -58,7 +58,12 @@ class _BrnDateTimeWidgetState extends State { DateTime _minTime, _maxTime; int _currYear, _currMonth, _currDay, _currHour, _currMinute, _currSecond; - List _yearRange, _monthRange, _dayRange, _hourRange, _minuteRange, _secondRange; + List _yearRange, + _monthRange, + _dayRange, + _hourRange, + _minuteRange, + _secondRange; FixedExtentScrollController _yearScrollCtrl, _monthScrollCtrl, _dayScrollCtrl, @@ -73,8 +78,8 @@ class _BrnDateTimeWidgetState extends State { int _minuteDivider; - _BrnDateTimeWidgetState( - DateTime minTime, DateTime maxTime, DateTime initTime, int minuteDivider) { + _BrnDateTimeWidgetState(DateTime minTime, DateTime maxTime, DateTime initTime, + int minuteDivider) { // check minTime value if (minTime == null) { minTime = DateTime.parse(DATE_PICKER_MIN_DATETIME); @@ -125,21 +130,28 @@ class _BrnDateTimeWidgetState extends State { this._currHour = min(max(_hourRange.first, _currHour), _hourRange.last); // limit the range of minute this._minuteRange = _calcMinuteRange(); - this._currMinute = min(max(_minuteRange.first, _currMinute), _minuteRange.last); + this._currMinute = + min(max(_minuteRange.first, _currMinute), _minuteRange.last); _currMinute -= _currMinute % _minuteDivider; // limit the range of second this._secondRange = _calcSecondRange(); - this._currSecond = min(max(_secondRange.first, _currSecond), _secondRange.last); + this._currSecond = + min(max(_secondRange.first, _currSecond), _secondRange.last); // create scroll controller - _yearScrollCtrl = FixedExtentScrollController(initialItem: _currYear - _yearRange.first); - _monthScrollCtrl = FixedExtentScrollController(initialItem: _currMonth - _monthRange.first); - _dayScrollCtrl = FixedExtentScrollController(initialItem: _currDay - _dayRange.first); - _hourScrollCtrl = FixedExtentScrollController(initialItem: _currHour - _hourRange.first); + _yearScrollCtrl = + FixedExtentScrollController(initialItem: _currYear - _yearRange.first); + _monthScrollCtrl = FixedExtentScrollController( + initialItem: _currMonth - _monthRange.first); + _dayScrollCtrl = + FixedExtentScrollController(initialItem: _currDay - _dayRange.first); + _hourScrollCtrl = + FixedExtentScrollController(initialItem: _currHour - _hourRange.first); _minuteScrollCtrl = FixedExtentScrollController( initialItem: (_currMinute - _minuteRange.first) ~/ _minuteDivider); - _secondScrollCtrl = FixedExtentScrollController(initialItem: _currSecond - _secondRange.first); + _secondScrollCtrl = FixedExtentScrollController( + initialItem: _currSecond - _secondRange.first); _scrollCtrlMap = { 'y': _yearScrollCtrl, @@ -162,7 +174,8 @@ class _BrnDateTimeWidgetState extends State { @override Widget build(BuildContext context) { return GestureDetector( - child: Material(color: Colors.transparent, child: _renderPickerView(context)), + child: Material( + color: Colors.transparent, child: _renderPickerView(context)), ); } @@ -171,7 +184,8 @@ class _BrnDateTimeWidgetState extends State { Widget pickerWidget = _renderDatePickerWidget(); // display the title widget - if (widget.pickerTitleConfig.title != null || widget.pickerTitleConfig.showTitle) { + if (widget.pickerTitleConfig.title != null || + widget.pickerTitleConfig.showTitle) { Widget titleWidget = BrnPickerTitle( pickerTitleConfig: widget.pickerTitleConfig, locale: widget.locale, @@ -194,24 +208,35 @@ class _BrnDateTimeWidgetState extends State { /// pressed confirm widget void _onPressedConfirm() { if (widget.onConfirm != null) { - List formatArr = DateTimeFormatter.splitDateFormat(widget.dateFormat); + List formatArr = + DateTimeFormatter.splitDateFormat(widget.dateFormat); /// 如果传入的时间格式不包含 月、天、小时、分钟、秒。则相对应的时间置为 1,1,0,0,0; DateTime dateTime = DateTime( _currYear, - (formatArr?.where((format) => format.contains('M'))?.toList() ?? List()).length > 0 + (formatArr?.where((format) => format.contains('M'))?.toList() ?? List()) + .length > + 0 ? _currMonth : 1, - (formatArr?.where((format) => format.contains('d'))?.toList() ?? List()).length > 0 + (formatArr?.where((format) => format.contains('d'))?.toList() ?? List()) + .length > + 0 ? _currDay : 1, - (formatArr?.where((format) => format.contains('H'))?.toList() ?? List()).length > 0 + (formatArr?.where((format) => format.contains('H'))?.toList() ?? List()) + .length > + 0 ? _currHour : 0, - (formatArr?.where((format) => format.contains('m'))?.toList() ?? List()).length > 0 + (formatArr?.where((format) => format.contains('m'))?.toList() ?? List()) + .length > + 0 ? _currMinute : 0, - (formatArr?.where((format) => format.contains('s'))?.toList() ?? List()).length > 0 + (formatArr?.where((format) => format.contains('s'))?.toList() ?? List()) + .length > + 0 ? _currSecond : 0, ); @@ -223,8 +248,8 @@ class _BrnDateTimeWidgetState extends State { /// notify selected datetime changed void _onSelectedChange() { if (widget.onChange != null) { - DateTime dateTime = - DateTime(_currYear, _currMonth, _currDay, _currHour, _currMinute, _currSecond); + DateTime dateTime = DateTime( + _currYear, _currMonth, _currDay, _currHour, _currMinute, _currSecond); widget.onChange(dateTime, _calcSelectIndexList()); } } @@ -254,7 +279,8 @@ class _BrnDateTimeWidgetState extends State { /// render the picker widget of year、month and day Widget _renderDatePickerWidget() { List pickers = List(); - List formatArr = DateTimeFormatter.splitDateFormat(widget.dateFormat); + List formatArr = + DateTimeFormatter.splitDateFormat(widget.dateFormat); // render time picker column formatArr.forEach((format) { @@ -283,7 +309,8 @@ class _BrnDateTimeWidgetState extends State { ); pickers.add(pickerColumn); }); - return Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers); + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers); } Widget _renderDatePickerColumnComponent( @@ -313,7 +340,8 @@ class _BrnDateTimeWidgetState extends State { if (format.contains('m')) { value = valueRange.first + _minuteDivider * index; } - return _renderDatePickerItemComponent(getColumnType(format), index, value, format); + return _renderDatePickerItemComponent( + getColumnType(format), index, value, format); }, ), ); @@ -391,15 +419,16 @@ class _BrnDateTimeWidgetState extends State { _isChangeTimeRange = true; List monthRange = _calcMonthRange(); - bool monthRangeChanged = - _monthRange.first != monthRange.first || _monthRange.last != monthRange.last; + bool monthRangeChanged = _monthRange.first != monthRange.first || + _monthRange.last != monthRange.last; if (monthRangeChanged) { // selected year changed _currMonth = max(min(_currMonth, monthRange.last), monthRange.first); } List dayRange = _calcDayRange(); - bool dayRangeChanged = _dayRange.first != dayRange.first || _dayRange.last != dayRange.last; + bool dayRangeChanged = + _dayRange.first != dayRange.first || _dayRange.last != dayRange.last; if (dayRangeChanged) { // day range changed, need limit the value of selected day _currDay = max(min(_currDay, dayRange.last), dayRange.first); @@ -437,18 +466,23 @@ class _BrnDateTimeWidgetState extends State { ColumnType columnType, int index, int value, String format) { TextStyle textStyle = widget.themeData.itemTextStyle.generateTextStyle(); if ((ColumnType.Year == columnType && index == _calcSelectIndexList()[0]) || - (ColumnType.Month == columnType && index == _calcSelectIndexList()[1]) || + (ColumnType.Month == columnType && + index == _calcSelectIndexList()[1]) || (ColumnType.Day == columnType && index == _calcSelectIndexList()[2]) || (ColumnType.Hour == columnType && index == _calcSelectIndexList()[3]) || - (ColumnType.Minute == columnType && index == _calcSelectIndexList()[4]) || - (ColumnType.Second == columnType && index == _calcSelectIndexList()[5])) { + (ColumnType.Minute == columnType && + index == _calcSelectIndexList()[4]) || + (ColumnType.Second == columnType && + index == _calcSelectIndexList()[5])) { textStyle = widget.themeData.itemTextSelectedStyle.generateTextStyle(); } return Container( height: widget.themeData.itemHeight, alignment: Alignment.center, - child: Text(DateTimeFormatter.formatDateTime(value, format, widget.locale), style: textStyle), + child: Text( + DateTimeFormatter.formatDateTime(value, format, widget.locale), + style: textStyle), ); } @@ -496,24 +530,24 @@ class _BrnDateTimeWidgetState extends State { _isChangeTimeRange = true; List hourRange = _calcHourRange(); - bool hourRangeChanged = - _hourRange.first != hourRange.first || _hourRange.last != hourRange.last; + bool hourRangeChanged = _hourRange.first != hourRange.first || + _hourRange.last != hourRange.last; if (hourRangeChanged) { // selected day changed _currHour = max(min(_currHour, hourRange.last), hourRange.first); } List minuteRange = _calcMinuteRange(); - bool minuteRangeChanged = - _minuteRange.first != minuteRange.first || _minuteRange.last != minuteRange.last; + bool minuteRangeChanged = _minuteRange.first != minuteRange.first || + _minuteRange.last != minuteRange.last; if (minuteRangeChanged) { // selected hour changed _currMinute = max(min(_currMinute, minuteRange.last), minuteRange.first); } List secondRange = _calcSecondRange(); - bool secondRangeChanged = - _secondRange.first != secondRange.first || _secondRange.last != secondRange.last; + bool secondRangeChanged = _secondRange.first != secondRange.first || + _secondRange.last != secondRange.last; if (secondRangeChanged) { // second range changed, need limit the value of selected second _currSecond = max(min(_currSecond, secondRange.last), secondRange.first); @@ -539,9 +573,11 @@ class _BrnDateTimeWidgetState extends State { if (minuteRangeChanged) { // CupertinoPicker refresh data not working (https://github.com/flutter/flutter/issues/22999) - _minuteScrollCtrl.jumpToItem((minuteRange.last - minuteRange.first) ~/ _minuteDivider); + _minuteScrollCtrl + .jumpToItem((minuteRange.last - minuteRange.first) ~/ _minuteDivider); if (_currMinute < minuteRange.last) { - _minuteScrollCtrl.jumpToItem((_currMinute - minuteRange.first) ~/ _minuteDivider); + _minuteScrollCtrl + .jumpToItem((_currMinute - minuteRange.first) ~/ _minuteDivider); } } @@ -564,7 +600,14 @@ class _BrnDateTimeWidgetState extends State { int hourIndex = _currHour - _hourRange.first; int minuteIndex = (_currMinute - _minuteRange.first) ~/ _minuteDivider; int secondIndex = _currSecond - _secondRange.first; - return [yearIndex, monthIndex, dayIndex, hourIndex, minuteIndex, secondIndex]; + return [ + yearIndex, + monthIndex, + dayIndex, + hourIndex, + minuteIndex, + secondIndex + ]; } /// calculate the range of year @@ -589,7 +632,15 @@ class _BrnDateTimeWidgetState extends State { } /// Solar months of 31 days. - static const List _solarMonthsOf31Days = const [1, 3, 5, 7, 8, 10, 12]; + static const List _solarMonthsOf31Days = const [ + 1, + 3, + 5, + 7, + 8, + 10, + 12 + ]; /// whether or not is leap year bool isLeapYear(int year) { @@ -630,17 +681,23 @@ class _BrnDateTimeWidgetState extends State { /// calculate the range of hour List _calcHourRange() { int minHour = 0, maxHour = 23; - if (_currYear == _minTime.year && _currMonth == _minTime.month && _currDay == _minTime.day) { + if (_currYear == _minTime.year && + _currMonth == _minTime.month && + _currDay == _minTime.day) { minHour = _minTime.hour; } int modValue = _minTime.minute % _minuteDivider; - int minMinute = modValue == 0 ? _minTime.minute : (_minTime.minute - modValue + _minuteDivider); + int minMinute = modValue == 0 + ? _minTime.minute + : (_minTime.minute - modValue + _minuteDivider); if (minMinute == 60) { minHour = minHour + 1 > _maxTime.hour ? _maxTime.hour : minHour + 1; } - if (_currYear == _maxTime.year && _currMonth == _maxTime.month && _currDay == _maxTime.day) { + if (_currYear == _maxTime.year && + _currMonth == _maxTime.month && + _currDay == _maxTime.day) { maxHour = _maxTime.hour; } return [minHour, maxHour]; @@ -659,7 +716,9 @@ class _BrnDateTimeWidgetState extends State { _currHour == _minTime.hour) { // selected minimum day、hour, limit minute range int modValue = _minTime.minute % _minuteDivider; - minMinute = modValue == 0 ? _minTime.minute : (_minTime.minute - modValue + _minuteDivider); + minMinute = modValue == 0 + ? _minTime.minute + : (_minTime.minute - modValue + _minuteDivider); if (minMinute == 60) { minMinute = 0; currHour = currHour + 1 > _maxTime.hour ? _maxTime.hour : currHour + 1; diff --git a/lib/src/components/picker/time_picker/date_picker/brn_time_widget.dart b/lib/src/components/picker/time_picker/date_picker/brn_time_widget.dart index 61aa189b..d6dd6255 100755 --- a/lib/src/components/picker/time_picker/date_picker/brn_time_widget.dart +++ b/lib/src/components/picker/time_picker/date_picker/brn_time_widget.dart @@ -50,8 +50,8 @@ class BrnTimeWidget extends StatefulWidget { BrnPickerConfig themeData; @override - State createState() => _BrnTimeWidgetState( - this.minDateTime, this.maxDateTime, this.initDateTime, this.minuteDivider); + State createState() => _BrnTimeWidgetState(this.minDateTime, + this.maxDateTime, this.initDateTime, this.minuteDivider); } class _BrnTimeWidgetState extends State { @@ -61,14 +61,17 @@ class _BrnTimeWidgetState extends State { int _currHour, _currMinute, _currSecond; int _minuteDivider; List _hourRange, _minuteRange, _secondRange; - FixedExtentScrollController _hourScrollCtrl, _minuteScrollCtrl, _secondScrollCtrl; + FixedExtentScrollController _hourScrollCtrl, + _minuteScrollCtrl, + _secondScrollCtrl; Map _scrollCtrlMap; Map> _valueRangeMap; bool _isChangeTimeRange = false; - _BrnTimeWidgetState(DateTime minTime, DateTime maxTime, DateTime initTime, int minuteDivider) { + _BrnTimeWidgetState(DateTime minTime, DateTime maxTime, DateTime initTime, + int minuteDivider) { if (minTime == null) { minTime = DateTime.parse(DATE_PICKER_MIN_DATETIME); } @@ -97,26 +100,35 @@ class _BrnTimeWidgetState extends State { // limit the range of minute this._minuteRange = _calcMinuteRange(); - this._currMinute = min(max(_minuteRange.first, _currMinute), _minuteRange.last); + this._currMinute = + min(max(_minuteRange.first, _currMinute), _minuteRange.last); _currMinute -= _currMinute % _minuteDivider; // limit the range of second this._secondRange = _calcSecondRange(); - this._currSecond = min(max(_secondRange.first, _currSecond), _secondRange.last); + this._currSecond = + min(max(_secondRange.first, _currSecond), _secondRange.last); // create scroll controller - _hourScrollCtrl = FixedExtentScrollController(initialItem: _currHour - _hourRange.first); + _hourScrollCtrl = + FixedExtentScrollController(initialItem: _currHour - _hourRange.first); _minuteScrollCtrl = FixedExtentScrollController( initialItem: (_currMinute - _minuteRange.first) ~/ _minuteDivider); - _secondScrollCtrl = FixedExtentScrollController(initialItem: _currSecond - _secondRange.first); - - _scrollCtrlMap = {'H': _hourScrollCtrl, 'm': _minuteScrollCtrl, 's': _secondScrollCtrl}; + _secondScrollCtrl = FixedExtentScrollController( + initialItem: _currSecond - _secondRange.first); + + _scrollCtrlMap = { + 'H': _hourScrollCtrl, + 'm': _minuteScrollCtrl, + 's': _secondScrollCtrl + }; _valueRangeMap = {'H': _hourRange, 'm': _minuteRange, 's': _secondRange}; } @override Widget build(BuildContext context) { return GestureDetector( - child: Material(color: Colors.transparent, child: _renderPickerView(context)), + child: Material( + color: Colors.transparent, child: _renderPickerView(context)), ); } @@ -125,7 +137,8 @@ class _BrnTimeWidgetState extends State { Widget pickerWidget = _renderDatePickerWidget(); // display the title widget - if (widget.pickerTitleConfig.title != null || widget.pickerTitleConfig.showTitle) { + if (widget.pickerTitleConfig.title != null || + widget.pickerTitleConfig.showTitle) { Widget titleWidget = BrnPickerTitle( pickerTitleConfig: widget.pickerTitleConfig, locale: widget.locale, @@ -149,8 +162,8 @@ class _BrnTimeWidgetState extends State { void _onPressedConfirm() { if (widget.onConfirm != null) { DateTime now = DateTime.now(); - DateTime dateTime = - DateTime(now.year, now.month, now.day, _currHour, _currMinute, _currSecond); + DateTime dateTime = DateTime( + now.year, now.month, now.day, _currHour, _currMinute, _currSecond); widget.onConfirm(dateTime, _calcSelectIndexList()); } Navigator.pop(context); @@ -160,8 +173,8 @@ class _BrnTimeWidgetState extends State { void _onSelectedChange() { if (widget.onChange != null) { DateTime now = DateTime.now(); - DateTime dateTime = - DateTime(now.year, now.month, now.day, _currHour, _currMinute, _currSecond); + DateTime dateTime = DateTime( + now.year, now.month, now.day, _currHour, _currMinute, _currSecond); widget.onChange(dateTime, _calcSelectIndexList()); } } @@ -191,7 +204,8 @@ class _BrnTimeWidgetState extends State { /// render the picker widget of year、month and day Widget _renderDatePickerWidget() { List pickers = List(); - List formatArr = DateTimeFormatter.splitDateFormat(widget.dateFormat); + List formatArr = + DateTimeFormatter.splitDateFormat(widget.dateFormat); formatArr.forEach((format) { List valueRange = _findPickerItemRange(format); @@ -211,7 +225,8 @@ class _BrnTimeWidgetState extends State { ); pickers.add(pickerColumn); }); - return Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers); + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers); } Widget _renderDatePickerColumnComponent({ @@ -241,7 +256,8 @@ class _BrnTimeWidgetState extends State { value = _minuteDivider * index; } - return _renderDatePickerItemComponent(getColumnType(format), index, value, format); + return _renderDatePickerItemComponent( + getColumnType(format), index, value, format); }, ), ), @@ -273,14 +289,18 @@ class _BrnTimeWidgetState extends State { ColumnType columnType, int index, int value, String format) { TextStyle textStyle = widget.themeData.itemTextStyle.generateTextStyle(); if ((ColumnType.Hour == columnType && index == _calcSelectIndexList()[0]) || - (ColumnType.Minute == columnType && index == _calcSelectIndexList()[1]) || - (ColumnType.Second == columnType && index == _calcSelectIndexList()[2])) { + (ColumnType.Minute == columnType && + index == _calcSelectIndexList()[1]) || + (ColumnType.Second == columnType && + index == _calcSelectIndexList()[2])) { textStyle = widget.themeData.itemTextSelectedStyle.generateTextStyle(); } return Container( height: widget.themeData.itemHeight, alignment: Alignment.center, - child: Text(DateTimeFormatter.formatDateTime(value, format, widget.locale), style: textStyle), + child: Text( + DateTimeFormatter.formatDateTime(value, format, widget.locale), + style: textStyle), ); } @@ -322,8 +342,8 @@ class _BrnTimeWidgetState extends State { _isChangeTimeRange = true; List minuteRange = _calcMinuteRange(); - bool minuteRangeChanged = - _minuteRange.first != minuteRange.first || _minuteRange.last != minuteRange.last; + bool minuteRangeChanged = _minuteRange.first != minuteRange.first || + _minuteRange.last != minuteRange.last; if (minuteRangeChanged) { // selected hour changed _currMinute = max(min(_currMinute, minuteRange.last), minuteRange.first); @@ -331,8 +351,8 @@ class _BrnTimeWidgetState extends State { } List secondRange = _calcSecondRange(); - bool secondRangeChanged = - _secondRange.first != secondRange.first || _secondRange.last != secondRange.last; + bool secondRangeChanged = _secondRange.first != secondRange.first || + _secondRange.last != secondRange.last; if (secondRangeChanged) { // second range changed, need limit the value of selected second _currSecond = max(min(_currSecond, secondRange.last), secondRange.first); @@ -349,7 +369,8 @@ class _BrnTimeWidgetState extends State { if (minuteRangeChanged) { // CupertinoPicker refresh data not working (https://github.com/flutter/flutter/issues/22999) int currMinute = _currMinute; - _minuteScrollCtrl.jumpToItem((minuteRange.last - minuteRange.first) ~/ _minuteDivider); + _minuteScrollCtrl + .jumpToItem((minuteRange.last - minuteRange.first) ~/ _minuteDivider); if (currMinute < minuteRange.last) { _minuteScrollCtrl.jumpToItem(currMinute - minuteRange.first); } diff --git a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_picker.dart b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_picker.dart index df2dccf4..9ad2b890 100755 --- a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_picker.dart +++ b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_picker.dart @@ -67,7 +67,8 @@ class BrnDateRangePicker { } // Set value of date format - dateFormat = DateTimeFormatter.generateDateRangePickerFormat(dateFormat, pickerMode); + dateFormat = + DateTimeFormatter.generateDateRangePickerFormat(dateFormat, pickerMode); Navigator.push( context, @@ -86,7 +87,8 @@ class BrnDateRangePicker { onChange: onChange, onConfirm: onConfirm, isDismissible: isDismissible, - barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, + barrierLabel: + MaterialLocalizations.of(context).modalBarrierDismissLabel, themeData: themeData, ), ).whenComplete(onClose); @@ -94,7 +96,10 @@ class BrnDateRangePicker { } class _DatePickerRoute extends PopupRoute { - final DateTime minDateTime, maxDateTime, initialStartDateTime, initialEndDateTime; + final DateTime minDateTime, + maxDateTime, + initialStartDateTime, + initialEndDateTime; final bool isLimitTimeRange; final String dateFormat; final DateTimePickerLocale locale; @@ -152,13 +157,14 @@ class _DatePickerRoute extends PopupRoute { @override AnimationController createAnimationController() { assert(_animationController == null); - _animationController = BottomSheet.createAnimationController(navigator.overlay); + _animationController = + BottomSheet.createAnimationController(navigator.overlay); return _animationController; } @override - Widget buildPage( - BuildContext context, Animation animation, Animation secondaryAnimation) { + Widget buildPage(BuildContext context, Animation animation, + Animation secondaryAnimation) { double height = themeData.pickerHeight; if (pickerTitleConfig.title != null || pickerTitleConfig.showTitle) { height += themeData.titleHeight; @@ -230,7 +236,8 @@ class _DatePickerComponent extends StatelessWidget { builder: (BuildContext context, Widget child) { return ClipRect( child: CustomSingleChildLayout( - delegate: _BottomPickerLayout(route.animation.value, contentHeight: _pickerHeight), + delegate: _BottomPickerLayout(route.animation.value, + contentHeight: _pickerHeight), child: BrnPickerClipRRect( borderRadius: BorderRadius.only( topLeft: Radius.circular(route.themeData.cornerRadius), diff --git a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_side_widget.dart b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_side_widget.dart index dc3b1565..d6eb8871 100755 --- a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_side_widget.dart +++ b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_side_widget.dart @@ -59,7 +59,10 @@ class BrnDateRangeSideWidget extends StatefulWidget { @override State createState() => _DatePickerWidgetState( - this.minDateTime, this.maxDateTime, this.initialStartDateTime, this.onInitSelectChange); + this.minDateTime, + this.maxDateTime, + this.initialStartDateTime, + this.onInitSelectChange); } class _DatePickerWidgetState extends State { @@ -77,13 +80,14 @@ class _DatePickerWidgetState extends State { DateRangeSideValueCallback _onInitSelectChange; - _DatePickerWidgetState(DateTime minDateTime, DateTime maxDateTime, DateTime initialDateTime, - DateRangeSideValueCallback onInitSelectChange) { + _DatePickerWidgetState(DateTime minDateTime, DateTime maxDateTime, + DateTime initialDateTime, DateRangeSideValueCallback onInitSelectChange) { _onInitSelectChange = onInitSelectChange; _initData(initialDateTime, minDateTime, maxDateTime); } - void _initData(DateTime initialDateTime, DateTime minDateTime, DateTime maxDateTime) { + void _initData( + DateTime initialDateTime, DateTime minDateTime, DateTime maxDateTime) { DateTime initDateTime = initialDateTime ?? DateTime.now(); this._currYear = initDateTime.year; this._currMonth = initDateTime.month; @@ -106,18 +110,28 @@ class _DatePickerWidgetState extends State { this._currDay = min(max(_dayRange.first, _currDay), _dayRange.last); _onInitSelectedChange(); // create scroll controller - _yearScrollCtrl = FixedExtentScrollController(initialItem: _currYear - _yearRange.first); - _monthScrollCtrl = FixedExtentScrollController(initialItem: _currMonth - _monthRange.first); - _dayScrollCtrl = FixedExtentScrollController(initialItem: _currDay - _dayRange.first); - _scrollCtrlMap = {'y': _yearScrollCtrl, 'M': _monthScrollCtrl, 'd': _dayScrollCtrl}; + _yearScrollCtrl = + FixedExtentScrollController(initialItem: _currYear - _yearRange.first); + _monthScrollCtrl = FixedExtentScrollController( + initialItem: _currMonth - _monthRange.first); + _dayScrollCtrl = + FixedExtentScrollController(initialItem: _currDay - _dayRange.first); + _scrollCtrlMap = { + 'y': _yearScrollCtrl, + 'M': _monthScrollCtrl, + 'd': _dayScrollCtrl + }; _valueRangeMap = {'y': _yearRange, 'M': _monthRange, 'd': _dayRange}; } @override Widget build(BuildContext context) { - _initData(widget.initialStartDateTime, widget.minDateTime, widget.maxDateTime); + _initData( + widget.initialStartDateTime, widget.minDateTime, widget.maxDateTime); return GestureDetector( - child: Container(color: widget.themeData.backgroundColor, child: _renderDatePickerWidget()), + child: Container( + color: widget.themeData.backgroundColor, + child: _renderDatePickerWidget()), ); } @@ -162,7 +176,8 @@ class _DatePickerWidgetState extends State { /// render the picker widget of year、month and day Widget _renderDatePickerWidget() { List pickers = List(); - List formatArr = DateTimeFormatter.splitDateFormat(widget.dateFormat); + List formatArr = + DateTimeFormatter.splitDateFormat(widget.dateFormat); formatArr.forEach((format) { List valueRange = _findPickerItemRange(format); @@ -182,7 +197,8 @@ class _DatePickerWidgetState extends State { ); pickers.add(pickerColumn); }); - return Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers); + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers); } Widget _renderDatePickerColumnComponent({ @@ -230,7 +246,8 @@ class _DatePickerWidgetState extends State { ColumnType columnType, int index, int value, String format) { TextStyle textStyle = widget.themeData.itemTextStyle.generateTextStyle(); if ((ColumnType.Year == columnType && index == _calcSelectIndexList()[0]) || - (ColumnType.Month == columnType && index == _calcSelectIndexList()[1]) || + (ColumnType.Month == columnType && + index == _calcSelectIndexList()[1]) || (ColumnType.Day == columnType && index == _calcSelectIndexList()[2])) { textStyle = widget.themeData.itemTextSelectedStyle.generateTextStyle(); } @@ -275,15 +292,16 @@ class _DatePickerWidgetState extends State { _isChangeDateRange = true; List monthRange = _calcMonthRange(); - bool monthRangeChanged = - _monthRange.first != monthRange.first || _monthRange.last != monthRange.last; + bool monthRangeChanged = _monthRange.first != monthRange.first || + _monthRange.last != monthRange.last; if (monthRangeChanged) { // selected year changed _currMonth = max(min(_currMonth, monthRange.last), monthRange.first); } List dayRange = _calcDayRange(); - bool dayRangeChanged = _dayRange.first != dayRange.first || _dayRange.last != dayRange.last; + bool dayRangeChanged = + _dayRange.first != dayRange.first || _dayRange.last != dayRange.last; if (dayRangeChanged) { // day range changed, need limit the value of selected day _currDay = max(min(_currDay, dayRange.last), dayRange.first); diff --git a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_widget.dart b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_widget.dart index 6a0c910f..cacab725 100755 --- a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_widget.dart +++ b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_widget.dart @@ -72,7 +72,10 @@ class BrnDateRangeWidget extends StatefulWidget { @override State createState() => _DatePickerWidgetState( - this.minDateTime, this.maxDateTime, this.initialStartDateTime, this.initialEndDateTime); + this.minDateTime, + this.maxDateTime, + this.initialStartDateTime, + this.initialEndDateTime); } class _DatePickerWidgetState extends State { @@ -89,14 +92,15 @@ class _DatePickerWidgetState extends State { bool _isFirstScroll = false; bool _isSecondScroll = false; - _DatePickerWidgetState(DateTime minDateTime, DateTime maxDateTime, DateTime initialStartDateTime, - DateTime initialEndDateTime) { + _DatePickerWidgetState(DateTime minDateTime, DateTime maxDateTime, + DateTime initialStartDateTime, DateTime initialEndDateTime) { // handle current selected year、month、day - _initData(initialStartDateTime, initialEndDateTime, minDateTime, maxDateTime); + _initData( + initialStartDateTime, initialEndDateTime, minDateTime, maxDateTime); } - void _initData(DateTime initialStartDateTime, DateTime initialEndDateTime, DateTime minDateTime, - DateTime maxDateTime) { + void _initData(DateTime initialStartDateTime, DateTime initialEndDateTime, + DateTime minDateTime, DateTime maxDateTime) { DateTime initStartDateTime = initialStartDateTime ?? DateTime.now(); DateTime initEndDateTime = initialEndDateTime ?? DateTime.now(); @@ -113,21 +117,25 @@ class _DatePickerWidgetState extends State { this._maxDateTime = maxDateTime ?? DateTime.parse(DATE_PICKER_MAX_DATETIME); // limit the range of year - this._currStartYear = min(max(_minDateTime.year, _currStartYear), _maxDateTime.year); + this._currStartYear = + min(max(_minDateTime.year, _currStartYear), _maxDateTime.year); this._currEndYear = min(_maxDateTime.year, _currEndYear); // limit the range of month this._monthRange = _calcMonthRange(); - this._currStartMonth = min(max(_monthRange.first, _currStartMonth), _monthRange.last); + this._currStartMonth = + min(max(_monthRange.first, _currStartMonth), _monthRange.last); this._currEndMonth = min(_monthRange.last, _currEndMonth); // limit the range of day this._startDayRange = _calcDayRange(currMonth: _currStartMonth); - this._currStartDay = min(max(_startDayRange.first, _currStartDay), _startDayRange.last); + this._currStartDay = + min(max(_startDayRange.first, _currStartDay), _startDayRange.last); this._endDayRange = _calcDayRange(currMonth: _currEndMonth); this._currEndDay = min(_endDayRange.last, _currEndDay); - _startSelectedDateTime = DateTime(_currStartYear, _currStartMonth, _currStartDay); + _startSelectedDateTime = + DateTime(_currStartYear, _currStartMonth, _currStartDay); _endSelectedDateTime = DateTime(_currEndYear, _currEndMonth, _currEndDay); _startSelectedIndex = _calcSelectIndexList(true); _endSelectedIndex = _calcSelectIndexList(false); @@ -135,9 +143,11 @@ class _DatePickerWidgetState extends State { @override Widget build(BuildContext context) { - _initData(_startSelectedDateTime, _endSelectedDateTime, _minDateTime, _maxDateTime); + _initData(_startSelectedDateTime, _endSelectedDateTime, _minDateTime, + _maxDateTime); return GestureDetector( - child: Material(color: Colors.transparent, child: _renderPickerView(context)), + child: Material( + color: Colors.transparent, child: _renderPickerView(context)), ); } @@ -146,7 +156,8 @@ class _DatePickerWidgetState extends State { Widget datePickerWidget = _renderDatePickerWidget(); // display the title widget - if (widget.pickerTitleConfig.title != null || widget.pickerTitleConfig.showTitle) { + if (widget.pickerTitleConfig.title != null || + widget.pickerTitleConfig.showTitle) { Widget titleWidget = BrnPickerTitle( pickerTitleConfig: widget.pickerTitleConfig, locale: widget.locale, @@ -169,8 +180,8 @@ class _DatePickerWidgetState extends State { /// pressed confirm widget void _onPressedConfirm() { if (widget.onConfirm != null) { - widget.onConfirm( - _startSelectedDateTime, _endSelectedDateTime, _startSelectedIndex, _endSelectedIndex); + widget.onConfirm(_startSelectedDateTime, _endSelectedDateTime, + _startSelectedIndex, _endSelectedIndex); } Navigator.pop(context); } @@ -202,7 +213,8 @@ class _DatePickerWidgetState extends State { minDateTime: widget.minDateTime, maxDateTime: widget.maxDateTime, initialStartDateTime: _startSelectedDateTime, - onInitSelectChange: (DateTime selectedDateTime, List selected) { + onInitSelectChange: + (DateTime selectedDateTime, List selected) { _startSelectedDateTime = selectedDateTime; _startSelectedIndex = selected; }, @@ -225,10 +237,12 @@ class _DatePickerWidgetState extends State { dateFormat: widget.dateFormat, minDateTime: _startSelectedDateTime, maxDateTime: widget.maxDateTime, - initialStartDateTime: _endSelectedDateTime.compareTo(_startSelectedDateTime) > 0 - ? _endSelectedDateTime - : _startSelectedDateTime, - onInitSelectChange: (DateTime selectedDateTime, List selectedIndex) { + initialStartDateTime: + _endSelectedDateTime.compareTo(_startSelectedDateTime) > 0 + ? _endSelectedDateTime + : _startSelectedDateTime, + onInitSelectChange: + (DateTime selectedDateTime, List selectedIndex) { _endSelectedDateTime = selectedDateTime; _endSelectedIndex = selectedIndex; }, @@ -240,7 +254,8 @@ class _DatePickerWidgetState extends State { }); }, )))); - return Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers); + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers); } Widget _renderDatePickerMiddleColumnComponent() { diff --git a/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_side_widget.dart b/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_side_widget.dart index 854c36bd..47421443 100755 --- a/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_side_widget.dart +++ b/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_side_widget.dart @@ -55,8 +55,12 @@ class BrnTimeRangeSideWidget extends StatefulWidget { } @override - State createState() => _TimePickerWidgetState(this.minDateTime, this.maxDateTime, - this.initialStartDateTime, this.minuteDivider, this.onInitSelectChange); + State createState() => _TimePickerWidgetState( + this.minDateTime, + this.maxDateTime, + this.initialStartDateTime, + this.minuteDivider, + this.onInitSelectChange); } class _TimePickerWidgetState extends State { @@ -77,13 +81,18 @@ class _TimePickerWidgetState extends State { DateRangeSideValueCallback _onInitSelectChange; - _TimePickerWidgetState(DateTime minTime, DateTime maxTime, DateTime initStartTime, - int minuteDivider, DateRangeSideValueCallback onInitSelectChange) { + _TimePickerWidgetState( + DateTime minTime, + DateTime maxTime, + DateTime initStartTime, + int minuteDivider, + DateRangeSideValueCallback onInitSelectChange) { _onInitSelectChange = onInitSelectChange; _initData(minTime, maxTime, initStartTime, minuteDivider); } - void _initData(DateTime minTime, DateTime maxTime, DateTime initStartTime, int minuteDivider) { + void _initData(DateTime minTime, DateTime maxTime, DateTime initStartTime, + int minuteDivider) { if (minTime == null) { minTime = DateTime.parse(DATE_PICKER_MIN_DATETIME); } @@ -110,16 +119,18 @@ class _TimePickerWidgetState extends State { if (_currStartHour == null || _currStartMinute == null) { this._currStartHour = initStartTime.hour; - this._currStartHour = min(max(_hourRange.first, _currStartHour), _hourRange.last); + this._currStartHour = + min(max(_hourRange.first, _currStartHour), _hourRange.last); this._currStartMinute = initStartTime.minute; - this._currStartMinute = min(max(_minuteRange.first, _currStartMinute), _minuteRange.last); + this._currStartMinute = + min(max(_minuteRange.first, _currStartMinute), _minuteRange.last); _currStartMinute -= _currStartMinute % _minuteDivider; } _onInitSelectedChange(); // create scroll controller - _startHourScrollCtrl = - FixedExtentScrollController(initialItem: _currStartHour - _hourRange.first); + _startHourScrollCtrl = FixedExtentScrollController( + initialItem: _currStartHour - _hourRange.first); _startMinuteScrollCtrl = FixedExtentScrollController( initialItem: (_currStartMinute - _minuteRange.first) ~/ _minuteDivider); _startScrollCtrlMap = { @@ -134,7 +145,9 @@ class _TimePickerWidgetState extends State { Widget build(BuildContext context) { _initData(_minTime, _maxTime, widget.initialStartDateTime, _minuteDivider); return GestureDetector( - child: Container(color: widget.themeData.backgroundColor, child: _renderPickerView(context)), + child: Container( + color: widget.themeData.backgroundColor, + child: _renderPickerView(context)), ); } @@ -147,8 +160,8 @@ class _TimePickerWidgetState extends State { void _onInitSelectedChange() { if (_onInitSelectChange != null) { DateTime now = DateTime.now(); - DateTime startDateTime = - DateTime(now.year, now.month, now.day, _currStartHour, _currStartMinute); + DateTime startDateTime = DateTime( + now.year, now.month, now.day, _currStartHour, _currStartMinute); _onInitSelectChange(startDateTime, _calcStartSelectIndexList()); } } @@ -157,8 +170,8 @@ class _TimePickerWidgetState extends State { void _onSelectedChange() { if (widget.onChange != null) { DateTime now = DateTime.now(); - DateTime startDateTime = - DateTime(now.year, now.month, now.day, _currStartHour, _currStartMinute); + DateTime startDateTime = DateTime( + now.year, now.month, now.day, _currStartHour, _currStartMinute); widget.onChange(startDateTime, _calcStartSelectIndexList()); } } @@ -188,7 +201,8 @@ class _TimePickerWidgetState extends State { /// render the picker widget of year、month and day Widget _renderDatePickerWidget() { List pickers = List(); - List formatArr = DateTimeFormatter.splitDateFormat(widget.dateFormat); + List formatArr = + DateTimeFormatter.splitDateFormat(widget.dateFormat); formatArr.forEach((format) { List valueRange = _findPickerItemRange(format); @@ -206,7 +220,8 @@ class _TimePickerWidgetState extends State { ); pickers.add(pickerColumn); }); - return Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers); + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers); } Widget _renderDatePickerColumnComponent({ @@ -247,7 +262,8 @@ class _TimePickerWidgetState extends State { if (format.contains('m')) { value = valueRange.first + _minuteDivider * index; } - return _renderDatePickerItemComponent(index, format.contains('m'), value, format); + return _renderDatePickerItemComponent( + index, format.contains('m'), value, format); }, ), ), @@ -263,7 +279,8 @@ class _TimePickerWidgetState extends State { return ((valueRange.last - valueRange.first) ~/ divider) + 1; } - Widget _renderDatePickerItemComponent(int index, bool isMinuteColumn, int value, String format) { + Widget _renderDatePickerItemComponent( + int index, bool isMinuteColumn, int value, String format) { TextStyle textStyle = widget.themeData.itemTextStyle.generateTextStyle(); if ((!isMinuteColumn && (index == _calcStartSelectIndexList()[0])) || ((isMinuteColumn && (index == _calcStartSelectIndexList()[1])))) { @@ -302,11 +319,12 @@ class _TimePickerWidgetState extends State { _isChangeTimeRange = true; List minuteRange = _calcMinuteRange(); - bool minuteRangeChanged = - _minuteRange.first != minuteRange.first || _minuteRange.last != minuteRange.last; + bool minuteRangeChanged = _minuteRange.first != minuteRange.first || + _minuteRange.last != minuteRange.last; if (minuteRangeChanged) { // selected hour changed - _currStartMinute = max(min(_currStartMinute, minuteRange.last), minuteRange.first); + _currStartMinute = + max(min(_currStartMinute, minuteRange.last), minuteRange.first); } setState(() { @@ -317,9 +335,11 @@ class _TimePickerWidgetState extends State { if (minuteRangeChanged) { // CupertinoPicker refresh data not working (https://github.com/flutter/flutter/issues/22999) int currMinute = _currStartMinute; - _startMinuteScrollCtrl.jumpToItem((minuteRange.last - minuteRange.first) ~/ _minuteDivider); + _startMinuteScrollCtrl + .jumpToItem((minuteRange.last - minuteRange.first) ~/ _minuteDivider); if (currMinute < minuteRange.last) { - _startMinuteScrollCtrl.jumpToItem((currMinute - minuteRange.first) ~/ _minuteDivider); + _startMinuteScrollCtrl + .jumpToItem((currMinute - minuteRange.first) ~/ _minuteDivider); } } diff --git a/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_widget.dart b/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_widget.dart index 29d4839a..0b521810 100755 --- a/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_widget.dart +++ b/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_widget.dart @@ -80,8 +80,12 @@ class BrnTimeRangeWidget extends StatefulWidget { } @override - State createState() => _TimePickerWidgetState(this.minDateTime, this.maxDateTime, - this.initialStartDateTime, this.initialEndDateTime, this.minuteDivider); + State createState() => _TimePickerWidgetState( + this.minDateTime, + this.maxDateTime, + this.initialStartDateTime, + this.initialEndDateTime, + this.minuteDivider); } class _TimePickerWidgetState extends State { @@ -97,13 +101,13 @@ class _TimePickerWidgetState extends State { DateTime _startSelectedDateTime; DateTime _endSelectedDateTime; - _TimePickerWidgetState(DateTime minTime, DateTime maxTime, DateTime initStartTime, - DateTime initEndTime, int minuteDivider) { + _TimePickerWidgetState(DateTime minTime, DateTime maxTime, + DateTime initStartTime, DateTime initEndTime, int minuteDivider) { _initData(minTime, maxTime, initStartTime, initEndTime, minuteDivider); } - void _initData(DateTime minTime, DateTime maxTime, DateTime initStartTime, DateTime initEndTime, - int minuteDivider) { + void _initData(DateTime minTime, DateTime maxTime, DateTime initStartTime, + DateTime initEndTime, int minuteDivider) { if (minTime == null) { minTime = DateTime.parse(DATE_PICKER_MIN_DATETIME); } @@ -111,10 +115,10 @@ class _TimePickerWidgetState extends State { maxTime = DateTime.parse(DATE_PICKER_MAX_DATETIME); } DateTime now = DateTime.now(); - this._minTime = - DateTime(now.year, now.month, now.day, minTime.hour, minTime.minute, minTime.second); - this._maxTime = - DateTime(now.year, now.month, now.day, maxTime.hour, maxTime.minute, maxTime.second); + this._minTime = DateTime(now.year, now.month, now.day, minTime.hour, + minTime.minute, minTime.second); + this._maxTime = DateTime(now.year, now.month, now.day, maxTime.hour, + maxTime.minute, maxTime.second); if (initStartTime == null) { // init time is now @@ -142,19 +146,22 @@ class _TimePickerWidgetState extends State { this._hourRange = _calcHourRange(); this._minuteRange = _calcMinuteRange(); - this._currStartHour = min(max(_hourRange.first, _currStartHour), _hourRange.last); + this._currStartHour = + min(max(_hourRange.first, _currStartHour), _hourRange.last); this._currEndHour = min(_currEndHour, _hourRange.last); // limit the range of minute - this._currStartMinute = min(max(_minuteRange.first, _currStartMinute), _minuteRange.last); + this._currStartMinute = + min(max(_minuteRange.first, _currStartMinute), _minuteRange.last); _currStartMinute -= _currStartMinute % _minuteDivider; this._currEndMinute = min(_currEndMinute, _minuteRange.last); _currEndMinute -= _currEndMinute % _minuteDivider; - _startSelectedDateTime = - DateTime(now.year, now.month, now.day, _currStartHour, _currStartMinute); - _endSelectedDateTime = DateTime(now.year, now.month, now.day, _currEndHour, _currEndMinute); + _startSelectedDateTime = DateTime( + now.year, now.month, now.day, _currStartHour, _currStartMinute); + _endSelectedDateTime = + DateTime(now.year, now.month, now.day, _currEndHour, _currEndMinute); _startSelectedIndex = _calcStartSelectIndexList(_minuteDivider); _endSelectedIndex = _calcEndSelectIndexList(_minuteDivider); @@ -162,9 +169,11 @@ class _TimePickerWidgetState extends State { @override Widget build(BuildContext context) { - _initData(_minTime, _maxTime, _startSelectedDateTime, _endSelectedDateTime, _minuteDivider); + _initData(_minTime, _maxTime, _startSelectedDateTime, _endSelectedDateTime, + _minuteDivider); return GestureDetector( - child: Material(color: Colors.transparent, child: _renderPickerView(context)), + child: Material( + color: Colors.transparent, child: _renderPickerView(context)), ); } @@ -173,7 +182,8 @@ class _TimePickerWidgetState extends State { Widget pickerWidget = _renderDatePickerWidget(); // display the title widget - if (widget.pickerTitleConfig.title != null || widget.pickerTitleConfig.showTitle) { + if (widget.pickerTitleConfig.title != null || + widget.pickerTitleConfig.showTitle) { Widget titleWidget = BrnPickerTitle( pickerTitleConfig: widget.pickerTitleConfig, locale: widget.locale, @@ -196,8 +206,8 @@ class _TimePickerWidgetState extends State { /// pressed confirm widget void _onPressedConfirm() { if (widget.onConfirm != null) { - widget.onConfirm( - _startSelectedDateTime, _endSelectedDateTime, _startSelectedIndex, _endSelectedIndex); + widget.onConfirm(_startSelectedDateTime, _endSelectedDateTime, + _startSelectedIndex, _endSelectedIndex); } Navigator.pop(context); } @@ -253,7 +263,9 @@ class _TimePickerWidgetState extends State { child: BrnTimeRangeSideWidget( key: secondGlobalKey, dateFormat: widget.dateFormat, - minDateTime: (widget.isLimitTimeRange ?? true) ? _startSelectedDateTime : _minTime, + minDateTime: (widget.isLimitTimeRange ?? true) + ? _startSelectedDateTime + : _minTime, maxDateTime: _maxTime, initialStartDateTime: (widget.isLimitTimeRange ?? true) ? _endSelectedDateTime.compareTo(_startSelectedDateTime) > 0 @@ -275,7 +287,8 @@ class _TimePickerWidgetState extends State { }); }, )))); - return Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers); + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: pickers); } /// calculate selected index list diff --git a/lib/src/components/popup/brn_overlay_window.dart b/lib/src/components/popup/brn_overlay_window.dart index 47b21e69..6469dbb9 100644 --- a/lib/src/components/popup/brn_overlay_window.dart +++ b/lib/src/components/popup/brn_overlay_window.dart @@ -41,7 +41,8 @@ class BrnOverlayWindow extends StatefulWidget { /// [content] 要展示的内容 /// [autoDismissOnTouchOutSide] 点击 OverlayWindow 外部是否自动消失 /// [onDismiss] OverlayWindow 消失回调 - static BrnOverlayController showOverlayWindow(BuildContext context, Key targetKey, + static BrnOverlayController showOverlayWindow( + BuildContext context, Key targetKey, {Widget content, BrnOverlayPopDirection popDirection, bool autoDismissOnTouchOutSide, @@ -113,13 +114,15 @@ class _BrnOverlayWindowState extends State { var placeHolderPart = GestureDetector(); Widget realContent; - double marginTop = _showRect.top + (_showRect.height - _targetViewSize.height) / 2; + double marginTop = + _showRect.top + (_showRect.height - _targetViewSize.height) / 2; if (_screenSize.height - marginTop < _targetViewSize.height) { marginTop = max(0, _screenSize.height - _targetViewSize.height); } marginTop = max(0, marginTop); - double marginLeft = _showRect.left + (_showRect.width - _targetViewSize.width) / 2; + double marginLeft = + _showRect.left + (_showRect.width - _targetViewSize.width) / 2; if (_screenSize.width - marginLeft < _targetViewSize.width) { marginLeft = max(0, _screenSize.width - _targetViewSize.width); } @@ -203,7 +206,8 @@ class _BrnOverlayWindowState extends State { } RenderBox renderBox = key.currentContext.findRenderObject(); var offset = renderBox.localToGlobal(Offset.zero); - return Rect.fromLTWH(offset.dx, offset.dy, renderBox.size.width, renderBox.size.height); + return Rect.fromLTWH( + offset.dx, offset.dy, renderBox.size.width, renderBox.size.height); } /// diff --git a/lib/src/components/popup/brn_popup_window.dart b/lib/src/components/popup/brn_popup_window.dart index cd1bc93b..640fe796 100644 --- a/lib/src/components/popup/brn_popup_window.dart +++ b/lib/src/components/popup/brn_popup_window.dart @@ -97,12 +97,14 @@ class BrnPopupWindow extends StatefulWidget { static void showPopWindow(context, String text, GlobalKey popKey, {BrnPopupDirection popDirection = BrnPopupDirection.bottom, double arrowHeight = 6.0, - TextStyle textStyle = const TextStyle(fontSize: 16, color: Color(0xFFFFFFFF)), + TextStyle textStyle = + const TextStyle(fontSize: 16, color: Color(0xFFFFFFFF)), Color backgroundColor = const Color(0xFF1A1A1A), bool hasCloseIcon = false, double offset = 0, Widget widget, - EdgeInsets paddingInsets = const EdgeInsets.only(left: 18, top: 14, right: 18, bottom: 14), + EdgeInsets paddingInsets = + const EdgeInsets.only(left: 18, top: 14, right: 18, bottom: 14), double borderRadius = 8, Color borderColor = Colors.transparent, double borderWidth = 1, @@ -183,7 +185,8 @@ class _BrnPopupWindowState extends State { } RenderBox renderBox = key.currentContext.findRenderObject(); var offset = renderBox.localToGlobal(Offset.zero); - return Rect.fromLTWH(offset.dx, offset.dy, renderBox.size.width, renderBox.size.height); + return Rect.fromLTWH( + offset.dx, offset.dy, renderBox.size.width, renderBox.size.height); } // 计算popUpWindow显示的位置 @@ -248,9 +251,15 @@ class _BrnPopupWindowState extends State { return _expandedRight ? Positioned( left: widget.arrowOffset ?? - _left + (_showRect.width - _arrowSpacing) / 2 - widget.spaceMargin, - top: _popDirection == BrnPopupDirection.bottom ? _top - widget.arrowHeight : null, - bottom: _popDirection == BrnPopupDirection.top ? _bottom - widget.arrowHeight : null, + _left + + (_showRect.width - _arrowSpacing) / 2 - + widget.spaceMargin, + top: _popDirection == BrnPopupDirection.bottom + ? _top - widget.arrowHeight + : null, + bottom: _popDirection == BrnPopupDirection.top + ? _bottom - widget.arrowHeight + : null, child: CustomPaint( size: Size(15.0, widget.arrowHeight), painter: _TrianglePainter( @@ -261,9 +270,15 @@ class _BrnPopupWindowState extends State { ) : Positioned( right: widget.arrowOffset ?? - _right + (_showRect.width - _arrowSpacing) / 2 - widget.spaceMargin, - top: _popDirection == BrnPopupDirection.bottom ? _top - widget.arrowHeight : null, - bottom: _popDirection == BrnPopupDirection.top ? _bottom - widget.arrowHeight : null, + _right + + (_showRect.width - _arrowSpacing) / 2 - + widget.spaceMargin, + top: _popDirection == BrnPopupDirection.bottom + ? _top - widget.arrowHeight + : null, + bottom: _popDirection == BrnPopupDirection.top + ? _bottom - widget.arrowHeight + : null, child: CustomPaint( size: Size(15.0, widget.arrowHeight), painter: _TrianglePainter( @@ -290,7 +305,9 @@ class _BrnPopupWindowState extends State { border: Border.all(color: _borderColor, width: 0.5), borderRadius: BorderRadius.circular(widget.borderRadius ?? 4)), constraints: BoxConstraints( - maxWidth: _expandedRight ? _screenSize.width - _left : _screenSize.width - _right, + maxWidth: _expandedRight + ? _screenSize.width - _left + : _screenSize.width - _right, maxHeight: _popDirection == BrnPopupDirection.bottom ? _screenSize.height - _top : _screenSize.height - _bottom - statusBarHeight), @@ -299,13 +316,15 @@ class _BrnPopupWindowState extends State { child: widget.canWrap ? RichText( text: TextSpan(children: [ - TextSpan(text: widget.text, style: widget.textStyle), + TextSpan( + text: widget.text, style: widget.textStyle), widget.isShowCloseIcon ? WidgetSpan( alignment: PlaceholderAlignment.middle, child: Padding( padding: EdgeInsets.only(left: 6), - child: BrunoTools.getAssetImage(BrnAsset.ICON_POPUP_CLOSE), + child: BrunoTools.getAssetImage( + BrnAsset.ICON_POPUP_CLOSE), )) : TextSpan(text: "") ])) @@ -324,7 +343,8 @@ class _BrnPopupWindowState extends State { widget.isShowCloseIcon ? Padding( padding: EdgeInsets.only(left: 6), - child: BrunoTools.getAssetImage(BrnAsset.ICON_POPUP_CLOSE), + child: BrunoTools.getAssetImage( + BrnAsset.ICON_POPUP_CLOSE), ) : Text("") ], @@ -405,8 +425,8 @@ class BrnPopupRoute extends PopupRoute { String get barrierLabel => null; @override - Widget buildPage( - BuildContext context, Animation animation, Animation secondaryAnimation) { + Widget buildPage(BuildContext context, Animation animation, + Animation secondaryAnimation) { return child; } @@ -438,7 +458,11 @@ class BrnPopupListWindow { BrnPopupListItemBuilder itemBuilder, BrnPopupListItemClick onItemClick}) { TextStyle textStyle = TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, fontSize: 16); + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, + fontSize: 16); double arrowHeight = 6.0; Color borderColor = Color(0xffCCCCCC); Color backgroundColor = Colors.white; @@ -462,16 +486,18 @@ class BrnPopupListWindow { offset: offset, widget: BrunoTools.isEmpty(data) ? Container( - constraints: BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), + constraints: + BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), ) : Container( - constraints: BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), + constraints: + BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), child: SingleChildScrollView( child: Container( padding: EdgeInsets.only(top: 6, bottom: 6), child: Column( - children: _getItems(context, minWidth, maxWidth, itemBuilder, textStyle, - data, onItemClick, null), + children: _getItems(context, minWidth, maxWidth, + itemBuilder, textStyle, data, onItemClick, null), ), ), ), @@ -503,10 +529,15 @@ class BrnPopupListWindow { double maxWidth = 150; double maxHeight = 200; double arrowOffset; - Color borderColor = BrnThemeConfigurator.instance.getConfig().commonConfig.dividerColorBase; + Color borderColor = + BrnThemeConfigurator.instance.getConfig().commonConfig.dividerColorBase; Color backgroundColor = Colors.white; TextStyle textStyle = TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, fontSize: 14); + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, + fontSize: 14); bool hasCloseIcon = true; Navigator.push( @@ -523,16 +554,18 @@ class BrnPopupListWindow { offset: offset, widget: BrunoTools.isEmpty(data) ? Container( - constraints: BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), + constraints: + BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), ) : Container( - constraints: BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), + constraints: + BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), child: SingleChildScrollView( child: Container( padding: EdgeInsets.only(top: 6, bottom: 6), child: Column( - children: _getItems(context, minWidth, maxWidth, null, textStyle, data, - onItemClick, onDismiss), + children: _getItems(context, minWidth, maxWidth, null, + textStyle, data, onItemClick, onDismiss), ), ), ), @@ -554,8 +587,8 @@ class BrnPopupListWindow { List data, BrnPopupListItemClick onItemClick, VoidCallback onDismiss) { - double textMaxWidth = - _getMaxWidth(textStyle ?? TextStyle(fontSize: 16, color: Color(0xFFFFFFFF)), data); + double textMaxWidth = _getMaxWidth( + textStyle ?? TextStyle(fontSize: 16, color: Color(0xFFFFFFFF)), data); if (textMaxWidth + 52 < minWidth) { textMaxWidth = minWidth; } else if (textMaxWidth + 52 > maxWidth) { @@ -579,7 +612,8 @@ class BrnPopupListWindow { width: textMaxWidth, alignment: Alignment.center, color: Colors.transparent, - padding: EdgeInsets.only(left: 26, right: 26, top: 6, bottom: 6), + padding: + EdgeInsets.only(left: 26, right: 26, top: 6, bottom: 6), child: _getTextWidget(itemBuilder, data, f, textStyle))); })?.toList() ?? List(); @@ -605,12 +639,13 @@ class BrnPopupListWindow { return maxWidth; } - static Widget _getTextWidget( - BrnPopupListItemBuilder itemBuilder, List data, String text, TextStyle textStyle) { + static Widget _getTextWidget(BrnPopupListItemBuilder itemBuilder, + List data, String text, TextStyle textStyle) { if (itemBuilder == null) { return _getDefaultText(text, textStyle); } else { - return itemBuilder(data.indexOf(text), text) ?? _getDefaultText(text, textStyle); + return itemBuilder(data.indexOf(text), text) ?? + _getDefaultText(text, textStyle); } } diff --git a/lib/src/components/radio/brn_checkbox.dart b/lib/src/components/radio/brn_checkbox.dart index 2f8b2468..0f067a9e 100644 --- a/lib/src/components/radio/brn_checkbox.dart +++ b/lib/src/components/radio/brn_checkbox.dart @@ -78,10 +78,13 @@ class BrnCheckboxState extends State { childOnRight: widget.childOnRight, mainAxisAlignment: widget.mainAxisAlignment, mainAxisSize: widget.mainAxisSize, - selectedImage: BrunoTools.getAssetImageWithBandColor(BrnAsset.ICON_RADIO_MULTI_SELECTED), + selectedImage: BrunoTools.getAssetImageWithBandColor( + BrnAsset.ICON_RADIO_MULTI_SELECTED), unselectedImage: BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_UNSELECTED), - disSelectedImage: BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_DISABLE_SINGLE_SELECTED), - disUnselectedImage: BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_DISABLE_UNSELECTED), + disSelectedImage: + BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_DISABLE_SINGLE_SELECTED), + disUnselectedImage: + BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_DISABLE_UNSELECTED), child: widget.child, onRadioItemClick: () { setState(() { diff --git a/lib/src/components/radio/brn_radio_button.dart b/lib/src/components/radio/brn_radio_button.dart index 81e0b7c6..b15306f9 100644 --- a/lib/src/components/radio/brn_radio_button.dart +++ b/lib/src/components/radio/brn_radio_button.dart @@ -63,10 +63,13 @@ class BrnRadioButton extends StatelessWidget { childOnRight: childOnRight, mainAxisAlignment: mainAxisAlignment, mainAxisSize: mainAxisSize, - selectedImage: BrunoTools.getAssetImageWithBandColor(BrnAsset.ICON_RADIO_SINGLE_SELECTED), + selectedImage: BrunoTools.getAssetImageWithBandColor( + BrnAsset.ICON_RADIO_SINGLE_SELECTED), unselectedImage: BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_UNSELECTED), - disSelectedImage: BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_DISABLE_MULTI_SELECTED), - disUnselectedImage: BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_DISABLE_UNSELECTED), + disSelectedImage: + BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_DISABLE_MULTI_SELECTED), + disUnselectedImage: + BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_DISABLE_UNSELECTED), child: child, onRadioItemClick: () { onValueChangedAtIndex(radioIndex, true); diff --git a/lib/src/components/radio/brn_radio_core.dart b/lib/src/components/radio/brn_radio_core.dart index 9fc2f1e0..05fc52b0 100644 --- a/lib/src/components/radio/brn_radio_core.dart +++ b/lib/src/components/radio/brn_radio_core.dart @@ -104,7 +104,9 @@ class _BrnRadioCoreState extends State { padding: widget.iconPadding ?? EdgeInsets.all(5), child: this._isSelected ? (this._disable ? widget.disSelectedImage : widget.selectedImage) - : (this._disable ? widget.disUnselectedImage : widget.unselectedImage), + : (this._disable + ? widget.disUnselectedImage + : widget.unselectedImage), ); Widget radioWidget; diff --git a/lib/src/components/rating/brn_rating_star.dart b/lib/src/components/rating/brn_rating_star.dart index 818aab66..f8d1a49c 100644 --- a/lib/src/components/rating/brn_rating_star.dart +++ b/lib/src/components/rating/brn_rating_star.dart @@ -94,7 +94,9 @@ class _BrnRatingStarState extends State { } else { state = RatingState.unselect; } - var rating = widget.starBuilder != null ? widget.starBuilder(state) : _buildRating(state); + var rating = widget.starBuilder != null + ? widget.starBuilder(state) + : _buildRating(state); if (widget.onSelected != null) { list.add(GestureDetector( @@ -133,7 +135,8 @@ class _BrnRatingStarState extends State { return BrunoTools.getAssetSizeImage(BrnAsset.ICON_STAR_HALF, 16, 16); case RatingState.unselect: default: - return BrunoTools.getAssetSizeImage(BrnAsset.ICON_STAR, 16, 16, color: Color(0xFFF0F0F0)); + return BrunoTools.getAssetSizeImage(BrnAsset.ICON_STAR, 16, 16, + color: Color(0xFFF0F0F0)); } } } diff --git a/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart b/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart index 01ded761..9f0945df 100644 --- a/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart +++ b/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart @@ -6,10 +6,12 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; /// 构建指定索引的Widget -typedef AnchorTabWidgetIndexedBuilder = Widget Function(BuildContext context, int index); +typedef AnchorTabWidgetIndexedBuilder = Widget Function( + BuildContext context, int index); /// 构建指定索引的Tab -typedef AnchorTabIndexedBuilder = BadgeTab Function(BuildContext context, int index); +typedef AnchorTabIndexedBuilder = BadgeTab Function( + BuildContext context, int index); class BrnAnchorTab extends StatefulWidget { // TabBar的样式 @@ -29,7 +31,8 @@ class BrnAnchorTab extends StatefulWidget { this.tabBarStyle = const BrnAnchorTabBarStyle()}); @override - _BrnScrollAnchorTabWidgetState createState() => _BrnScrollAnchorTabWidgetState(); + _BrnScrollAnchorTabWidgetState createState() => + _BrnScrollAnchorTabWidgetState(); } class _BrnScrollAnchorTabWidgetState extends State @@ -126,7 +129,8 @@ class _BrnScrollAnchorTabWidgetState extends State tab = true; scrollController .animateTo(cardOffsetList[index], - duration: Duration(milliseconds: 100), curve: Curves.linear) + duration: Duration(milliseconds: 100), + curve: Curves.linear) .whenComplete(() { tab = false; }); @@ -157,7 +161,9 @@ class _BrnScrollAnchorTabWidgetState extends State if (widget.widgetIndexedBuilder != null) { for (int i = 0, n = widget.itemCount; i < n; i++) { bodyWidgetList.add( - Container(key: bodyKeyList[i], child: widget.widgetIndexedBuilder(context, i)), + Container( + key: bodyKeyList[i], + child: widget.widgetIndexedBuilder(context, i)), ); } } @@ -170,15 +176,17 @@ class _BrnScrollAnchorTabWidgetState extends State } void fillOffset() { - Offset globalToLocal = - (key.currentContext.findRenderObject() as RenderBox).localToGlobal(Offset.zero); + Offset globalToLocal = (key.currentContext.findRenderObject() as RenderBox) + .localToGlobal(Offset.zero); listDy = globalToLocal.dy; for (int i = 0, n = widget.itemCount; i < n; i++) { - if (cardOffsetList[i] == -1.0) if (bodyKeyList[i].currentContext != null) { - double cardOffset = (bodyKeyList[i].currentContext.findRenderObject() as RenderBox) - .localToGlobal(Offset.zero) //相对于原点 控件的位置 - .dy; //y点坐标 + if (cardOffsetList[i] == -1.0) if (bodyKeyList[i].currentContext != + null) { + double cardOffset = + (bodyKeyList[i].currentContext.findRenderObject() as RenderBox) + .localToGlobal(Offset.zero) //相对于原点 控件的位置 + .dy; //y点坐标 cardOffsetList[i] = cardOffset + scrollController.offset - listDy; } @@ -195,10 +203,12 @@ class _BrnScrollAnchorTabWidgetState extends State void updateOffset() { for (int i = 0, n = widget.itemCount; i < n; i++) { - if (cardOffsetList[i] == -1.0) if (bodyKeyList[i].currentContext != null) { - double cardOffset = (bodyKeyList[i].currentContext.findRenderObject() as RenderBox) - .localToGlobal(Offset.zero) //相对于原点 控件的位置 - .dy; //y点坐标 + if (cardOffsetList[i] == -1.0) if (bodyKeyList[i].currentContext != + null) { + double cardOffset = + (bodyKeyList[i].currentContext.findRenderObject() as RenderBox) + .localToGlobal(Offset.zero) //相对于原点 控件的位置 + .dy; //y点坐标 cardOffsetList[i] = cardOffset + scrollController.offset - listDy; } diff --git a/lib/src/components/selectcity/brn_az_listview.dart b/lib/src/components/selectcity/brn_az_listview.dart index 5a069809..0c39ed98 100644 --- a/lib/src/components/selectcity/brn_az_listview.dart +++ b/lib/src/components/selectcity/brn_az_listview.dart @@ -123,8 +123,9 @@ class _AzListViewState extends State { _isShowIndexBarHint = model.isTouchDown; int offset = _suspensionSectionMap[model.tag]; if (offset != null) { - _scrollController - .jumpTo(offset.toDouble().clamp(.0, _scrollController.position.maxScrollExtent)); + _scrollController.jumpTo(offset + .toDouble() + .clamp(.0, _scrollController.position.maxScrollExtent)); } }); } @@ -168,7 +169,8 @@ class _AzListViewState extends State { itemBuilder: (BuildContext context, int index) { if (index == 0 && _cityList[index] is _Header) { return SizedBox( - height: widget.header.height.toDouble(), child: widget.header.builder(context)); + height: widget.header.height.toDouble(), + child: widget.header.builder(context)); } return widget.itemBuilder(context, _cityList[index]); }), @@ -178,7 +180,8 @@ class _AzListViewState extends State { itemHeight: widget.itemHeight, onSusTagChanged: widget.onSusTagChanged, header: widget.header, - onSusSectionInited: (Map map) => _suspensionSectionMap = map, + onSusSectionInited: (Map map) => + _suspensionSectionMap = map, ) ]; diff --git a/lib/src/components/selectcity/brn_base_azlistview_page.dart b/lib/src/components/selectcity/brn_base_azlistview_page.dart index 9f831c7b..04a8a3c4 100644 --- a/lib/src/components/selectcity/brn_base_azlistview_page.dart +++ b/lib/src/components/selectcity/brn_base_azlistview_page.dart @@ -95,7 +95,8 @@ class _BaseAZListViewPageState extends State { List top = widget.getTopData(); if (_dataList.isEmpty && top.isEmpty) { - return BrnAbnormalStateUtils.getEmptyWidgetByState(context, AbnormalState.noData, (index) {}); + return BrnAbnormalStateUtils.getEmptyWidgetByState( + context, AbnormalState.noData, (index) {}); } suspensionTag = top.isEmpty ? _dataList[0].tag : top[0].tag; diff --git a/lib/src/components/selectcity/brn_index_bar.dart b/lib/src/components/selectcity/brn_index_bar.dart index bdd803eb..e8ffe23d 100644 --- a/lib/src/components/selectcity/brn_index_bar.dart +++ b/lib/src/components/selectcity/brn_index_bar.dart @@ -52,9 +52,11 @@ class IndexBar extends StatefulWidget { this.width = 30, this.itemHeight = 16, this.color = Colors.transparent, - this.textStyle = const TextStyle(fontSize: 12.0, color: Color(0xFF101D37)), + this.textStyle = + const TextStyle(fontSize: 12.0, color: Color(0xFF101D37)), this.touchDownColor = const Color(0xffeeeeee), - this.touchDownTextStyle = const TextStyle(fontSize: 12.0, color: Colors.black)}); + this.touchDownTextStyle = + const TextStyle(fontSize: 12.0, color: Colors.black)}); /// index data. final List data; @@ -80,7 +82,8 @@ class IndexBar extends StatefulWidget { final IndexBarTouchCallback onTouch; @override - _SuspensionListViewIndexBarState createState() => _SuspensionListViewIndexBarState(); + _SuspensionListViewIndexBarState createState() => + _SuspensionListViewIndexBarState(); } class _SuspensionListViewIndexBarState extends State { diff --git a/lib/src/components/selectcity/brn_single_select_city_page.dart b/lib/src/components/selectcity/brn_single_select_city_page.dart index 79664898..789b9b60 100644 --- a/lib/src/components/selectcity/brn_single_select_city_page.dart +++ b/lib/src/components/selectcity/brn_single_select_city_page.dart @@ -86,7 +86,8 @@ class _BrnSingleSelectCityPageState extends State { if (widget.cityList == null || widget.cityList.isEmpty) { //加载城市列表 rootBundle - .loadString('packages/${BrnStrings.flutterPackageName}/assets/json/china.json') + .loadString( + 'packages/${BrnStrings.flutterPackageName}/assets/json/china.json') .then((value) { Map countyMap = json.decode(value); List list = countyMap['china']; @@ -281,7 +282,9 @@ class _BrnSingleSelectCityPageState extends State { Divider( height: .0, ), - _showCityStack ? _buildCityList() : _buildSearchResultList(_searchText), + _showCityStack + ? _buildCityList() + : _buildSearchResultList(_searchText), ], ), )); @@ -320,9 +323,11 @@ class _BrnSingleSelectCityPageState extends State { alignment: Alignment.center, width: 40.0, height: 40.0, - decoration: - BoxDecoration(color: Color(0x22222222), borderRadius: BorderRadius.circular(5.0)), - child: Text(hint, style: TextStyle(color: Colors.white, fontSize: 20.0)), + decoration: BoxDecoration( + color: Color(0x22222222), + borderRadius: BorderRadius.circular(5.0)), + child: Text(hint, + style: TextStyle(color: Colors.white, fontSize: 20.0)), ); }, )); diff --git a/lib/src/components/selectcity/brn_suspension_view.dart b/lib/src/components/selectcity/brn_suspension_view.dart index 0c70f1b3..5282705d 100644 --- a/lib/src/components/selectcity/brn_suspension_view.dart +++ b/lib/src/components/selectcity/brn_suspension_view.dart @@ -87,7 +87,8 @@ class _SuspensionWidgetState extends State { int _getIndex(int offset) { if (widget.header != null && offset < widget.header.height) { - if (_suspensionTop != -widget.header.height && widget.suspensionWidget != null) { + if (_suspensionTop != -widget.header.height && + widget.suspensionWidget != null) { setState(() { _suspensionTop = -widget.header.height; }); diff --git a/lib/src/components/selection/bean/brn_selection_common_entity.dart b/lib/src/components/selection/bean/brn_selection_common_entity.dart index e35ea01e..93c84fb9 100644 --- a/lib/src/components/selection/bean/brn_selection_common_entity.dart +++ b/lib/src/components/selection/bean/brn_selection_common_entity.dart @@ -51,7 +51,6 @@ enum BrnSelectionWindowType { } class BrnSelectionEntity { - /// 类型 是单选、复选还是有自定义输入 String type; @@ -116,8 +115,7 @@ class BrnSelectionEntity { bool canJoinTitle = false; BrnSelectionEntity( - { - this.key, + {this.key, this.value, this.defaultValue, this.title, @@ -135,7 +133,8 @@ class BrnSelectionEntity { this.originalCustomMap = Map(); /// 默认支持最大选中个数为 65535 - this.maxSelectedCount = maxSelectedCount ?? BrnSelectionConstant.MAX_SELECT_COUNT; + this.maxSelectedCount = + maxSelectedCount ?? BrnSelectionConstant.MAX_SELECT_COUNT; } /// 构造简单筛选数据 @@ -151,7 +150,8 @@ class BrnSelectionEntity { this.isSelected = false; /// 默认支持最大选中个数为 65535 - this.maxSelectedCount = maxSelectedCount ?? BrnSelectionConstant.MAX_SELECT_COUNT; + this.maxSelectedCount = + maxSelectedCount ?? BrnSelectionConstant.MAX_SELECT_COUNT; } BrnSelectionEntity.fromJson(Map map) { @@ -162,14 +162,16 @@ class BrnSelectionEntity { type = map['type'] ?? ""; defaultValue = map['defaultValue'] ?? ""; value = map['value'] ?? ""; - if (map['maxSelectedCount'] != null && int.tryParse(map['maxSelectedCount']) != null) { + if (map['maxSelectedCount'] != null && + int.tryParse(map['maxSelectedCount']) != null) { maxSelectedCount = int.tryParse(map['maxSelectedCount']); } else { maxSelectedCount = BrnSelectionConstant.MAX_SELECT_COUNT; } extMap = map['ext'] ?? {}; children = List() - ..addAll((map['children'] as List ?? []).map((o) => BrnSelectionEntity.fromMap(o))); + ..addAll((map['children'] as List ?? []) + .map((o) => BrnSelectionEntity.fromMap(o))); filterType = parserFilterTypeWithType(map['type'] ?? ""); isSelected = false; } @@ -184,23 +186,25 @@ class BrnSelectionEntity { entity.type = map['type'] ?? ""; entity.defaultValue = map['defaultValue'] ?? ""; entity.value = map['value'] ?? ""; - if (map['maxSelectedCount'] != null && int.tryParse(map['maxSelectedCount']) != null) { + if (map['maxSelectedCount'] != null && + int.tryParse(map['maxSelectedCount']) != null) { entity.maxSelectedCount = int.tryParse(map['maxSelectedCount']); } else { entity.maxSelectedCount = BrnSelectionConstant.MAX_SELECT_COUNT; } entity.extMap = map['ext'] ?? {}; entity.children = List() - ..addAll((map['children'] as List ?? []).map((o) => BrnSelectionEntity.fromMap(o))); + ..addAll((map['children'] as List ?? []) + .map((o) => BrnSelectionEntity.fromMap(o))); entity.filterType = entity.parserFilterTypeWithType(map['type'] ?? ""); return entity; } - + void configRelationshipAndDefaultValue() { configRelationship(); configDefaultValue(); } - + void configRelationship() { if (this.children != null && this.children.length > 0) { for (BrnSelectionEntity entity in this.children) { @@ -249,7 +253,8 @@ class BrnSelectionEntity { if (hasCheckBoxBrother()) { isSelected = children.where((_) => _.isSelected).length > 0; } else { - isSelected = isSelected || children.where((_) => _.isSelected).length > 0; + isSelected = + isSelected || children.where((_) => _.isSelected).length > 0; } } } @@ -348,7 +353,8 @@ class BrnSelectionEntity { ?.where((_) => !_.isUnLimit()) ?.where((_) => (_.filterType != BrnSelectionFilterType.Range) || - (_.filterType == BrnSelectionFilterType.Range && !BrunoTools.isEmpty(_.customMap))) + (_.filterType == BrnSelectionFilterType.Range && + !BrunoTools.isEmpty(_.customMap))) ?.where((_) => (_.filterType != BrnSelectionFilterType.DateRange) || (_.filterType == BrnSelectionFilterType.DateRange && @@ -366,7 +372,8 @@ class BrnSelectionEntity { return this.selectedLastColumnList(); } else { List results = List(); - List firstColumn = BrnSelectionUtil.currentSelectListForEntity(this); + List firstColumn = + BrnSelectionUtil.currentSelectListForEntity(this); results.addAll(firstColumn); if (firstColumn != null && firstColumn.length > 0) { for (BrnSelectionEntity firstEntity in firstColumn) { @@ -390,7 +397,8 @@ class BrnSelectionEntity { List allSelectedList() { List results = List(); - List firstColumn = BrnSelectionUtil.currentSelectListForEntity(this); + List firstColumn = + BrnSelectionUtil.currentSelectListForEntity(this); results.addAll(firstColumn); if (firstColumn != null && firstColumn.length > 0) { for (BrnSelectionEntity firstEntity in firstColumn) { @@ -421,7 +429,8 @@ class BrnSelectionEntity { BrnSelectionEntity getRootEntity(BrnSelectionEntity rootEntity) { if (rootEntity.parent == null || - rootEntity.parent.maxSelectedCount == BrnSelectionConstant.MAX_SELECT_COUNT) { + rootEntity.parent.maxSelectedCount == + BrnSelectionConstant.MAX_SELECT_COUNT) { return rootEntity; } else { return getRootEntity(rootEntity.parent); @@ -442,7 +451,9 @@ class BrnSelectionEntity { /// 判断当前的筛选 Item 是否为当前层次中第一个被选中的 Item。 /// 用于展开筛选弹窗时显示选中效果。 int getIndexInCurrentLevel() { - if (parent == null || parent.children == null || parent.children.length == 0) return -1; + if (parent == null || + parent.children == null || + parent.children.length == 0) return -1; for (BrnSelectionEntity entity in parent.children) { if (entity == this) { @@ -454,7 +465,9 @@ class BrnSelectionEntity { /// 是否在筛选数据的最后一层。 如果最大层次为 3;某个筛选数据层次为 2,但其无子节点。此时认为不在最后一层。 bool isInLastLevel() { - if (parent == null || parent.children == null || parent.children.length == 0) return true; + if (parent == null || + parent.children == null || + parent.children.length == 0) return true; for (BrnSelectionEntity entity in parent.children) { if (entity.children != null && entity.children.length > 0) { @@ -466,8 +479,9 @@ class BrnSelectionEntity { /// 检查自己的兄弟结点是否存在 checkbox 类型。 bool hasCheckBoxBrother() { - int count = - parent?.children?.where((f) => f.filterType == BrnSelectionFilterType.Checkbox)?.length; + int count = parent?.children + ?.where((f) => f.filterType == BrnSelectionFilterType.Checkbox) + ?.length; return count == null ? false : count > 0; } @@ -567,7 +581,9 @@ class BrnSelectionEntity { int inputMax = int.tryParse(customMap['max'] ?? ""); if (inputMax != null && inputMin != null) { - if (inputMin >= limitMin && inputMax <= limitMax && inputMax >= inputMin) { + if (inputMin >= limitMin && + inputMax <= limitMax && + inputMax >= inputMin) { return true; } else { return false; diff --git a/lib/src/components/selection/brn_flat_selection.dart b/lib/src/components/selection/brn_flat_selection.dart index 92bdf298..9e78535f 100644 --- a/lib/src/components/selection/brn_flat_selection.dart +++ b/lib/src/components/selection/brn_flat_selection.dart @@ -59,7 +59,8 @@ class BrnFlatSelection extends StatefulWidget { _BrnFlatSelectionState createState() => _BrnFlatSelectionState(); } -class _BrnFlatSelectionState extends State with SingleTickerProviderStateMixin { +class _BrnFlatSelectionState extends State + with SingleTickerProviderStateMixin { List _originalSelectedItemsList; StreamController clearController; @@ -74,7 +75,8 @@ class _BrnFlatSelectionState extends State with SingleTickerPr _controller = widget.controller; if (widget.isNeedConfigChild ?? true) { - widget.entityDataList?.forEach((f) => f.configRelationshipAndDefaultValue()); + widget.entityDataList + ?.forEach((f) => f.configRelationshipAndDefaultValue()); } _controller?.addListener(_handleFlatControllerTick); @@ -202,7 +204,8 @@ class _BrnFlatSelectionState extends State with SingleTickerPr } }); - widget.confirmCallback(DefaultSelectionConverter().convertSelectedData(widget.entityDataList)); + widget.confirmCallback( + DefaultSelectionConverter().convertSelectedData(widget.entityDataList)); } /// 标题+筛选条件的 列表 diff --git a/lib/src/components/selection/brn_more_selection.dart b/lib/src/components/selection/brn_more_selection.dart index 546287be..7747b340 100644 --- a/lib/src/components/selection/brn_more_selection.dart +++ b/lib/src/components/selection/brn_more_selection.dart @@ -32,7 +32,10 @@ class BrnMoreSelectionPage extends StatefulWidget { final BrnSelectionConfig themeData; BrnMoreSelectionPage( - {this.entityData, this.confirmCallback, this.onCustomFloatingLayerClick, this.themeData}); + {this.entityData, + this.confirmCallback, + this.onCustomFloatingLayerClick, + this.themeData}); @override _BrnMoreSelectionPageState createState() => _BrnMoreSelectionPageState(); @@ -53,12 +56,14 @@ class _BrnMoreSelectionPageState extends State duration: const Duration(milliseconds: 300), vsync: this, ); - animation = Tween(end: Offset.zero, begin: Offset(1.0, 0.0)).animate(_controller); + animation = + Tween(end: Offset.zero, begin: Offset(1.0, 0.0)).animate(_controller); _controller.forward(); _originalSelectedItemsList = List(); _originalSelectedItemsList.clear(); - _originalSelectedItemsList.addAll(widget.entityData?.allSelectedList() ?? List()); + _originalSelectedItemsList + .addAll(widget.entityData?.allSelectedList() ?? List()); for (BrnSelectionEntity entity in _originalSelectedItemsList) { entity.isSelected = true; if (entity.customMap != null) { @@ -246,8 +251,10 @@ class _BrnMoreSelectionPageState extends State node.filterType == BrnSelectionFilterType.DateRange || node.filterType == BrnSelectionFilterType.DateRangeCalendar)) { if (node.customMap != null && - ((node.customMap['min'] != null && node.customMap['min'].length > 0) || - (node.customMap['max'] != null && node.customMap['max'].length > 0))) { + ((node.customMap['min'] != null && + node.customMap['min'].length > 0) || + (node.customMap['max'] != null && + node.customMap['max'].length > 0))) { if (!node.isValidRange()) { isValid = false; if (node?.filterType == BrnSelectionFilterType.Range) { diff --git a/lib/src/components/selection/brn_selection_list_entity.dart b/lib/src/components/selection/brn_selection_list_entity.dart index 51d4cd75..89b80bbb 100644 --- a/lib/src/components/selection/brn_selection_list_entity.dart +++ b/lib/src/components/selection/brn_selection_list_entity.dart @@ -9,7 +9,8 @@ class BrnSelectionEntityListBean { if (map == null) return null; BrnSelectionEntityListBean bean = BrnSelectionEntityListBean(null); bean.list = List() - ..addAll((map['list'] as List ?? []).map((o) => BrnSelectionEntity.fromMap(o))); + ..addAll((map['list'] as List ?? []) + .map((o) => BrnSelectionEntity.fromMap(o))); return bean; } } diff --git a/lib/src/components/selection/brn_selection_util.dart b/lib/src/components/selection/brn_selection_util.dart index df0577f6..7fe2315a 100644 --- a/lib/src/components/selection/brn_selection_util.dart +++ b/lib/src/components/selection/brn_selection_util.dart @@ -7,7 +7,8 @@ const double DESIGN_SCREEN_HEIGHT = 812; class BrnSelectionUtil { /// 处理兄弟结点为未选中状态,将自己置为选中状态 - static void processBrotherItemSelectStatus(BrnSelectionEntity selectionEntity) { + static void processBrotherItemSelectStatus( + BrnSelectionEntity selectionEntity) { if (BrnSelectionFilterType.Checkbox == selectionEntity.filterType) { selectionEntity.isSelected = !selectionEntity.isSelected; List allBrothers = selectionEntity.parent?.children; @@ -47,13 +48,18 @@ class BrnSelectionUtil { rootEntity = rootEntity.parent; } - if (rootEntity != null && rootEntity.children != null && rootEntity.children.length > 0) { + if (rootEntity != null && + rootEntity.children != null && + rootEntity.children.length > 0) { level = level > 1 ? level : 1; for (BrnSelectionEntity firstLevelEntity in rootEntity.children) { - if (firstLevelEntity.children != null && firstLevelEntity.children.length > 0) { + if (firstLevelEntity.children != null && + firstLevelEntity.children.length > 0) { level = level > 2 ? level : 2; - for (BrnSelectionEntity secondLevelEntity in firstLevelEntity.children) { - if (secondLevelEntity.children != null && secondLevelEntity.children.length > 0) { + for (BrnSelectionEntity secondLevelEntity + in firstLevelEntity.children) { + if (secondLevelEntity.children != null && + secondLevelEntity.children.length > 0) { level = 3; break; } @@ -65,7 +71,8 @@ class BrnSelectionUtil { } /// 返回状态为选中的子节点 - static List currentSelectListForEntity(BrnSelectionEntity entity) { + static List currentSelectListForEntity( + BrnSelectionEntity entity) { List list = List(); if (entity.children != null && entity.children.length > 0) { for (BrnSelectionEntity entity in entity.children) { @@ -91,7 +98,8 @@ class BrnSelectionUtil { } /// 判断列表中是否有range类型 - static BrnSelectionEntity getFilledCustomInputItem(List list) { + static BrnSelectionEntity getFilledCustomInputItem( + List list) { BrnSelectionEntity filledCustomInputItem; if (list == null) return filledCustomInputItem; for (BrnSelectionEntity entity in list) { @@ -133,7 +141,8 @@ class BrnSelectionUtil { /// 返回 true 符合条件,false 不符合条件 static bool checkMaxSelectionCount(BrnSelectionEntity entity) { if (entity == null) return false; - return entity.getLimitedRootSelectedChildCount() < entity.getLimitedRootMaxSelectedCount(); + return entity.getLimitedRootSelectedChildCount() < + entity.getLimitedRootMaxSelectedCount(); } //设置数据为未选中状态 diff --git a/lib/src/components/selection/brn_selection_view.dart b/lib/src/components/selection/brn_selection_view.dart index 50fdcfb6..3b61d541 100644 --- a/lib/src/components/selection/brn_selection_view.dart +++ b/lib/src/components/selection/brn_selection_view.dart @@ -15,10 +15,14 @@ typedef BrnConfigTagCountPerRow(int index, BrnSelectionEntity entity); /// [menuTitle] 设置自定义 menu 的Title文案 /// [isMenuTitleHighLight] 设置自定义 menu 的 title 是否高亮 -typedef BrnSetCustomSelectionMenuTitle = void Function({String menuTitle, bool isMenuTitleHighLight}); +typedef BrnSetCustomSelectionMenuTitle = void Function( + {String menuTitle, bool isMenuTitleHighLight}); -typedef BrnOnSelectionChanged = void Function(int menuIndex, Map selectedParams, - Map customParams, BrnSetCustomSelectionMenuTitle setCustomMenuTitle); +typedef BrnOnSelectionChanged = void Function( + int menuIndex, + Map selectedParams, + Map customParams, + BrnSetCustomSelectionMenuTitle setCustomMenuTitle); /// menu 点击拦截回调 /// [index] menu 的索引位置 @@ -26,26 +30,32 @@ typedef BrnOnSelectionChanged = void Function(int menuIndex, Map typedef BrnOnMenuItemInterceptor = bool Function(int index); /// 筛选弹窗打开前的回调方法。 -typedef BrnOnSelectionPreShow = BrnSelectionWindowType Function(int index, BrnSelectionEntity entity); +typedef BrnOnSelectionPreShow = BrnSelectionWindowType Function( + int index, BrnSelectionEntity entity); /// 点击【更多】筛选项时的回调, /// [index] 为点击的位置, /// [openMorePage] 为让用户触发的回调用于展开更多筛选页面 -typedef BrnOnMoreSelectionMenuClick = void Function(int index, BrnOpenMorePage openMorePage); +typedef BrnOnMoreSelectionMenuClick = void Function( + int index, BrnOpenMorePage openMorePage); /// 打开更多筛选页面, /// [updateData] 是否要更新更多筛选的数据, /// [moreSelections] 最新的更多筛选数据,是否更新取决于 [updateData] -typedef BrnOpenMorePage = void Function({bool updateData, List moreSelections}); +typedef BrnOpenMorePage = void Function( + {bool updateData, List moreSelections}); /// 自定义类型的 Menu 被点击时 让外部设置选中的 value 进来统一更新 UI,并将 function 传给外部设置筛选值。 -typedef BrnSetCustomSelectionParams = void Function(Map customParams); +typedef BrnSetCustomSelectionParams = void Function( + Map customParams); /// 自定义类型的 menu 被点击的回调, /// [index] 点击位置, /// [customMenuItem] 自定义筛选 menu 原始数据, /// [customSelectionParams] 开放给外部回调给函数,用于更新自定义筛选参数,触发[BrnOnSelectionChanged]。 -typedef BrnOnCustomSelectionMenuClick = Function(int index, BrnSelectionEntity customMenuItem, +typedef BrnOnCustomSelectionMenuClick = Function( + int index, + BrnSelectionEntity customMenuItem, BrnSetCustomSelectionParams customSelectionParams); /// 当更多筛选页面中,类型为 CustomLayer 被回调时,该函数用于回传参数进 BrnSelectionView 中, @@ -60,16 +70,18 @@ typedef BrnSetCustomFloatingLayerSelectionParams = void Function( typedef BrnOnCustomFloatingLayerClick = Function( int index, BrnSelectionEntity customFloatingLayerEntity, - BrnSetCustomFloatingLayerSelectionParams setCustomFloatingLayerSelectionParams); + BrnSetCustomFloatingLayerSelectionParams + setCustomFloatingLayerSelectionParams); -typedef OnDefaultParamsPrepared = void Function(Map selectedParams); +typedef OnDefaultParamsPrepared = void Function( + Map selectedParams); /// 默认筛选参数转换器,对传入的筛选数据做处理,返回 Map 参数对象。 -const BrnSelectionConverterDelegate _defaultConverter = const DefaultSelectionConverter(); +const BrnSelectionConverterDelegate _defaultConverter = + const DefaultSelectionConverter(); // ignore: must_be_immutable class BrnSelectionView extends StatefulWidget { - final BrnSelectionConverterDelegate selectionConverterDelegate; final BrnOnCustomSelectionMenuClick onCustomSelectionMenuClick; final BrnOnCustomFloatingLayerClick onCustomFloatingLayerClick; @@ -143,7 +155,8 @@ class BrnSelectionViewState extends State { _onDefaultParamsPrepared = widget.onDefaultParamsPrepared; if (_onDefaultParamsPrepared != null) { - _onDefaultParamsPrepared(_selectionConverterDelegate?.convertSelectedData(_selectionData)); + _onDefaultParamsPrepared( + _selectionConverterDelegate?.convertSelectedData(_selectionData)); } } @@ -159,7 +172,8 @@ class BrnSelectionViewState extends State { constantTop: widget.constantTop, configRowCount: widget.configRowCount, onMenuItemClick: (int menuIndex) { - if (widget.onMenuClickInterceptor != null && widget.onMenuClickInterceptor(menuIndex)) { + if (widget.onMenuClickInterceptor != null && + widget.onMenuClickInterceptor(menuIndex)) { return true; } @@ -172,9 +186,11 @@ class BrnSelectionViewState extends State { /// 1、外部设置选中的 key-value 参数。 /// 2、触发更新 UI。 /// 3、触发 _onSelectionChanged 统一回调给外部 - if (_selectionData[menuIndex].filterType == BrnSelectionFilterType.CustomHandle && + if (_selectionData[menuIndex].filterType == + BrnSelectionFilterType.CustomHandle && widget.onCustomSelectionMenuClick != null) { - widget.onCustomSelectionMenuClick(menuIndex, _selectionData[menuIndex], + widget.onCustomSelectionMenuClick( + menuIndex, _selectionData[menuIndex], (Map customParams) { _customParams.clear(); if (customParams != null) { @@ -186,10 +202,12 @@ class BrnSelectionViewState extends State { } /// 自定义 Menu 的时候,让外部设置选中的 value 进来统一更新 UI。 然后触发 _onSelectionChanged 统一回调给外部 - if (_selectionData[menuIndex].filterType == BrnSelectionFilterType.More && + if (_selectionData[menuIndex].filterType == + BrnSelectionFilterType.More && widget.onMoreSelectionMenuClick != null) { widget.onMoreSelectionMenuClick(menuIndex, ( - {bool updateData = false, List moreSelections}) { + {bool updateData = false, + List moreSelections}) { if (updateData != null && updateData) { List moreSelectionEntities = moreSelections; _selectionData[menuIndex].children = moreSelectionEntities; @@ -197,12 +215,14 @@ class BrnSelectionViewState extends State { } setState(() {}); _openMore(_selectionData[menuIndex], - onCustomFloatingLayerClick: widget.onCustomFloatingLayerClick); + onCustomFloatingLayerClick: + widget.onCustomFloatingLayerClick); }); } return false; }, - onConfirm: (BrnSelectionEntity results, int firstIndex, int secondIndex, int thirdIndex) { + onConfirm: (BrnSelectionEntity results, int firstIndex, int secondIndex, + int thirdIndex) { _onSelectionChanged(_selectionData.indexOf(results)); }, ); @@ -217,7 +237,8 @@ class BrnSelectionViewState extends State { _customParams, ({String menuTitle, bool isMenuTitleHighLight}) { /// 说明没有 menu 被选中,不需要更新。 if (menuIndex >= 0) { - _selectionData[menuIndex].isCustomTitleHighLight = isMenuTitleHighLight ?? false; + _selectionData[menuIndex].isCustomTitleHighLight = + isMenuTitleHighLight ?? false; _selectionData[menuIndex].customTitle = menuTitle; } diff --git a/lib/src/components/selection/brn_simple_selection.dart b/lib/src/components/selection/brn_simple_selection.dart index 97c8cfd2..8931d4a7 100644 --- a/lib/src/components/selection/brn_simple_selection.dart +++ b/lib/src/components/selection/brn_simple_selection.dart @@ -4,7 +4,8 @@ import 'package:bruno/src/components/selection/brn_selection_view.dart'; import 'package:bruno/src/constants/brn_constants.dart'; import 'package:flutter/material.dart'; -typedef BrnSimpleSelectionOnSelectionChanged = void Function(List selectedParams); +typedef BrnSimpleSelectionOnSelectionChanged = void Function( + List selectedParams); const String defaultMenuKey = "defaultMenuKey"; @@ -103,7 +104,8 @@ class BrnSimpleSelectionState extends State { Widget build(BuildContext context) { return BrnSelectionView( originalSelectionData: selectionEntityList, - onSelectionChanged: (menuIndex, selectedParams, customParams, setCustomTitleFunction) { + onSelectionChanged: + (menuIndex, selectedParams, customParams, setCustomTitleFunction) { if (widget.onSimpleSelectionChanged != null && selectedParams != null) { List selectedItems = List(); String valueStr = selectedParams[widget.menuKey ?? defaultMenuKey]; @@ -113,7 +115,9 @@ class BrnSimpleSelectionState extends State { ///遍历获取选中的items for (String value in values) { for (ItemEntity item in widget.items) { - if (item.value != null && value != null && item.value == value) { + if (item.value != null && + value != null && + item.value == value) { selectedItems.add(item); break; } diff --git a/lib/src/components/selection/converter/brn_selection_converter.dart b/lib/src/components/selection/converter/brn_selection_converter.dart index d47cd659..76681e69 100644 --- a/lib/src/components/selection/converter/brn_selection_converter.dart +++ b/lib/src/components/selection/converter/brn_selection_converter.dart @@ -4,14 +4,16 @@ import 'package:bruno/src/utils/brn_tools.dart'; abstract class BrnSelectionConverterDelegate { /// 统一的数据结构 转换为 用户需要的数据结构,并通过 [BrnSelectionOnSelectionChanged] 回传给用户使用。 - Map convertSelectedData(List selectedResults); + Map convertSelectedData( + List selectedResults); } class DefaultSelectionConverter implements BrnSelectionConverterDelegate { const DefaultSelectionConverter(); @override - Map convertSelectedData(List selectedResults) { + Map convertSelectedData( + List selectedResults) { return getSelectionParams(selectedResults); } } @@ -20,29 +22,34 @@ class DefaultMoreSelectionConverter implements BrnSelectionConverterDelegate { const DefaultMoreSelectionConverter(); @override - Map convertSelectedData(List selectedResults) { + Map convertSelectedData( + List selectedResults) { return getSelectionParams(selectedResults); } } -class DefaultSelectionQuickFilterConverter implements BrnSelectionConverterDelegate { +class DefaultSelectionQuickFilterConverter + implements BrnSelectionConverterDelegate { const DefaultSelectionQuickFilterConverter(); @override - Map convertSelectedData(List selectedResults) { + Map convertSelectedData( + List selectedResults) { return getSelectionParams(selectedResults); } } /// 注意,此方法仅在初始化筛选项之前调用。如果再筛选之后使用会影响筛选View 的展示以及筛选结果。 -Map getSelectionParamsWithConfigChild(List selectedResults) { +Map getSelectionParamsWithConfigChild( + List selectedResults) { Map params = Map(); if (selectedResults == null) return params; selectedResults?.forEach((f) => f.configRelationshipAndDefaultValue()); return getSelectionParams(selectedResults); } -Map getSelectionParams(List selectedResults) { +Map getSelectionParams( + List selectedResults) { Map params = Map(); if (selectedResults == null) return params; for (BrnSelectionEntity menuItemEntity in selectedResults) { @@ -68,8 +75,8 @@ Map getSelectionParams(List selectedResults) params.addAll(getCurrentSelectionEntityParams(menuItemEntity)); } else if (levelCount == 2) { params.addAll(getCurrentSelectionEntityParams(menuItemEntity)); - menuItemEntity.children?.forEach( - (firstLevelItem) => params.addAll(getCurrentSelectionEntityParams(firstLevelItem))); + menuItemEntity.children?.forEach((firstLevelItem) => + params.addAll(getCurrentSelectionEntityParams(firstLevelItem))); } else if (levelCount == 3) { params.addAll(getCurrentSelectionEntityParams(menuItemEntity)); menuItemEntity.children?.forEach((firstLevelItem) { @@ -84,7 +91,8 @@ Map getSelectionParams(List selectedResults) return params; } -Map getCurrentSelectionEntityParams(BrnSelectionEntity selectionEntity) { +Map getCurrentSelectionEntityParams( + BrnSelectionEntity selectionEntity) { Map params = Map(); String parentKey = selectionEntity.key; var selectedEntity = selectionEntity.children @@ -92,7 +100,8 @@ Map getCurrentSelectionEntityParams(BrnSelectionEntity selection ?.where((BrnSelectionEntity f) => !BrunoTools.isEmpty(f.value)) ?.map((BrnSelectionEntity f) => f.value) ?.toList(); - String selectedParams = selectedEntity == null ? "" : selectedEntity.join(","); + String selectedParams = + selectedEntity == null ? "" : selectedEntity.join(","); if (!BrunoTools.isEmpty(selectedParams) && !BrunoTools.isEmpty(parentKey)) { params[parentKey] = selectedParams; } diff --git a/lib/src/components/selection/widget/brn_flat_selection_item.dart b/lib/src/components/selection/widget/brn_flat_selection_item.dart index 9b397511..cf5d89d3 100644 --- a/lib/src/components/selection/widget/brn_flat_selection_item.dart +++ b/lib/src/components/selection/widget/brn_flat_selection_item.dart @@ -61,7 +61,8 @@ class _BrnFlatMoreSelectionState extends State { Widget build(BuildContext context) { //弹出浮层 if (widget.selectionEntity.filterType == BrnSelectionFilterType.Layer || - widget.selectionEntity.filterType == BrnSelectionFilterType.CustomLayer) { + widget.selectionEntity.filterType == + BrnSelectionFilterType.CustomLayer) { return FilterLayerTypeWidget( selectionEntity: widget.selectionEntity, onCustomFloatingLayerClick: widget.onCustomFloatingLayerClick, @@ -97,7 +98,8 @@ class _FilterCommonTypeWidget extends StatefulWidget { this.themeData}); @override - __FilterCommonTypeWidgetState createState() => __FilterCommonTypeWidgetState(); + __FilterCommonTypeWidgetState createState() => + __FilterCommonTypeWidgetState(); } class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { @@ -131,7 +133,9 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { setState(() { if (!event.filter) { //将所有tag设置为未选中 - event.rangeEntity.parent?.currentTagListForEntity()?.forEach((data) { + event.rangeEntity.parent + ?.currentTagListForEntity() + ?.forEach((data) { data.clearSelectedEntity(); }); } @@ -151,11 +155,14 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { @override Widget build(BuildContext context) { try { - _tagWidth = (widget.parentWidth - _spacing * (widget.preLineTagSize - 1) - _padding * 2) / + _tagWidth = (widget.parentWidth - + _spacing * (widget.preLineTagSize - 1) - + _padding * 2) / widget.preLineTagSize; //保留小数点后3位 - _tagWidth = double.parse( - _tagWidth.toStringAsFixed(4).substring(0, _tagWidth.toStringAsFixed(4).length - 1)); + _tagWidth = double.parse(_tagWidth + .toStringAsFixed(4) + .substring(0, _tagWidth.toStringAsFixed(4).length - 1)); _tagWidth = _tagWidth < 75 ? 75 : _tagWidth; } catch (e) { debugPrint('get tag width error'); @@ -173,7 +180,10 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { child: _buildTitleWidget(), ), Visibility( - visible: widget.selectionEntity.currentShowTagByExpanded(isExpanded).length > 0, + visible: widget.selectionEntity + .currentShowTagByExpanded(isExpanded) + .length > + 0, child: Container( padding: EdgeInsets.only(top: 12), child: _buildOptionWidgets(), @@ -297,9 +307,12 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { if (data.value == null || data.value.isEmpty) { showName = data.title; } else { - int time = int.tryParse(data.value ?? "") ?? DateTime.now().millisecondsSinceEpoch; + int time = int.tryParse(data.value ?? "") ?? + DateTime.now().millisecondsSinceEpoch; showName = DateTimeFormatter.formatDate( - DateTime.fromMillisecondsSinceEpoch(time), 'yyyy/MMMM/dd', DateTimePickerLocale.zh_cn); + DateTime.fromMillisecondsSinceEpoch(time), + 'yyyy/MMMM/dd', + DateTimePickerLocale.zh_cn); } } else { showName = data.title; @@ -331,7 +344,8 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { } void _showDatePicker(BrnSelectionEntity data) { - int time = int.tryParse(data.value ?? "") ?? DateTime.now().millisecondsSinceEpoch; + int time = + int.tryParse(data.value ?? "") ?? DateTime.now().millisecondsSinceEpoch; BrnDatePicker.showDatePicker(context, pickerMode: BrnDateTimePickerMode.date, pickerTitleConfig: BrnPickerTitleConfig.Default, @@ -366,7 +380,8 @@ class __MoreArrowState extends State<_MoreArrow> { @override Widget build(BuildContext context) { - String asset = isExpanded ? BrnAsset.ICON_UP_ARROW : BrnAsset.ICON_DOWN_ARROW; + String asset = + isExpanded ? BrnAsset.ICON_UP_ARROW : BrnAsset.ICON_DOWN_ARROW; return GestureDetector( behavior: HitTestBehavior.opaque, @@ -383,7 +398,8 @@ class __MoreArrowState extends State<_MoreArrow> { child: Row( mainAxisSize: MainAxisSize.min, children: [ - Text('更多', style: widget.themeData.moreTextStyle.generateTextStyle()), + Text('更多', + style: widget.themeData.moreTextStyle.generateTextStyle()), Container( height: 16, width: 16, @@ -471,8 +487,10 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { ? widget.rangeEntity.customMap['max']?.toString() : null; - min = int.tryParse(widget.rangeEntity?.extMap['min']?.toString() ?? "") ?? 0; - max = int.tryParse(widget.rangeEntity?.extMap['max']?.toString() ?? "") ?? 9999; + min = + int.tryParse(widget.rangeEntity?.extMap['min']?.toString() ?? "") ?? 0; + max = int.tryParse(widget.rangeEntity?.extMap['max']?.toString() ?? "") ?? + 9999; ///处理的逻辑: /// 1:将输入框的 文本写入 customMap中 @@ -524,13 +542,15 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { /// 如果是多选 则不处理 minFocusNode.addListener(() { if (minFocusNode.hasFocus) { - widget.streamController.add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); + widget.streamController + .add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); } }); maxFocusNode.addListener(() { if (maxFocusNode.hasFocus) { - widget.streamController.add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); + widget.streamController + .add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); } }); @@ -554,7 +574,8 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _buildRangeField('最小值', minController, minFocusNode, widget.width, widget.themeData), + _buildRangeField( + '最小值', minController, minFocusNode, widget.width, widget.themeData), Padding( padding: EdgeInsets.only(left: 2), ), @@ -566,7 +587,8 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { Padding( padding: EdgeInsets.only(right: 2), ), - _buildRangeField('最大值', maxController, maxFocusNode, widget.width, widget.themeData), + _buildRangeField( + '最大值', maxController, maxFocusNode, widget.width, widget.themeData), ], ); } @@ -580,7 +602,8 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { ) { return Container( decoration: BoxDecoration( - color: Color(0xFFF9F9F9), borderRadius: BorderRadius.all(Radius.circular(4.0))), + color: Color(0xFFF9F9F9), + borderRadius: BorderRadius.all(Radius.circular(4.0))), height: 32, width: width, child: Center( @@ -608,7 +631,8 @@ class FilterLayerTypeWidget extends StatefulWidget { final BrnOnCustomFloatingLayerClick onCustomFloatingLayerClick; BrnSelectionConfig themeData; - FilterLayerTypeWidget({this.selectionEntity, this.onCustomFloatingLayerClick, this.themeData}); + FilterLayerTypeWidget( + {this.selectionEntity, this.onCustomFloatingLayerClick, this.themeData}); @override _FilterLayerTypeWidgetState createState() => _FilterLayerTypeWidgetState(); @@ -632,7 +656,8 @@ class _FilterLayerTypeWidgetState extends State { padding: const EdgeInsets.only(left: 20, right: 20, top: 6), child: GestureDetector( onTap: () { - if (widget.selectionEntity.filterType == BrnSelectionFilterType.Layer) { + if (widget.selectionEntity.filterType == + BrnSelectionFilterType.Layer) { Navigator.of(context) .push(PageRouteBuilder( opaque: false, @@ -645,19 +670,22 @@ class _FilterLayerTypeWidgetState extends State { .then((data) { updateContent(); }); - } else if (widget.selectionEntity.filterType == BrnSelectionFilterType.CustomLayer) { + } else if (widget.selectionEntity.filterType == + BrnSelectionFilterType.CustomLayer) { if (widget.onCustomFloatingLayerClick != null) { int entityIndex = -1; if (widget.selectionEntity.parent != null && widget.selectionEntity.parent.children != null) { - entityIndex = - widget.selectionEntity.parent.children.indexOf(widget.selectionEntity); + entityIndex = widget.selectionEntity.parent.children + .indexOf(widget.selectionEntity); } - widget.onCustomFloatingLayerClick(entityIndex, widget.selectionEntity, + widget.onCustomFloatingLayerClick( + entityIndex, widget.selectionEntity, (List customFloatingLayerParams) { widget.selectionEntity.children?.clear(); widget.selectionEntity.children = []; - widget.selectionEntity.children.addAll(customFloatingLayerParams); + widget.selectionEntity.children + .addAll(customFloatingLayerParams); widget.selectionEntity.configDefaultValue(); setState(() {}); }); @@ -671,7 +699,8 @@ class _FilterLayerTypeWidgetState extends State { child: Text(isEmptyCondition() ? '请选择' : getCondition(), style: isEmptyCondition() ? widget.themeData.hintTextStyle.generateTextStyle() - : widget.themeData.optionTextStyle.generateTextStyle()), + : widget.themeData.optionTextStyle + .generateTextStyle()), ), Container( height: 16, @@ -699,7 +728,8 @@ class _FilterLayerTypeWidgetState extends State { String getCondition() { String tmp = ""; //返回所有选中的 - List selectedList = widget.selectionEntity.selectedList(); + List selectedList = + widget.selectionEntity.selectedList(); //判断步骤: //第一步:取出来所有选中的: 房山 不限 小白楼 西城 不限 diff --git a/lib/src/components/selection/widget/brn_layer_more_selection_page.dart b/lib/src/components/selection/widget/brn_layer_more_selection_page.dart index 9cd493ed..06ec0098 100644 --- a/lib/src/components/selection/widget/brn_layer_more_selection_page.dart +++ b/lib/src/components/selection/widget/brn_layer_more_selection_page.dart @@ -23,7 +23,8 @@ class BrnLayerMoreSelectionPage extends StatefulWidget { BrnLayerMoreSelectionPage({this.entityData, this.themeData}); @override - _BrnLayerMoreSelectionPageState createState() => _BrnLayerMoreSelectionPageState(); + _BrnLayerMoreSelectionPageState createState() => + _BrnLayerMoreSelectionPageState(); } class _BrnLayerMoreSelectionPageState extends State @@ -49,7 +50,8 @@ class _BrnLayerMoreSelectionPageState extends State duration: const Duration(milliseconds: 300), vsync: this, ); - animation = Tween(end: Offset.zero, begin: Offset(1.0, 0.0)).animate(_controller); + animation = + Tween(end: Offset.zero, begin: Offset(1.0, 0.0)).animate(_controller); _controller.forward(); currentIndex = 0; @@ -128,7 +130,10 @@ class _BrnLayerMoreSelectionPageState extends State leading: IconButton( icon: Icon( Icons.arrow_back, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, ), onPressed: () { //将选中的筛选项返回 @@ -143,7 +148,10 @@ class _BrnLayerMoreSelectionPageState extends State title: Text( '选择${widget.entityData.title}', style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, fontSize: 16, fontWeight: FontWeight.w600), ), @@ -225,7 +233,8 @@ class _BrnLayerMoreSelectionPageState extends State }); if (!this.firstList[index].isSelected) { - if (!BrnSelectionUtil.checkMaxSelectionCount(firstList[index])) { + if (!BrnSelectionUtil.checkMaxSelectionCount( + firstList[index])) { BrnToast.show('您选择的筛选条件数量已达上限', context); setState(() {}); return; @@ -291,10 +300,12 @@ class _BrnLayerMoreSelectionPageState extends State Widget _buildLeftItem(int index) { //如果房山 被选中了或者房山处于正在选择的状态 则加粗 - TextStyle textStyle = widget.themeData.flayNormalTextStyle.generateTextStyle(); + TextStyle textStyle = + widget.themeData.flayNormalTextStyle.generateTextStyle(); if (index == currentIndex) { textStyle = widget.themeData.flatSelectedTextStyle.generateTextStyle(); - } else if ((firstList[index].isSelected) && firstList[index].selectedList().isNotEmpty) { + } else if ((firstList[index].isSelected) && + firstList[index].selectedList().isNotEmpty) { textStyle = widget.themeData.flatBoldTextStyle.generateTextStyle(); } @@ -314,7 +325,8 @@ class _BrnLayerMoreSelectionPageState extends State bool containsCheckChildren = false; if (firstList[index].children.isNotEmpty) { - containsCheckChildren = firstList[index].children[0].hasCheckBoxBrother(); + containsCheckChildren = + firstList[index].children[0].hasCheckBoxBrother(); } if (containsCheck && containsCheckChildren) { name += '(${list.length})'; @@ -336,9 +348,10 @@ class _BrnLayerMoreSelectionPageState extends State } Widget _buildRightItem(int index) { - bool isSingle = - (currentFirstEntity.children[index].filterType == BrnSelectionFilterType.Radio) || - (currentFirstEntity.children[index].filterType == BrnSelectionFilterType.UnLimit); + bool isSingle = (currentFirstEntity.children[index].filterType == + BrnSelectionFilterType.Radio) || + (currentFirstEntity.children[index].filterType == + BrnSelectionFilterType.UnLimit); return GestureDetector( onTap: () { diff --git a/lib/src/components/selection/widget/brn_selection_animate_widget.dart b/lib/src/components/selection/widget/brn_selection_animate_widget.dart index 7ca09e0e..1683a157 100644 --- a/lib/src/components/selection/widget/brn_selection_animate_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_animate_widget.dart @@ -9,14 +9,19 @@ class BrnSelectionAnimationWidget extends StatefulWidget { final int animationMilliseconds; const BrnSelectionAnimationWidget( - {Key key, @required this.controller, @required this.view, this.animationMilliseconds = 100}) + {Key key, + @required this.controller, + @required this.view, + this.animationMilliseconds = 100}) : super(key: key); @override - _BrnSelectionAnimationWidgetState createState() => _BrnSelectionAnimationWidgetState(); + _BrnSelectionAnimationWidgetState createState() => + _BrnSelectionAnimationWidgetState(); } -class _BrnSelectionAnimationWidgetState extends State +class _BrnSelectionAnimationWidgetState + extends State with SingleTickerProviderStateMixin { bool _isControllerDisposed = false; Animation _animation; @@ -28,7 +33,8 @@ class _BrnSelectionAnimationWidgetState extends State f.isSelected && !f.isUnLimit()).length; + if ((BrnSelectionUtil.getTotalLevel(item) < 3 || !isFirstLevel) && + item.children != null) { + int count = + item.children.where((f) => f.isSelected && !f.isUnLimit()).length; if (count > 1) { return '($count)'; } else if (count == 1 && item.hasCheckBoxBrother()) { return '($count)'; } else { - var unLimited = item.children.where((f) => f.isSelected && f.isUnLimit()).toList(); + var unLimited = + item.children.where((f) => f.isSelected && f.isUnLimit()).toList(); if (unLimited.length > 0) { return '(全部)'; } diff --git a/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart b/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart index c103b80a..27d5ea03 100644 --- a/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart @@ -54,29 +54,34 @@ class BrnSelectionDateRangeItemWidget extends StatefulWidget { this.onTapped, this.themeData}); - _BrnSelectionDateRangeItemWidgetState createState() => _BrnSelectionDateRangeItemWidgetState(); + _BrnSelectionDateRangeItemWidgetState createState() => + _BrnSelectionDateRangeItemWidgetState(); } -class _BrnSelectionDateRangeItemWidgetState extends State { - BrnSelectionDatePickerController _datePickerController = BrnSelectionDatePickerController(); +class _BrnSelectionDateRangeItemWidgetState + extends State { + BrnSelectionDatePickerController _datePickerController = + BrnSelectionDatePickerController(); @override void initState() { var minDateTime; if (widget.item.customMap != null && widget.item.customMap['min'] != null) { - minDateTime = DateTimeFormatter.convertIntValueToDateTime(widget.item?.customMap['min']); + minDateTime = DateTimeFormatter.convertIntValueToDateTime( + widget.item?.customMap['min']); } var maxDateTime; if (widget.item.customMap != null && widget.item.customMap['max'] != null) { - maxDateTime = DateTimeFormatter.convertIntValueToDateTime(widget.item?.customMap['max']); + maxDateTime = DateTimeFormatter.convertIntValueToDateTime( + widget.item?.customMap['max']); } widget.minTextEditingController.text = minDateTime != null - ? DateTimeFormatter.formatDate( - minDateTime, widget.dateFormat ?? 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn) + ? DateTimeFormatter.formatDate(minDateTime, + widget.dateFormat ?? 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn) : ''; widget.maxTextEditingController.text = maxDateTime != null - ? DateTimeFormatter.formatDate( - maxDateTime, widget.dateFormat ?? 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn) + ? DateTimeFormatter.formatDate(maxDateTime, + widget.dateFormat ?? 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn) : ''; super.initState(); } @@ -96,7 +101,8 @@ class _BrnSelectionDateRangeItemWidgetState extends State selectedIndex) { widget.item.isSelected = true; - String selectedDateStr = DateTimeFormatter.formatDate( - selectedDate, widget.dateFormat ?? 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn); + String selectedDateStr = DateTimeFormatter.formatDate(selectedDate, + widget.dateFormat ?? 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn); if (isMax) { widget.maxTextEditingController.text = selectedDateStr; } else { @@ -211,7 +222,8 @@ class _BrnSelectionDateRangeItemWidgetState extends State { - final int maxShowCount = 6; List _firstList = List(); @@ -94,7 +94,8 @@ class _BrnSelectionGroupViewState extends State { widgetList.add(_listWidget()); // TODO 判断是否添加 Bottom if (_firstList != null) { - if (totalLevel == 1 && widget.entity.filterType == BrnSelectionFilterType.Radio) { + if (totalLevel == 1 && + widget.entity.filterType == BrnSelectionFilterType.Radio) { } else { widgetList.add(_bottomWidget()); } @@ -118,9 +119,11 @@ class _BrnSelectionGroupViewState extends State { maxHeight: widget.maxContentHeight, flex: getFlexByListIndex(1), focusedIndex: _firstIndex, - singleListItemSelect: (int listIndex, int index, BrnSelectionEntity entity) { + singleListItemSelect: + (int listIndex, int index, BrnSelectionEntity entity) { _setFirstIndex(index); - if (totalLevel == 1 && widget.entity.filterType == BrnSelectionFilterType.Radio) { + if (totalLevel == 1 && + widget.entity.filterType == BrnSelectionFilterType.Radio) { _confirmButtonClickEvent(); } })); @@ -135,7 +138,8 @@ class _BrnSelectionGroupViewState extends State { selectedBackgroundColor: getSelectBgByListIndex(1), flex: getFlexByListIndex(1), focusedIndex: _firstIndex, - singleListItemSelect: (int listIndex, int index, BrnSelectionEntity entity) { + singleListItemSelect: + (int listIndex, int index, BrnSelectionEntity entity) { _setFirstIndex(index); })); @@ -146,7 +150,8 @@ class _BrnSelectionGroupViewState extends State { selectedBackgroundColor: getSelectBgByListIndex(2), flex: getFlexByListIndex(2), focusedIndex: _secondIndex, - singleListItemSelect: (int listIndex, int index, BrnSelectionEntity entity) { + singleListItemSelect: + (int listIndex, int index, BrnSelectionEntity entity) { _setSecondIndex(index); })); } else if (!BrunoTools.isEmpty(_firstList) && @@ -160,7 +165,8 @@ class _BrnSelectionGroupViewState extends State { selectedBackgroundColor: getSelectBgByListIndex(1), flex: getFlexByListIndex(1), focusedIndex: _firstIndex, - singleListItemSelect: (int listIndex, int index, BrnSelectionEntity entity) { + singleListItemSelect: + (int listIndex, int index, BrnSelectionEntity entity) { _setFirstIndex(index); })); @@ -171,7 +177,8 @@ class _BrnSelectionGroupViewState extends State { selectedBackgroundColor: getSelectBgByListIndex(2), flex: getFlexByListIndex(2), focusedIndex: _secondIndex, - singleListItemSelect: (int listIndex, int index, BrnSelectionEntity entity) { + singleListItemSelect: + (int listIndex, int index, BrnSelectionEntity entity) { _setSecondIndex(index); })); widgets.add(BrnSelectionSingleListWidget( @@ -181,7 +188,8 @@ class _BrnSelectionGroupViewState extends State { selectedBackgroundColor: getSelectBgByListIndex(3), flex: getFlexByListIndex(3), focusedIndex: _thirdIndex, - singleListItemSelect: (int listIndex, int index, BrnSelectionEntity entity) { + singleListItemSelect: + (int listIndex, int index, BrnSelectionEntity entity) { if (entity.isSelected) { _thirdIndex = index; } else { @@ -250,11 +258,13 @@ class _BrnSelectionGroupViewState extends State { Container( height: 24, width: 24, - child: BrunoTools.getAssetImage(BrnAsset.iconSelectionReset), + child: BrunoTools.getAssetImage( + BrnAsset.iconSelectionReset), ), Text( "重置", - style: widget.themeData.resetTextStyle.generateTextStyle(), + style: + widget.themeData.resetTextStyle.generateTextStyle(), ) ], ), @@ -285,7 +295,8 @@ class _BrnSelectionGroupViewState extends State { _processFilterDataOnConfirm(); if (widget.onSelectionConfirm != null) { //更多和无tips等外部调用的多选需要传递此值selectedLastColumnArray - widget.onSelectionConfirm(widget.entity, _firstIndex, _secondIndex, _thirdIndex); + widget.onSelectionConfirm( + widget.entity, _firstIndex, _secondIndex, _thirdIndex); } } @@ -404,7 +415,8 @@ class _BrnSelectionGroupViewState extends State { _firstIndex = firstIndex; _secondIndex = -1; if (widget.entity.children.length > _firstIndex) { - List seconds = widget.entity.children[_firstIndex].children; + List seconds = + widget.entity.children[_firstIndex].children; if (seconds != null) { _secondIndex = getInitialSelectIndex(seconds); @@ -421,7 +433,8 @@ class _BrnSelectionGroupViewState extends State { void _setSecondIndex(int secondIndex) { _secondIndex = secondIndex; _thirdIndex = -1; - List seconds = widget.entity.children[_firstIndex].children; + List seconds = + widget.entity.children[_firstIndex].children; if (seconds.length > _secondIndex) { List thirds = seconds[_secondIndex].children; if (thirds != null) { @@ -560,10 +573,13 @@ class _BrnSelectionGroupViewState extends State { } _processSelectedStatus(BrnSelectionEntity entity) { - if (entity != null && entity.children != null && entity.children.length > 0) { + if (entity != null && + entity.children != null && + entity.children.length > 0) { entity.children.forEach((f) => _processSelectedStatus(f)); if (entity.hasCheckBoxBrother()) { - entity.isSelected = entity.children.where((_) => _.isSelected).length > 0; + entity.isSelected = + entity.children.where((_) => _.isSelected).length > 0; } } } diff --git a/lib/src/components/selection/widget/brn_selection_menu_item_widget.dart b/lib/src/components/selection/widget/brn_selection_menu_item_widget.dart index 29c4d56a..c9703753 100644 --- a/lib/src/components/selection/widget/brn_selection_menu_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_menu_item_widget.dart @@ -53,14 +53,17 @@ class BrnSelectionMenuItemWidget extends StatelessWidget { padding: EdgeInsets.only(left: 4), child: isHighLight ? (active - ? BrunoTools.getAssetImageWithBandColor(BrnAsset.ICON_ARROWUP_SELECT, + ? BrunoTools.getAssetImageWithBandColor( + BrnAsset.ICON_ARROWUP_SELECT, configId: themeData.configId) - : BrunoTools.getAssetImageWithBandColor(BrnAsset.ICON_ARROWDOWN_SELECT)) + : BrunoTools.getAssetImageWithBandColor( + BrnAsset.ICON_ARROWDOWN_SELECT)) : (active - ? BrunoTools.getAssetImageWithBandColor(BrnAsset.ICON_ARROWUP_SELECT, + ? BrunoTools.getAssetImageWithBandColor( + BrnAsset.ICON_ARROWUP_SELECT, configId: themeData.configId) - : BrunoTools.getAssetImage(BrnAsset.ICON_ARROWDOWN_UNSELECT)) - ) + : BrunoTools.getAssetImage( + BrnAsset.ICON_ARROWDOWN_UNSELECT))) ], ), ), diff --git a/lib/src/components/selection/widget/brn_selection_menu_widget.dart b/lib/src/components/selection/widget/brn_selection_menu_widget.dart index 88270ab7..fb3b6b66 100644 --- a/lib/src/components/selection/widget/brn_selection_menu_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_menu_widget.dart @@ -17,8 +17,8 @@ import 'package:flutter/material.dart'; typedef bool BrnOnMenuItemClick(int index); -typedef void BrnOnRangeSelectionConfirm( - BrnSelectionEntity results, int firstIndex, int secondIndex, int thirdIndex); +typedef void BrnOnRangeSelectionConfirm(BrnSelectionEntity results, + int firstIndex, int secondIndex, int thirdIndex); class BrnSelectionMenuWidget extends StatefulWidget { final List data; @@ -62,7 +62,8 @@ class _BrnSelectionMenuWidgetState extends State { List titles = List(); List menuItemActiveState = List(); List menuItemHighlightState = List(); - BrnSelectionListViewController listViewController = BrnSelectionListViewController(); + BrnSelectionListViewController listViewController = + BrnSelectionListViewController(); ScrollController _scrollController; StreamSubscription _refreshTitleSubscription; @@ -72,14 +73,16 @@ class _BrnSelectionMenuWidgetState extends State { @override void initState() { super.initState(); - _refreshTitleSubscription = - EventBus.instance.on().listen((RefreshMenuTitleEvent event) { + _refreshTitleSubscription = EventBus.instance + .on() + .listen((RefreshMenuTitleEvent event) { _needRefreshTitle = true; setState(() {}); }); - _closeSelectionPopupWindowSubscription = - EventBus.instance.on().listen((CloseSelectionViewEvent event) { + _closeSelectionPopupWindowSubscription = EventBus.instance + .on() + .listen((CloseSelectionViewEvent event) { _closeSelectionPopupWindow(); }); @@ -132,7 +135,9 @@ class _BrnSelectionMenuWidgetState extends State { /// 根据【Filter组】 创建 widget。 void _createEntry(BrnSelectionEntity entity) { - var content = isRange(entity) ? _createRangeView(entity) : _createSelectionListView(entity); + var content = isRange(entity) + ? _createRangeView(entity) + : _createSelectionListView(entity); OverlayEntry entry = OverlayEntry(builder: (context) { return GestureDetector( onTap: () { @@ -144,7 +149,8 @@ class _BrnSelectionMenuWidgetState extends State { ), child: Stack( children: [ - BrnSelectionAnimationWidget(controller: listViewController, view: content) + BrnSelectionAnimationWidget( + controller: listViewController, view: content) ], ), ), @@ -159,7 +165,9 @@ class _BrnSelectionMenuWidgetState extends State { Widget build(BuildContext context) { return Container( height: widget.height, - width: (widget.width != null) ? widget.width : MediaQuery.of(context).size.width, + width: (widget.width != null) + ? widget.width + : MediaQuery.of(context).size.width, color: Colors.white, child: Column( mainAxisAlignment: MainAxisAlignment.start, @@ -202,7 +210,8 @@ class _BrnSelectionMenuWidgetState extends State { title: titles[index], themeData: widget.themeData, active: menuItemActiveState[index], - isHighLight: menuItemActiveState[index] || menuItemHighlightState[index], + isHighLight: + menuItemActiveState[index] || menuItemHighlightState[index], itemClickFunction: () { if (widget.onMenuItemClick != null) { /// 拦截 menuItem 点击。 @@ -212,10 +221,13 @@ class _BrnSelectionMenuWidgetState extends State { } final RenderBox dropDownItemRenderBox = context.findRenderObject(); - var position = dropDownItemRenderBox.localToGlobal(Offset.zero, ancestor: null); + var position = + dropDownItemRenderBox.localToGlobal(Offset.zero, ancestor: null); var size = dropDownItemRenderBox.size; - listViewController.listViewTop = size.height + (widget.constantTop ?? position.dy); - if (listViewController.isShow && listViewController.menuIndex != index) { + listViewController.listViewTop = + size.height + (widget.constantTop ?? position.dy); + if (listViewController.isShow && + listViewController.menuIndex != index) { listViewController.hide(); listViewController.entry?.remove(); listViewController.entry = null; @@ -228,12 +240,14 @@ class _BrnSelectionMenuWidgetState extends State { } else { /// 点击不是 More、自定义类型,则直接展开。 if (widget.data[index].filterType != BrnSelectionFilterType.More && - widget.data[index].filterType != BrnSelectionFilterType.CustomHandle) { + widget.data[index].filterType != + BrnSelectionFilterType.CustomHandle) { /// 创建 筛选组件的的入口 _createEntry(widget.data[index]); Overlay.of(widget.context).insert(listViewController.entry); listViewController.show(index); - } else if (widget.data[index].filterType == BrnSelectionFilterType.CustomHandle) { + } else if (widget.data[index].filterType == + BrnSelectionFilterType.CustomHandle) { /// 记录自定义筛选 menu 的点击状态,当点击自定义的 menu 时,menu 文案默认高亮。 listViewController.show(index); refreshSelectionMenuTitle(index, widget.data[index]); @@ -276,7 +290,8 @@ class _BrnSelectionMenuWidgetState extends State { return true; } var totalLevel = BrnSelectionUtil.getTotalLevel(entity); - if (totalLevel == 1 && entity.filterType == BrnSelectionFilterType.Checkbox) { + if (totalLevel == 1 && + entity.filterType == BrnSelectionFilterType.Checkbox) { return true; } } @@ -286,13 +301,15 @@ class _BrnSelectionMenuWidgetState extends State { Widget _createRangeView(BrnSelectionEntity entity) { int rowCount; if (widget.configRowCount != null) { - rowCount = widget.configRowCount(widget.data.indexOf(entity), entity) ?? rowCount; + rowCount = widget.configRowCount(widget.data.indexOf(entity), entity) ?? + rowCount; } return BrnRangeSelectionGroupWidget( entity: entity, marginTop: listViewController.listViewTop, - maxContentHeight: - DESIGN_SELECTION_HEIGHT / DESIGN_SCREEN_HEIGHT * MediaQuery.of(context).size.height, + maxContentHeight: DESIGN_SELECTION_HEIGHT / + DESIGN_SCREEN_HEIGHT * + MediaQuery.of(context).size.height, // UI 给出的内容高度比例 248:812 themeData: widget.themeData, rowount: rowCount, @@ -307,8 +324,8 @@ class _BrnSelectionMenuWidgetState extends State { listViewController.entry = null; }); }, - onSelectionConfirm: - (BrnSelectionEntity result, int firstIndex, int secondIndex, int thirdIndex) { + onSelectionConfirm: (BrnSelectionEntity result, int firstIndex, + int secondIndex, int thirdIndex) { setState(() { onConfirmSelect(entity, result, firstIndex, secondIndex, thirdIndex); }); @@ -320,8 +337,9 @@ class _BrnSelectionMenuWidgetState extends State { /// 顶层筛选 Tab return BrnListSelectionGroupWidget( entity: entity, - maxContentHeight: - DESIGN_SELECTION_HEIGHT / DESIGN_SCREEN_HEIGHT * MediaQuery.of(context).size.height, + maxContentHeight: DESIGN_SELECTION_HEIGHT / + DESIGN_SCREEN_HEIGHT * + MediaQuery.of(context).size.height, themeData: widget.themeData, // UI 给出的内容高度比例 248:812 bgClickFunction: () { @@ -335,8 +353,8 @@ class _BrnSelectionMenuWidgetState extends State { listViewController.entry = null; }); }, - onSelectionConfirm: - (BrnSelectionEntity result, int firstIndex, int secondIndex, int thirdIndex) { + onSelectionConfirm: (BrnSelectionEntity result, int firstIndex, + int secondIndex, int thirdIndex) { setState(() { onConfirmSelect(entity, result, firstIndex, secondIndex, thirdIndex); }); @@ -344,8 +362,8 @@ class _BrnSelectionMenuWidgetState extends State { ); } - void onConfirmSelect(BrnSelectionEntity entity, BrnSelectionEntity result, int firstIndex, - int secondIndex, int thirdIndex) { + void onConfirmSelect(BrnSelectionEntity entity, BrnSelectionEntity result, + int firstIndex, int secondIndex, int thirdIndex) { if (listViewController.menuIndex < titles.length) { if (widget.onConfirm != null) { widget.onConfirm(result, firstIndex, secondIndex, thirdIndex); @@ -374,16 +392,19 @@ class _BrnSelectionMenuWidgetState extends State { String getTitle(BrnSelectionEntity entity) { String title; if (entity != null) { - List firstColumn = BrnSelectionUtil.currentSelectListForEntity(entity); + List firstColumn = + BrnSelectionUtil.currentSelectListForEntity(entity); List secondColumn = List(); List thirdColumn = List(); if (firstColumn != null && firstColumn.length > 0) { for (BrnSelectionEntity firstEntity in firstColumn) { if (firstEntity != null) { - secondColumn.addAll(BrnSelectionUtil.currentSelectListForEntity(firstEntity)); + secondColumn.addAll( + BrnSelectionUtil.currentSelectListForEntity(firstEntity)); if (secondColumn != null && secondColumn.length > 0) { for (BrnSelectionEntity secondEntity in secondColumn) { - thirdColumn.addAll(BrnSelectionUtil.currentSelectListForEntity(secondEntity)); + thirdColumn.addAll( + BrnSelectionUtil.currentSelectListForEntity(secondEntity)); } } } @@ -399,7 +420,8 @@ class _BrnSelectionMenuWidgetState extends State { } else if (firstColumn[0].filterType == BrnSelectionFilterType.Range || firstColumn[0].filterType == BrnSelectionFilterType.Date || firstColumn[0].filterType == BrnSelectionFilterType.DateRange || - firstColumn[0].filterType == BrnSelectionFilterType.DateRangeCalendar) { + firstColumn[0].filterType == + BrnSelectionFilterType.DateRangeCalendar) { title = getDateAndRangeTitle(firstColumn, entity); } else { if (secondColumn.length == 0 || secondColumn.length > 1) { @@ -408,10 +430,13 @@ class _BrnSelectionMenuWidgetState extends State { /// 第二列选中了一个,为【不限】类型,使用上一级别的名字展示。 if (secondColumn[0].isUnLimit()) { title = firstColumn[0].title; - } else if (secondColumn[0].filterType == BrnSelectionFilterType.Range || + } else if (secondColumn[0].filterType == + BrnSelectionFilterType.Range || secondColumn[0].filterType == BrnSelectionFilterType.Date || - secondColumn[0].filterType == BrnSelectionFilterType.DateRange || - secondColumn[0].filterType == BrnSelectionFilterType.DateRangeCalendar) { + secondColumn[0].filterType == + BrnSelectionFilterType.DateRange || + secondColumn[0].filterType == + BrnSelectionFilterType.DateRangeCalendar) { title = getDateAndRangeTitle(secondColumn, firstColumn[0]); } else { if (thirdColumn.length == 0 || thirdColumn.length > 1) { @@ -420,10 +445,13 @@ class _BrnSelectionMenuWidgetState extends State { /// 第三列选中了一个,为【不限】类型,使用上一级别的名字展示。 if (thirdColumn[0].isUnLimit()) { title = secondColumn[0].title; - } else if (thirdColumn[0].filterType == BrnSelectionFilterType.Range || + } else if (thirdColumn[0].filterType == + BrnSelectionFilterType.Range || thirdColumn[0].filterType == BrnSelectionFilterType.Date || - thirdColumn[0].filterType == BrnSelectionFilterType.DateRange || - thirdColumn[0].filterType == BrnSelectionFilterType.DateRangeCalendar) { + thirdColumn[0].filterType == + BrnSelectionFilterType.DateRange || + thirdColumn[0].filterType == + BrnSelectionFilterType.DateRangeCalendar) { title = getDateAndRangeTitle(thirdColumn, secondColumn[0]); } else { title = thirdColumn[0].title; @@ -433,13 +461,15 @@ class _BrnSelectionMenuWidgetState extends State { } } } - String joinTitle = getJoinTitle(entity, firstColumn, secondColumn, thirdColumn); + String joinTitle = + getJoinTitle(entity, firstColumn, secondColumn, thirdColumn); title = BrunoTools.isEmpty(joinTitle) ? title : joinTitle; } return title; } - String getDateAndRangeTitle(List list, BrnSelectionEntity entity) { + String getDateAndRangeTitle( + List list, BrnSelectionEntity entity) { String title = ""; if (!BrunoTools.isEmpty(list[0].customMap)) { if (list[0].filterType == BrnSelectionFilterType.Range) { @@ -485,14 +515,19 @@ class _BrnSelectionMenuWidgetState extends State { String title = ""; int msDateTime = int.tryParse(list[0].value ?? ""); title = msDateTime != null - ? DateTimeFormatter.formatDate(DateTime.fromMillisecondsSinceEpoch(msDateTime), - 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn) + ? DateTimeFormatter.formatDate( + DateTime.fromMillisecondsSinceEpoch(msDateTime), + 'yyyy年MM月dd日', + DateTimePickerLocale.zh_cn) : list[0].title; return title; } - String getJoinTitle(BrnSelectionEntity entity, List firstColumn, - List secondColumn, List thirdColumn) { + String getJoinTitle( + BrnSelectionEntity entity, + List firstColumn, + List secondColumn, + List thirdColumn) { String title = ""; if (entity.canJoinTitle) { if (firstColumn.length == 1) { diff --git a/lib/src/components/selection/widget/brn_selection_more_item_widget.dart b/lib/src/components/selection/widget/brn_selection_more_item_widget.dart index c3b47e40..7bd115ef 100644 --- a/lib/src/components/selection/widget/brn_selection_more_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_more_item_widget.dart @@ -47,7 +47,8 @@ class _BrnMoreSelectionWidgetState extends State { Widget build(BuildContext context) { //弹出浮层 if (widget.selectionEntity.filterType == BrnSelectionFilterType.Layer || - widget.selectionEntity.filterType == BrnSelectionFilterType.CustomLayer) { + widget.selectionEntity.filterType == + BrnSelectionFilterType.CustomLayer) { return FilterLayerTypeWidget( selectionEntity: widget.selectionEntity, onCustomFloatingLayerClick: widget.onCustomFloatingLayerClick, @@ -71,10 +72,12 @@ class _FilterCommonTypeWidget extends StatefulWidget { final StreamController clearController; BrnSelectionConfig themeData; - _FilterCommonTypeWidget({this.selectionEntity, this.clearController, this.themeData}); + _FilterCommonTypeWidget( + {this.selectionEntity, this.clearController, this.themeData}); @override - __FilterCommonTypeWidgetState createState() => __FilterCommonTypeWidgetState(); + __FilterCommonTypeWidgetState createState() => + __FilterCommonTypeWidgetState(); } class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { @@ -99,7 +102,9 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { setState(() { if (!event.filter) { //将所有tag设置为未选中 - event.rangeEntity.parent?.currentTagListForEntity()?.forEach((data) { + event.rangeEntity.parent + ?.currentTagListForEntity() + ?.forEach((data) { data.clearSelectedEntity(); }); } @@ -126,14 +131,18 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: EdgeInsets.only(top: 20, right: _isVisibleMore() ? 40 : 0), + padding: + EdgeInsets.only(top: 20, right: _isVisibleMore() ? 40 : 0), child: _buildTitleWidget(), ), //自定义输入框 _buildRangeWidget(), //标签的筛选条件 Visibility( - visible: widget.selectionEntity.currentShowTagByExpanded(isExpanded).length > 0, + visible: widget.selectionEntity + .currentShowTagByExpanded(isExpanded) + .length > + 0, child: Padding( padding: EdgeInsets.only(top: 12), child: _buildSelectionTag(), @@ -250,9 +259,12 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { if (data.value == null || data.value.isEmpty) { showName = data.title; } else { - int time = int.tryParse(data.value ?? "") ?? DateTime.now().millisecondsSinceEpoch; + int time = int.tryParse(data.value ?? "") ?? + DateTime.now().millisecondsSinceEpoch; showName = DateTimeFormatter.formatDate( - DateTime.fromMillisecondsSinceEpoch(time), 'yyyy/MMMM/dd', DateTimePickerLocale.zh_cn); + DateTime.fromMillisecondsSinceEpoch(time), + 'yyyy/MMMM/dd', + DateTimePickerLocale.zh_cn); } } else { showName = data.title; @@ -283,7 +295,8 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { } void _showDatePicker(BrnSelectionEntity data) { - int time = int.tryParse(data.value ?? "") ?? DateTime.now().millisecondsSinceEpoch; + int time = + int.tryParse(data.value ?? "") ?? DateTime.now().millisecondsSinceEpoch; BrnDatePicker.showDatePicker(context, pickerMode: BrnDateTimePickerMode.date, pickerTitleConfig: BrnPickerTitleConfig.Default, @@ -319,7 +332,8 @@ class __MoreArrowState extends State<_MoreArrow> { @override Widget build(BuildContext context) { - String asset = isExpanded ? BrnAsset.ICON_UP_ARROW : BrnAsset.ICON_DOWN_ARROW; + String asset = + isExpanded ? BrnAsset.ICON_UP_ARROW : BrnAsset.ICON_DOWN_ARROW; return GestureDetector( behavior: HitTestBehavior.opaque, @@ -370,7 +384,11 @@ class _MoreRangeWidget extends StatefulWidget { BrnSelectionConfig themeData; _MoreRangeWidget( - {this.streamController, this.rangeEntity, this.clearController, this.themeData, Key key}) + {this.streamController, + this.rangeEntity, + this.clearController, + this.themeData, + Key key}) : super(key: key); @override @@ -420,8 +438,10 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { ? widget.rangeEntity.customMap['max']?.toString() : null; - min = int.tryParse(widget.rangeEntity?.extMap['min']?.toString() ?? "") ?? 0; - max = int.tryParse(widget.rangeEntity?.extMap['max']?.toString() ?? "") ?? 9999; + min = + int.tryParse(widget.rangeEntity?.extMap['min']?.toString() ?? "") ?? 0; + max = int.tryParse(widget.rangeEntity?.extMap['max']?.toString() ?? "") ?? + 9999; ///处理的逻辑: /// 1:将输入框的 文本写入 customMap中 @@ -460,13 +480,15 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { /// 如果是多选 则不处理 minFocusNode.addListener(() { if (minFocusNode.hasFocus) { - widget.streamController.add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); + widget.streamController + .add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); } }); maxFocusNode.addListener(() { if (maxFocusNode.hasFocus) { - widget.streamController.add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); + widget.streamController + .add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); } }); @@ -497,14 +519,16 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { themeData: widget.themeData, onTapped: () { //点击选择框通知标签清空 - widget.streamController.add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); + widget.streamController.add( + InputEvent(filter: false, rangeEntity: widget.rangeEntity)); }); } else { return Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( - child: _buildRangeField('最小值', minController, minFocusNode, widget.themeData), + child: _buildRangeField( + '最小值', minController, minFocusNode, widget.themeData), ), Container( // height: 38, @@ -516,7 +540,8 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { ), ), Expanded( - child: _buildRangeField('最大值', maxController, maxFocusNode, widget.themeData), + child: _buildRangeField( + '最大值', maxController, maxFocusNode, widget.themeData), ), ], ); @@ -535,20 +560,27 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { focusNode: focusNode, textAlign: TextAlign.center, controller: textEditingController, - cursorColor: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + cursorColor: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, inputFormatters: [WhitelistingTextInputFormatter.digitsOnly], style: widget.themeData.inputTextStyle.generateTextStyle(), decoration: InputDecoration( hintText: hint, hintStyle: widget.themeData.hintTextStyle.generateTextStyle(), enabledBorder: UnderlineInputBorder( - borderRadius: BorderRadius.circular(widget.themeData.tagRadius), - borderSide: - BorderSide(width: 1, color: widget.themeData.commonConfig.borderColorBase)), + borderRadius: + BorderRadius.circular(widget.themeData.tagRadius), + borderSide: BorderSide( + width: 1, + color: widget.themeData.commonConfig.borderColorBase)), focusedBorder: UnderlineInputBorder( - borderRadius: BorderRadius.circular(widget.themeData.tagRadius), - borderSide: - BorderSide(width: 1, color: widget.themeData.commonConfig.borderColorBase))), + borderRadius: + BorderRadius.circular(widget.themeData.tagRadius), + borderSide: BorderSide( + width: 1, + color: widget.themeData.commonConfig.borderColorBase))), ), ), ); @@ -563,7 +595,8 @@ class FilterLayerTypeWidget extends StatefulWidget { final BrnOnCustomFloatingLayerClick onCustomFloatingLayerClick; BrnSelectionConfig themeData; - FilterLayerTypeWidget({this.selectionEntity, this.onCustomFloatingLayerClick, this.themeData}); + FilterLayerTypeWidget( + {this.selectionEntity, this.onCustomFloatingLayerClick, this.themeData}); @override _FilterLayerTypeWidgetState createState() => _FilterLayerTypeWidgetState(); @@ -586,7 +619,8 @@ class _FilterLayerTypeWidgetState extends State { padding: const EdgeInsets.only(left: 20, right: 20, top: 6), child: GestureDetector( onTap: () { - if (widget.selectionEntity.filterType == BrnSelectionFilterType.Layer) { + if (widget.selectionEntity.filterType == + BrnSelectionFilterType.Layer) { Navigator.of(context) .push(PageRouteBuilder( opaque: false, @@ -599,19 +633,22 @@ class _FilterLayerTypeWidgetState extends State { .then((data) { updateContent(); }); - } else if (widget.selectionEntity.filterType == BrnSelectionFilterType.CustomLayer) { + } else if (widget.selectionEntity.filterType == + BrnSelectionFilterType.CustomLayer) { if (widget.onCustomFloatingLayerClick != null) { int entityIndex = -1; if (widget.selectionEntity.parent != null && widget.selectionEntity.parent.children != null) { - entityIndex = - widget.selectionEntity.parent.children.indexOf(widget.selectionEntity); + entityIndex = widget.selectionEntity.parent.children + .indexOf(widget.selectionEntity); } - widget.onCustomFloatingLayerClick(entityIndex, widget.selectionEntity, + widget.onCustomFloatingLayerClick( + entityIndex, widget.selectionEntity, (List customFloatingLayerParams) { widget.selectionEntity.children?.clear(); widget.selectionEntity.children = []; - widget.selectionEntity.children.addAll(customFloatingLayerParams); + widget.selectionEntity.children + .addAll(customFloatingLayerParams); widget.selectionEntity.configDefaultValue(); setState(() {}); }); @@ -625,7 +662,8 @@ class _FilterLayerTypeWidgetState extends State { child: Text(isEmptyCondition() ? '请选择' : getCondition(), style: isEmptyCondition() ? widget.themeData.hintTextStyle.generateTextStyle() - : widget.themeData.optionTextStyle.generateTextStyle()), + : widget.themeData.optionTextStyle + .generateTextStyle()), ), Container( height: 16, @@ -653,7 +691,8 @@ class _FilterLayerTypeWidgetState extends State { String getCondition() { String tmp = ""; //返回所有选中的 - List selectedList = widget.selectionEntity.selectedList(); + List selectedList = + widget.selectionEntity.selectedList(); //判断步骤: //第一步:取出来所有选中的: 房山 不限 小白楼 西城 不限 diff --git a/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart b/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart index 4957cb0b..08349c7d 100644 --- a/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart @@ -33,10 +33,12 @@ class BrnSelectionRangeItemWidget extends StatefulWidget { this.onRangeChanged, this.onFocusChanged}); - _BrnSelectionRangeItemWidgetState createState() => _BrnSelectionRangeItemWidgetState(); + _BrnSelectionRangeItemWidgetState createState() => + _BrnSelectionRangeItemWidgetState(); } -class _BrnSelectionRangeItemWidgetState extends State { +class _BrnSelectionRangeItemWidgetState + extends State { FocusNode _minFocusNode = FocusNode(); FocusNode _maxFocusNode = FocusNode(); @@ -83,7 +85,9 @@ class _BrnSelectionRangeItemWidgetState extends State().listen((ClearSelectionFocusEvent event) { + EventBus.instance + .on() + .listen((ClearSelectionFocusEvent event) { _minFocusNode?.unfocus(); _maxFocusNode?.unfocus(); }); @@ -107,7 +111,8 @@ class _BrnSelectionRangeItemWidgetState extends State _BrnSelectionRangeTagWidgetState(); + _BrnSelectionRangeTagWidgetState createState() => + _BrnSelectionRangeTagWidgetState(); } -class _BrnSelectionRangeTagWidgetState extends State { +class _BrnSelectionRangeTagWidgetState + extends State { @override Widget build(BuildContext context) { return Wrap( @@ -61,7 +63,9 @@ class _BrnSelectionRangeTagWidgetState extends State List _tagWidgetList(context) { List list = List(); - for (int nameIndex = 0; nameIndex < widget.tagFilterList.length; nameIndex++) { + for (int nameIndex = 0; + nameIndex < widget.tagFilterList.length; + nameIndex++) { Widget tagWidget = _tagWidgetAtIndex(nameIndex); GestureDetector gdt = GestureDetector( child: tagWidget, @@ -86,14 +90,16 @@ class _BrnSelectionRangeTagWidgetState extends State } Widget _tagWidgetAtIndex(int nameIndex) { - bool selected = - widget.tagFilterList[nameIndex].isSelected || nameIndex == widget.initFocusedindex; + bool selected = widget.tagFilterList[nameIndex].isSelected || + nameIndex == widget.initFocusedindex; String text = widget.tagFilterList[nameIndex].title; - if (widget.tagFilterList[nameIndex].filterType == BrnSelectionFilterType.Date && + if (widget.tagFilterList[nameIndex].filterType == + BrnSelectionFilterType.Date && !BrunoTools.isEmpty(widget.tagFilterList[nameIndex].value)) { if (int.tryParse(widget.tagFilterList[nameIndex].value) != null) { text = DateTimeFormatter.formatDate( - DateTimeFormatter.convertIntValueToDateTime(widget.tagFilterList[nameIndex].value), + DateTimeFormatter.convertIntValueToDateTime( + widget.tagFilterList[nameIndex].value), 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn); } diff --git a/lib/src/components/selection/widget/brn_selection_range_widget.dart b/lib/src/components/selection/widget/brn_selection_range_widget.dart index 547a40cc..20e3baf6 100644 --- a/lib/src/components/selection/widget/brn_selection_range_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_range_widget.dart @@ -24,7 +24,8 @@ typedef void BrnOnRangeSelectionBgClick(); // ignore: must_be_immutable class BrnRangeSelectionGroupWidget extends StatefulWidget { - static final double screenWidth = window.physicalSize.width / window.devicePixelRatio; + static final double screenWidth = + window.physicalSize.width / window.devicePixelRatio; final BrnSelectionEntity entity; final double maxContentHeight; @@ -50,10 +51,12 @@ class BrnRangeSelectionGroupWidget extends StatefulWidget { this.themeData}); @override - _BrnRangeSelectionGroupWidgetState createState() => _BrnRangeSelectionGroupWidgetState(); + _BrnRangeSelectionGroupWidgetState createState() => + _BrnRangeSelectionGroupWidgetState(); } -class _BrnRangeSelectionGroupWidgetState extends State +class _BrnRangeSelectionGroupWidgetState + extends State with SingleTickerProviderStateMixin { List _originalSelectedItemsList = List(); List _firstList = List(); @@ -79,7 +82,9 @@ class _BrnRangeSelectionGroupWidgetState extends State firstList, List secondList, Color white) { - if (firstList != null && BrnSelectionUtil.getTotalLevel(widget.entity) == 1) { + Widget _createNewTagAndRangeWidget(List firstList, + List secondList, Color white) { + if (firstList != null && + BrnSelectionUtil.getTotalLevel(widget.entity) == 1) { return Column( mainAxisSize: MainAxisSize.min, children: [ Flexible( child: SingleChildScrollView( - child: - Column(mainAxisSize: MainAxisSize.min, children: getOneTabContent(widget.entity)), + child: Column( + mainAxisSize: MainAxisSize.min, + children: getOneTabContent(widget.entity)), ), ), BrnLine( @@ -165,7 +176,8 @@ class _BrnRangeSelectionGroupWidgetState extends State twoCountTagWidth) { tagWidth = oneCountTagWidth; } else if (threeCountTagWidth < maxWidthSize.width && @@ -238,7 +254,9 @@ class _BrnRangeSelectionGroupWidgetState extends State subFilterList = widget.entity.children[_tabController.index].children; - List selectItems = subFilterList.where((f) => f.isSelected).toList(); + List selectItems = + subFilterList.where((f) => f.isSelected).toList(); if (selectItems.length > 0) { _firstList[_tabController.index].isSelected = true; } else { @@ -399,18 +424,23 @@ class _BrnRangeSelectionGroupWidgetState extends State 0) || - (rangeEntity.customMap['max'] != null && rangeEntity.customMap['max'].length > 0))) { + ((rangeEntity.customMap['min'] != null && + rangeEntity.customMap['min'].length > 0) || + (rangeEntity.customMap['max'] != null && + rangeEntity.customMap['max'].length > 0))) { if (!rangeEntity.isValidRange()) { FocusScope.of(context).requestFocus(FocusNode()); if (rangeEntity?.filterType == BrnSelectionFilterType.Range) { BrnToast.show('您输入的区间有误', context); - } else if (rangeEntity?.filterType == BrnSelectionFilterType.DateRange || - rangeEntity?.filterType == BrnSelectionFilterType.DateRangeCalendar) { + } else if (rangeEntity?.filterType == + BrnSelectionFilterType.DateRange || + rangeEntity?.filterType == + BrnSelectionFilterType.DateRangeCalendar) { BrnToast.show('您选择的区间有误', context); } return; @@ -427,7 +457,9 @@ class _BrnRangeSelectionGroupWidgetState extends State _firstIndex) { - List seconds = widget.entity.children[_firstIndex].children; + List seconds = + widget.entity.children[_firstIndex].children; if (seconds != null) { for (BrnSelectionEntity entity in seconds) { if (entity.isSelected) { diff --git a/lib/src/components/selection/widget/brn_selection_single_list_widget.dart b/lib/src/components/selection/widget/brn_selection_single_list_widget.dart index 8ad05a9e..2e084623 100644 --- a/lib/src/components/selection/widget/brn_selection_single_list_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_single_list_widget.dart @@ -43,7 +43,8 @@ class BrnSelectionSingleListWidget extends StatefulWidget { } /// 当前 Items 所在的层级 - currentListIndex = BrnSelectionUtil.getCurrentListIndex(items.length > 0 ? items[0] : null); + currentListIndex = BrnSelectionUtil.getCurrentListIndex( + items.length > 0 ? items[0] : null); _selectedItems = items?.where((f) => f.isSelected)?.toList(); if (_selectedItems == null) { @@ -52,14 +53,16 @@ class BrnSelectionSingleListWidget extends StatefulWidget { } @override - _BrnSelectionSingleListWidgetState createState() => _BrnSelectionSingleListWidgetState(); + _BrnSelectionSingleListWidgetState createState() => + _BrnSelectionSingleListWidgetState(); List getSelectedItems() { return _selectedItems; } } -class _BrnSelectionSingleListWidgetState extends State { +class _BrnSelectionSingleListWidgetState + extends State { @override Widget build(BuildContext context) { return Expanded( @@ -90,12 +93,18 @@ class _BrnSelectionSingleListWidgetState extends State f.isSelected).length > 0 || - entity.parent.children.where((f) => f.isSelected && f.isUnLimit()).length > + entity.parent.children + .where((f) => f.isSelected) + .length > + 0 || + entity.parent.children + .where((f) => f.isSelected && f.isUnLimit()) + .length > 0) { ///点击的是不限类型,且不限类型同级别已经有选中的 Item 则不用检查数量。 /// 不限类型已经选中,选择非不限类型时,什么也不做, @@ -112,7 +121,8 @@ class _BrnSelectionSingleListWidgetState extends State 0) { - widget.items[0].parent?.isSelected = - widget.items[0].parent.children.where((BrnSelectionEntity f) => f.isSelected).length > 0; + widget.items[0].parent?.isSelected = widget.items[0].parent.children + .where((BrnSelectionEntity f) => f.isSelected) + .length > + 0; } for (BrnSelectionEntity item in widget.items) { @@ -198,10 +210,13 @@ class _BrnSelectionSingleListWidgetState extends State f != selectedEntity)?.forEach((f) { + selectedEntity.parent?.children + ?.where((f) => f != selectedEntity) + ?.forEach((f) { f.clearChildSelection(); f.isSelected = false; }); @@ -209,7 +224,9 @@ class _BrnSelectionSingleListWidgetState extends State f != selectedEntity)?.forEach((f) { + selectedEntity.parent?.children + ?.where((f) => f != selectedEntity) + ?.forEach((f) { f.clearChildSelection(); f.isSelected = false; }); diff --git a/lib/src/components/step/brn_horizontal_steps.dart b/lib/src/components/step/brn_horizontal_steps.dart index 5bea0fd9..996f6b3f 100644 --- a/lib/src/components/step/brn_horizontal_steps.dart +++ b/lib/src/components/step/brn_horizontal_steps.dart @@ -36,7 +36,10 @@ class BrnHorizontalStepsManager { } return Container( child: BrnHorizontalSteps( - steps: steps, controller: controller, doingIcon: doingIcon, completedIcon: completedIcon), + steps: steps, + controller: controller, + doingIcon: doingIcon, + completedIcon: completedIcon), ); } @@ -67,7 +70,8 @@ class BrnHorizontalStepsManager { /// 向后一步 /// void backStep() { - int backIndex = controller.currentIndex <= 0 ? 0 : controller.currentIndex - 1; + int backIndex = + controller.currentIndex <= 0 ? 0 : controller.currentIndex - 1; controller.setCurrentIndex(backIndex); } } @@ -84,7 +88,8 @@ class BrnHorizontalSteps extends StatefulWidget { final Widget doingIcon; final Widget completedIcon; - BrnHorizontalSteps({this.steps, this.controller, this.doingIcon, this.completedIcon}) + BrnHorizontalSteps( + {this.steps, this.controller, this.doingIcon, this.completedIcon}) : assert(steps.length < 6); @override @@ -187,7 +192,10 @@ class BrnHorizontalStepsState extends State { margin: EdgeInsets.fromLTRB(0, 0, 0, 28), color: index >= widget.controller.currentIndex ? Color(0xFFE7E7E7) - : BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + : BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, height: 1, ), ); @@ -225,7 +233,9 @@ class BrnHorizontalStepsState extends State { step.stepContentText, style: TextStyle( fontSize: 14, - color: index > widget.controller.currentIndex ? Color(0xFFCCCCCC) : Color(0xFF222222), + color: index > widget.controller.currentIndex + ? Color(0xFFCCCCCC) + : Color(0xFF222222), ), )); } @@ -241,7 +251,10 @@ class BrnHorizontalStepsState extends State { } // 使用组件默认的icon return BrunoTools.getAssetSizeImage(BrnAsset.ICON_STEP_COMPLETED, 20, 20, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary); + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary); } Widget _getDoingIcon(BrunoStep step) { @@ -255,7 +268,10 @@ class BrnHorizontalStepsState extends State { } // 使用组件默认的icon return BrunoTools.getAssetSizeImage(BrnAsset.ICON_STEP_DOING, 20, 20, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary); + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary); } } diff --git a/lib/src/components/step/brn_step_line.dart b/lib/src/components/step/brn_step_line.dart index aeac14c7..1d4081a4 100644 --- a/lib/src/components/step/brn_step_line.dart +++ b/lib/src/components/step/brn_step_line.dart @@ -183,7 +183,10 @@ class _BrnStepLineState extends State { } else { lineColor.clear(); lineColor.add(widget.highlightColor ?? - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary); + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary); return lineColor; } } else { @@ -192,7 +195,10 @@ class _BrnStepLineState extends State { } return List() ..add(widget.highlightColor ?? - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary); + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary); } } diff --git a/lib/src/components/sugsearch/brn_search_text.dart b/lib/src/components/sugsearch/brn_search_text.dart index a6bcea43..ec7531eb 100644 --- a/lib/src/components/sugsearch/brn_search_text.dart +++ b/lib/src/components/sugsearch/brn_search_text.dart @@ -83,32 +83,33 @@ class BrnSearchText extends StatefulWidget { /// 用于控制清除 Icon 和右侧 Action 的显示与隐藏。等其他复杂的操作。 final BrnSearchTextController searchController; - const BrnSearchText( - {Key key, - this.searchController, - this.controller, - this.maxLines = 1, - this.maxLength, - this.hintText, - this.hintStyle, - this.textStyle, - this.prefixIcon, - this.onTextChange, - this.onTextCommit, - this.onTextClear, - this.onActionTap, - this.action, - this.maxHeight = 60, - this.innerPadding = const EdgeInsets.only(top: 10, bottom: 10, left: 20, right: 20), - this.outSideColor = Colors.white, - this.innerColor = const Color(0xfff8f8f8), - this.normalBorder, - this.activeBorder, - this.borderRadius = const BorderRadius.all(const Radius.circular(6.0)), - this.focusNode, - this.autoFocus = false, - this.textInputAction,}) - : super(key: key); + const BrnSearchText({ + Key key, + this.searchController, + this.controller, + this.maxLines = 1, + this.maxLength, + this.hintText, + this.hintStyle, + this.textStyle, + this.prefixIcon, + this.onTextChange, + this.onTextCommit, + this.onTextClear, + this.onActionTap, + this.action, + this.maxHeight = 60, + this.innerPadding = + const EdgeInsets.only(top: 10, bottom: 10, left: 20, right: 20), + this.outSideColor = Colors.white, + this.innerColor = const Color(0xfff8f8f8), + this.normalBorder, + this.activeBorder, + this.borderRadius = const BorderRadius.all(const Radius.circular(6.0)), + this.focusNode, + this.autoFocus = false, + this.textInputAction, + }) : super(key: key); @override State createState() { @@ -211,8 +212,10 @@ class _SearchTextState extends State { // 控制器属性,控制正在编辑的文本。 controller: textEditingController, // 光标颜色属性,绘制光标时使用的颜色。 - cursorColor: - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + cursorColor: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, // 光标宽度属性,光标的厚度,默认是2.0。 cursorWidth: 2.0, // 样式属性,用于正在编辑的文本的样式。 @@ -271,14 +274,17 @@ class _SearchTextState extends State { } textEditingController.clear(); if (this.widget.onTextChange != null) { - this.widget.onTextChange(textEditingController.value.text); + this + .widget + .onTextChange(textEditingController.value.text); } setState(() {}); }, child: Visibility( visible: textEditingController.text.isNotEmpty, child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), + padding: + const EdgeInsets.symmetric(horizontal: 12.0), child: BrunoTools.getAssetImage( BrnAsset.ICON_DELETE_TEXT, ), diff --git a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart index c98e9174..9ec1c5d3 100644 --- a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart +++ b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart @@ -161,7 +161,8 @@ class _BottomNavigationTile extends StatelessWidget { alignment: Alignment.bottomCenter, heightFactor: 1.0, child: Container( - margin: const EdgeInsets.only(bottom: _kBottomMargin, top: _kmiddleInterval), + margin: const EdgeInsets.only( + bottom: _kBottomMargin, top: _kmiddleInterval), child: DefaultTextStyle.merge( style: TextStyle( fontSize: _kActiveFontSize, @@ -171,7 +172,9 @@ class _BottomNavigationTile extends StatelessWidget { /// 使用矩阵变化控制字体大小 child: Transform( transform: Matrix4.diagonal3Values( - scale, scale, scale, + scale, + scale, + scale, ), alignment: Alignment.bottomCenter, child: item.title, @@ -304,7 +307,8 @@ class _BottomNavigationTile extends StatelessWidget { } /// 底部导航栏中状态控制类 -class _BottomTabBarState extends State with TickerProviderStateMixin { +class _BottomTabBarState extends State + with TickerProviderStateMixin { List _controllers = []; List _animations; @@ -314,20 +318,23 @@ class _BottomTabBarState extends State with TickerProviderState /// 执行完动画之后的背景颜色 Color _backgroundColor; - static final Animatable _flexTween = Tween(begin: 1.0, end: 1.5); + static final Animatable _flexTween = + Tween(begin: 1.0, end: 1.5); void _resetState() { for (AnimationController controller in _controllers) controller.dispose(); for (_Circle circle in _circles) circle.dispose(); _circles.clear(); - _controllers = List.generate(widget.items.length, (int index) { + _controllers = + List.generate(widget.items.length, (int index) { return AnimationController( duration: kThemeAnimationDuration, vsync: this, )..addListener(_rebuild); }); - _animations = List.generate(widget.items.length, (int index) { + _animations = + List.generate(widget.items.length, (int index) { return CurvedAnimation( parent: _controllers[index], curve: Curves.fastOutSlowIn, @@ -357,7 +364,8 @@ class _BottomTabBarState extends State with TickerProviderState super.dispose(); } - double _evaluateFlex(Animation animation) => _flexTween.evaluate(animation); + double _evaluateFlex(Animation animation) => + _flexTween.evaluate(animation); void _pushCircle(int index) { if (widget.items[index].backgroundColor != null) { @@ -417,7 +425,8 @@ class _BottomTabBarState extends State with TickerProviderState /// 生成瓦片 List _createTiles() { - final MaterialLocalizations localizations = MaterialLocalizations.of(context); + final MaterialLocalizations localizations = + MaterialLocalizations.of(context); assert(localizations != null); final List children = []; switch (widget.type) { @@ -449,10 +458,13 @@ class _BottomTabBarState extends State with TickerProviderState }, colorTween: colorTween, selected: i == widget.currentIndex, - indexLabel: localizations.tabLabel(tabIndex: i + 1, tabCount: widget.items.length), + indexLabel: localizations.tabLabel( + tabIndex: i + 1, tabCount: widget.items.length), isAnimation: widget.isAnimation, isInkResponse: widget.isInkResponse, - badgeColor: widget.badgeColor == null ? widget.fixedColor : widget.badgeColor, + badgeColor: widget.badgeColor == null + ? widget.fixedColor + : widget.badgeColor, ), ); } @@ -470,10 +482,13 @@ class _BottomTabBarState extends State with TickerProviderState }, flex: _evaluateFlex(_animations[i]), selected: i == widget.currentIndex, - indexLabel: localizations.tabLabel(tabIndex: i + 1, tabCount: widget.items.length), + indexLabel: localizations.tabLabel( + tabIndex: i + 1, tabCount: widget.items.length), isAnimation: widget.isAnimation, isInkResponse: widget.isInkResponse, - badgeColor: widget.badgeColor == null ? widget.fixedColor : widget.badgeColor, + badgeColor: widget.badgeColor == null + ? widget.fixedColor + : widget.badgeColor, ), ); } @@ -524,8 +539,9 @@ class _BottomTabBarState extends State with TickerProviderState ), ), ConstrainedBox( - constraints: - BoxConstraints(minHeight: kBottomNavigationBarHeight + additionalBottomPadding), + constraints: BoxConstraints( + minHeight: + kBottomNavigationBarHeight + additionalBottomPadding), child: Stack( children: [ Positioned.fill( @@ -596,10 +612,13 @@ class _Circle { final double allWeights = weightSum(state._animations); /// 这些权重和到索引项的起始边 - final double leadingWeights = weightSum(state._animations.sublist(0, index)); + final double leadingWeights = + weightSum(state._animations.sublist(0, index)); /// 添加其伸缩值的一半,以到达中心 - return (leadingWeights + state._evaluateFlex(state._animations[index]) / 2.0) / allWeights; + return (leadingWeights + + state._evaluateFlex(state._animations[index]) / 2.0) / + allWeights; } void dispose() { @@ -651,7 +670,8 @@ class _RadialPainter extends CustomPainter { leftFraction = circle.horizontalLeadingOffset; break; } - final Offset center = Offset(leftFraction * size.width, size.height / 2.0); + final Offset center = + Offset(leftFraction * size.width, size.height / 2.0); final Tween radiusTween = Tween( begin: 0.0, end: _maxRadius(center, size), diff --git a/lib/src/components/tabbar/indicator/brn_custom_width_indicator.dart b/lib/src/components/tabbar/indicator/brn_custom_width_indicator.dart index d6f83b2f..e2c80176 100644 --- a/lib/src/components/tabbar/indicator/brn_custom_width_indicator.dart +++ b/lib/src/components/tabbar/indicator/brn_custom_width_indicator.dart @@ -73,8 +73,8 @@ class _UnderlinePainter extends BoxPainter { double wantWidth = width ?? 24; //取中间坐标 double cw = (indicator.left + indicator.right) / 2; - return Rect.fromLTWH( - cw - wantWidth / 2, indicator.bottom - borderSide.width, wantWidth, borderSide.width); + return Rect.fromLTWH(cw - wantWidth / 2, + indicator.bottom - borderSide.width, wantWidth, borderSide.width); } @override @@ -83,7 +83,8 @@ class _UnderlinePainter extends BoxPainter { assert(configuration.size != null); final Rect rect = offset & configuration.size; final TextDirection textDirection = configuration.textDirection; - final Rect indicator = _indicatorRectFor(rect, textDirection).deflate(borderSide.width / 2.0); + final Rect indicator = + _indicatorRectFor(rect, textDirection).deflate(borderSide.width / 2.0); final Paint paint = borderSide.toPaint()..strokeCap = StrokeCap.round; canvas.drawLine(indicator.bottomLeft, indicator.bottomRight, paint); } diff --git a/lib/src/components/tabbar/indicator/brn_fixed_underline_decoration.dart b/lib/src/components/tabbar/indicator/brn_fixed_underline_decoration.dart index 6111f92f..5ed7dc14 100644 --- a/lib/src/components/tabbar/indicator/brn_fixed_underline_decoration.dart +++ b/lib/src/components/tabbar/indicator/brn_fixed_underline_decoration.dart @@ -102,7 +102,8 @@ class _FixedUnderlinePainter extends BoxPainter { assert(configuration.size != null); final Rect rect = offset & configuration.size; final TextDirection textDirection = configuration.textDirection; - final Rect indicator = _indicatorRectFor(rect, textDirection).deflate(borderSide.width / 2.0); + final Rect indicator = + _indicatorRectFor(rect, textDirection).deflate(borderSide.width / 2.0); final Paint paint = borderSide.toPaint()..strokeCap = StrokeCap.square; paint.color = decoration.color; paint.strokeWidth = decoration.thickness; diff --git a/lib/src/components/tabbar/indicator/brn_triangle_decoration.dart b/lib/src/components/tabbar/indicator/brn_triangle_decoration.dart index 03017d00..3b500068 100644 --- a/lib/src/components/tabbar/indicator/brn_triangle_decoration.dart +++ b/lib/src/components/tabbar/indicator/brn_triangle_decoration.dart @@ -27,7 +27,6 @@ class BrnTriangleIndicator extends Decoration { this.shape, }); - factory BrnTriangleIndicator.fromBoxDecoration(BoxDecoration source) { ShapeBorder shape; assert(source.shape != null); @@ -74,7 +73,8 @@ class BrnTriangleIndicator extends Decoration { @override BrnTriangleIndicator lerpFrom(Decoration a, double t) { if (a is BoxDecoration) { - return BrnTriangleIndicator.lerp(BrnTriangleIndicator.fromBoxDecoration(a), this, t); + return BrnTriangleIndicator.lerp( + BrnTriangleIndicator.fromBoxDecoration(a), this, t); } else if (a == null || a is BrnTriangleIndicator) { return BrnTriangleIndicator.lerp(a, this, t); } @@ -84,14 +84,16 @@ class BrnTriangleIndicator extends Decoration { @override BrnTriangleIndicator lerpTo(Decoration b, double t) { if (b is BoxDecoration) { - return BrnTriangleIndicator.lerp(this, BrnTriangleIndicator.fromBoxDecoration(b), t); + return BrnTriangleIndicator.lerp( + this, BrnTriangleIndicator.fromBoxDecoration(b), t); } else if (b == null || b is BrnTriangleIndicator) { return BrnTriangleIndicator.lerp(this, b, t); } return super.lerpTo(b, t); } - static BrnTriangleIndicator lerp(BrnTriangleIndicator a, BrnTriangleIndicator b, double t) { + static BrnTriangleIndicator lerp( + BrnTriangleIndicator a, BrnTriangleIndicator b, double t) { assert(t != null); if (a == null && b == null) return null; if (a != null && b != null) { @@ -140,9 +142,12 @@ class BrnTriangleIndicator extends Decoration { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.whitespace; - properties.add(DiagnosticsProperty('color', color, defaultValue: null)); - properties.add(DiagnosticsProperty('gradient', gradient, defaultValue: null)); - properties.add(DiagnosticsProperty('image', image, defaultValue: null)); + properties + .add(DiagnosticsProperty('color', color, defaultValue: null)); + properties.add(DiagnosticsProperty('gradient', gradient, + defaultValue: null)); + properties.add(DiagnosticsProperty('image', image, + defaultValue: null)); properties.add(IterableProperty('shadows', shadows, defaultValue: null, style: DiagnosticsTreeStyle.whitespace)); properties.add(DiagnosticsProperty('shape', shape)); @@ -150,7 +155,9 @@ class BrnTriangleIndicator extends Decoration { @override bool hitTest(Size size, Offset position, {TextDirection textDirection}) { - return shape.getOuterPath(Offset.zero & size, textDirection: textDirection).contains(position); + return shape + .getOuterPath(Offset.zero & size, textDirection: textDirection) + .contains(position); } @override @@ -164,7 +171,8 @@ class BrnTriangleIndicator extends Decoration { /// An object that paints a [BrnTriangleIndicator] into a canvas. class _TriangleDecorationPainter extends BoxPainter { - _TriangleDecorationPainter(this._decoration, this._path, this._paint, VoidCallback onChanged) + _TriangleDecorationPainter( + this._decoration, this._path, this._paint, VoidCallback onChanged) : assert(_decoration != null), super(onChanged); @@ -173,7 +181,8 @@ class _TriangleDecorationPainter extends BoxPainter { Paint _paint; //画笔 Path _path; //绘制路径 - void _paintTriangle(Canvas canvas, Offset offset, Rect rect, ImageConfiguration configuration) { + void _paintTriangle(Canvas canvas, Offset offset, Rect rect, + ImageConfiguration configuration) { final baseX = offset.dx + rect.width / 2; final width = _decoration.triWidth; final height = _decoration.triHeight; diff --git a/lib/src/components/tabbar/normal/brn_sub_switch_title.dart b/lib/src/components/tabbar/normal/brn_sub_switch_title.dart index e0d01736..0eb3b1a9 100644 --- a/lib/src/components/tabbar/normal/brn_sub_switch_title.dart +++ b/lib/src/components/tabbar/normal/brn_sub_switch_title.dart @@ -34,7 +34,8 @@ class BrnSubSwitchTitle extends StatefulWidget { _BrnSubSwitchTitleState createState() => _BrnSubSwitchTitleState(); } -class _BrnSubSwitchTitleState extends State with TickerProviderStateMixin { +class _BrnSubSwitchTitleState extends State + with TickerProviderStateMixin { List widgetList; TabController _controller; @@ -105,7 +106,8 @@ class _BrnSubSwitchTitleState extends State with TickerProvid ), labelPadding: EdgeInsets.all(0), //未选中态颜色 - unselectedLabelColor: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, + unselectedLabelColor: + BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, //未选中态样式 unselectedLabelStyle: TextStyle( fontWeight: FontWeight.w400, diff --git a/lib/src/components/tabbar/normal/brn_tab_bar.dart b/lib/src/components/tabbar/normal/brn_tab_bar.dart index 591457ce..825605ce 100644 --- a/lib/src/components/tabbar/normal/brn_tab_bar.dart +++ b/lib/src/components/tabbar/normal/brn_tab_bar.dart @@ -11,7 +11,6 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; - /// 单个tab选中的回调 /// [state]:当前组件的State对象,[BrnTabBarState] /// [index]:当前组件的角标 @@ -232,7 +231,8 @@ class BrnTabBarState extends State { } void _handleTabIndexChangeTick() { - if (widget.controller.index.toDouble() == widget.controller.animation.value) { + if (widget.controller.index.toDouble() == + widget.controller.animation.value) { _brnTabbarController?.selectIndex = widget.controller?.index ?? 0; _brnTabbarController?.isShow = false; } @@ -263,12 +263,15 @@ class BrnTabBarState extends State { return TabBar( tabs: fillWidgetByDataList(), controller: widget.controller, - isScrollable: widget.tabs.length > 4 || widget.tabWidth != null || widget.isScroll, + isScrollable: widget.tabs.length > 4 || + widget.tabWidth != null || + widget.isScroll, labelColor: widget.labelColor ?? widget.themeData.labelStyle.color, - labelStyle: widget.labelStyle ?? widget.themeData.labelStyle.generateTextStyle(), + labelStyle: widget.labelStyle ?? + widget.themeData.labelStyle.generateTextStyle(), labelPadding: widget.labelPadding, - unselectedLabelColor: - widget.unselectedLabelColor ?? widget.themeData.unselectedLabelStyle.color, + unselectedLabelColor: widget.unselectedLabelColor ?? + widget.themeData.unselectedLabelStyle.color, unselectedLabelStyle: widget.unselectedLabelStyle ?? widget.themeData.unselectedLabelStyle.generateTextStyle(), dragStartBehavior: widget.dragStartBehavior, @@ -298,7 +301,8 @@ class BrnTabBarState extends State { child: GestureDetector( onTap: () { if (!_brnTabbarController.isShow && - widget.controller.index.toDouble() == widget.controller.animation.value) { + widget.controller.index.toDouble() == + widget.controller.animation.value) { _brnTabbarController?.show(); if (widget.onMorePop != null) { widget.onMorePop(); @@ -316,12 +320,16 @@ class BrnTabBarState extends State { decoration: BoxDecoration( color: Colors.white, boxShadow: [ - BoxShadow(color: Color(0x05000000), offset: Offset(-3, 0), spreadRadius: -1) + BoxShadow( + color: Color(0x05000000), + offset: Offset(-3, 0), + spreadRadius: -1) ], ), child: !_brnTabbarController.isShow ? BrunoTools.getAssetImage(BrnAsset.ICON_TRIANGLE_DOWN) - : BrunoTools.getAssetImageWithBandColor(BrnAsset.ICON_TRIANGLE_UP)), + : BrunoTools.getAssetImageWithBandColor( + BrnAsset.ICON_TRIANGLE_UP)), ), ); } @@ -358,7 +366,8 @@ class BrnTabBarState extends State { for (int i = 0; i < tabList.length; i++) { BadgeTab badgeTab = tabList[i]; if (widget.mode == BrnTabBarBadgeMode.average) { - widgets.add(_wrapAverageWidget(badgeTab, minWidth, i == tabList.length - 1)); + widgets.add( + _wrapAverageWidget(badgeTab, minWidth, i == tabList.length - 1)); } else { widgets.add(_wrapOriginWidget(badgeTab, i == tabList.length - 1)); } @@ -387,12 +396,17 @@ class BrnTabBarState extends State { overflow: TextOverflow.ellipsis, )), Badge( - showBadge: (badgeTab.badgeNum != null ? badgeTab.badgeNum > 0 : false) || + showBadge: (badgeTab.badgeNum != null + ? badgeTab.badgeNum > 0 + : false) || badgeTab.showRedBadge || - (badgeTab.badgeText != null ? badgeTab.badgeText.isNotEmpty : false), + (badgeTab.badgeText != null + ? badgeTab.badgeText.isNotEmpty + : false), badgeContent: Text( _badgeText, - style: TextStyle(color: Color(0xFFFFFFFF), fontSize: 10, height: 1), + style: TextStyle( + color: Color(0xFFFFFFFF), fontSize: 10, height: 1), ), shape: _badgeShape, elevation: 0, @@ -400,9 +414,12 @@ class BrnTabBarState extends State { borderRadius: _borderRadius, alignment: Alignment.topLeft, padding: _badgePadding, - position: BadgePosition.topEnd(top: _paddingTop, end: _paddingRight), + position: + BadgePosition.topEnd(top: _paddingTop, end: _paddingRight), child: Text(badgeTab.text, - maxLines: 1, softWrap: true, overflow: TextOverflow.ellipsis), + maxLines: 1, + softWrap: true, + overflow: TextOverflow.ellipsis), ) ], ), @@ -420,7 +437,8 @@ class BrnTabBarState extends State { } // 定制的等分tab样式 - Widget _wrapAverageWidget(BadgeTab badgeTab, double minWidth, bool lastElement) { + Widget _wrapAverageWidget( + BadgeTab badgeTab, double minWidth, bool lastElement) { caculateBadgeParams(badgeTab); return Container( width: minWidth, @@ -443,12 +461,17 @@ class BrnTabBarState extends State { overflow: TextOverflow.ellipsis, )), Badge( - showBadge: (badgeTab.badgeNum != null ? badgeTab.badgeNum > 0 : false) || + showBadge: (badgeTab.badgeNum != null + ? badgeTab.badgeNum > 0 + : false) || badgeTab.showRedBadge || - (badgeTab.badgeText != null ? badgeTab.badgeText.isNotEmpty : false), + (badgeTab.badgeText != null + ? badgeTab.badgeText.isNotEmpty + : false), badgeContent: Text( _badgeText, - style: TextStyle(color: Color(0xFFFFFFFF), fontSize: 10, height: 1), + style: TextStyle( + color: Color(0xFFFFFFFF), fontSize: 10, height: 1), ), shape: _badgeShape, elevation: 0, @@ -456,9 +479,12 @@ class BrnTabBarState extends State { borderRadius: _borderRadius, alignment: Alignment.topLeft, padding: _badgePadding, - position: BadgePosition.topEnd(top: _paddingTop, end: _paddingRight), + position: BadgePosition.topEnd( + top: _paddingTop, end: _paddingRight), child: Text(badgeTab.text, - maxLines: 1, softWrap: true, overflow: TextOverflow.ellipsis), + maxLines: 1, + softWrap: true, + overflow: TextOverflow.ellipsis), ) ], ), @@ -526,7 +552,8 @@ class BrnTabBarState extends State { // 展开更多 void showMoreWindow(BuildContext context) { final RenderBox dropDownItemRenderBox = context.findRenderObject(); - var position = dropDownItemRenderBox.localToGlobal(Offset.zero, ancestor: null); + var position = + dropDownItemRenderBox.localToGlobal(Offset.zero, ancestor: null); var size = dropDownItemRenderBox.size; _brnTabbarController.top = size.height + position.dy; @@ -554,7 +581,8 @@ class BrnTabBarState extends State { color: Color(0xB3000000), child: Container( width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height - _brnTabbarController.top, + height: MediaQuery.of(context).size.height - + _brnTabbarController.top, child: Padding( padding: EdgeInsets.all(0), child: _TabBarOverlayWidget( @@ -667,7 +695,8 @@ class _TabBarOverlayWidgetState extends State<_TabBarOverlayWidget> { mainAxisAlignment: MainAxisAlignment.start, children: [ Visibility( - visible: widget.moreWindowText != null && widget.moreWindowText.isNotEmpty, + visible: widget.moreWindowText != null && + widget.moreWindowText.isNotEmpty, child: Padding( padding: EdgeInsets.only(bottom: 16), child: Text( @@ -694,7 +723,9 @@ class _TabBarOverlayWidgetState extends State<_TabBarOverlayWidget> { Widget _createMoreItems() { // 计算tag的宽度 - _tagWidth = (_parentWidth - widget.spacing * (widget.preLineTagCount - 1) - _padding * 2) / + _tagWidth = (_parentWidth - + widget.spacing * (widget.preLineTagCount - 1) - + _padding * 2) / widget.preLineTagCount; List widgets = List(); diff --git a/lib/src/components/tabbar/normal/brn_tabbar_controller.dart b/lib/src/components/tabbar/normal/brn_tabbar_controller.dart index 80711ffd..e67c9153 100644 --- a/lib/src/components/tabbar/normal/brn_tabbar_controller.dart +++ b/lib/src/components/tabbar/normal/brn_tabbar_controller.dart @@ -59,7 +59,8 @@ class BrnCloseWindowController { /// bool isShow = false; - StreamController _closeController = StreamController.broadcast(); + StreamController _closeController = + StreamController.broadcast(); StreamController getCloseController() { return _closeController; diff --git a/lib/src/components/tag/brn_state_tag.dart b/lib/src/components/tag/brn_state_tag.dart index 1f7f13a4..6da94437 100644 --- a/lib/src/components/tag/brn_state_tag.dart +++ b/lib/src/components/tag/brn_state_tag.dart @@ -34,7 +34,8 @@ class BrnStateTag extends StatelessWidget { tagText: tagText, textPadding: EdgeInsets.only(bottom: 0, left: 4, right: 4, top: 0), textColor: textColor ?? getTagColor(tagState), - backgroundColor: backgroundColor ?? getTagColor(tagState).withOpacity(0.1), + backgroundColor: + backgroundColor ?? getTagColor(tagState).withOpacity(0.1), ); } diff --git a/lib/src/components/tag/brn_tag_custom.dart b/lib/src/components/tag/brn_tag_custom.dart index 935f18b1..1c7f04d0 100644 --- a/lib/src/components/tag/brn_tag_custom.dart +++ b/lib/src/components/tag/brn_tag_custom.dart @@ -62,7 +62,8 @@ class BrnTagCustom extends StatelessWidget { Key key, this.backgroundColor = Colors.transparent, this.tagText = "", - this.textPadding = const EdgeInsets.only(bottom: 3, left: 3, right: 3, top: 0), + this.textPadding = + const EdgeInsets.only(bottom: 3, left: 3, right: 3, top: 0), this.fontSize = 11, this.fontWeight = FontWeight.normal, this.tagBorderRadius, @@ -72,27 +73,36 @@ class BrnTagCustom extends StatelessWidget { double borderRadius = 3, }) : this.maxWidth = double.infinity, this.border = Border.all( - color: borderColor ?? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + color: borderColor ?? + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, width: borderWidth ?? 1, ), - this.textColor = - textColor ?? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + this.textColor = textColor ?? + BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, super(key: key); @override Widget build(BuildContext context) { - BorderRadius bRadius = tagBorderRadius ?? BorderRadius.all(Radius.circular(2)); + BorderRadius bRadius = + tagBorderRadius ?? BorderRadius.all(Radius.circular(2)); return Container( constraints: BoxConstraints( maxWidth: maxWidth, ), decoration: BoxDecoration( color: backgroundColor ?? - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, shape: BoxShape.rectangle, borderRadius: bRadius, border: border), - padding: textPadding ?? EdgeInsets.only(bottom: 0.5, left: 3, right: 3, top: 0), + padding: textPadding ?? + EdgeInsets.only(bottom: 0.5, left: 3, right: 3, top: 0), child: Text( tagText ?? "", textAlign: TextAlign.center, @@ -100,7 +110,10 @@ class BrnTagCustom extends StatelessWidget { style: TextStyle( fontSize: fontSize ?? 11, color: textColor ?? - BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBaseInverse, + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBaseInverse, fontWeight: fontWeight, ), )); diff --git a/lib/src/components/tag/tagview/brn_delete_tag.dart b/lib/src/components/tag/tagview/brn_delete_tag.dart index 8e4e146d..4ea6cd9e 100644 --- a/lib/src/components/tag/tagview/brn_delete_tag.dart +++ b/lib/src/components/tag/tagview/brn_delete_tag.dart @@ -71,7 +71,8 @@ class BrnDeleteTag extends StatefulWidget { : super(key: key) { themeData ??= BrnTagConfig(); themeData = themeData.merge(BrnTagConfig( - tagBackgroundColor: this.backgroundColor, tagTextStyle: BrnTextStyle.withStyle(tagTextStyle))); + tagBackgroundColor: this.backgroundColor, + tagTextStyle: BrnTextStyle.withStyle(tagTextStyle))); themeData = BrnThemeConfigurator.instance .getConfig(configId: themeData.configId) .tagConfig @@ -88,7 +89,8 @@ class _BrnDeleteTagState extends State { @override void initState() { super.initState(); - _controller = widget.controller ?? BrnDeleteTagController(initTags: widget.tags); + _controller = + widget.controller ?? BrnDeleteTagController(initTags: widget.tags); } @override @@ -127,14 +129,17 @@ class _BrnDeleteTagState extends State { if (widget.softWrap ?? true) { result = Wrap( spacing: widget.horizontalSpacing ?? 10, - runSpacing: widget.verticalSpacing != null ? widget.verticalSpacing - 16 : -6, + runSpacing: + widget.verticalSpacing != null ? widget.verticalSpacing - 16 : -6, alignment: WrapAlignment.start, children: itemList, ); } else { int tagIdx = 0; var finalTagList = itemList.map((tag) { - double rightPadding = (tagIdx == itemList.length - 1) ? 0 : widget.horizontalSpacing ?? 12; + double rightPadding = (tagIdx == itemList.length - 1) + ? 0 + : widget.horizontalSpacing ?? 12; var padding = Padding( child: tag, padding: EdgeInsets.only(right: rightPadding), @@ -196,15 +201,18 @@ class DeleteTagItemWidget extends StatelessWidget { labelPadding: EdgeInsets.fromLTRB(0, 0, -3, 0), backgroundColor: themeData.tagBackgroundColor, label: Text(this.title, - overflow: TextOverflow.ellipsis, style: themeData?.tagTextStyle?.generateTextStyle()), + overflow: TextOverflow.ellipsis, + style: themeData?.tagTextStyle?.generateTextStyle()), shape: shape ?? - RoundedRectangleBorder(borderRadius: BorderRadius.circular(themeData?.tagRadius)), + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(themeData?.tagRadius)), //删除图标 deleteIcon: deleteIconSize != null ? BrunoTools.getAssetSizeImage( BrnAsset.ICON_CLOSE, deleteIconSize.width, deleteIconSize.height, color: deleteIconColor) - : BrunoTools.getAssetImageWithColor(BrnAsset.ICON_CLOSE, deleteIconColor), + : BrunoTools.getAssetImageWithColor( + BrnAsset.ICON_CLOSE, deleteIconColor), onDeleted: () { debugPrint('$index'); didDeleted(index); diff --git a/lib/src/components/tag/tagview/brn_select_tag.dart b/lib/src/components/tag/tagview/brn_select_tag.dart index e178a70a..cba62a0c 100644 --- a/lib/src/components/tag/tagview/brn_select_tag.dart +++ b/lib/src/components/tag/tagview/brn_select_tag.dart @@ -109,7 +109,9 @@ class _BrnSelectTagState extends State { super.initState(); _tagState = widget.tags.map((name) => false).toList(); if (widget.initTagState != null) { - for (int index = 0; index < min(widget.initTagState.length, widget.tags.length); index++) { + for (int index = 0; + index < min(widget.initTagState.length, widget.tags.length); + index++) { _tagState[index] = widget.initTagState[index]; } } @@ -200,7 +202,8 @@ class _BrnSelectTagState extends State { constraints: BoxConstraints(minWidth: widget.themeData.tagMinWidth), decoration: BoxDecoration( color: selected - ? (widget.themeData?.selectedTagBackgroundColor?.withOpacity(0.12)) + ? (widget.themeData?.selectedTagBackgroundColor + ?.withOpacity(0.12)) : (widget.themeData?.tagBackgroundColor), borderRadius: BorderRadius.circular(widget.themeData?.tagRadius)), width: widget.fixWidthMode ? widget.themeData?.tagWidth : null, @@ -223,13 +226,17 @@ class _BrnSelectTagState extends State { void didUpdateWidget(BrnSelectTag oldWidget) { super.didUpdateWidget(oldWidget); // 如果两个数组不相等,重置选中状态 - if (!sameList(oldWidget.tags, widget.tags)) _tagState = List.filled(widget.tags.length, false); + if (!sameList(oldWidget.tags, widget.tags)) + _tagState = List.filled(widget.tags.length, false); } /// 比较两个数组内容是否一致,如果一致,返回 true,否则 false bool sameList(List first, List second) { - if (first == null || second == null || first.length != second.length) return false; + if (first == null || second == null || first.length != second.length) + return false; int index = 0; - return first.firstWhere((item) => item != second[index++], orElse: () => null) == null; + return first.firstWhere((item) => item != second[index++], + orElse: () => null) == + null; } } diff --git a/lib/src/components/text/brn_expandable_text.dart b/lib/src/components/text/brn_expandable_text.dart index 9ab0440a..5bf52d7b 100644 --- a/lib/src/components/text/brn_expandable_text.dart +++ b/lib/src/components/text/brn_expandable_text.dart @@ -2,7 +2,7 @@ import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -typedef TextExpandedCallback = Function(bool) ; +typedef TextExpandedCallback = Function(bool); /// 具备展开收起功能的文字面板 /// @@ -116,7 +116,11 @@ class _BrnExpandableTextState extends State { Text tx = Text( '更多', style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, fontSize: 14), + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, + fontSize: 14), ); Container cnt = Container( padding: EdgeInsets.only(left: 22), @@ -144,10 +148,10 @@ class _BrnExpandableTextState extends State { Widget _expandedText(context, String text) { return RichText( - textScaleFactor: MediaQuery.of(context).textScaleFactor, + textScaleFactor: MediaQuery.of(context).textScaleFactor, text: TextSpan(text: text, style: _defaultTextStyle(), children: [ - _foldButtonSpan(context), - ])); + _foldButtonSpan(context), + ])); } TextStyle _defaultTextStyle() { @@ -155,7 +159,10 @@ class _BrnExpandableTextState extends State { TextStyle( fontSize: 14, fontWeight: FontWeight.w400, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, ); return style; } @@ -164,7 +171,10 @@ class _BrnExpandableTextState extends State { return TextSpan( text: ' 收起', style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, fontSize: 14, ), recognizer: TapGestureRecognizer() diff --git a/lib/src/components/toast/brn_toast.dart b/lib/src/components/toast/brn_toast.dart index c4187ba6..b3b83b2b 100644 --- a/lib/src/components/toast/brn_toast.dart +++ b/lib/src/components/toast/brn_toast.dart @@ -13,7 +13,6 @@ class BrnToast { static _ToastView preToastView; - /// 显示在中间。如不设置duration则会自动根据内容长度来计算(更友好,最长5秒) static void showInCenter(String text, BuildContext context, {int duration}) { show(text, context, duration: duration, gravity: CENTER); @@ -44,8 +43,8 @@ class BrnToast { toastView.overlayState = overlayState; OverlayEntry overlayEntry; overlayEntry = OverlayEntry(builder: (context) { - return _buildToastLayout( - context, backgroundColor, backgroundRadius, preIcon, text, textStyle, gravity, + return _buildToastLayout(context, backgroundColor, backgroundRadius, + preIcon, text, textStyle, gravity, verticalOffset: verticalOffset); }); toastView._overlayEntry = overlayEntry; @@ -53,11 +52,14 @@ class BrnToast { toastView._show(aiDuration, onDismiss: onDismiss); } - static double getRealVerticalOffset(double verticalOffset, int gravity, BuildContext context) { + static double getRealVerticalOffset( + double verticalOffset, int gravity, BuildContext context) { if (gravity == BrnToast.TOP) { - verticalOffset = (verticalOffset ?? 0) + MediaQuery.of(context).viewInsets.top + 50; + verticalOffset = + (verticalOffset ?? 0) + MediaQuery.of(context).viewInsets.top + 50; } else if (gravity == BrnToast.BOTTOM) { - verticalOffset = (verticalOffset ?? 0) + MediaQuery.of(context).viewInsets.bottom + 50; + verticalOffset = + (verticalOffset ?? 0) + MediaQuery.of(context).viewInsets.bottom + 50; } else { verticalOffset = 0; } @@ -65,8 +67,14 @@ class BrnToast { } } -_ToastWidget _buildToastLayout(BuildContext context, Color background, double backgroundRadius, - Image preIcon, String msg, TextStyle textStyle, int gravity, +_ToastWidget _buildToastLayout( + BuildContext context, + Color background, + double backgroundRadius, + Image preIcon, + String msg, + TextStyle textStyle, + int gravity, {double verticalOffset}) { Alignment alignment = Alignment.center; EdgeInsets padding; @@ -118,7 +126,8 @@ class _ToastView { _show(int duration, {VoidCallback onDismiss}) async { _isVisible = true; overlayState.insert(_overlayEntry); - await Future.delayed(Duration(seconds: duration == null ? BrnToast.LENGTH_SHORT : duration)); + await Future.delayed( + Duration(seconds: duration == null ? BrnToast.LENGTH_SHORT : duration)); _dismiss(); if (onDismiss != null) { onDismiss(); diff --git a/lib/src/constants/brn_asset_constants.dart b/lib/src/constants/brn_asset_constants.dart index 7b0ac022..f2850b54 100644 --- a/lib/src/constants/brn_asset_constants.dart +++ b/lib/src/constants/brn_asset_constants.dart @@ -1,6 +1,4 @@ class BrnAsset { - - static const String emptyState = "images/empty_state.png"; static const String stepTitle = 'images/img_step_title.png'; @@ -12,22 +10,29 @@ class BrnAsset { static const String iconUnSelect = "images/icon_unselect.png"; static const String iconMore = "images/icon_more.png"; static const String iconAlert = "icons/icon_alert.png"; - static const String iconWarning ="icons/icon_warning.png"; + static const String iconWarning = "icons/icon_warning.png"; static const String iconSuccess = "icons/icon_success.png"; static const String iconStarSize = "images/icon_star_size.png"; - static const String iconStarSizeSelected = "images/icon_star_size_selected.png"; - static const String iconBottomPickerRightTopBg = "images/icon_bottom_picker_right_top_bg.png"; + static const String iconStarSizeSelected = + "images/icon_star_size_selected.png"; + static const String iconBottomPickerRightTopBg = + "images/icon_bottom_picker_right_top_bg.png"; static const String ICON_ARROWUP_SELECT = "images/icon_arrow_up_selected.png"; static const String ICON_REFRESH = "assets/images/icon_refresh.png"; - static const String ICON_ARROWDOWN_SELECT = "images/icon_arrow_down_selected.png"; - static const String ICON_ARROWDOWN_UNSELECT = "images/icon_arrow_down_unselected.png"; + static const String ICON_ARROWDOWN_SELECT = + "images/icon_arrow_down_selected.png"; + static const String ICON_ARROWDOWN_UNSELECT = + "images/icon_arrow_down_unselected.png"; static const String ICON_ARROW_RIGHT_1 = "icons/icon_right_arrow_1.png"; - static const String SELECT_CHECKED_STATUS = "images/select_checked_status.png"; + static const String SELECT_CHECKED_STATUS = + "images/select_checked_status.png"; static const String SELECT_NORMAL_STATUS = "icons/normol_border.png"; - static const String ICON_SELECTED_UP_TRIANGLE = "icons/icon_selcted_triangle.png"; - static const String ICON_UNSELECT_DOWN_TRIANGLE = "icons/icon_unselected_triangle.png"; + static const String ICON_SELECTED_UP_TRIANGLE = + "icons/icon_selcted_triangle.png"; + static const String ICON_UNSELECT_DOWN_TRIANGLE = + "icons/icon_unselected_triangle.png"; static const String ICON_REQUIRE_RED = 'icons/icon_require_red.png'; static const String ICON_RIGHT_ARROW = 'icons/icon_right_arrow.png'; static const String ICON_BACK_WHITE = 'assets/icons/icon_back_white.png'; @@ -44,8 +49,10 @@ class BrnAsset { static const String ICON_POPUP_CLOSE = 'icons/icon_popup_close.png'; static const String ICON_CLOSE = 'icons/icon_close.png'; - static const String ICON_CALENDAR_PRE_MONTH = 'icons/icon_calendar_pre_month.png'; - static const String ICON_CALENDAR_NEXT_MONTH = 'icons/icon_calendar_next_month.png'; + static const String ICON_CALENDAR_PRE_MONTH = + 'icons/icon_calendar_pre_month.png'; + static const String ICON_CALENDAR_NEXT_MONTH = + 'icons/icon_calendar_next_month.png'; static const String ICON_UP_ARROW = 'icons/icon_up_arrow.png'; static const String ICON_DOWN_ARROW = 'icons/icon_down_arrow.png'; @@ -58,37 +65,49 @@ class BrnAsset { static const String ICON_TRIANGLE_DOWN = 'icons/icon_triangle_down.png'; static const String ICON_TRIANGLE_UP = 'icons/icon_triangle_up.png'; - static const String ICON_PAIR_INFO_QUESTION = 'icons/icon_pait_info_question.png'; + static const String ICON_PAIR_INFO_QUESTION = + 'icons/icon_pait_info_question.png'; static const String ICON_PICKER_CLOSE = 'images/icon_guanbi.png'; static const String ICON_NOTICE = 'icons/icon_notice.png'; - static const String ICON_NOTICE_ARROW_BLUE = 'icons/icon_notice_arrow_blue.png'; - static const String ICON_NOTICE_ARROW_GREEN = 'icons/icon_notice_arrow_green.png'; - static const String ICON_NOTICE_ARROW_ORANGE = 'icons/icon_notice_arrow_orange.png'; + static const String ICON_NOTICE_ARROW_BLUE = + 'icons/icon_notice_arrow_blue.png'; + static const String ICON_NOTICE_ARROW_GREEN = + 'icons/icon_notice_arrow_green.png'; + static const String ICON_NOTICE_ARROW_ORANGE = + 'icons/icon_notice_arrow_orange.png'; static const String ICON_NOTICE_ARROW_RED = 'icons/icon_notice_arrow_red.png'; - static const String ICON_NOTICE_CLOSE_BLUE = 'icons/icon_notice_close_blue.png'; - static const String ICON_NOTICE_CLOSE_GREEN = 'icons/icon_notice_close_green.png'; - static const String ICON_NOTICE_CLOSE_ORANGE = 'icons/icon_notice_close_orange.png'; + static const String ICON_NOTICE_CLOSE_BLUE = + 'icons/icon_notice_close_blue.png'; + static const String ICON_NOTICE_CLOSE_GREEN = + 'icons/icon_notice_close_green.png'; + static const String ICON_NOTICE_CLOSE_ORANGE = + 'icons/icon_notice_close_orange.png'; static const String ICON_NOTICE_CLOSE_RED = 'icons/icon_notice_close_red.png'; static const String ICON_NOTICE_FAIL = 'icons/icon_notice_fail.png'; static const String ICON_NOTICE_RUNNING = 'icons/icon_notice_running.png'; static const String ICON_NOTICE_SUCCEED = 'icons/icon_notice_succeed.png'; static const String ICON_NOTICE_WARNING = 'icons/icon_notice_warning.png'; - static const String ICON_OPERATION_OTHER_RIGHT = 'icons/icon_operation_line_right.png'; - static const String ICON_OPERATION_OTHER_LEFT = 'icons/icon_operation_line_left.png'; + static const String ICON_OPERATION_OTHER_RIGHT = + 'icons/icon_operation_line_right.png'; + static const String ICON_OPERATION_OTHER_LEFT = + 'icons/icon_operation_line_left.png'; static const String ICON_RESULT_SUCCESS = 'icons/icon_result_success.png'; static const String ICON_RESULT_ERROR = 'icons/icon_result_error.png'; static const String ICON_STAR = 'icons/icon_star.png'; static const String ICON_STAR_HALF = 'icons/icon_star_half.png'; static const String ICON_UPARROW = 'icons/icon_uparrow.png'; static const String ICOS_QRCODE_BG = 'assets/images/icon_qrcode_bg.png'; - static const String ICONS_QRCODE_FAILED = '/assets/images/icon_qrcode_failed.png'; - static const String ICONS_REFRESH_WHITE = 'assets/images/icon_refresh_white.png'; + static const String ICONS_QRCODE_FAILED = + '/assets/images/icon_qrcode_failed.png'; + static const String ICONS_REFRESH_WHITE = + 'assets/images/icon_refresh_white.png'; static const String ICONS_AVATAR_NEW = '/assets/icons/img_avatar_new.png'; static const String ICON_AUDIOPALYER_PLAY = 'icons/icon_audioplayer_play.png'; - static const String ICON_AUDIOPALYER_PAUSE = 'icons/icon_audioplayer_pause.png'; + static const String ICON_AUDIOPALYER_PAUSE = + 'icons/icon_audioplayer_pause.png'; static const String ICON_GREY_PLACE_HOLDER = 'icons/grey_place_holder.png'; @@ -104,14 +123,19 @@ class BrnAsset { static const String ICON_IM = 'images/icon_im_blue.png'; static const String ICON_CALL = 'images/icon_call.png'; static const String ICON_CALL_DISABLE = 'images/icon_call_disable.png'; - static const String PERSON_PLACE_HOLDER = 'packages/bruno/assets/icons/img_avatar_new.png'; + static const String PERSON_PLACE_HOLDER = + 'packages/bruno/assets/icons/img_avatar_new.png'; /// radio组件,用于单选和多选 - static const String ICON_RADIO_MULTI_SELECTED = 'icons/radio/multiple_selected.png'; + static const String ICON_RADIO_MULTI_SELECTED = + 'icons/radio/multiple_selected.png'; static const String ICON_RADIO_UNSELECTED = 'icons/radio/unselected.png'; - static const String ICON_RADIO_DISABLE_MULTI_SELECTED = 'icons/radio/disable_multi_selected.png'; - static const String ICON_RADIO_DISABLE_UNSELECTED = 'icons/radio/disable_unselected.png'; - static const String ICON_RADIO_SINGLE_SELECTED = 'icons/radio/single_selected.png'; + static const String ICON_RADIO_DISABLE_MULTI_SELECTED = + 'icons/radio/disable_multi_selected.png'; + static const String ICON_RADIO_DISABLE_UNSELECTED = + 'icons/radio/disable_unselected.png'; + static const String ICON_RADIO_SINGLE_SELECTED = + 'icons/radio/single_selected.png'; static const String ICON_RADIO_DISABLE_SINGLE_SELECTED = 'icons/radio/disable_single_selected.png'; @@ -120,25 +144,32 @@ class BrnAsset { 'assets/images/icon_appraise_bad_unselected.png'; static const String ICON_APPRAISE_NOT_GOOD_UNSELECTED = 'assets/images/icon_appraise_not_good_unselected.png'; - static const String ICON_APPRAISE_OK_UNSELECTED = 'assets/images/icon_appraise_ok_unselected.png'; + static const String ICON_APPRAISE_OK_UNSELECTED = + 'assets/images/icon_appraise_ok_unselected.png'; static const String ICON_APPRAISE_GOOD_UNSELECTED = 'assets/images/icon_appraise_good_unselected.png'; static const String ICON_APPRAISE_SURPRISE_UNSELECTED = 'assets/images/icon_appraise_surprise_unselected.png'; - static const String ICON_APPRAISE_BAD_DEFAULT = 'assets/images/icon_appraise_bad_default.png'; + static const String ICON_APPRAISE_BAD_DEFAULT = + 'assets/images/icon_appraise_bad_default.png'; static const String ICON_APPRAISE_NOT_GOOD_DEFAULT = 'assets/images/icon_appraise_not_good_default.png'; - static const String ICON_APPRAISE_OK_DEFAULT = 'assets/images/icon_appraise_ok_default.png'; - static const String ICON_APPRAISE_GOOD_DEFAULT = 'assets/images/icon_appraise_good_default.png'; + static const String ICON_APPRAISE_OK_DEFAULT = + 'assets/images/icon_appraise_ok_default.png'; + static const String ICON_APPRAISE_GOOD_DEFAULT = + 'assets/images/icon_appraise_good_default.png'; static const String ICON_APPRAISE_SURPRISE_DEFAULT = 'assets/images/icon_appraise_surprise_default.png'; - static const String ICON_APPRAISE_BAD_SELECTED = 'assets/images/icon_appraise_bad_selected.png'; + static const String ICON_APPRAISE_BAD_SELECTED = + 'assets/images/icon_appraise_bad_selected.png'; static const String ICON_APPRAISE_NOT_GOOD_SELECTED = 'assets/images/icon_appraise_not_good_selected.png'; - static const String ICON_APPRAISE_OK_SELECTED = 'assets/images/icon_appraise_ok_selected.png'; - static const String ICON_APPRAISE_GOOD_SELECTED = 'assets/images/icon_appraise_good_selected.png'; + static const String ICON_APPRAISE_OK_SELECTED = + 'assets/images/icon_appraise_ok_selected.png'; + static const String ICON_APPRAISE_GOOD_SELECTED = + 'assets/images/icon_appraise_good_selected.png'; static const String ICON_APPRAISE_SURPRISE_SELECTED = 'assets/images/icon_appraise_surprise_selected.png'; static const String ICON_QUESTION = "icons/icon_question.png"; @@ -149,5 +180,4 @@ class BrnAsset { static const String ICON_MINUS_DISABLE = "icons/icon_minus_disable.png"; static const String ICON_MINUS_ENABLE = "icons/icon_minus_enable.png"; - } diff --git a/lib/src/theme/base/brn_base_config.dart b/lib/src/theme/base/brn_base_config.dart index d6584207..860c0005 100644 --- a/lib/src/theme/base/brn_base_config.dart +++ b/lib/src/theme/base/brn_base_config.dart @@ -8,7 +8,8 @@ abstract class BrnBaseConfig { BrnCommonConfig _currentLevelCommonConfig; BrnBaseConfig( - {this.configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID, bool autoFlatConfig = false}) { + {this.configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID, + bool autoFlatConfig = false}) { if (autoFlatConfig) { initThemeConfig(configId); } @@ -23,7 +24,8 @@ abstract class BrnBaseConfig { /// 当detailTextStyle中字段(如:color)为null时会使用commonConfig.colorTextBase /// 第二步 以默认上一级配置为基础merge 第一步结果,当第一步中字段(如:color)为空时 , /// 使用上一层级配置的color(cardTitleConfig.detailTextStyle.color) - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { _currentLevelCommonConfig = currentLevelCommonConfig; } diff --git a/lib/src/theme/base/brn_default_config_utils.dart b/lib/src/theme/base/brn_default_config_utils.dart index 16bd3ee8..ecad8989 100644 --- a/lib/src/theme/base/brn_default_config_utils.dart +++ b/lib/src/theme/base/brn_default_config_utils.dart @@ -177,20 +177,24 @@ class BrnDefaultConfigUtils { /// 表单项默认配置 static BrnFormItemConfig defaultFormItemConfig = BrnFormItemConfig( headTitleTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeHead), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeHead), titleTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeSubHead), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead), subTitleTextStyle: BrnTextStyle( color: defaultCommonConfig.colorTextSecondary, fontSize: defaultCommonConfig.fontSizeCaption), errorTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandError, fontSize: defaultCommonConfig.fontSizeCaption), + color: defaultCommonConfig.brandError, + fontSize: defaultCommonConfig.fontSizeCaption), hintTextStyle: BrnTextStyle( color: defaultCommonConfig.colorTextHint, fontSize: defaultCommonConfig.fontSizeSubHead, ), contentTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeSubHead), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead), optionsMiddlePadding: EdgeInsets.only(left: defaultCommonConfig.hSpacingMd), optionTextStyle: BrnTextStyle( height: 1.3, @@ -207,16 +211,19 @@ class BrnDefaultConfigUtils { bottom: defaultCommonConfig.vSpacingLg), titlePaddingSm: EdgeInsets.only(left: 10), titlePaddingLg: EdgeInsets.only(left: defaultCommonConfig.hSpacingLg), - subTitlePadding: - EdgeInsets.only(left: defaultCommonConfig.hSpacingLg, top: defaultCommonConfig.vSpacingXs), - errorPadding: - EdgeInsets.only(left: defaultCommonConfig.hSpacingLg, top: defaultCommonConfig.vSpacingXs), + subTitlePadding: EdgeInsets.only( + left: defaultCommonConfig.hSpacingLg, + top: defaultCommonConfig.vSpacingXs), + errorPadding: EdgeInsets.only( + left: defaultCommonConfig.hSpacingLg, + top: defaultCommonConfig.vSpacingXs), disableTextStyle: BrnTextStyle( color: defaultCommonConfig.colorTextDisabled, fontSize: defaultCommonConfig.fontSizeSubHead, ), tipsTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextSecondary, fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextSecondary, + fontSize: defaultCommonConfig.fontSizeBase), ); /// Dialog默认配置 @@ -225,18 +232,26 @@ class BrnDefaultConfigUtils { radius: defaultCommonConfig.radiusLg, iconPadding: EdgeInsets.only(top: defaultCommonConfig.vSpacingXxl), titlePaddingSm: EdgeInsets.only( - top: 12, left: defaultCommonConfig.hSpacingXxl, right: defaultCommonConfig.hSpacingXxl), + top: 12, + left: defaultCommonConfig.hSpacingXxl, + right: defaultCommonConfig.hSpacingXxl), titlePaddingLg: EdgeInsets.only( - top: 28, left: defaultCommonConfig.hSpacingXxl, right: defaultCommonConfig.hSpacingXxl), + top: 28, + left: defaultCommonConfig.hSpacingXxl, + right: defaultCommonConfig.hSpacingXxl), titleTextStyle: BrnTextStyle( fontWeight: FontWeight.w600, fontSize: defaultCommonConfig.fontSizeHead, color: defaultCommonConfig.colorTextBase), titleTextAlign: TextAlign.center, contentPaddingSm: EdgeInsets.only( - top: 8, left: defaultCommonConfig.hSpacingXl, right: defaultCommonConfig.hSpacingXl), + top: 8, + left: defaultCommonConfig.hSpacingXl, + right: defaultCommonConfig.hSpacingXl), contentPaddingLg: EdgeInsets.only( - top: 28, left: defaultCommonConfig.hSpacingXl, right: defaultCommonConfig.hSpacingXl), + top: 28, + left: defaultCommonConfig.hSpacingXl, + right: defaultCommonConfig.hSpacingXl), contentTextStyle: BrnTextStyle( fontSize: defaultCommonConfig.fontSizeBase, color: defaultCommonConfig.colorTextImportant, @@ -244,9 +259,13 @@ class BrnDefaultConfigUtils { ), contentTextAlign: TextAlign.center, warningPaddingSm: EdgeInsets.only( - top: 6, left: defaultCommonConfig.hSpacingXl, right: defaultCommonConfig.hSpacingXl), + top: 6, + left: defaultCommonConfig.hSpacingXl, + right: defaultCommonConfig.hSpacingXl), warningPaddingLg: EdgeInsets.only( - top: 28, left: defaultCommonConfig.hSpacingXl, right: defaultCommonConfig.hSpacingXl), + top: 28, + left: defaultCommonConfig.hSpacingXl, + right: defaultCommonConfig.hSpacingXl), warningTextAlign: TextAlign.center, warningTextStyle: BrnTextStyle( fontSize: defaultCommonConfig.fontSizeBase, @@ -283,41 +302,48 @@ class BrnDefaultConfigUtils { fontSize: defaultCommonConfig.fontSizeBase, ), detailTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeBase), accessoryTextStyle: BrnTextStyle( color: defaultCommonConfig.colorTextSecondary, fontSize: defaultCommonConfig.fontSizeBase, ), cardTitlePadding: EdgeInsets.only( - top: defaultCommonConfig.vSpacingXl, bottom: defaultCommonConfig.vSpacingMd), + top: defaultCommonConfig.vSpacingXl, + bottom: defaultCommonConfig.vSpacingMd), alignment: PlaceholderAlignment.middle, cardBackgroundColor: defaultCommonConfig.fillBase, ); /// 空页面配置 - static BrnAbnormalStateConfig defaultAbnormalStateConfig = BrnAbnormalStateConfig( - titleTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeSubHead, - fontWeight: FontWeight.w600), - contentTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextHint, fontSize: defaultCommonConfig.fontSizeBase), - operateTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, fontSize: defaultCommonConfig.fontSizeBase), - btnRadius: 4, - doubleBrnTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, fontSize: defaultCommonConfig.fontSizeSubHead), - singleBrnTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBaseInverse, - fontSize: defaultCommonConfig.fontSizeSubHead, - ), - singleMinWidth: 160, - doubleMinWidth: 120); + static BrnAbnormalStateConfig defaultAbnormalStateConfig = + BrnAbnormalStateConfig( + titleTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead, + fontWeight: FontWeight.w600), + contentTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextHint, + fontSize: defaultCommonConfig.fontSizeBase), + operateTextStyle: BrnTextStyle( + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeBase), + btnRadius: 4, + doubleBrnTextStyle: BrnTextStyle( + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeSubHead), + singleBrnTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBaseInverse, + fontSize: defaultCommonConfig.fontSizeSubHead, + ), + singleMinWidth: 160, + doubleMinWidth: 120); /// 标签配置 static BrnTagConfig defaultTagConfig = BrnTagConfig( tagTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeCaption), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeCaption), selectTagTextStyle: BrnTextStyle( fontWeight: FontWeight.w600, color: defaultCommonConfig.brandPrimary, @@ -357,20 +383,25 @@ class BrnDefaultConfigUtils { systemUiOverlayStyle: SystemUiOverlayStyle.dark); /// 内容信息(两列)配置 - static BrnPairInfoTableConfig defaultPairInfoTableConfig = BrnPairInfoTableConfig( + static BrnPairInfoTableConfig defaultPairInfoTableConfig = + BrnPairInfoTableConfig( rowSpacing: 4, itemSpacing: 2, keyTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextSecondary, fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextSecondary, + fontSize: defaultCommonConfig.fontSizeBase), valueTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeBase), linkTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeBase), configId: BrnThemeConfigurator.BRUNO_CONFIG_ID, ); /// 内容信息(一列)配置 - static BrnPairRichInfoGridConfig defaultPairRichInfoGridConfig = BrnPairRichInfoGridConfig( + static BrnPairRichInfoGridConfig defaultPairRichInfoGridConfig = + BrnPairRichInfoGridConfig( rowSpacing: 4, itemSpacing: 2, itemHeight: 20, @@ -403,7 +434,8 @@ class BrnDefaultConfigUtils { static BrnActionSheetConfig defaultActionSheetConfig = BrnActionSheetConfig( topRadius: defaultCommonConfig.radiusLg, titleStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextSecondary, fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextSecondary, + fontSize: defaultCommonConfig.fontSizeBase), itemTitleStyle: BrnTextStyle( color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeSubHead, @@ -445,9 +477,11 @@ class BrnDefaultConfigUtils { static BrnPickerConfig defaultPickerConfig = BrnPickerConfig( backgroundColor: PICKER_BACKGROUND_COLOR, cancelTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeSubHead), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead), confirmTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, fontSize: defaultCommonConfig.fontSizeSubHead), + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeSubHead), titleTextStyle: BrnTextStyle( color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeSubHead, @@ -458,7 +492,8 @@ class BrnDefaultConfigUtils { itemHeight: PICKER_ITEM_HEIGHT, dividerColor: Color(0xFFF0F0F0), itemTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeHead), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeHead), itemTextSelectedStyle: BrnTextStyle( color: defaultCommonConfig.brandPrimary, fontSize: defaultCommonConfig.fontSizeHead, @@ -468,11 +503,13 @@ class BrnDefaultConfigUtils { ); /// 数字增强信息配置 - static BrnEnhanceNumberCardConfig defaultNumberInfoConfig = BrnEnhanceNumberCardConfig( + static BrnEnhanceNumberCardConfig defaultNumberInfoConfig = + BrnEnhanceNumberCardConfig( runningSpace: 16, itemRunningSpace: 8, titleTextStyle: BrnTextStyle(fontSize: 28, fontWeight: FontWeight.w600), - descTextStyle: BrnTextStyle(fontSize: 12, color: defaultCommonConfig.colorTextSecondary), + descTextStyle: BrnTextStyle( + fontSize: 12, color: defaultCommonConfig.colorTextSecondary), dividerWidth: 0.5, ); @@ -491,10 +528,12 @@ class BrnDefaultConfigUtils { fontWeight: FontWeight.normal), tagRadius: defaultCommonConfig.radiusSm, tagNormalTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeCaption), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeCaption), tagNormalBgColor: defaultCommonConfig.brandPrimary.withAlpha(0x14), tagSelectedTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, fontSize: defaultCommonConfig.fontSizeCaption), + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeCaption), tagSelectedBgColor: defaultCommonConfig.fillBody, tagSpacing: 12, preLineTagCount: 4, @@ -504,13 +543,15 @@ class BrnDefaultConfigUtils { /// 筛选项配置 static BrnSelectionConfig defaultSelectionConfig = BrnSelectionConfig( menuNormalTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeBase), menuSelectedTextStyle: BrnTextStyle( fontWeight: FontWeight.w600, fontSize: defaultCommonConfig.fontSizeBase, color: defaultCommonConfig.brandPrimary), tagNormalTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeCaption), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeCaption), tagSelectedTextStyle: BrnTextStyle( color: defaultCommonConfig.brandPrimary, fontSize: defaultCommonConfig.fontSizeCaption, @@ -518,17 +559,21 @@ class BrnDefaultConfigUtils { ), tagRadius: defaultCommonConfig.radiusSm, tagNormalBackgroundColor: defaultCommonConfig.fillBody, - tagSelectedBackgroundColor: defaultCommonConfig.brandPrimary.withOpacity(0.12), + tagSelectedBackgroundColor: + defaultCommonConfig.brandPrimary.withOpacity(0.12), rangeTitleTextStyle: BrnTextStyle( color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeSubHead, fontWeight: FontWeight.w600), hintTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextHint, fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextHint, + fontSize: defaultCommonConfig.fontSizeBase), inputTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeBase), itemNormalTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeBase), itemSelectedTextStyle: BrnTextStyle( color: defaultCommonConfig.brandPrimary, fontSize: defaultCommonConfig.fontSizeBase, @@ -554,13 +599,15 @@ class BrnDefaultConfigUtils { fontWeight: FontWeight.w600, ), optionTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeBase), moreTextStyle: BrnTextStyle( color: defaultCommonConfig.colorTextSecondary, fontSize: defaultCommonConfig.fontSizeCaption, ), flayNormalTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeSubHead), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead), flatSelectedTextStyle: BrnTextStyle( color: defaultCommonConfig.brandPrimary, fontSize: defaultCommonConfig.fontSizeSubHead, @@ -571,7 +618,8 @@ class BrnDefaultConfigUtils { fontWeight: FontWeight.w600)); /// 查看图片配置 - static BrnGalleryDetailConfig defaultGalleryDetailConfig = BrnGalleryDetailConfig( + static BrnGalleryDetailConfig defaultGalleryDetailConfig = + BrnGalleryDetailConfig( appbarTitleStyle: BrnTextStyle( color: defaultCommonConfig.colorTextBaseInverse, fontSize: defaultCommonConfig.fontSizeSubHead, @@ -583,7 +631,8 @@ class BrnDefaultConfigUtils { fontWeight: FontWeight.w600), appbarBackgroundColor: Colors.black, appbarBrightness: Brightness.dark, - tabBarUnSelectedLabelStyle: BrnTextStyle(fontSize: 16, color: Color(0XFFCCCCCC)), + tabBarUnSelectedLabelStyle: + BrnTextStyle(fontSize: 16, color: Color(0XFFCCCCCC)), tabBarLabelStyle: BrnTextStyle( fontSize: defaultCommonConfig.fontSizeSubHead, fontWeight: FontWeight.w600, @@ -595,8 +644,8 @@ class BrnDefaultConfigUtils { color: defaultCommonConfig.colorTextBaseInverse, fontSize: defaultCommonConfig.fontSizeHead, fontWeight: FontWeight.w600), - contentStyle: - BrnTextStyle(color: Color(0xFFCCCCCC), fontSize: defaultCommonConfig.fontSizeBase), + contentStyle: BrnTextStyle( + color: Color(0xFFCCCCCC), fontSize: defaultCommonConfig.fontSizeBase), actionStyle: BrnTextStyle( color: defaultCommonConfig.colorTextBaseInverse, fontSize: defaultCommonConfig.fontSizeBase), diff --git a/lib/src/theme/brn_initializer.dart b/lib/src/theme/brn_initializer.dart index 0057ef10..a8f19d88 100644 --- a/lib/src/theme/brn_initializer.dart +++ b/lib/src/theme/brn_initializer.dart @@ -15,6 +15,7 @@ class BrnInitializer { if (brunoImgUtils != null) { BrnThemeImg.register(brunoImgUtils: brunoImgUtils); } + /// 配置主题定制 BrnThemeConfigurator.instance.register(allThemeConfig, configId: configId); } diff --git a/lib/src/theme/brn_theme_configurator.dart b/lib/src/theme/brn_theme_configurator.dart index 47483106..90fa0e4e 100644 --- a/lib/src/theme/brn_theme_configurator.dart +++ b/lib/src/theme/brn_theme_configurator.dart @@ -15,7 +15,8 @@ class BrnThemeConfigurator { } /// 手动注册时,默认注册渠道是 GLOBAL_CONFIG_ID - void register(BrnAllThemeConfig allThemeConfig, {String configId = GLOBAL_CONFIG_ID}) { + void register(BrnAllThemeConfig allThemeConfig, + {String configId = GLOBAL_CONFIG_ID}) { assert(configId != null); /// 先赋值默认配置 diff --git a/lib/src/theme/configs/brn_abnormal_state_config.dart b/lib/src/theme/configs/brn_abnormal_state_config.dart index 2ce6168e..48265af7 100644 --- a/lib/src/theme/configs/brn_abnormal_state_config.dart +++ b/lib/src/theme/configs/brn_abnormal_state_config.dart @@ -50,31 +50,43 @@ class BrnAbnormalStateConfig extends BrnBaseConfig { : super(configId: configId); @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); /// 用户全局组件配置 - BrnAbnormalStateConfig abnormalStateConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).abnormalStateConfig; + BrnAbnormalStateConfig abnormalStateConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .abnormalStateConfig; - this.singleBrnTextStyle = abnormalStateConfig.singleBrnTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBaseInverse, fontSize: commonConfig.fontSizeSubHead) - .merge(this.singleBrnTextStyle)); + this.singleBrnTextStyle = abnormalStateConfig.singleBrnTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBaseInverse, + fontSize: commonConfig.fontSizeSubHead) + .merge(this.singleBrnTextStyle)); - this.titleTextStyle = abnormalStateConfig.titleTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeSubHead) - .merge(this.titleTextStyle)); + this.titleTextStyle = abnormalStateConfig.titleTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead) + .merge(this.titleTextStyle)); this.contentTextStyle = abnormalStateConfig.contentTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextHint, fontSize: commonConfig.fontSizeSubHead) + BrnTextStyle( + color: commonConfig.colorTextHint, + fontSize: commonConfig.fontSizeSubHead) .merge(this.contentTextStyle)); this.operateTextStyle = abnormalStateConfig.operateTextStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeBase) + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeBase) .merge(this.operateTextStyle)); this.doubleBrnTextStyle = abnormalStateConfig.doubleBrnTextStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeSubHead) + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeSubHead) .merge(this.doubleBrnTextStyle)); this.btnRadius ??= abnormalStateConfig.btnRadius; @@ -109,14 +121,17 @@ class BrnAbnormalStateConfig extends BrnBaseConfig { BrnAbnormalStateConfig merge(BrnAbnormalStateConfig other) { if (other == null) return this; return copyWith( - titleTextStyle: titleTextStyle?.merge(other.titleTextStyle) ?? other.titleTextStyle, - contentTextStyle: contentTextStyle?.merge(other.contentTextStyle) ?? other.contentTextStyle, - operateTextStyle: operateTextStyle?.merge(other.operateTextStyle) ?? other.operateTextStyle, + titleTextStyle: + titleTextStyle?.merge(other.titleTextStyle) ?? other.titleTextStyle, + contentTextStyle: contentTextStyle?.merge(other.contentTextStyle) ?? + other.contentTextStyle, + operateTextStyle: operateTextStyle?.merge(other.operateTextStyle) ?? + other.operateTextStyle, btnRadius: other.btnRadius, - doubleBrnTextStyle: - doubleBrnTextStyle?.merge(other.doubleBrnTextStyle) ?? other.doubleBrnTextStyle, - singleBrnTextStyle: - singleBrnTextStyle?.merge(other.singleBrnTextStyle) ?? other.singleBrnTextStyle, + doubleBrnTextStyle: doubleBrnTextStyle?.merge(other.doubleBrnTextStyle) ?? + other.doubleBrnTextStyle, + singleBrnTextStyle: singleBrnTextStyle?.merge(other.singleBrnTextStyle) ?? + other.singleBrnTextStyle, singleMinWidth: other.singleMinWidth, doubleMinWidth: other.doubleMinWidth, ); diff --git a/lib/src/theme/configs/brn_action_sheet_config.dart b/lib/src/theme/configs/brn_action_sheet_config.dart index 721225f5..788b1ddb 100644 --- a/lib/src/theme/configs/brn_action_sheet_config.dart +++ b/lib/src/theme/configs/brn_action_sheet_config.dart @@ -67,48 +67,63 @@ class BrnActionSheetConfig extends BrnBaseConfig { EdgeInsets titlePadding; @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); /// 用户全局组件配置 - BrnActionSheetConfig actionSheetConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).actionSheetConfig; + BrnActionSheetConfig actionSheetConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .actionSheetConfig; this.titlePadding ??= actionSheetConfig.titlePadding; this.contentPadding ??= actionSheetConfig.contentPadding; - this.titleStyle = actionSheetConfig.titleStyle.merge( - BrnTextStyle(color: commonConfig.colorTextSecondary, fontSize: commonConfig.fontSizeBase) - .merge(this.titleStyle)); + this.titleStyle = actionSheetConfig.titleStyle.merge(BrnTextStyle( + color: commonConfig.colorTextSecondary, + fontSize: commonConfig.fontSizeBase) + .merge(this.titleStyle)); - this.itemTitleStyle = actionSheetConfig.itemTitleStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeSubHead) - .merge(this.itemTitleStyle)); + this.itemTitleStyle = actionSheetConfig.itemTitleStyle.merge(BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead) + .merge(this.itemTitleStyle)); this.itemTitleStyleLink = actionSheetConfig.itemTitleStyleLink.merge( - BrnTextStyle(color: commonConfig.colorLink, fontSize: commonConfig.fontSizeSubHead) + BrnTextStyle( + color: commonConfig.colorLink, + fontSize: commonConfig.fontSizeSubHead) .merge(this.itemTitleStyleLink)); this.itemTitleStyleAlert = actionSheetConfig.itemTitleStyleAlert.merge( - BrnTextStyle(color: commonConfig.brandError, fontSize: commonConfig.fontSizeBase) + BrnTextStyle( + color: commonConfig.brandError, + fontSize: commonConfig.fontSizeBase) .merge(this.itemTitleStyleAlert)); - this.itemDescStyle = actionSheetConfig.itemDescStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeCaption) - .merge(this.itemDescStyle)); + this.itemDescStyle = actionSheetConfig.itemDescStyle.merge(BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeCaption) + .merge(this.itemDescStyle)); this.itemDescStyleLink = actionSheetConfig.itemDescStyleLink.merge( - BrnTextStyle(color: commonConfig.colorLink, fontSize: commonConfig.fontSizeCaption) + BrnTextStyle( + color: commonConfig.colorLink, + fontSize: commonConfig.fontSizeCaption) .merge(this.itemDescStyleLink)); this.itemDescStyleAlert = actionSheetConfig.itemDescStyleAlert.merge( - BrnTextStyle(color: commonConfig.brandError, fontSize: commonConfig.fontSizeCaption) + BrnTextStyle( + color: commonConfig.brandError, + fontSize: commonConfig.fontSizeCaption) .merge(this.itemDescStyleAlert)); - this.cancelStyle = actionSheetConfig.cancelStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeSubHead) - .merge(this.cancelStyle)); + this.cancelStyle = actionSheetConfig.cancelStyle.merge(BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead) + .merge(this.cancelStyle)); this.topRadius ??= commonConfig.radiusLg; } @@ -161,17 +176,24 @@ class BrnActionSheetConfig extends BrnBaseConfig { if (other == null) return this; return copyWith( titleStyle: this.titleStyle?.merge(other.titleStyle) ?? other.titleStyle, - itemTitleStyle: this.itemTitleStyle?.merge(other.itemTitleStyle) ?? other.itemTitleStyle, + itemTitleStyle: this.itemTitleStyle?.merge(other.itemTitleStyle) ?? + other.itemTitleStyle, itemTitleStyleLink: - this.itemTitleStyleLink?.merge(other.itemTitleStyleLink) ?? other.itemTitleStyleLink, + this.itemTitleStyleLink?.merge(other.itemTitleStyleLink) ?? + other.itemTitleStyleLink, itemTitleStyleAlert: - this.itemTitleStyleAlert?.merge(other.itemTitleStyleAlert) ?? other.itemTitleStyleAlert, - itemDescStyle: this.itemDescStyle?.merge(other.itemDescStyle) ?? other.itemDescStyle, + this.itemTitleStyleAlert?.merge(other.itemTitleStyleAlert) ?? + other.itemTitleStyleAlert, + itemDescStyle: + this.itemDescStyle?.merge(other.itemDescStyle) ?? other.itemDescStyle, itemDescStyleLink: - this.itemDescStyleLink?.merge(other.itemDescStyleLink) ?? other.itemDescStyleLink, + this.itemDescStyleLink?.merge(other.itemDescStyleLink) ?? + other.itemDescStyleLink, itemDescStyleAlert: - this.itemDescStyleAlert?.merge(other.itemDescStyleAlert) ?? other.itemDescStyleAlert, - cancelStyle: this.cancelStyle?.merge(other.cancelStyle) ?? other.cancelStyle, + this.itemDescStyleAlert?.merge(other.itemDescStyleAlert) ?? + other.itemDescStyleAlert, + cancelStyle: + this.cancelStyle?.merge(other.cancelStyle) ?? other.cancelStyle, topRadius: other.topRadius, contentPadding: other.contentPadding, titlePadding: other.titlePadding, diff --git a/lib/src/theme/configs/brn_all_config.dart b/lib/src/theme/configs/brn_all_config.dart index a161fc28..d3292b26 100644 --- a/lib/src/theme/configs/brn_all_config.dart +++ b/lib/src/theme/configs/brn_all_config.dart @@ -47,7 +47,6 @@ class BrnAllThemeConfig { String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID}); void initThemeConfig(String configId) { - this.commonConfig ??= BrnCommonConfig(); this.appBarConfig ??= BrnAppBarConfig(); this.buttonConfig ??= BrnButtonConfig(); @@ -67,20 +66,35 @@ class BrnAllThemeConfig { this.galleryDetailConfig ??= BrnGalleryDetailConfig(); commonConfig?.initThemeConfig(configId); - appBarConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); - buttonConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); - dialogConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); - formItemConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); - cardTitleConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); - abnormalStateConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); - tagConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); - pairInfoTableConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); - pairRichInfoGridConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); - selectionConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); - actionSheetConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); - pickerConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); - enhanceNumberCardConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); - tabBarConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); - galleryDetailConfig?.initThemeConfig(configId, currentLevelCommonConfig: commonConfig); + appBarConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); + buttonConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); + dialogConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); + formItemConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); + cardTitleConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); + abnormalStateConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); + tagConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); + pairInfoTableConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); + pairRichInfoGridConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); + selectionConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); + actionSheetConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); + pickerConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); + enhanceNumberCardConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); + tabBarConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); + galleryDetailConfig?.initThemeConfig(configId, + currentLevelCommonConfig: commonConfig); } } diff --git a/lib/src/theme/configs/brn_appbar_config.dart b/lib/src/theme/configs/brn_appbar_config.dart index 62ba6703..4633f6c6 100644 --- a/lib/src/theme/configs/brn_appbar_config.dart +++ b/lib/src/theme/configs/brn_appbar_config.dart @@ -134,12 +134,15 @@ class BrnAppBarConfig extends BrnBaseConfig { SystemUiOverlayStyle systemUiOverlayStyle; @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); /// 用户全局组件配置 - BrnAppBarConfig appbarConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).appBarConfig; + BrnAppBarConfig appbarConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .appBarConfig; this.backgroundColor ??= appbarConfig?.backgroundColor; this.appBarHeight ??= appbarConfig?.appBarHeight; @@ -181,7 +184,8 @@ class BrnAppBarConfig extends BrnBaseConfig { titlePadding: titlePading ?? this.titlePadding, iconSize: iconSize ?? this.iconSize, flexibleSpace: flexibleSpace ?? this.flexibleSpace, - systemUiOverlayStyle: systemUiOverlayStyle ?? this.systemUiOverlayStyle); + systemUiOverlayStyle: + systemUiOverlayStyle ?? this.systemUiOverlayStyle); } BrnAppBarConfig merge(BrnAppBarConfig other) { @@ -190,8 +194,10 @@ class BrnAppBarConfig extends BrnBaseConfig { backgroundColor: other.backgroundColor, appBarHeight: other.appBarHeight, leadIconBuilder: other.leadIconBuilder, - titleStyle: this.titleStyle?.merge(other.titleStyle) ?? other.titleStyle, - actionsStyle: this.actionsStyle?.merge(other.actionsStyle) ?? other.actionsStyle, + titleStyle: + this.titleStyle?.merge(other.titleStyle) ?? other.titleStyle, + actionsStyle: + this.actionsStyle?.merge(other.actionsStyle) ?? other.actionsStyle, titleMaxLength: other.titleMaxLength, leftAndRightPadding: other.leftAndRightPadding, itemSpacing: other.itemSpacing, diff --git a/lib/src/theme/configs/brn_button_config.dart b/lib/src/theme/configs/brn_button_config.dart index bed40ff9..b57dc912 100644 --- a/lib/src/theme/configs/brn_button_config.dart +++ b/lib/src/theme/configs/brn_button_config.dart @@ -32,11 +32,14 @@ class BrnButtonConfig extends BrnBaseConfig { double smallButtonFontSize; @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); - BrnButtonConfig userConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).buttonConfig; + BrnButtonConfig userConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .buttonConfig; this.bigButtonRadius ??= userConfig?.bigButtonRadius; this.bigButtonHeight ??= userConfig?.bigButtonHeight; diff --git a/lib/src/theme/configs/brn_card_title_config.dart b/lib/src/theme/configs/brn_card_title_config.dart index 16ac79a5..84a32fd7 100644 --- a/lib/src/theme/configs/brn_card_title_config.dart +++ b/lib/src/theme/configs/brn_card_title_config.dart @@ -52,11 +52,14 @@ class BrnCardTitleConfig extends BrnBaseConfig { /// cardTitleConfig 获取逻辑详见 [BrnThemeConfigurator.getConfig] 方法 @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); - BrnCardTitleConfig cardTitleConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).cardTitleConfig; + BrnCardTitleConfig cardTitleConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .cardTitleConfig; this.cardBackgroundColor ??= commonConfig.fillBase; @@ -68,8 +71,10 @@ class BrnCardTitleConfig extends BrnBaseConfig { bottom: commonConfig.vSpacingMd); } - this.titleWithHeightTextStyle = cardTitleConfig.titleWithHeightTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeHead) + this.titleWithHeightTextStyle = cardTitleConfig.titleWithHeightTextStyle + .merge(BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeHead) .merge(this.titleWithHeightTextStyle)); this.titleTextStyle = cardTitleConfig.titleTextStyle.merge(BrnTextStyle( @@ -77,12 +82,14 @@ class BrnCardTitleConfig extends BrnBaseConfig { fontSize: commonConfig.fontSizeHead, ).merge(this.titleTextStyle)); - this.subtitleTextStyle = cardTitleConfig.subtitleTextStyle.merge(BrnTextStyle( + this.subtitleTextStyle = + cardTitleConfig.subtitleTextStyle.merge(BrnTextStyle( color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeBase, ).merge(this.subtitleTextStyle)); - this.accessoryTextStyle = cardTitleConfig.accessoryTextStyle.merge(BrnTextStyle( + this.accessoryTextStyle = + cardTitleConfig.accessoryTextStyle.merge(BrnTextStyle( color: commonConfig.colorTextSecondary, fontSize: commonConfig.fontSizeHead, ).merge(this.accessoryTextStyle)); @@ -106,7 +113,8 @@ class BrnCardTitleConfig extends BrnBaseConfig { Color cardBackgroundColor}) { return BrnCardTitleConfig( cardTitlePadding: cardTitlePadding ?? this.cardTitlePadding, - titleWithHeightTextStyle: titleWithHeightTextStyle ?? this.titleWithHeightTextStyle, + titleWithHeightTextStyle: + titleWithHeightTextStyle ?? this.titleWithHeightTextStyle, titleTextStyle: titleTextStyle ?? this.titleTextStyle, subtitleTextStyle: subtitleTextStyle ?? this.subtitleTextStyle, detailTextStyle: detailTextStyle ?? this.detailTextStyle, @@ -119,15 +127,20 @@ class BrnCardTitleConfig extends BrnBaseConfig { if (other == null) return this; return copyWith( cardTitlePadding: other.cardTitlePadding, - titleWithHeightTextStyle: - this.titleWithHeightTextStyle?.merge(other.titleWithHeightTextStyle) ?? - other.titleWithHeightTextStyle, - titleTextStyle: this.titleTextStyle?.merge(other.titleTextStyle) ?? other.titleTextStyle, + titleWithHeightTextStyle: this + .titleWithHeightTextStyle + ?.merge(other.titleWithHeightTextStyle) ?? + other.titleWithHeightTextStyle, + titleTextStyle: this.titleTextStyle?.merge(other.titleTextStyle) ?? + other.titleTextStyle, subtitleTextStyle: - this.subtitleTextStyle?.merge(other.subtitleTextStyle) ?? other.subtitleTextStyle, - detailTextStyle: this.detailTextStyle?.merge(other.detailTextStyle) ?? other.detailTextStyle, + this.subtitleTextStyle?.merge(other.subtitleTextStyle) ?? + other.subtitleTextStyle, + detailTextStyle: this.detailTextStyle?.merge(other.detailTextStyle) ?? + other.detailTextStyle, accessoryTextStyle: - this.accessoryTextStyle?.merge(other.accessoryTextStyle) ?? other.accessoryTextStyle, + this.accessoryTextStyle?.merge(other.accessoryTextStyle) ?? + other.accessoryTextStyle, alignment: other.alignment, cardBackgroundColor: other.cardBackgroundColor, ); diff --git a/lib/src/theme/configs/brn_common_config.dart b/lib/src/theme/configs/brn_common_config.dart index ccbcdeb0..4b80efda 100644 --- a/lib/src/theme/configs/brn_common_config.dart +++ b/lib/src/theme/configs/brn_common_config.dart @@ -67,12 +67,10 @@ class BrnCommonConfig extends BrnBaseConfig { /// default value is Color(0xFF999999) Color colorTextDisabled; - /// 文本框提示暗文文字色 /// default value is Color(0xFFCCCCCC) Color colorTextHint; - /// 跟随主题色[brandPrimary] Color colorLink; @@ -325,7 +323,8 @@ class BrnCommonConfig extends BrnBaseConfig { /// 优先级 [GLOBAL_CONFIG_ID] 获取配置 > [BRUNO_CONFIG_ID] 获取配置 @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { /// 获取合适的 完整配置(BrnAllConfig) this.colorTextBase ??= commonConfig.colorTextBase; this.colorTextImportant ??= commonConfig.colorTextImportant; diff --git a/lib/src/theme/configs/brn_dialog_config.dart b/lib/src/theme/configs/brn_dialog_config.dart index 04f01c6c..3529ec86 100644 --- a/lib/src/theme/configs/brn_dialog_config.dart +++ b/lib/src/theme/configs/brn_dialog_config.dart @@ -129,12 +129,15 @@ class BrnDialogConfig extends BrnBaseConfig { /// ③ 如果全局配置中的配置同样为 null 则根据 [configId] 取出全局配置。 /// ④ 如果没有配置 [configId] 的全局配置,则使用 Bruno 默认的配置 @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); /// 用户全局组件配置 - BrnDialogConfig dialogConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).dialogConfig; + BrnDialogConfig dialogConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .dialogConfig; this.dialogWidth ??= dialogConfig?.dialogWidth; @@ -164,24 +167,30 @@ class BrnDialogConfig extends BrnBaseConfig { bottom: dialogConfig.iconPadding.bottom); } - this.titleTextStyle = dialogConfig.titleTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeHead) - .merge(this.titleTextStyle)); + this.titleTextStyle = dialogConfig.titleTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeHead) + .merge(this.titleTextStyle)); - this.contentTextStyle = dialogConfig.contentTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextImportant, fontSize: commonConfig.fontSizeBase) - .merge(this.contentTextStyle)); + this.contentTextStyle = dialogConfig.contentTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextImportant, + fontSize: commonConfig.fontSizeBase) + .merge(this.contentTextStyle)); - this.warningTextStyle = dialogConfig.warningTextStyle.merge( - BrnTextStyle(color: commonConfig.brandError, fontSize: commonConfig.fontSizeBase) - .merge(this.warningTextStyle)); + this.warningTextStyle = dialogConfig.warningTextStyle.merge(BrnTextStyle( + color: commonConfig.brandError, fontSize: commonConfig.fontSizeBase) + .merge(this.warningTextStyle)); this.mainActionTextStyle = dialogConfig.mainActionTextStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeSubHead) + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeSubHead) .merge(this.mainActionTextStyle)); this.assistActionsTextStyle = dialogConfig.assistActionsTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeSubHead) + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead) .merge(this.assistActionsTextStyle)); if (this.contentPaddingSm == null) { @@ -274,8 +283,10 @@ class BrnDialogConfig extends BrnBaseConfig { warningTextAlign: warningTextAlign ?? this.warningTextAlign, dividerPadding: dividerPadding ?? this.dividerPadding, mainActionTextStyle: mainActionTextStyle ?? this.mainActionTextStyle, - assistActionsTextStyle: assistActionsTextStyle ?? this.assistActionsTextStyle, - mainActionBackgroundColor: mainActionBackgroundColor ?? this.mainActionBackgroundColor, + assistActionsTextStyle: + assistActionsTextStyle ?? this.assistActionsTextStyle, + mainActionBackgroundColor: + mainActionBackgroundColor ?? this.mainActionBackgroundColor, assistActionsBackgroundColor: assistActionsBackgroundColor ?? this.assistActionsBackgroundColor, bottomHeight: bottomHeight ?? this.bottomHeight, @@ -290,21 +301,26 @@ class BrnDialogConfig extends BrnBaseConfig { iconPadding: other.iconPadding, titlePaddingSm: other.titlePaddingSm, titlePaddingLg: other.titlePaddingLg, - titleTextStyle: titleTextStyle?.merge(other.titleTextStyle) ?? other.titleTextStyle, + titleTextStyle: + titleTextStyle?.merge(other.titleTextStyle) ?? other.titleTextStyle, titleTextAlign: other.titleTextAlign, contentPaddingSm: other.contentPaddingSm, contentPaddingLg: other.contentPaddingLg, - contentTextStyle: contentTextStyle?.merge(other.contentTextStyle) ?? other.contentTextStyle, + contentTextStyle: contentTextStyle?.merge(other.contentTextStyle) ?? + other.contentTextStyle, contentTextAlign: other.contentTextAlign, warningPaddingSm: other.warningPaddingSm, warningPaddingLg: other.warningPaddingLg, - warningTextStyle: warningTextStyle?.merge(other.warningTextStyle) ?? other.warningTextStyle, + warningTextStyle: warningTextStyle?.merge(other.warningTextStyle) ?? + other.warningTextStyle, warningTextAlign: other.warningTextAlign, dividerPadding: other.dividerPadding, mainActionTextStyle: - mainActionTextStyle?.merge(other.mainActionTextStyle) ?? other.mainActionTextStyle, - assistActionsTextStyle: assistActionsTextStyle?.merge(other.assistActionsTextStyle) ?? - other.assistActionsTextStyle, + mainActionTextStyle?.merge(other.mainActionTextStyle) ?? + other.mainActionTextStyle, + assistActionsTextStyle: + assistActionsTextStyle?.merge(other.assistActionsTextStyle) ?? + other.assistActionsTextStyle, mainActionBackgroundColor: other.mainActionBackgroundColor, assistActionsBackgroundColor: other.assistActionsBackgroundColor, bottomHeight: other.bottomHeight, diff --git a/lib/src/theme/configs/brn_enhance_number_card_config.dart b/lib/src/theme/configs/brn_enhance_number_card_config.dart index fc5b3ec4..231d8faa 100644 --- a/lib/src/theme/configs/brn_enhance_number_card_config.dart +++ b/lib/src/theme/configs/brn_enhance_number_card_config.dart @@ -25,21 +25,26 @@ class BrnEnhanceNumberCardConfig extends BrnBaseConfig { BrnTextStyle descTextStyle; @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); - BrnEnhanceNumberCardConfig userConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).enhanceNumberCardConfig; + BrnEnhanceNumberCardConfig userConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .enhanceNumberCardConfig; this.runningSpace ??= userConfig.runningSpace; this.itemRunningSpace ??= userConfig.itemRunningSpace; this.dividerWidth ??= userConfig.dividerWidth; - this.titleTextStyle = userConfig.titleTextStyle - .merge(BrnTextStyle(color: commonConfig.colorTextBase).merge(this.titleTextStyle)); + this.titleTextStyle = userConfig.titleTextStyle.merge( + BrnTextStyle(color: commonConfig.colorTextBase) + .merge(this.titleTextStyle)); - this.descTextStyle = userConfig.descTextStyle - .merge(BrnTextStyle(color: commonConfig.colorTextSecondary).merge(this.descTextStyle)); + this.descTextStyle = userConfig.descTextStyle.merge( + BrnTextStyle(color: commonConfig.colorTextSecondary) + .merge(this.descTextStyle)); } BrnEnhanceNumberCardConfig copyWith({ @@ -64,8 +69,10 @@ class BrnEnhanceNumberCardConfig extends BrnBaseConfig { runningSpace: other.runningSpace, itemRunningSpace: other.itemRunningSpace, dividerWidth: other.dividerWidth, - titleTextStyle: titleTextStyle?.merge(other.titleTextStyle) ?? other.titleTextStyle, - descTextStyle: descTextStyle?.merge(other.descTextStyle) ?? other.descTextStyle, + titleTextStyle: + titleTextStyle?.merge(other.titleTextStyle) ?? other.titleTextStyle, + descTextStyle: + descTextStyle?.merge(other.descTextStyle) ?? other.descTextStyle, ); } } diff --git a/lib/src/theme/configs/brn_form_config.dart b/lib/src/theme/configs/brn_form_config.dart index 9ce19726..93cbd523 100644 --- a/lib/src/theme/configs/brn_form_config.dart +++ b/lib/src/theme/configs/brn_form_config.dart @@ -101,28 +101,35 @@ class BrnFormItemConfig extends BrnBaseConfig { /// ③ 如果全局配置中的配置同样为 null 则根据 [configId] 取出全局配置。 /// ④ 如果没有配置 [configId] 的全局配置,则使用 Bruno 默认的配置 @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); /// 用户全局form组件配置 - BrnFormItemConfig formItemThemeData = - BrnThemeConfigurator.instance.getConfig(configId: configId).formItemConfig; + BrnFormItemConfig formItemThemeData = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .formItemConfig; this.titlePaddingSm ??= formItemThemeData.titlePaddingSm; this.titlePaddingLg ??= formItemThemeData.titlePaddingLg; - this.optionSelectedTextStyle = formItemThemeData.optionSelectedTextStyle.merge(BrnTextStyle( + this.optionSelectedTextStyle = + formItemThemeData.optionSelectedTextStyle.merge(BrnTextStyle( color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeSubHead, ).merge(this.optionSelectedTextStyle)); - this.optionTextStyle = formItemThemeData.optionTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeSubHead) - .merge(this.optionTextStyle)); + this.optionTextStyle = formItemThemeData.optionTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead) + .merge(this.optionTextStyle)); this.headTitleTextStyle = formItemThemeData.headTitleTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeHead) + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeHead) .merge(this.headTitleTextStyle)); if (this.errorPadding == null) { @@ -151,33 +158,43 @@ class BrnFormItemConfig extends BrnBaseConfig { bottom: commonConfig.vSpacingLg); } - this.tipsTextStyle = formItemThemeData.tipsTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextSecondary, fontSize: commonConfig.fontSizeBase) - .merge(this.tipsTextStyle)); + this.tipsTextStyle = formItemThemeData.tipsTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextSecondary, + fontSize: commonConfig.fontSizeBase) + .merge(this.tipsTextStyle)); this.disableTextStyle = formItemThemeData.disableTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextDisabled, fontSize: commonConfig.fontSizeSubHead) + BrnTextStyle( + color: commonConfig.colorTextDisabled, + fontSize: commonConfig.fontSizeSubHead) .merge(this.disableTextStyle)); this.contentTextStyle = formItemThemeData.contentTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeSubHead) + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead) .merge(this.contentTextStyle)); - this.hintTextStyle = formItemThemeData.hintTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextHint, fontSize: commonConfig.fontSizeSubHead) - .merge(this.hintTextStyle)); + this.hintTextStyle = formItemThemeData.hintTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextHint, + fontSize: commonConfig.fontSizeSubHead) + .merge(this.hintTextStyle)); - this.titleTextStyle = formItemThemeData.titleTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeSubHead) - .merge(this.titleTextStyle)); + this.titleTextStyle = formItemThemeData.titleTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead) + .merge(this.titleTextStyle)); this.subTitleTextStyle = formItemThemeData.subTitleTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextSecondary, fontSize: commonConfig.fontSizeCaption) + BrnTextStyle( + color: commonConfig.colorTextSecondary, + fontSize: commonConfig.fontSizeCaption) .merge(this.subTitleTextStyle)); - this.errorTextStyle = formItemThemeData.errorTextStyle.merge( - BrnTextStyle(color: commonConfig.brandError, fontSize: commonConfig.fontSizeCaption) - .merge(this.errorTextStyle)); + this.errorTextStyle = formItemThemeData.errorTextStyle.merge(BrnTextStyle( + color: commonConfig.brandError, + fontSize: commonConfig.fontSizeCaption) + .merge(this.errorTextStyle)); this.optionsMiddlePadding ??= formItemThemeData?.optionsMiddlePadding; } @@ -216,31 +233,41 @@ class BrnFormItemConfig extends BrnBaseConfig { tipsTextStyle: tipsTextStyle ?? this.tipsTextStyle, headTitleTextStyle: headTitleTextStyle ?? this.headTitleTextStyle, optionTextStyle: optionTextStyle ?? this.optionTextStyle, - optionSelectedTextStyle: optionSelectedTextStyle ?? this.optionSelectedTextStyle, + optionSelectedTextStyle: + optionSelectedTextStyle ?? this.optionSelectedTextStyle, ); } BrnFormItemConfig merge(BrnFormItemConfig other) { if (other == null) return this; return copyWith( - titleTextStyle: titleTextStyle?.merge(other.titleTextStyle) ?? other.titleTextStyle, - subTitleTextStyle: - subTitleTextStyle?.merge(other.subTitleTextStyle) ?? other.subTitleTextStyle, - errorTextStyle: errorTextStyle?.merge(other.errorTextStyle) ?? other.errorTextStyle, - hintTextStyle: hintTextStyle?.merge(other.hintTextStyle) ?? other.hintTextStyle, - contentTextStyle: contentTextStyle?.merge(other.contentTextStyle) ?? other.contentTextStyle, + titleTextStyle: + titleTextStyle?.merge(other.titleTextStyle) ?? other.titleTextStyle, + subTitleTextStyle: subTitleTextStyle?.merge(other.subTitleTextStyle) ?? + other.subTitleTextStyle, + errorTextStyle: + errorTextStyle?.merge(other.errorTextStyle) ?? other.errorTextStyle, + hintTextStyle: + hintTextStyle?.merge(other.hintTextStyle) ?? other.hintTextStyle, + contentTextStyle: contentTextStyle?.merge(other.contentTextStyle) ?? + other.contentTextStyle, formPadding: other.formPadding, titlePaddingSm: other.titlePaddingSm, titlePaddingLg: other.titlePaddingLg, optionsMiddlePadding: other.optionsMiddlePadding, subTitlePadding: other.subTitlePadding, errorPadding: other.errorPadding, - disableTextStyle: disableTextStyle?.merge(other.disableTextStyle) ?? other.disableTextStyle, - tipsTextStyle: tipsTextStyle?.merge(other.tipsTextStyle) ?? other.tipsTextStyle, + disableTextStyle: disableTextStyle?.merge(other.disableTextStyle) ?? + other.disableTextStyle, + tipsTextStyle: + tipsTextStyle?.merge(other.tipsTextStyle) ?? other.tipsTextStyle, headTitleTextStyle: - headTitleTextStyle?.merge(other.headTitleTextStyle) ?? other.headTitleTextStyle, - optionTextStyle: optionTextStyle?.merge(other.optionTextStyle) ?? other.optionTextStyle, - optionSelectedTextStyle: optionSelectedTextStyle?.merge(other.optionSelectedTextStyle) ?? - other.optionSelectedTextStyle); + headTitleTextStyle?.merge(other.headTitleTextStyle) ?? + other.headTitleTextStyle, + optionTextStyle: optionTextStyle?.merge(other.optionTextStyle) ?? + other.optionTextStyle, + optionSelectedTextStyle: + optionSelectedTextStyle?.merge(other.optionSelectedTextStyle) ?? + other.optionSelectedTextStyle); } } diff --git a/lib/src/theme/configs/brn_gallery_detail_config.dart b/lib/src/theme/configs/brn_gallery_detail_config.dart index f432b4ff..daa027a9 100644 --- a/lib/src/theme/configs/brn_gallery_detail_config.dart +++ b/lib/src/theme/configs/brn_gallery_detail_config.dart @@ -97,12 +97,14 @@ class BrnGalleryDetailConfig extends BrnBaseConfig { this.iconColor, String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID}) : super(configId: configId) { - this.appbarTitleStyle = BrnTextStyle(color: commonConfig.colorTextBaseInverse); + this.appbarTitleStyle = + BrnTextStyle(color: commonConfig.colorTextBaseInverse); this.appbarActionStyle = BrnTextStyle(color: BrnAppBarTheme.lightTextColor); this.appbarBackgroundColor = Colors.black; this.appbarBrightness = Brightness.dark; this.tabBarUnSelectedLabelStyle = BrnTextStyle(color: Color(0XFFCCCCCC)); - this.tabBarLabelStyle = BrnTextStyle(color: commonConfig.colorTextBaseInverse); + this.tabBarLabelStyle = + BrnTextStyle(color: commonConfig.colorTextBaseInverse); this.tabBarBackgroundColor = Colors.black; this.pageBackgroundColor = Colors.black; this.bottomBackgroundColor = Color(0X88000000); @@ -133,7 +135,8 @@ class BrnGalleryDetailConfig extends BrnBaseConfig { this.appbarActionStyle = BrnTextStyle(color: commonConfig.colorTextBase); this.appbarBackgroundColor = commonConfig.fillBody; this.appbarBrightness = Brightness.light; - this.tabBarUnSelectedLabelStyle = BrnTextStyle(color: commonConfig.colorTextBase); + this.tabBarUnSelectedLabelStyle = + BrnTextStyle(color: commonConfig.colorTextBase); this.tabBarLabelStyle = BrnTextStyle(color: commonConfig.brandPrimary); this.tabBarBackgroundColor = commonConfig.fillBody; this.pageBackgroundColor = commonConfig.fillBody; @@ -145,30 +148,38 @@ class BrnGalleryDetailConfig extends BrnBaseConfig { } @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); /// 用户全局组件配置 - BrnGalleryDetailConfig galleryDetailConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).galleryDetailConfig; + BrnGalleryDetailConfig galleryDetailConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .galleryDetailConfig; - this.appbarTitleStyle = galleryDetailConfig.appbarTitleStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBaseInverse, fontSize: commonConfig.fontSizeSubHead) - .merge(this.appbarTitleStyle)); + this.appbarTitleStyle = galleryDetailConfig.appbarTitleStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBaseInverse, + fontSize: commonConfig.fontSizeSubHead) + .merge(this.appbarTitleStyle)); - this.appbarActionStyle = galleryDetailConfig.appbarActionStyle.merge(this.appbarActionStyle); + this.appbarActionStyle = + galleryDetailConfig.appbarActionStyle.merge(this.appbarActionStyle); this.appbarBrightness ??= galleryDetailConfig.appbarBrightness; this.appbarBackgroundColor ??= galleryDetailConfig.appbarBackgroundColor; - this.tabBarUnSelectedLabelStyle = galleryDetailConfig.tabBarUnSelectedLabelStyle + this.tabBarUnSelectedLabelStyle = galleryDetailConfig + .tabBarUnSelectedLabelStyle .merge(BrnTextStyle(fontSize: commonConfig.fontSizeSubHead)) .merge(this.tabBarUnSelectedLabelStyle); this.tabBarLabelStyle = galleryDetailConfig.tabBarLabelStyle .merge(BrnTextStyle( - color: commonConfig.colorTextBaseInverse, fontSize: commonConfig.fontSizeSubHead)) + color: commonConfig.colorTextBaseInverse, + fontSize: commonConfig.fontSizeSubHead)) .merge(this.tabBarLabelStyle); this.tabBarBackgroundColor ??= galleryDetailConfig.tabBarBackgroundColor; @@ -179,7 +190,8 @@ class BrnGalleryDetailConfig extends BrnBaseConfig { this.titleStyle = galleryDetailConfig.titleStyle .merge(BrnTextStyle( - color: commonConfig.colorTextBaseInverse, fontSize: commonConfig.fontSizeHead)) + color: commonConfig.colorTextBaseInverse, + fontSize: commonConfig.fontSizeHead)) .merge(this.titleStyle); this.contentStyle = galleryDetailConfig.contentStyle @@ -188,7 +200,8 @@ class BrnGalleryDetailConfig extends BrnBaseConfig { this.actionStyle = galleryDetailConfig.actionStyle .merge(BrnTextStyle( - color: commonConfig.colorTextBaseInverse, fontSize: commonConfig.fontSizeBase)) + color: commonConfig.colorTextBaseInverse, + fontSize: commonConfig.fontSizeBase)) .merge(this.actionStyle); this.iconColor ??= galleryDetailConfig.iconColor; @@ -215,13 +228,17 @@ class BrnGalleryDetailConfig extends BrnBaseConfig { return BrnGalleryDetailConfig( appbarTitleStyle: appbarTitleStyle ?? this.appbarTitleStyle, appbarActionStyle: appbarActionStyle ?? this.appbarActionStyle, - appbarBackgroundColor: appbarBackgroundColor ?? this.appbarBackgroundColor, + appbarBackgroundColor: + appbarBackgroundColor ?? this.appbarBackgroundColor, appbarBrightness: appbarBrightness ?? this.appbarBrightness, - tabBarUnSelectedLabelStyle: tabBarUnSelectedLabelStyle ?? this.tabBarUnSelectedLabelStyle, + tabBarUnSelectedLabelStyle: + tabBarUnSelectedLabelStyle ?? this.tabBarUnSelectedLabelStyle, tabBarLabelStyle: tabBarLabelStyle ?? this.tabBarLabelStyle, - tabBarBackgroundColor: tabBarBackgroundColor ?? this.tabBarBackgroundColor, + tabBarBackgroundColor: + tabBarBackgroundColor ?? this.tabBarBackgroundColor, pageBackgroundColor: pageBackgroundColor ?? this.pageBackgroundColor, - bottomBackgroundColor: bottomBackgroundColor ?? this.bottomBackgroundColor, + bottomBackgroundColor: + bottomBackgroundColor ?? this.bottomBackgroundColor, titleStyle: titleStyle ?? this.titleStyle, contentStyle: contentStyle ?? this.contentStyle, actionStyle: actionStyle ?? this.actionStyle, @@ -232,20 +249,23 @@ class BrnGalleryDetailConfig extends BrnBaseConfig { BrnGalleryDetailConfig merge(BrnGalleryDetailConfig other) { if (other == null) return this; return copyWith( - appbarTitleStyle: appbarTitleStyle?.merge(other.appbarTitleStyle) ?? other.appbarTitleStyle, - appbarActionStyle: - appbarActionStyle?.merge(other.appbarActionStyle) ?? other.appbarActionStyle, + appbarTitleStyle: appbarTitleStyle?.merge(other.appbarTitleStyle) ?? + other.appbarTitleStyle, + appbarActionStyle: appbarActionStyle?.merge(other.appbarActionStyle) ?? + other.appbarActionStyle, appbarBackgroundColor: other.appbarBackgroundColor, appbarBrightness: other.appbarBrightness, tabBarUnSelectedLabelStyle: tabBarUnSelectedLabelStyle?.merge(other.tabBarUnSelectedLabelStyle) ?? other.tabBarUnSelectedLabelStyle, - tabBarLabelStyle: tabBarLabelStyle?.merge(other.tabBarLabelStyle) ?? other.tabBarLabelStyle, + tabBarLabelStyle: tabBarLabelStyle?.merge(other.tabBarLabelStyle) ?? + other.tabBarLabelStyle, tabBarBackgroundColor: other.tabBarBackgroundColor, pageBackgroundColor: other.pageBackgroundColor, bottomBackgroundColor: other.bottomBackgroundColor, titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle, - contentStyle: contentStyle?.merge(other.contentStyle) ?? other.contentStyle, + contentStyle: + contentStyle?.merge(other.contentStyle) ?? other.contentStyle, actionStyle: actionStyle?.merge(other.actionStyle) ?? other.actionStyle, iconColor: other.iconColor, ); diff --git a/lib/src/theme/configs/brn_pair_info_config.dart b/lib/src/theme/configs/brn_pair_info_config.dart index ccea5f46..cb55dfb5 100644 --- a/lib/src/theme/configs/brn_pair_info_config.dart +++ b/lib/src/theme/configs/brn_pair_info_config.dart @@ -31,26 +31,32 @@ class BrnPairInfoTableConfig extends BrnBaseConfig { BrnTextStyle linkTextStyle; @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); /// 用户全局组件配置 - BrnPairInfoTableConfig pairInfoTableConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).pairInfoTableConfig; + BrnPairInfoTableConfig pairInfoTableConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .pairInfoTableConfig; this.rowSpacing ??= pairInfoTableConfig?.rowSpacing; - this.keyTextStyle = pairInfoTableConfig.keyTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextSecondary, fontSize: commonConfig.fontSizeBase) - .merge(this.keyTextStyle)); + this.keyTextStyle = pairInfoTableConfig.keyTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextSecondary, + fontSize: commonConfig.fontSizeBase) + .merge(this.keyTextStyle)); - this.valueTextStyle = pairInfoTableConfig.valueTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeBase) - .merge(this.valueTextStyle)); + this.valueTextStyle = pairInfoTableConfig.valueTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase) + .merge(this.valueTextStyle)); - this.linkTextStyle = pairInfoTableConfig.linkTextStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeBase) - .merge(this.linkTextStyle)); + this.linkTextStyle = pairInfoTableConfig.linkTextStyle.merge(BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeBase) + .merge(this.linkTextStyle)); this.itemSpacing ??= pairInfoTableConfig?.itemSpacing; } @@ -75,9 +81,12 @@ class BrnPairInfoTableConfig extends BrnBaseConfig { return copyWith( rowSpacing: other.rowSpacing, itemSpacing: other.itemSpacing, - keyTextStyle: keyTextStyle?.merge(other.keyTextStyle) ?? other.keyTextStyle, - valueTextStyle: valueTextStyle?.merge(other.valueTextStyle) ?? other.valueTextStyle, - linkTextStyle: linkTextStyle?.merge(other.linkTextStyle) ?? other.linkTextStyle, + keyTextStyle: + keyTextStyle?.merge(other.keyTextStyle) ?? other.keyTextStyle, + valueTextStyle: + valueTextStyle?.merge(other.valueTextStyle) ?? other.valueTextStyle, + linkTextStyle: + linkTextStyle?.merge(other.linkTextStyle) ?? other.linkTextStyle, ); } } @@ -116,12 +125,16 @@ class BrnPairRichInfoGridConfig extends BrnBaseConfig { BrnTextStyle linkTextStyle; @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); /// 用户全局组件配置 - BrnPairRichInfoGridConfig pairRichInfoGridConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).pairRichInfoGridConfig; + BrnPairRichInfoGridConfig pairRichInfoGridConfig = BrnThemeConfigurator + .instance + .getConfig(configId: configId) + .pairRichInfoGridConfig; this.rowSpacing ??= pairRichInfoGridConfig?.rowSpacing; this.itemSpacing ??= pairRichInfoGridConfig?.itemSpacing; @@ -133,11 +146,15 @@ class BrnPairRichInfoGridConfig extends BrnBaseConfig { ).merge(this.keyTextStyle)); this.valueTextStyle = pairRichInfoGridConfig.valueTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeBase) + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase) .merge(this.valueTextStyle)); this.linkTextStyle = pairRichInfoGridConfig.linkTextStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeBase) + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeBase) .merge(this.linkTextStyle)); } @@ -165,9 +182,12 @@ class BrnPairRichInfoGridConfig extends BrnBaseConfig { rowSpacing: other.rowSpacing, itemSpacing: other.itemSpacing, itemHeight: other.itemHeight, - keyTextStyle: keyTextStyle?.merge(other.keyTextStyle) ?? other.keyTextStyle, - valueTextStyle: valueTextStyle?.merge(other.valueTextStyle) ?? other.valueTextStyle, - linkTextStyle: linkTextStyle?.merge(other.linkTextStyle) ?? other.linkTextStyle, + keyTextStyle: + keyTextStyle?.merge(other.keyTextStyle) ?? other.keyTextStyle, + valueTextStyle: + valueTextStyle?.merge(other.valueTextStyle) ?? other.valueTextStyle, + linkTextStyle: + linkTextStyle?.merge(other.linkTextStyle) ?? other.linkTextStyle, ); } } diff --git a/lib/src/theme/configs/brn_picker_config.dart b/lib/src/theme/configs/brn_picker_config.dart index f03fbf37..a15bf8e1 100644 --- a/lib/src/theme/configs/brn_picker_config.dart +++ b/lib/src/theme/configs/brn_picker_config.dart @@ -61,12 +61,15 @@ class BrnPickerConfig extends BrnBaseConfig { double cornerRadius; @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); /// 用户全局组件配置 - BrnPickerConfig pickerConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).pickerConfig; + BrnPickerConfig pickerConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .pickerConfig; this.backgroundColor ??= pickerConfig.backgroundColor; this.pickerHeight ??= pickerConfig.pickerHeight; @@ -75,25 +78,31 @@ class BrnPickerConfig extends BrnBaseConfig { this.dividerColor ??= pickerConfig.dividerColor; this.cornerRadius ??= pickerConfig.cornerRadius; - this.titleTextStyle = pickerConfig.titleTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeSubHead) - .merge(this.titleTextStyle)); + this.titleTextStyle = pickerConfig.titleTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead) + .merge(this.titleTextStyle)); this.cancelTextStyle = pickerConfig.cancelTextStyle - .merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeSubHead)) + .merge(BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead)) .merge(this.cancelTextStyle); - this.confirmTextStyle = pickerConfig.confirmTextStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeSubHead) - .merge(this.confirmTextStyle)); + this.confirmTextStyle = pickerConfig.confirmTextStyle.merge(BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeSubHead) + .merge(this.confirmTextStyle)); - this.itemTextStyle = pickerConfig.itemTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeHead) - .merge(this.itemTextStyle)); + this.itemTextStyle = pickerConfig.itemTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeHead) + .merge(this.itemTextStyle)); this.itemTextSelectedStyle = pickerConfig.itemTextSelectedStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeHead) + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeHead) .merge(this.itemTextSelectedStyle)); } @@ -118,7 +127,8 @@ class BrnPickerConfig extends BrnBaseConfig { titleHeight: titleHeight ?? this.titleHeight, itemHeight: itemHeight ?? this.itemHeight, itemTextStyle: itemTextStyle ?? this.itemTextStyle, - itemTextSelectedStyle: itemTextSelectedStyle ?? this.itemTextSelectedStyle, + itemTextSelectedStyle: + itemTextSelectedStyle ?? this.itemTextSelectedStyle, dividerColor: dividerColor ?? this.dividerColor, cornerRadius: cornerRadius ?? this.cornerRadius, ); @@ -128,17 +138,21 @@ class BrnPickerConfig extends BrnBaseConfig { if (other == null) return this; return copyWith( backgroundColor: other.backgroundColor, - cancelTextStyle: - this.cancelTextStyle?.merge(other.cancelTextStyle) ?? other.cancelTextStyle, + cancelTextStyle: this.cancelTextStyle?.merge(other.cancelTextStyle) ?? + other.cancelTextStyle, confirmTextStyle: - this.confirmTextStyle?.merge(other.confirmTextStyle) ?? other.confirmTextStyle, - titleTextStyle: this.titleTextStyle?.merge(other.titleTextStyle) ?? other.titleTextStyle, + this.confirmTextStyle?.merge(other.confirmTextStyle) ?? + other.confirmTextStyle, + titleTextStyle: this.titleTextStyle?.merge(other.titleTextStyle) ?? + other.titleTextStyle, pickerHeight: other.pickerHeight, titleHeight: other.titleHeight, itemHeight: other.itemHeight, - itemTextStyle: this.itemTextStyle?.merge(other.itemTextStyle) ?? other.itemTextStyle, - itemTextSelectedStyle: this.itemTextSelectedStyle?.merge(other.itemTextSelectedStyle) ?? - other.itemTextSelectedStyle, + itemTextStyle: this.itemTextStyle?.merge(other.itemTextStyle) ?? + other.itemTextStyle, + itemTextSelectedStyle: + this.itemTextSelectedStyle?.merge(other.itemTextSelectedStyle) ?? + other.itemTextSelectedStyle, dividerColor: other.dividerColor, cornerRadius: other.cornerRadius); } diff --git a/lib/src/theme/configs/brn_selection_config.dart b/lib/src/theme/configs/brn_selection_config.dart index 05bf38d8..190f3266 100644 --- a/lib/src/theme/configs/brn_selection_config.dart +++ b/lib/src/theme/configs/brn_selection_config.dart @@ -143,12 +143,15 @@ class BrnSelectionConfig extends BrnBaseConfig { : super(configId: configId); @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); /// 用户全局筛选配置 - BrnSelectionConfig selectionConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).selectionConfig; + BrnSelectionConfig selectionConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .selectionConfig; lightSelectBgColor ??= selectionConfig.lightSelectBgColor; @@ -169,71 +172,100 @@ class BrnSelectionConfig extends BrnBaseConfig { tagRadius ??= commonConfig.radiusSm; this.flatBoldTextStyle = selectionConfig.flatBoldTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeSubHead) + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead) .merge(this.flatBoldTextStyle)); this.flatSelectedTextStyle = selectionConfig.flatSelectedTextStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeSubHead) + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeSubHead) .merge(this.flatSelectedTextStyle)); this.flayNormalTextStyle = selectionConfig.flayNormalTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeSubHead) + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead) .merge(this.flayNormalTextStyle)); - this.moreTextStyle = selectionConfig.moreTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextSecondary, fontSize: commonConfig.fontSizeCaption) - .merge(this.moreTextStyle)); + this.moreTextStyle = selectionConfig.moreTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextSecondary, + fontSize: commonConfig.fontSizeCaption) + .merge(this.moreTextStyle)); - this.optionTextStyle = selectionConfig.optionTextStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeBase) - .merge(this.optionTextStyle)); + this.optionTextStyle = selectionConfig.optionTextStyle.merge(BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeBase) + .merge(this.optionTextStyle)); this.titleForMoreTextStyle = selectionConfig.titleForMoreTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeBase) + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase) .merge(this.titleForMoreTextStyle)); - this.resetTextStyle = selectionConfig.resetTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextImportant, fontSize: commonConfig.fontSizeCaption) - .merge(this.resetTextStyle)); + this.resetTextStyle = selectionConfig.resetTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextImportant, + fontSize: commonConfig.fontSizeCaption) + .merge(this.resetTextStyle)); this.itemBoldTextStyle = selectionConfig.itemBoldTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeBase) + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase) .merge(this.itemBoldTextStyle)); this.itemSelectedTextStyle = selectionConfig.itemSelectedTextStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeBase) + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeBase) .merge(this.itemSelectedTextStyle)); this.itemNormalTextStyle = selectionConfig.itemNormalTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeBase) + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase) .merge(this.itemNormalTextStyle)); - this.inputTextStyle = selectionConfig.inputTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeBase) - .merge(this.inputTextStyle)); + this.inputTextStyle = selectionConfig.inputTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase) + .merge(this.inputTextStyle)); - this.hintTextStyle = selectionConfig.hintTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextHint, fontSize: commonConfig.fontSizeBase) - .merge(this.hintTextStyle)); + this.hintTextStyle = selectionConfig.hintTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextHint, + fontSize: commonConfig.fontSizeBase) + .merge(this.hintTextStyle)); this.rangeTitleTextStyle = selectionConfig.rangeTitleTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeSubHead) + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead) .merge(this.rangeTitleTextStyle)); this.tagSelectedTextStyle = selectionConfig.tagSelectedTextStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeCaption) + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeCaption) .merge(this.tagSelectedTextStyle)); this.tagNormalTextStyle = selectionConfig.tagNormalTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeCaption) + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeCaption) .merge(this.tagNormalTextStyle)); this.menuNormalTextStyle = selectionConfig.menuNormalTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeBase) + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase) .merge(this.menuNormalTextStyle)); this.menuSelectedTextStyle = selectionConfig.menuSelectedTextStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeBase) + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeBase) .merge(this.menuSelectedTextStyle)); } @@ -267,17 +299,21 @@ class BrnSelectionConfig extends BrnBaseConfig { }) { return BrnSelectionConfig( menuNormalTextStyle: menuNormalTextStyle ?? this.menuNormalTextStyle, - menuSelectedTextStyle: menuSelectedTextStyle ?? this.menuSelectedTextStyle, + menuSelectedTextStyle: + menuSelectedTextStyle ?? this.menuSelectedTextStyle, tagNormalTextStyle: tagTextStyle ?? this.tagNormalTextStyle, tagSelectedTextStyle: tagSelectedTextStyle ?? this.tagSelectedTextStyle, tagRadius: tagRadius ?? this.tagRadius, - tagNormalBackgroundColor: tagBackgroundColor ?? this.tagNormalBackgroundColor, - tagSelectedBackgroundColor: tagSelectedBackgroundColor ?? this.tagSelectedBackgroundColor, + tagNormalBackgroundColor: + tagBackgroundColor ?? this.tagNormalBackgroundColor, + tagSelectedBackgroundColor: + tagSelectedBackgroundColor ?? this.tagSelectedBackgroundColor, hintTextStyle: hintTextStyle ?? this.hintTextStyle, rangeTitleTextStyle: rangeTitleTextStyle ?? this.rangeTitleTextStyle, inputTextStyle: inputTextStyle ?? this.inputTextStyle, itemNormalTextStyle: itemNormalTextStyle ?? this.itemNormalTextStyle, - itemSelectedTextStyle: itemSelectedTextStyle ?? this.itemSelectedTextStyle, + itemSelectedTextStyle: + itemSelectedTextStyle ?? this.itemSelectedTextStyle, itemBoldTextStyle: itemBoldTextStyle ?? this.itemBoldTextStyle, deepNormalBgColor: deepNormalBgColor ?? this.deepNormalBgColor, deepSelectBgColor: deepSelectBgColor ?? this.deepSelectBgColor, @@ -286,37 +322,45 @@ class BrnSelectionConfig extends BrnBaseConfig { lightNormalBgColor: lightNormalBgColor ?? this.lightNormalBgColor, lightSelectBgColor: lightSelectBgColor ?? this.lightSelectBgColor, resetTextStyle: resetTextStyle ?? this.resetTextStyle, - titleForMoreTextStyle: titleForMoreTextStyle ?? this.titleForMoreTextStyle, + titleForMoreTextStyle: + titleForMoreTextStyle ?? this.titleForMoreTextStyle, optionTextStyle: optionTextStyle ?? this.optionTextStyle, moreTextStyle: moreTextStyle ?? this.moreTextStyle, flayNormalTextStyle: flayNormalTextStyle ?? this.flayNormalTextStyle, - flatSelectedTextStyle: flatSelectedTextStyle ?? this.flatSelectedTextStyle, + flatSelectedTextStyle: + flatSelectedTextStyle ?? this.flatSelectedTextStyle, flatBoldTextStyle: flatBoldTextStyle ?? this.flatBoldTextStyle); } BrnSelectionConfig merge(BrnSelectionConfig other) { return copyWith( - menuNormalTextStyle: - this.menuNormalTextStyle?.merge(other.menuNormalTextStyle) ?? other.menuNormalTextStyle, - menuSelectedTextStyle: this.menuSelectedTextStyle?.merge(other.menuSelectedTextStyle) ?? - other.menuSelectedTextStyle, - tagTextStyle: - this.tagNormalTextStyle?.merge(other.tagNormalTextStyle) ?? other.tagNormalTextStyle, - tagSelectedTextStyle: this.tagSelectedTextStyle?.merge(other.tagSelectedTextStyle) ?? - other.tagSelectedTextStyle, + menuNormalTextStyle: this.menuNormalTextStyle?.merge(other.menuNormalTextStyle) ?? + other.menuNormalTextStyle, + menuSelectedTextStyle: + this.menuSelectedTextStyle?.merge(other.menuSelectedTextStyle) ?? + other.menuSelectedTextStyle, + tagTextStyle: this.tagNormalTextStyle?.merge(other.tagNormalTextStyle) ?? + other.tagNormalTextStyle, + tagSelectedTextStyle: + this.tagSelectedTextStyle?.merge(other.tagSelectedTextStyle) ?? + other.tagSelectedTextStyle, tagRadius: other.tagRadius, tagBackgroundColor: other.tagNormalBackgroundColor, tagSelectedBackgroundColor: other.tagSelectedBackgroundColor, - hintTextStyle: this.hintTextStyle?.merge(other.hintTextStyle) ?? other.hintTextStyle, - rangeTitleTextStyle: - this.rangeTitleTextStyle?.merge(other.rangeTitleTextStyle) ?? other.rangeTitleTextStyle, - inputTextStyle: this.inputTextStyle?.merge(other.inputTextStyle) ?? other.inputTextStyle, + hintTextStyle: this.hintTextStyle?.merge(other.hintTextStyle) ?? + other.hintTextStyle, + rangeTitleTextStyle: this.rangeTitleTextStyle?.merge(other.rangeTitleTextStyle) ?? + other.rangeTitleTextStyle, + inputTextStyle: this.inputTextStyle?.merge(other.inputTextStyle) ?? + other.inputTextStyle, itemNormalTextStyle: - this.itemNormalTextStyle?.merge(other.itemNormalTextStyle) ?? other.itemNormalTextStyle, - itemSelectedTextStyle: this.itemSelectedTextStyle?.merge(other.itemSelectedTextStyle) ?? - other.itemSelectedTextStyle, - itemBoldTextStyle: - this.itemBoldTextStyle?.merge(other.itemBoldTextStyle) ?? other.itemBoldTextStyle, + this.itemNormalTextStyle?.merge(other.itemNormalTextStyle) ?? + other.itemNormalTextStyle, + itemSelectedTextStyle: + this.itemSelectedTextStyle?.merge(other.itemSelectedTextStyle) ?? + other.itemSelectedTextStyle, + itemBoldTextStyle: this.itemBoldTextStyle?.merge(other.itemBoldTextStyle) ?? + other.itemBoldTextStyle, deepNormalBgColor: other.deepNormalBgColor, deepSelectBgColor: other.deepSelectBgColor, middleNormalBgColor: other.middleNormalBgColor, @@ -324,16 +368,11 @@ class BrnSelectionConfig extends BrnBaseConfig { lightNormalBgColor: other.lightNormalBgColor, lightSelectBgColor: other.lightSelectBgColor, resetTextStyle: this.resetTextStyle?.merge(other.resetTextStyle) ?? other.resetTextStyle, - titleForMoreTextStyle: this.titleForMoreTextStyle?.merge(other.titleForMoreTextStyle) ?? - other.titleForMoreTextStyle, - optionTextStyle: - this.optionTextStyle?.merge(other.optionTextStyle) ?? other.optionTextStyle, + titleForMoreTextStyle: this.titleForMoreTextStyle?.merge(other.titleForMoreTextStyle) ?? other.titleForMoreTextStyle, + optionTextStyle: this.optionTextStyle?.merge(other.optionTextStyle) ?? other.optionTextStyle, moreTextStyle: this.moreTextStyle?.merge(other.moreTextStyle) ?? other.moreTextStyle, - flayNormalTextStyle: - this.flayNormalTextStyle?.merge(other.flayNormalTextStyle) ?? other.flayNormalTextStyle, - flatSelectedTextStyle: this.flatSelectedTextStyle?.merge(other.flatSelectedTextStyle) ?? - other.flatSelectedTextStyle, - flatBoldTextStyle: - this.flatBoldTextStyle?.merge(other.flatBoldTextStyle) ?? other.flatBoldTextStyle); + flayNormalTextStyle: this.flayNormalTextStyle?.merge(other.flayNormalTextStyle) ?? other.flayNormalTextStyle, + flatSelectedTextStyle: this.flatSelectedTextStyle?.merge(other.flatSelectedTextStyle) ?? other.flatSelectedTextStyle, + flatBoldTextStyle: this.flatBoldTextStyle?.merge(other.flatBoldTextStyle) ?? other.flatBoldTextStyle); } } diff --git a/lib/src/theme/configs/brn_tabbar_config.dart b/lib/src/theme/configs/brn_tabbar_config.dart index 754487ab..6c5145cc 100644 --- a/lib/src/theme/configs/brn_tabbar_config.dart +++ b/lib/src/theme/configs/brn_tabbar_config.dart @@ -81,32 +81,42 @@ class BrnTabBarConfig extends BrnBaseConfig { double tagHeight; @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); - BrnTabBarConfig tabBarConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).tabBarConfig; + BrnTabBarConfig tabBarConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .tabBarConfig; this.tabHeight ??= tabBarConfig.tabHeight; this.indicatorHeight ??= tabBarConfig.indicatorHeight; this.indicatorWidth ??= tabBarConfig.indicatorWidth; - this.labelStyle = tabBarConfig.labelStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeSubHead) - .merge(this.labelStyle)); + this.labelStyle = tabBarConfig.labelStyle.merge(BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeSubHead) + .merge(this.labelStyle)); this.unselectedLabelStyle = tabBarConfig.unselectedLabelStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeSubHead) + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead) .merge(this.unselectedLabelStyle)); this.backgroundColor ??= tabBarConfig.backgroundColor; this.tagNormalTextStyle = tabBarConfig.tagNormalTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeCaption) + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeCaption) .merge(this.tagNormalTextStyle)); this.tagSelectedTextStyle = tabBarConfig.tagSelectedTextStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeCaption) + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeCaption) .merge(this.tagSelectedTextStyle)); this.tagNormalBgColor ??= tabBarConfig.tagNormalBgColor; @@ -158,14 +168,17 @@ class BrnTabBarConfig extends BrnBaseConfig { indicatorHeight: other.indicatorHeight, indicatorWidth: other.indicatorWidth, labelStyle: this.labelStyle?.merge(other.labelStyle) ?? other.labelStyle, - unselectedLabelStyle: this.unselectedLabelStyle?.merge(other.unselectedLabelStyle) ?? - other.unselectedLabelStyle, + unselectedLabelStyle: + this.unselectedLabelStyle?.merge(other.unselectedLabelStyle) ?? + other.unselectedLabelStyle, backgroundColor: other.backgroundColor, tagNormalTextStyle: - this.tagNormalTextStyle?.merge(other.tagNormalTextStyle) ?? other.tagNormalTextStyle, + this.tagNormalTextStyle?.merge(other.tagNormalTextStyle) ?? + other.tagNormalTextStyle, tagNormalColor: other.tagNormalBgColor, - tagSelectedTextStyle: this.tagSelectedTextStyle?.merge(other.tagSelectedTextStyle) ?? - other.tagSelectedTextStyle, + tagSelectedTextStyle: + this.tagSelectedTextStyle?.merge(other.tagSelectedTextStyle) ?? + other.tagSelectedTextStyle, tagSelectedColor: other.tagSelectedBgColor, tagRadius: other.tagRadius, tagSpacing: other.tagSpacing, diff --git a/lib/src/theme/configs/brn_tag_config.dart b/lib/src/theme/configs/brn_tag_config.dart index 7822db4b..ceda9a6c 100644 --- a/lib/src/theme/configs/brn_tag_config.dart +++ b/lib/src/theme/configs/brn_tag_config.dart @@ -52,11 +52,14 @@ class BrnTagConfig extends BrnBaseConfig { : super(configId: configId); @override - void initThemeConfig(String configId, {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig(String configId, + {BrnCommonConfig currentLevelCommonConfig}) { + super.initThemeConfig(configId, + currentLevelCommonConfig: currentLevelCommonConfig); /// 用户全局组件配置 - BrnTagConfig tagConfig = BrnThemeConfigurator.instance.getConfig(configId: configId).tagConfig; + BrnTagConfig tagConfig = + BrnThemeConfigurator.instance.getConfig(configId: configId).tagConfig; this.tagHeight ??= tagConfig.tagHeight; @@ -69,13 +72,15 @@ class BrnTagConfig extends BrnBaseConfig { this.selectedTagBackgroundColor ??= commonConfig.brandPrimary; - this.tagTextStyle = tagConfig.tagTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase, fontSize: commonConfig.fontSizeCaption) - .merge(this.tagTextStyle)); + this.tagTextStyle = tagConfig.tagTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeCaption) + .merge(this.tagTextStyle)); - this.selectTagTextStyle = tagConfig.selectTagTextStyle.merge( - BrnTextStyle(color: commonConfig.brandPrimary, fontSize: commonConfig.fontSizeCaption) - .merge(this.selectTagTextStyle)); + this.selectTagTextStyle = tagConfig.selectTagTextStyle.merge(BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeCaption) + .merge(this.selectTagTextStyle)); } BrnTagConfig copyWith( @@ -92,7 +97,8 @@ class BrnTagConfig extends BrnBaseConfig { selectTagTextStyle: selectTextStyle ?? this.selectTagTextStyle, tagRadius: radius ?? this.tagRadius, tagBackgroundColor: backgroundColor ?? this.tagBackgroundColor, - selectedTagBackgroundColor: selectedBackgroundColor ?? this.selectedTagBackgroundColor, + selectedTagBackgroundColor: + selectedBackgroundColor ?? this.selectedTagBackgroundColor, tagHeight: height ?? this.tagHeight, tagWidth: width ?? this.tagWidth, tagMinWidth: tagMinWidth ?? this.tagMinWidth); @@ -100,9 +106,11 @@ class BrnTagConfig extends BrnBaseConfig { BrnTagConfig merge(BrnTagConfig other) { return copyWith( - textStyle: this.tagTextStyle?.merge(other.tagTextStyle) ?? other.tagTextStyle, + textStyle: + this.tagTextStyle?.merge(other.tagTextStyle) ?? other.tagTextStyle, selectTextStyle: - this.selectTagTextStyle?.merge(other.selectTagTextStyle) ?? other.selectTagTextStyle, + this.selectTagTextStyle?.merge(other.selectTagTextStyle) ?? + other.selectTagTextStyle, radius: other.tagRadius, backgroundColor: other.tagBackgroundColor, selectedBackgroundColor: other.selectedTagBackgroundColor, diff --git a/lib/src/theme/img/brn_theme_default_utils.dart b/lib/src/theme/img/brn_theme_default_utils.dart index 77996049..a8c8b0f6 100644 --- a/lib/src/theme/img/brn_theme_default_utils.dart +++ b/lib/src/theme/img/brn_theme_default_utils.dart @@ -39,7 +39,8 @@ class BrnThemeImg { BrunoTools.getAssetImage(BrnAsset.SELECT_CHECKED_STATUS); Image get STEP_ICON { - return _defaultBrunoImg?.getStepIcon() ?? BrunoTools.getAssetImage(BrnAsset.stepTitle); + return _defaultBrunoImg?.getStepIcon() ?? + BrunoTools.getAssetImage(BrnAsset.stepTitle); } } @@ -57,7 +58,8 @@ class BrnDefaultThemeImgUtil extends BrnThemeImgUtils { @override Image getCHECKED_STATUS() { - return BrunoTools.getAssetImageWithBandColor(BrnAsset.SELECT_CHECKED_STATUS); + return BrunoTools.getAssetImageWithBandColor( + BrnAsset.SELECT_CHECKED_STATUS); } @override diff --git a/lib/src/utils/brn_event_bus.dart b/lib/src/utils/brn_event_bus.dart index 06b2cc72..b59fa39a 100644 --- a/lib/src/utils/brn_event_bus.dart +++ b/lib/src/utils/brn_event_bus.dart @@ -24,13 +24,15 @@ class EventBus { /// during a [fire] call. If false (the default), the event will be passed to /// the listeners at a later time, after the code creating the event has /// completed. - EventBus({bool sync = false}) : _streamController = StreamController.broadcast(sync: sync); + EventBus({bool sync = false}) + : _streamController = StreamController.broadcast(sync: sync); /// Instead of using the default [StreamController] you can use this constructor /// to pass your own controller. /// /// An example would be to use an RxDart Subject as the controller. - EventBus.customController(StreamController controller) : _streamController = controller; + EventBus.customController(StreamController controller) + : _streamController = controller; /// Listens for events of Type [T] and its subtypes. /// diff --git a/lib/src/utils/brn_rich_text.dart b/lib/src/utils/brn_rich_text.dart index 7814dba1..ae864d1e 100644 --- a/lib/src/utils/brn_rich_text.dart +++ b/lib/src/utils/brn_rich_text.dart @@ -33,8 +33,11 @@ class BrnRichTextGenerator { _spanList.add(TextSpan( style: textStyle ?? TextStyle( - color: - linkColor ?? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + color: linkColor ?? + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, fontWeight: fontWeight ?? FontWeight.normal, fontSize: fontSize ?? 16, ), @@ -52,13 +55,19 @@ class BrnRichTextGenerator { /// fontsize 是文案大小 默认是16 /// color 是文案的颜色 默认是深黑色 BrnRichTextGenerator addText(String text, - {TextStyle textStyle, double fontSize, Color color, FontWeight fontWeight}) { + {TextStyle textStyle, + double fontSize, + Color color, + FontWeight fontWeight}) { _spanList.add(TextSpan( text: text ?? "", style: textStyle ?? TextStyle( - color: - color ?? BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, + color: color ?? + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, fontSize: fontSize ?? 16, fontWeight: fontWeight ?? FontWeight.normal))); return this; diff --git a/lib/src/utils/brn_text_util.dart b/lib/src/utils/brn_text_util.dart index 4eae8e1a..424c2837 100644 --- a/lib/src/utils/brn_text_util.dart +++ b/lib/src/utils/brn_text_util.dart @@ -8,7 +8,9 @@ class BrnTextUtil { static Size textSize(String text, TextStyle style) { if (BrunoTools.isEmpty(text)) return Size(0, 0); final TextPainter textPainter = TextPainter( - text: TextSpan(text: text, style: style), maxLines: 1, textDirection: TextDirection.ltr) + text: TextSpan(text: text, style: style), + maxLines: 1, + textDirection: TextDirection.ltr) ..layout(minWidth: 0, maxWidth: double.infinity); return textPainter.size; } diff --git a/lib/src/utils/brn_tools.dart b/lib/src/utils/brn_tools.dart index 7d6f3b89..b5b63290 100644 --- a/lib/src/utils/brn_tools.dart +++ b/lib/src/utils/brn_tools.dart @@ -7,8 +7,9 @@ class BrunoTools { /// 将 icon 根据主题色变色后返回 static Image getAssetImageWithBandColor(String assetFilePath, {String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID}) { - BrnCommonConfig commonConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).commonConfig; + BrnCommonConfig commonConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .commonConfig; if (!assetFilePath.startsWith("assets")) { assetFilePath = "assets/$assetFilePath"; } @@ -31,7 +32,8 @@ class BrunoTools { /// imgAssetPath: assets资源文件路径 /// package 访问某个package里的资源,这里默认flutter_alliance_package /// scale: 与所用的png资源是icon_2x.png (scale=2.0),icon_3x.png(scale=3.0) - static Image getAssetImage(String assetFilePath, {BoxFit fit, bool gaplessPlayback = false}) { + static Image getAssetImage(String assetFilePath, + {BoxFit fit, bool gaplessPlayback = false}) { if (!assetFilePath.startsWith("assets")) { assetFilePath = "assets/$assetFilePath"; } @@ -54,7 +56,8 @@ class BrunoTools { ); } - static Image getAssetSizeImage(String assetFilePath, double w, double h, {Color color}) { + static Image getAssetSizeImage(String assetFilePath, double w, double h, + {Color color}) { if (!assetFilePath.startsWith("assets")) { assetFilePath = "assets/$assetFilePath"; } @@ -94,7 +97,9 @@ class BrunoTools { static Size textSize(String text, TextStyle style) { if (isEmpty(text)) return Size(0, 0); final TextPainter textPainter = TextPainter( - text: TextSpan(text: text, style: style), maxLines: 1, textDirection: TextDirection.ltr) + text: TextSpan(text: text, style: style), + maxLines: 1, + textDirection: TextDirection.ltr) ..layout(minWidth: 0, maxWidth: double.infinity); return textPainter.size; } diff --git a/lib/src/utils/css/brn_core_funtion.dart b/lib/src/utils/css/brn_core_funtion.dart index d0322738..56baaf45 100644 --- a/lib/src/utils/css/brn_core_funtion.dart +++ b/lib/src/utils/css/brn_core_funtion.dart @@ -20,7 +20,8 @@ class BrnConvert { //外部传入的默认文本样式 TextStyle _defaultStyle; - BrnConvert(String cssContent, {Function linkCallBack, TextStyle defaultStyle}) { + BrnConvert(String cssContent, + {Function linkCallBack, TextStyle defaultStyle}) { _eventList = xml.parseEvents(cssContent); _linkCallBack = linkCallBack ?? null; _defaultStyle = defaultStyle; @@ -39,7 +40,10 @@ class BrnConvert { fontSize: 14, decoration: TextDecoration.none, fontWeight: FontWeight.normal, - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextImportant, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextImportant, ); List spans = []; @@ -52,13 +56,16 @@ class BrnConvert { xmlEvent.attributes.forEach((attr) { switch (attr.name) { case "color": - Color textColor = BrnConvertUtil.generateColorByString(attr.value); + Color textColor = + BrnConvertUtil.generateColorByString(attr.value); textStyle = textStyle.apply(color: textColor); break; case "weight": - FontWeight fontWeight = BrnConvertUtil.generateFontWidgetByString(attr.value); - textStyle = - textStyle.apply(fontWeightDelta: fontWeight.index - FontWeight.normal.index); + FontWeight fontWeight = + BrnConvertUtil.generateFontWidgetByString(attr.value); + textStyle = textStyle.apply( + fontWeightDelta: + fontWeight.index - FontWeight.normal.index); break; case "size": double size = BrnConvertUtil.generateFontSize(attr.value); @@ -80,7 +87,10 @@ class BrnConvert { switch (attr.name) { case "href": textStyle = textStyle.apply( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary); + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary); tag.linkUrl = attr.value; break; } @@ -127,7 +137,9 @@ class BrnConvert { } }; return TextSpan( - style: tag.style, text: text, recognizer: tag.isLink ? tapGestureRecognizer : null); + style: tag.style, + text: text, + recognizer: tag.isLink ? tapGestureRecognizer : null); } } diff --git a/lib/src/utils/css/brn_css_2_text.dart b/lib/src/utils/css/brn_css_2_text.dart index 2a248b16..dd35d20f 100644 --- a/lib/src/utils/css/brn_css_2_text.dart +++ b/lib/src/utils/css/brn_css_2_text.dart @@ -6,7 +6,8 @@ class BrnCSS2Text { static TextSpan toTextSpan(String htmlContent, {BrnHyperLinkCallback linksCallback, TextStyle defaultStyle}) { return TextSpan( - children: BrnConvert(htmlContent, linkCallBack: linksCallback, defaultStyle: defaultStyle) + children: BrnConvert(htmlContent, + linkCallBack: linksCallback, defaultStyle: defaultStyle) .convert(), ); } @@ -18,7 +19,8 @@ class BrnCSS2Text { TextAlign textAlign, TextOverflow textOverflow}) { return Text.rich( - toTextSpan(htmlContent, linksCallback: linksCallback, defaultStyle: defaultStyle), + toTextSpan(htmlContent, + linksCallback: linksCallback, defaultStyle: defaultStyle), maxLines: maxLines, textAlign: textAlign, overflow: textOverflow ?? TextOverflow.clip, diff --git a/lib/src/utils/css/brn_util.dart b/lib/src/utils/css/brn_util.dart index 4b9ab13d..bcbe5753 100644 --- a/lib/src/utils/css/brn_util.dart +++ b/lib/src/utils/css/brn_util.dart @@ -5,8 +5,10 @@ import 'package:bruno/src/theme/brn_theme_configurator.dart'; //将标签属性 转为 相当的style class BrnConvertUtil { //将标签color 转为 颜色 - static Color generateColorByString(String hexColor, {String defColor: 'ffffffff'}) { - Color color = BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary; + static Color generateColorByString(String hexColor, + {String defColor: 'ffffffff'}) { + Color color = + BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary; if (hexColor == null || hexColor.isEmpty) return color; hexColor = hexColor.toUpperCase().replaceAll("#", ""); hexColor = hexColor.replaceAll('0X', ''); diff --git a/lib/src/utils/i18n/brn_date_picker_i18n.dart b/lib/src/utils/i18n/brn_date_picker_i18n.dart index e447f413..2438c270 100755 --- a/lib/src/utils/i18n/brn_date_picker_i18n.dart +++ b/lib/src/utils/i18n/brn_date_picker_i18n.dart @@ -63,7 +63,8 @@ enum DateTimePickerLocale { } /// Default value of date locale -const DateTimePickerLocale DATETIME_PICKER_LOCALE_DEFAULT = DateTimePickerLocale.zh_cn; +const DateTimePickerLocale DATETIME_PICKER_LOCALE_DEFAULT = + DateTimePickerLocale.zh_cn; const Map datePickerI18n = { DateTimePickerLocale.zh_cn: const _StringsZhCn(), @@ -72,19 +73,24 @@ const Map datePickerI18n = { class DatePickerI18n { /// Get done button text static String getLocaleDone(DateTimePickerLocale locale) { - _StringsI18n i18n = datePickerI18n[locale] ?? datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT]; - return i18n.getDoneText() ?? datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT].getDoneText(); + _StringsI18n i18n = datePickerI18n[locale] ?? + datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT]; + return i18n.getDoneText() ?? + datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT].getDoneText(); } /// Get cancel button text static String getLocaleCancel(DateTimePickerLocale locale) { - _StringsI18n i18n = datePickerI18n[locale] ?? datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT]; - return i18n.getCancelText() ?? datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT].getCancelText(); + _StringsI18n i18n = datePickerI18n[locale] ?? + datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT]; + return i18n.getCancelText() ?? + datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT].getCancelText(); } /// Get locale month array static List getLocaleMonths(DateTimePickerLocale locale) { - _StringsI18n i18n = datePickerI18n[locale] ?? datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT]; + _StringsI18n i18n = datePickerI18n[locale] ?? + datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT]; List months = i18n.getMonths(); if (months != null && months.isNotEmpty) { return months; @@ -93,8 +99,10 @@ class DatePickerI18n { } /// Get locale week array - static List getLocaleWeeks(DateTimePickerLocale locale, [bool isFull = true]) { - _StringsI18n i18n = datePickerI18n[locale] ?? datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT]; + static List getLocaleWeeks(DateTimePickerLocale locale, + [bool isFull = true]) { + _StringsI18n i18n = datePickerI18n[locale] ?? + datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT]; if (isFull) { List weeks = i18n.getWeeksFull(); if (weeks != null && weeks.isNotEmpty) { @@ -110,7 +118,9 @@ class DatePickerI18n { List fullWeeks = i18n.getWeeksFull(); if (fullWeeks != null && fullWeeks.isNotEmpty) { - return fullWeeks.map((item) => item.substring(0, min(3, item.length))).toList(); + return fullWeeks + .map((item) => item.substring(0, min(3, item.length))) + .toList(); } return datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT].getWeeksShort(); } diff --git a/lib/src/utils/i18n/brn_strings_zh_cn.dart b/lib/src/utils/i18n/brn_strings_zh_cn.dart index 1daba64d..9248bb43 100755 --- a/lib/src/utils/i18n/brn_strings_zh_cn.dart +++ b/lib/src/utils/i18n/brn_strings_zh_cn.dart @@ -16,7 +16,20 @@ class _StringsZhCn extends _StringsI18n { @override List getMonths() { - return ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"]; + return [ + "01", + "02", + "03", + "04", + "05", + "06", + "07", + "08", + "09", + "10", + "11", + "12" + ]; } @override From 834f6cd3bdb11929df2426f9b3115358ab8d5773 Mon Sep 17 00:00:00 2001 From: violinday Date: Wed, 8 Dec 2021 11:03:34 +0800 Subject: [PATCH 03/24] perf: change the version number to 2.0.0 --- CHANGELOG.md | 3 ++- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63530156..4b3e551d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ -## [1.0.0] - first publish adapter flutter sdk 1.22.4. +## [1.0.0] - first publish adapter flutter sdk 1.22.4 +## [2.0.0] - adapter flutter sdk 2.2.2 diff --git a/pubspec.yaml b/pubspec.yaml index 79717056..75bdb5cd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: bruno description: An enterprise-class package of Flutter components for mobile applications. -version: 1.0.0 +version: 2.0.0 homepage: https://github.com/LianjiaTech/bruno environment: From 09e461362f249dafe1771ba725cca6ba645ac4bd Mon Sep 17 00:00:00 2001 From: zhoujuanjuan <15143015732@163.com> Date: Wed, 8 Dec 2021 11:21:07 +0800 Subject: [PATCH 04/24] pref: upgrade third_party --- example/pubspec.yaml | 4 ++-- lib/src/components/toast/brn_toast.dart | 1 - pubspec.yaml | 14 +++++++------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 6a4bf677..1d71f15b 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -27,9 +27,9 @@ dependencies: cupertino_icons: ^0.1.2 bruno: path: ../ - flutter_easyrefresh: 2.1.1 + flutter_easyrefresh: ^2.2.1 http: any - badges: 1.2.0 + badges: ^2.0.2 flutter_swiper: 1.1.6 dev_dependencies: diff --git a/lib/src/components/toast/brn_toast.dart b/lib/src/components/toast/brn_toast.dart index b3b83b2b..a37558fe 100644 --- a/lib/src/components/toast/brn_toast.dart +++ b/lib/src/components/toast/brn_toast.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 75bdb5cd..e5968969 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,14 +9,14 @@ environment: dependencies: flutter: sdk: flutter - xml: ^3.5.0 - lpinyin: ^1.0.7 - path_drawing: ^0.4.1 - flutter_easyrefresh: ^2.1.1 - intl: ^0.16.1 + xml: ^5.1.2 + lpinyin: ^2.0.3 + path_drawing: ^1.0.0 + flutter_easyrefresh: ^2.2.1 + intl: ^0.17.0 photo_view: ^0.13.0 - provider: ^3.2.0 - badges: ^1.2.0 + provider: ^6.0.1 + badges: ^2.0.2 dev_dependencies: flutter_test: From 48a3a5279a3cfd21595b7c8b44339d1889735cf2 Mon Sep 17 00:00:00 2001 From: LAIIIHZ <35956195+laiiihz@users.noreply.github.com> Date: Mon, 13 Dec 2021 11:08:55 +0800 Subject: [PATCH 05/24] flutter 2.8.x support (#8) * update TextTheme api usage * api usage change, WhitelistingTextInputFormatter -> FilteringTextInputFormatter --- .../dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md | 4 ++-- .../BrnTitleSelectInputFormItem.md | 2 +- example/lib/sample/components/dialog/dialog_entry_page.dart | 2 +- .../components/form/items_example/title_select_example.dart | 2 +- .../components/form/items/group/element_expand_widget.dart | 4 ++-- .../components/form/undetermined/brn_expandable_group.dart | 4 ++-- .../widget/brn_selection_date_range_item_widget.dart | 2 +- .../selection/widget/brn_selection_more_item_widget.dart | 2 +- .../widget/brn_selection_range_input_item_widget.dart | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md b/docs/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md index f2eed6f4..af1bf338 100644 --- a/docs/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md +++ b/docs/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md @@ -58,7 +58,7 @@ const BrnMiddleInputDialog( | cancelText | String | 取消文案 | 否 | 取消 | | confirmText | String | 确定文案 | 否 | 确定 | | inputFormatters | TextInputAction | 键盘操作按钮类型,可参见系统的 TextField.textInputAction | 否 | TextInputAction.newline | -| textInputAction | `List` | 用于控制输入的内容范围比如只能输入数字可以填写:`WhitelistingTextInputFormatter.digitsOnly` | 否 | 无 | +| textInputAction | `List` | 用于控制输入的内容范围比如只能输入数字可以填写:`FilteringTextInputFormatter.digitsOnly` | 否 | 无 | | dialogStyle | BrnDialogStyle | Dialog 风格设置 | 否 | BrnDialogStyle | | onConfirm | Function(String value) | 确定回调,返回输入的值 | 否 | | | onCancel | VoidCallback | 取消回调 | 否 | | @@ -86,7 +86,7 @@ BrnMiddleInputDialog( autoFocus: true, maxLength: 1000, maxLines: 2, - inputFormatters: [WhitelistingTextInputFormatter.digitsOnly], + inputFormatters: [FilteringTextInputFormatter.digitsOnly], dismissOnActionsTap: false, barrierDismissible: true, onConfirm: (value) { diff --git a/docs/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md b/docs/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md index ddc3711b..fe8f77d6 100644 --- a/docs/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md +++ b/docs/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md @@ -140,7 +140,7 @@ BrnTitleSelectInputFormItem( title: _list[0], hint: "请输入", controller: controller, - inputFormatters: [WhitelistingTextInputFormatter(RegExp('[0-9"]'))], + inputFormatters: [FilteringTextInputFormatter(RegExp('[0-9"]'))], selectedIndex: -1, selectList: _list, onTip: () { diff --git a/example/lib/sample/components/dialog/dialog_entry_page.dart b/example/lib/sample/components/dialog/dialog_entry_page.dart index 7b8d4f3b..ff961be6 100644 --- a/example/lib/sample/components/dialog/dialog_entry_page.dart +++ b/example/lib/sample/components/dialog/dialog_entry_page.dart @@ -489,7 +489,7 @@ class DialogEntryPage extends StatelessWidget { autoFocus: true, maxLength: 1000, maxLines: 2, - inputFormatters: [WhitelistingTextInputFormatter.digitsOnly], + inputFormatters: [FilteringTextInputFormatter.digitsOnly], textInputAction: TextInputAction.done, dismissOnActionsTap: false, barrierDismissible: true, diff --git a/example/lib/sample/components/form/items_example/title_select_example.dart b/example/lib/sample/components/form/items_example/title_select_example.dart index a0b18b30..698237bf 100644 --- a/example/lib/sample/components/form/items_example/title_select_example.dart +++ b/example/lib/sample/components/form/items_example/title_select_example.dart @@ -47,7 +47,7 @@ class TitleSelectInputState extends State { title: _list[0], hint: "请输入", controller: controller, - inputFormatters: [WhitelistingTextInputFormatter(RegExp('[0-9"]'))], + inputFormatters: [FilteringTextInputFormatter(RegExp('[0-9"]'))], selectedIndex: -1, selectList: _list, onTip: () { diff --git a/lib/src/components/form/items/group/element_expand_widget.dart b/lib/src/components/form/items/group/element_expand_widget.dart index 587dbb3a..dac9e2f7 100644 --- a/lib/src/components/form/items/group/element_expand_widget.dart +++ b/lib/src/components/form/items/group/element_expand_widget.dart @@ -271,8 +271,8 @@ class _ExpansionElementState extends State /// title 文字颜色 _headerColorTween - ..begin = theme.textTheme.subhead.color - ..end = theme.textTheme.subhead.color; + ..begin = theme.textTheme.subtitle1.color + ..end = theme.textTheme.subtitle1.color; /// 展开收起图标颜色 _iconColorTween diff --git a/lib/src/components/form/undetermined/brn_expandable_group.dart b/lib/src/components/form/undetermined/brn_expandable_group.dart index 4a7ba3fc..63f05eb1 100644 --- a/lib/src/components/form/undetermined/brn_expandable_group.dart +++ b/lib/src/components/form/undetermined/brn_expandable_group.dart @@ -236,8 +236,8 @@ class _BrnExpansionElementState extends State /// title 文字颜色 _headerColorTween - ..begin = theme.textTheme.subhead.color - ..end = theme.textTheme.subhead.color; + ..begin = theme.textTheme.subtitle1.color + ..end = theme.textTheme.subtitle1.color; /// 展开收起图标颜色 _iconColorTween diff --git a/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart b/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart index 27d5ea03..5684019f 100644 --- a/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart @@ -134,7 +134,7 @@ class _BrnSelectionDateRangeItemWidgetState onTextTapped(isMax); }, style: widget.themeData.inputTextStyle?.generateTextStyle(), - inputFormatters: [WhitelistingTextInputFormatter.digitsOnly], + inputFormatters: [FilteringTextInputFormatter.digitsOnly], keyboardType: TextInputType.numberWithOptions(), onChanged: (input) { widget.item.isSelected = true; diff --git a/lib/src/components/selection/widget/brn_selection_more_item_widget.dart b/lib/src/components/selection/widget/brn_selection_more_item_widget.dart index 7bd115ef..465ecb34 100644 --- a/lib/src/components/selection/widget/brn_selection_more_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_more_item_widget.dart @@ -564,7 +564,7 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { .getConfig() .commonConfig .brandPrimary, - inputFormatters: [WhitelistingTextInputFormatter.digitsOnly], + inputFormatters: [FilteringTextInputFormatter.digitsOnly], style: widget.themeData.inputTextStyle.generateTextStyle(), decoration: InputDecoration( hintText: hint, diff --git a/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart b/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart index 08349c7d..4af722b5 100644 --- a/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart @@ -137,7 +137,7 @@ class _BrnSelectionRangeItemWidgetState return Expanded( child: TextFormField( style: widget.themeData.inputTextStyle?.generateTextStyle(), - inputFormatters: [WhitelistingTextInputFormatter.digitsOnly], + inputFormatters: [FilteringTextInputFormatter.digitsOnly], keyboardType: TextInputType.numberWithOptions(), onChanged: (input) { widget.item.isSelected = true; From 458ba9d36f6ac89cb38270b830491f0fc2ee2126 Mon Sep 17 00:00:00 2001 From: lee <58846244+a1017480401@users.noreply.github.com> Date: Wed, 22 Dec 2021 23:47:00 +0800 Subject: [PATCH 06/24] =?UTF-8?q?=E4=BC=98=E5=8C=96radio=5Fbutton=E7=9A=84?= =?UTF-8?q?=E7=82=B9=E5=87=BB=E8=8C=83=E5=9B=B4=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 优化radio_button的点击范围 * 更改BrnRadioCore的behavior属性默认为HitTestBehavior.translucent * 代码修改部分格式化(AS) --- lib/src/components/radio/brn_checkbox.dart | 28 +++++++++++-------- .../components/radio/brn_radio_button.dart | 28 +++++++++++-------- lib/src/components/radio/brn_radio_core.dart | 9 ++++-- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/lib/src/components/radio/brn_checkbox.dart b/lib/src/components/radio/brn_checkbox.dart index 0f067a9e..73d3f7e5 100644 --- a/lib/src/components/radio/brn_checkbox.dart +++ b/lib/src/components/radio/brn_checkbox.dart @@ -40,18 +40,21 @@ class BrnCheckbox extends StatefulWidget { /// 默认值MainAxisSize.min final MainAxisSize mainAxisSize; - const BrnCheckbox({ - Key key, - @required this.radioIndex, - @required this.onValueChangedAtIndex, - this.disable = false, - this.isSelected = false, - this.iconPadding, - this.child, - this.childOnRight = true, - this.mainAxisAlignment = MainAxisAlignment.start, - this.mainAxisSize = MainAxisSize.min, - }); + /// 默认值HitTestBehavior.translucent控制widget.onRadioItemClick触发的点击范围 + final HitTestBehavior behavior; + + const BrnCheckbox( + {Key key, + @required this.radioIndex, + @required this.onValueChangedAtIndex, + this.disable = false, + this.isSelected = false, + this.iconPadding, + this.child, + this.childOnRight = true, + this.mainAxisAlignment = MainAxisAlignment.start, + this.mainAxisSize = MainAxisSize.min, + this.behavior = HitTestBehavior.translucent}); @override State createState() { @@ -92,6 +95,7 @@ class BrnCheckboxState extends State { }); widget.onValueChangedAtIndex(widget.radioIndex, _isSelected); }, + behavior: widget.behavior, ); } } diff --git a/lib/src/components/radio/brn_radio_button.dart b/lib/src/components/radio/brn_radio_button.dart index b15306f9..257bf65a 100644 --- a/lib/src/components/radio/brn_radio_button.dart +++ b/lib/src/components/radio/brn_radio_button.dart @@ -40,18 +40,21 @@ class BrnRadioButton extends StatelessWidget { /// 默认值MainAxisSize.min final MainAxisSize mainAxisSize; - const BrnRadioButton({ - Key key, - @required this.radioIndex, - @required this.onValueChangedAtIndex, - this.disable = false, - this.isSelected = false, - this.iconPadding, - this.child, - this.childOnRight = true, - this.mainAxisAlignment = MainAxisAlignment.start, - this.mainAxisSize = MainAxisSize.min, - }); + /// 默认值HitTestBehavior.translucent控制widget.onRadioItemClick触发的点击范围 + final HitTestBehavior behavior; + + const BrnRadioButton( + {Key key, + @required this.radioIndex, + @required this.onValueChangedAtIndex, + this.disable = false, + this.isSelected = false, + this.iconPadding, + this.child, + this.childOnRight = true, + this.mainAxisAlignment = MainAxisAlignment.start, + this.mainAxisSize = MainAxisSize.min, + this.behavior = HitTestBehavior.translucent}); @override Widget build(BuildContext context) { @@ -74,6 +77,7 @@ class BrnRadioButton extends StatelessWidget { onRadioItemClick: () { onValueChangedAtIndex(radioIndex, true); }, + behavior: behavior, ); } } diff --git a/lib/src/components/radio/brn_radio_core.dart b/lib/src/components/radio/brn_radio_core.dart index 05fc52b0..8f5c027a 100644 --- a/lib/src/components/radio/brn_radio_core.dart +++ b/lib/src/components/radio/brn_radio_core.dart @@ -1,3 +1,4 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -49,6 +50,9 @@ class BrnRadioCore extends StatefulWidget { final VoidCallback onRadioItemClick; + /// 默认值HitTestBehavior.translucent控制widget.onRadioItemClick触发的点击范围 + final HitTestBehavior behavior; + const BrnRadioCore( {Key key, @required this.radioIndex, @@ -63,7 +67,8 @@ class BrnRadioCore extends StatefulWidget { this.unselectedImage, this.disSelectedImage, this.disUnselectedImage, - this.onRadioItemClick}) + this.onRadioItemClick, + this.behavior = HitTestBehavior.translucent}) : super(key: key); @override @@ -131,7 +136,7 @@ class _BrnRadioCoreState extends State { return GestureDetector( child: radioWidget, - behavior: HitTestBehavior.translucent, + behavior: widget.behavior, onTap: () { if (widget.disable == true) return; widget.onRadioItemClick(); From 96287c6358480eddba9f59c9bb1703c7f022791a Mon Sep 17 00:00:00 2001 From: Sandy <15143015732@163.com> Date: Mon, 10 Jan 2022 11:42:15 +0800 Subject: [PATCH 07/24] =?UTF-8?q?=E4=BC=98=E5=8C=96sketch=E6=95=99?= =?UTF-8?q?=E7=A8=8B=E4=B8=BA=E8=A7=86=E9=A2=91=E6=95=99=E7=A8=8B=20(#61)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/sketch.md | 67 +++----------------------------------------------- 1 file changed, 4 insertions(+), 63 deletions(-) diff --git a/docs/sketch.md b/docs/sketch.md index 839a5cf6..03d90a2f 100644 --- a/docs/sketch.md +++ b/docs/sketch.md @@ -10,75 +10,16 @@ order: 4 ## 第一部分 安装插件&选取所需组件 -1. 将下载好的 Sketch 插件压缩包解压,双击安装到 Sketch 应用中(需安装 Sketch 应用) -
- 1.安装插件&选取所需组件-0001 -
- -2. 打开下载好的 Sketch 设计物料 -
- 1.安装插件&选取所需组件-0003 -
-3. 新建 Sketch 页面及画像 -
- 1.安装插件&选取所需组件-0005 -
- 1.安装插件&选取所需组件-0005 -
- 1.安装插件&选取所需组件-0005 -
- 1.安装插件&选取所需组件-0005 -
- 1.安装插件&选取所需组件-0011.png -
- 1.安装插件&选取所需组件-0015 -
-4. 选取左侧组件拖拽到右侧画像中 -
- 1.安装插件&选取所需组件-0013 -
- 1.安装插件&选取所需组件-0017 -
- 1.安装插件&选取所需组件-0019 -
+ ## 第二部分 关于组件的解绑与使用 -1. 组件解绑与删除 -
- 2.关于组件的解绑与使用-0036.png -
- 2.关于组件的解绑与使用-0024 -
- 2.关于组件的解绑与使用-0025 -
-2. 更改组件内容,页面 UI 位置调整 -
- 2.关于组件的解绑与使用-0026 -
- 2.关于组件的解绑与使用-0035 -
+ ## 第三部分 配合 Sketch 插件导出设计稿 -1. 打开之前安装的 Sketch 插件( Sketch MeaXure ),点击 ToolBar -
- 3.配合使用插件导出设计标注-0002.png -
- 3.配合使用插件导出设计标注-0003.png -
-2. 点击导出设计稿 -
- 3.配合使用插件导出设计标注-0010 -
- 3.配合使用插件导出设计标注-0005 -
- 3.配合使用插件导出设计标注-0009 -
+ ## 第四部分 查看标注中引用的组件信息 -点击页面中使用到组件的位置,页面中自动展示组件信息,并在右侧展示组件示例代码,可直接复制使用。 -
-4.查看标注中引用的组件信息-0001 -
+ From d8234a928d2eed306d61a647b05f7b91233237bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E8=84=B8=E5=84=BF?= Date: Wed, 26 Jan 2022 12:12:04 +0800 Subject: [PATCH 08/24] replace DIN font with Bebas font (#87) (#92) --- assets/fonts/Bebas-Regular.ttf | Bin 0 -> 17408 bytes assets/fonts/DINCondensed-Bold.ttf | Bin 81704 -> 0 bytes .../card/content/number_item_example.dart | 8 +++++--- example/lib/sample/theme/config_test_utils.dart | 4 ++-- .../content_card/brn_enhance_number_card.dart | 3 ++- .../theme/base/brn_default_config_utils.dart | 6 +++--- lib/src/theme/configs/brn_common_config.dart | 10 +++++----- pubspec.yaml | 4 ++-- 8 files changed, 19 insertions(+), 16 deletions(-) create mode 100644 assets/fonts/Bebas-Regular.ttf delete mode 100644 assets/fonts/DINCondensed-Bold.ttf diff --git a/assets/fonts/Bebas-Regular.ttf b/assets/fonts/Bebas-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d2e62a271a099337491735222cda5d14142f29b8 GIT binary patch literal 17408 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 V&LKGWTrf}JWn&Lf3Vmnn{{eQ3B1-@O literal 0 HcmV?d00001 diff --git a/assets/fonts/DINCondensed-Bold.ttf b/assets/fonts/DINCondensed-Bold.ttf deleted file mode 100644 index f05a1a96cde2353e89bc770aaf541a90a46ad95c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 81704 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 diff --git a/example/lib/sample/components/card/content/number_item_example.dart b/example/lib/sample/components/card/content/number_item_example.dart index 07bbba84..552ee602 100644 --- a/example/lib/sample/components/card/content/number_item_example.dart +++ b/example/lib/sample/components/card/content/number_item_example.dart @@ -178,12 +178,13 @@ class _NumberItemRowExampleState extends State { transform: Matrix4.translationValues(0, 1, 0), child: Text('3', style: TextStyle( + height: 1.0, textBaseline: TextBaseline.ideographic, color: Color(0xFF222222), package: BrnStrings.flutterPackageName, - fontWeight: FontWeight.w600, + fontWeight: FontWeight.w500, fontSize: 28, - fontFamily: 'Condensed', + fontFamily: 'Bebas', )), ), Padding( @@ -204,12 +205,13 @@ class _NumberItemRowExampleState extends State { transform: Matrix4.translationValues(0, 1, 0), child: Text('1', style: TextStyle( + height: 1.0, textBaseline: TextBaseline.ideographic, color: Color(0xFF222222), package: BrnStrings.flutterPackageName, fontWeight: FontWeight.w600, fontSize: 28, - fontFamily: 'Condensed', + fontFamily: 'Bebas', )), ), Padding( diff --git a/example/lib/sample/theme/config_test_utils.dart b/example/lib/sample/theme/config_test_utils.dart index f91dd885..7837353d 100644 --- a/example/lib/sample/theme/config_test_utils.dart +++ b/example/lib/sample/theme/config_test_utils.dart @@ -78,8 +78,8 @@ class TestConfigUtils { /// 文本字号 /// - /// 特殊数据展示,DIN Condensed数字字体,用于强吸引 - fontSizeDIN: 28, + /// 特殊数据展示,Bebas 数字字体,用于强吸引 + fontSizeBebas: 28, /// 标题字体 /// 名称/页面大标题 diff --git a/lib/src/components/card/content_card/brn_enhance_number_card.dart b/lib/src/components/card/content_card/brn_enhance_number_card.dart index 7e60a8bc..0081dbe2 100644 --- a/lib/src/components/card/content_card/brn_enhance_number_card.dart +++ b/lib/src/components/card/content_card/brn_enhance_number_card.dart @@ -209,12 +209,13 @@ class BrnEnhanceNumberCard extends StatelessWidget { transform: Matrix4.translationValues(0, 1, 0), child: Text(model.number, style: TextStyle( + height: 1.0, textBaseline: TextBaseline.ideographic, color: config.titleTextStyle.color, package: BrnStrings.flutterPackageName, fontWeight: config.titleTextStyle.fontWeight, fontSize: config.titleTextStyle.fontSize, - fontFamily: 'Condensed', + fontFamily: 'Bebas', )), ), _getLastWidget(model.lastDesc, config), diff --git a/lib/src/theme/base/brn_default_config_utils.dart b/lib/src/theme/base/brn_default_config_utils.dart index ecad8989..e781d0be 100644 --- a/lib/src/theme/base/brn_default_config_utils.dart +++ b/lib/src/theme/base/brn_default_config_utils.dart @@ -112,8 +112,8 @@ class BrnDefaultConfigUtils { /// 文本字号 /// - /// 特殊数据展示,DIN Condensed数字字体,用于强吸引 - fontSizeDIN: 28, + /// 特殊数据展示,Bebas 数字字体,用于强吸引 + fontSizeBebas: 28, /// 标题字体 /// 名称/页面大标题 @@ -507,7 +507,7 @@ class BrnDefaultConfigUtils { BrnEnhanceNumberCardConfig( runningSpace: 16, itemRunningSpace: 8, - titleTextStyle: BrnTextStyle(fontSize: 28, fontWeight: FontWeight.w600), + titleTextStyle: BrnTextStyle(fontSize: 28, fontWeight: FontWeight.w500), descTextStyle: BrnTextStyle( fontSize: 12, color: defaultCommonConfig.colorTextSecondary), dividerWidth: 0.5, diff --git a/lib/src/theme/configs/brn_common_config.dart b/lib/src/theme/configs/brn_common_config.dart index 4b80efda..5464eac7 100644 --- a/lib/src/theme/configs/brn_common_config.dart +++ b/lib/src/theme/configs/brn_common_config.dart @@ -98,9 +98,9 @@ class BrnCommonConfig extends BrnBaseConfig { /// 文本字号 /// - /// 特殊数据展示,DIN Condensed数字字体,用于强吸引 + /// 特殊数据展示,Bebas 数字字体,用于强吸引 /// default value is 28 - double fontSizeDIN; + double fontSizeBebas; /// 标题字体 /// 名称/页面大标题 @@ -232,7 +232,7 @@ class BrnCommonConfig extends BrnBaseConfig { this.fillMask, this.borderColorBase, this.dividerColorBase, - this.fontSizeDIN, + this.fontSizeBebas, this.fontSizeHeadLg, this.fontSizeBase, this.fontSizeHead, @@ -287,7 +287,7 @@ class BrnCommonConfig extends BrnBaseConfig { this.fillMask, this.borderColorBase, this.dividerColorBase, - this.fontSizeDIN, + this.fontSizeBebas, this.fontSizeHeadLg, this.fontSizeBase, this.fontSizeHead, @@ -346,7 +346,7 @@ class BrnCommonConfig extends BrnBaseConfig { this.brandImportantValue ??= commonConfig.brandImportantValue; this.borderColorBase ??= commonConfig.borderColorBase; this.dividerColorBase ??= commonConfig.dividerColorBase; - this.fontSizeDIN ??= commonConfig.fontSizeDIN; + this.fontSizeBebas ??= commonConfig.fontSizeBebas; this.fontSizeHeadLg ??= commonConfig.fontSizeHeadLg; this.fontSizeBase ??= commonConfig.fontSizeBase; this.fontSizeHead ??= commonConfig.fontSizeHead; diff --git a/pubspec.yaml b/pubspec.yaml index e5968969..4dfcf223 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,9 +55,9 @@ flutter: # list giving the asset and other descriptors for the font. For # example: fonts: - - family: Condensed + - family: Bebas fonts: - - asset: assets/fonts/DINCondensed-Bold.ttf + - asset: assets/fonts/Bebas-Regular.ttf # weight: 700 # - family: Trajan Pro # fonts: From 045a2d6e68f4d8c1a26f6160ffba7fa1bfc5d87c Mon Sep 17 00:00:00 2001 From: Sandy <15143015732@163.com> Date: Fri, 4 Mar 2022 15:42:26 +0800 Subject: [PATCH 09/24] Merge remote-tracking branch 'origin/null-safe' into 2.2.x (#102) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Null safe (#13) * remove useless comments * remove useless dependencies * adapt brn_expandable_text.dart null-safe * upgrade dependencies:collection to stable * migrate constants to null safety * migrate brn_multi_click_util to null safety * migrate font util to null safety * migrate brn_text_style to null safety * migrate brn picker constants to null safety * migrate brn appBar theme to null safety * optimize bruno theme's import (#16) * ♻️ [NNBD] Part 1. Migrate configs (#28) * ♻️ [NNBD] Part 2. Migrate utils (#30) * ♻️ Migrate utils to NNBD * 🎨 Improve the color getter * :art: BrnSearchText (#36) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null (#40) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 🎨 utils-EventBus添加null-safe (#23) * 🎨 utils-EventBus添加null-safe * 🎨 修改theme配置功能及utils/brn_tools工具函数 null-safe * 🎨 EventBus添加null-safe(其他提交请忽略,输入回退) Co-authored-by: 大脸儿 * refactor brn_toast (#33) * refactor brn_toast * refactor brn_toast * 优化修复 EventBus * 优化 EventBus 单例实现 (#43) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * brn_toast time change to seconds (#45) * migrate brn_loading to null safety (#32) * migrate brn_loading to null safety * mv loading content to brnString constants * optimization brn_theme_configurator instance constructor (#47) * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * Migrate BrnStateTag、BrnTagCustom、BrnSelectTag、BrnDeleteTag to null-safe (#46) * [null-safe]: BrnStateTag、BrnTagCustom、BrnSelectTag、BrnDeleteTag 空安全适配 * perf: BrnDeleteTag null-safe * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * reset and migrated package [rating] to null-safety. (#42) * 迁移example ,优化常量命名,增加export (#51) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * 空安全报错修改 (#55) * 空安全报错修改 * 优化sketch教程为视频教程 * Migrated package [selectcity] to null-safety (#56) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * migrate card_title to null safety (#59) * migrate card_title to null-safety * [fix] brn_action_card_title: _sub widget is not null * [optimize] empty widget use SizedBox instead of Container * replace empty widget SizedBox to SizedBox.shrink * Migrated package [radio] to null-safety (#62) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * 1.Migrated package [radio] to null-safety; 2.Modified not-need-nullable param in brn_single_select_city_page.dart; * Migrated tabbar to null-safety * Migrated package [guide] to null-safety (#65) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * 1.Migrated package [radio] to null-safety; 2.Modified not-need-nullable param in brn_single_select_city_page.dart; * Migrated package [guide] to null-safety * 🚀 Use the latest Podfile for the example (#68) * Null safe calendar (#64) * migrate calendar widget to null safety * brn_calendar_view fix _currentStartSelectedDate is not null * brn_calendar_view: simplify borderRadius usage * calendar widget late _displayMode * calendar widget add two constructors with date change * Card Components Null safe adapter (#53) * feat: support fvm * feat: Card components null-safey adpater * refactor: make code simple and clean * refactor: make code simple and clean * Migrated scroll_anchor to null-safety * fix #71 (#77) * fix content_card themeData is not null (#79) * Null safe of all buttons (#20) * icon button 增加null safe * null safe for normal button * null safe for normal button * null safe for button * null safe for all button * merge * rebase * rebase * merge * optimization * GlobalKey is not null * optimization * reset popup window * showButtonPanelPopList Co-authored-by: foreturn * Migrated package [navbar][input] to null-safety (#75) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * 1.Migrated package [radio] to null-safety; 2.Modified not-need-nullable param in brn_single_select_city_page.dart; * Migrated package [guide] to null-safety * Migrated package [navbar][input] to null-safety * Optimized codes in brn_appbar.dart * Restore partial modification * fix:修复迁移tabar问题 * Migrated tabbar & scroll_anchor to null-safety (#66) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * Migrate Selection to null-safe (#54) * [null-safe]: BrnStateTag、BrnTagCustom、BrnSelectTag、BrnDeleteTag 空安全适配 * perf: BrnDeleteTag null-safe * Migrate Selection to null-safe * Migrate Selection to null-safe * perf: ItemEntity name 字段的初始化 * Migrate Selection to null-safe * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * Migrated package [dialog] to null-safety (#81) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * 1.Migrated package [radio] to null-safety; 2.Modified not-need-nullable param in brn_single_select_city_page.dart; * Migrated package [guide] to null-safety * Migrated package [navbar][input] to null-safety * Optimized codes in brn_appbar.dart * Restore partial modification * Migrated package [dialog] to null-safety * Modified some params's default value or nullable type * migrate brn_horizontal_steps、brn_step_line to null safety (#89) * migrate charts to null safety (#80) * migrate DoughuntChart to null safety * migrate progress bar chart to null safety * update progress bar chart document * migrate progress chart to null safety * migrate radar chart to null safety * migrate funnel chart to null safety * migrate broken line chart to null safety * fix progress bar chart some value is required * fix progress bar chart some value is required * fix brn_line_paint _path is not null * fix brn_funnel_chart properties is not null * fix brn_radar_chart properties is not null * fix brn_line_painter not null values * fix brn_progress_bar_chart error * brn_broken_line some properties is not null value * replace empty Container to SizedBox.shrink * update progress_bar_chart null safety value by hand * update broken_line null safety values by hand * update funnel_chart null safety value by hand * make LineCanvasModel immutable * migrate actionsheet into null-safe (#73) * migrate actionsheet into null-safe * sheet: code review Co-authored-by: yuanjunliang * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate form to null safety (#86) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * migrate popup to null safety (#69) * migrate popup to null safety * fix MeasureSize null safe problems * fix popup migrate to null-safety review problems * migrate gallery to null safety (#90) * migrate gallery to null safety * change the type error * remove @ * change String? to String * fix:修复picker空安全迁移问题 * migrate appraise dir to null safety (#84) * migrate appraise dir to null safety * fix appraise migrate to null-safety review problems * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate picker to null safety (#91) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * fix:修复picker空安全迁移问题 * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate example to null safty * fix:修复部分example warning * fix:修复demo报错问题 * fix:追加未跟踪修复 * fix:优化部分接口可空参数为非空 * Perf:Button Null safe (#93) * perf: Migrate Button Null-Safe * perf:优化 HorizontalStep Null-Safe * fix: null exception when parse json to entity * perf Button Null-Safe, fix NullException perf more layer icon color when item selected * migrate example to null safety (#94) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * fix:修复picker空安全迁移问题 * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate example to null safty * fix:修复部分example warning * fix:修复demo报错问题 * fix:追加未跟踪修复 * fix:优化部分接口可空参数为非空 Co-authored-by: violinday * fix:修复tabar showmore overflow 问题 #98 以及 tabbar 标签颜色默认设置倒置问题 * Fix #98 问题及优化部分代码 (#99) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * fix:修复picker空安全迁移问题 * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate example to null safty * fix:修复部分example warning * fix:修复demo报错问题 * fix:追加未跟踪修复 * fix:优化部分接口可空参数为非空 * fix:修复tabar showmore overflow 问题 #98 以及 tabbar 标签颜色默认设置倒置问题 Co-authored-by: violinday * refactor:优化 BrnInputItemType 常量命名 * refactor:优化枚举值命名 * fix:修改docs目录下form相关常量命名及所有枚举命名 * 优化 BrnInputItemType 常量命名 (#100) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * fix:修复picker空安全迁移问题 * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate example to null safty * fix:修复部分example warning * fix:修复demo报错问题 * fix:追加未跟踪修复 * fix:优化部分接口可空参数为非空 * fix:修复tabar showmore overflow 问题 #98 以及 tabbar 标签颜色默认设置倒置问题 * refactor:优化 BrnInputItemType 常量命名 * refactor:优化枚举值命名 * fix:修改docs目录下form相关常量命名及所有枚举命名 Co-authored-by: violinday * refactor: 更新 changelog * refactor:BrnBubbleText 增加属性 bgColor、textStyle,修复demo actionSheet、gallery、selection、picker错误 * fix:修复changelog 错误,brn_gallery_summary_page.dart 中标题空处理 * fix:修复部分问题 * fix:修复部分问题 Co-authored-by: laiiihz Co-authored-by: LAIIIHZ <35956195+laiiihz@users.noreply.github.com> Co-authored-by: Alex Li Co-authored-by: kalifun <37646342+kalifun@users.noreply.github.com> Co-authored-by: kkkman22 <2594387207@qq.com> Co-authored-by: 大脸儿 Co-authored-by: leftcoding <137387869@qq.com> Co-authored-by: violinday Co-authored-by: jojinshallar Co-authored-by: HappyImp Co-authored-by: Kenneth Co-authored-by: donywan Co-authored-by: foreturn Co-authored-by: Junl <17602153700@163.com> Co-authored-by: yuanjunliang Co-authored-by: Nayuta403 <40540394+Nayuta403@users.noreply.github.com> --- .gitignore | 3 + CHANGELOG.md | 44 +- assets/icons/icon_uparrow.png | Bin 452 -> 0 bytes .../BrnAbnormalStateWidget.md | 2 +- .../form/BrnAddLabel/BrnAddLabel.md | 2 +- .../BrnExpandFormGroup/BrnExpandFormGroup.md | 2 +- .../BrnMultiChoiceInputFormItem.md | 8 +- .../BrnMultiChoicePortraitInputFormItem.md | 14 +- .../BrnNormalFormGroup/BrnNormalFormGroup.md | 2 +- .../BrnRadioInputFormItem.md | 19 +- .../BrnRadioPortraitInputFormItem.md | 14 +- .../BrnRangeInputFormItem.md | 33 +- .../BrnRatioInputFormItem.md | 6 +- .../form/BrnStarsFormItem/BrnStarsFormItem.md | 6 +- .../BrnStepInputFormItem.md | 5 +- .../BrnTextBlockInputFormItem.md | 42 +- .../BrnTextInputFormItem.md | 14 +- .../BrnTextQuickSelectFormItem.md | 8 +- .../BrnTextSelectFormItem.md | 18 +- .../form/BrnTitleFormItem/BrnTitleFormItem.md | 6 +- .../BrnTitleSelectInputFormItem.md | 32 +- .../BrnMultiColumnPicker.md | 6 +- .../BrnSelectionView/BrnSelectionView.md | 28 +- docs/sketch.md | 12 +- example/ios/Podfile | 79 +- example/lib/main.dart | 2 + .../actionsheet/actionsheet_entry_page.dart | 74 +- ...ionsheet_selected_list_custom_example.dart | 18 +- .../actionsheet_selected_list_example.dart | 25 +- .../components/appraise/appraise_example.dart | 11 +- .../bottom_tabbar/bottom_tabbar_example.dart | 12 +- .../button/common_collection_example.dart | 4 +- .../button/selection_collection_example.dart | 7 +- .../calendar/calendarview_example.dart | 53 +- .../components/card/brn_shadow_example.dart | 10 +- .../bubble/brn_expanded_bubble_example.dart | 4 +- .../card/bubble/bubble_entry_page.dart | 2 + .../card/bubble/common_bubble_example.dart | 2 + .../content/brn_two_rich_content_example.dart | 2 + .../content/brn_two_text_content_example.dart | 2 + .../keyvalue_align_content_example.dart | 16 +- .../keyvalue_close_content_example.dart | 8 +- .../card/content/number_item_example.dart | 8 +- .../card/content/text_content_entry_page.dart | 2 + .../content/text_value_arrow_example.dart | 6 +- .../card_title/brn_action_title_example.dart | 2 + .../card_title/brn_common_title_example.dart | 7 +- .../components/card_title/title_example.dart | 2 + .../charts/chart_entry_example.dart | 74 +- .../charts/doughnut_chart_example.dart | 8 +- .../charts/line/brn_broken_line_example.dart | 42 +- .../charts/line/db_data_node_model.dart | 31 +- .../charts/progress_bar_chart_example.dart | 2 + .../charts/progress_chart_entry_page.dart | 2 + .../components/dialog/dialog_entry_page.dart | 46 +- .../components/empty/abnormal_entry_page.dart | 2 + .../empty/abnormal_state_example.dart | 14 +- .../form/all_item_style_example.dart | 2 + .../form/form_item_entry_example.dart | 2 + .../components/form/form_page_example.dart | 19 +- .../expansion_group_example.dart | 2 + .../form/group_example/group_add_example.dart | 2 + .../group_example/normal_group_example.dart | 2 + .../items_example/base_title_example.dart | 2 + .../items_example/multi_choice_example.dart | 14 +- .../multi_choice_protrait_example.dart | 6 +- .../items_example/radio_input_example.dart | 8 +- .../items_example/radio_protrait_example.dart | 6 +- .../items_example/range_input_example.dart | 16 +- .../items_example/ratio_input_example.dart | 8 +- .../select_all_title_example.dart | 2 + .../form/items_example/star_example.dart | 6 +- .../items_example/step_input_example.dart | 8 +- .../text_block_input_example.dart | 8 +- .../items_example/text_input_example.dart | 8 +- .../text_quick_select_input_example.dart | 12 +- .../items_example/text_select_example.dart | 8 +- .../form/items_example/title_example.dart | 2 + .../items_example/title_select_example.dart | 16 +- .../photo_preview_page.dart | 69 -- .../gallery/gallery_detail_example.dart | 12 +- .../gallery_detail_page_theme_example.dart | 2 + .../components/gallery/gallery_example.dart | 4 +- .../components/guide/force_guide_example.dart | 6 +- .../components/guide/guide_entry_page.dart | 2 + .../components/guide/soft_intro_example.dart | 6 +- .../components/input/input_example.dart | 8 +- .../components/line/dashed_line_example.dart | 11 +- .../loading/loading_widget_example.dart | 2 + .../components/navbar/appbar_entry_page.dart | 2 + .../navbar/nav_bar_example_page.dart | 46 +- .../noticebar/brn_notice_bar_example.dart | 2 + .../noticebar/notice_bar_example.dart | 2 + .../notice_bar_with_button_example.dart | 2 + .../picker/cutomer_bottom_picker_example.dart | 2 + .../picker/date_picker_example.dart | 4 +- .../picker/multi_picker_example.dart | 10 +- .../components/picker/picker_entry_page.dart | 56 +- .../popup/overlay_window_example.dart | 10 +- .../components/popup/popwindow_example.dart | 43 +- .../components/rating/rating_example.dart | 8 +- .../scroll_actor_tab_example.dart | 2 + .../selectcity/selected_city_example.dart | 10 +- .../components/selection/filter_entity.dart | 20 +- .../flat_selection_five_tags_example.dart | 16 +- .../flat_selection_four_tags_example.dart | 14 +- .../flat_selection_three_tags_example.dart | 14 +- .../selection/selection_entry_page.dart | 20 +- .../selection/selection_flat_entry_page.dart | 8 +- ...ionview_custom_floating_layer_example.dart | 16 +- ...view_customhandle_filter_example_page.dart | 8 +- ...selectionview_customview_example_page.dart | 36 +- ...electionview_date_filter_example_page.dart | 4 +- ...selectionview_date_range_example_page.dart | 16 +- .../selectionview_interceptor_example.dart | 26 +- ...view_limit_max_selected_count_example.dart | 12 +- ...electionview_more_filter_example_page.dart | 6 +- ...selectionview_multi_list_example_page.dart | 8 +- ...electionview_multi_range_example_page.dart | 12 +- ...nview_simple_multi_check_example_page.dart | 6 +- ...nview_simple_single_list_example_page.dart | 6 +- .../step/brn_horizontal_step_example.dart | 172 +++- .../sample/components/step/step_example.dart | 2 + .../components/step/step_line_example.dart | 205 +++-- .../sugsearch/search_text_example.dart | 1 + .../components/switch/checkbox_example.dart | 2 + .../components/switch/radio_example.dart | 2 + .../tabbar/brn_switch_title_example.dart | 4 +- .../components/tabbar/brn_tab_example.dart | 30 +- .../tabbar/brn_tabbar_sticky_example.dart | 22 +- .../tabbar/sub_switch_title_example.dart | 4 +- .../components/tag/border_tag_example.dart | 2 + .../components/tag/custom_tag_example.dart | 2 + .../components/tag/delete_tag_example.dart | 45 +- .../components/tag/select_tag_example.dart | 7 +- .../components/tag/state_tag_example.dart | 2 + .../sample/components/tag/tag_example.dart | 2 + .../components/tag/tag_row_example.dart | 2 + .../components/toast/toast_example.dart | 116 ++- example/lib/sample/home/card_data_config.dart | 28 +- .../home/expandable_container_widget.dart | 57 +- example/lib/sample/home/group_card.dart | 37 +- example/lib/sample/home/home.dart | 4 +- example/lib/sample/home/list_item.dart | 18 +- .../lib/sample/theme/config_test_utils.dart | 12 +- example/pubspec.yaml | 6 +- lib/bruno.dart | 11 +- .../actionsheet/brn_common_action_sheet.dart | 74 +- .../brn_selected_list_action_sheet.dart | 153 ++-- .../actionsheet/brn_share_action_sheet.dart | 52 +- lib/src/components/appraise/brn_appraise.dart | 218 ++--- .../appraise/brn_appraise_bottom_picker.dart | 19 +- .../appraise/brn_appraise_config.dart | 97 ++ .../appraise/brn_appraise_emoji_item.dart | 36 +- .../brn_appraise_emoji_list_view.dart | 48 +- .../appraise/brn_appraise_header.dart | 42 +- .../appraise/brn_appraise_interface.dart | 19 + .../appraise/brn_appraise_star_list_view.dart | 19 +- .../appraise/brn_flutter_gif_image.dart | 58 +- .../appraise/brn_mulit_select_tags.dart | 56 +- .../button/brn_big_ghost_button.dart | 27 +- .../button/brn_big_main_button.dart | 27 +- .../button/brn_big_outline_button.dart | 30 +- .../components/button/brn_icon_button.dart | 80 +- .../components/button/brn_normal_button.dart | 153 ++-- .../button/brn_small_main_button.dart | 57 +- .../button/brn_small_outline_button.dart | 42 +- .../button/brn_vertical_icon_button.dart | 11 +- .../collection/brn_bottom_button_panel.dart | 60 +- .../button/collection/brn_button_panel.dart | 58 +- .../brn_multiple_bottom_button.dart | 97 +- .../collection/brn_text_button_panel.dart | 59 +- .../calendar/brn_calendar_view.dart | 205 +++-- .../card/bubble_card/brn_bubble_text.dart | 62 +- .../card/bubble_card/brn_insert_info.dart | 4 +- .../content_card/brn_enhance_number_card.dart | 76 +- .../content_card/brn_pair_info_rich_grid.dart | 76 +- .../content_card/brn_pair_info_table.dart | 219 +++-- .../card/shadow_card/brn_shadow_card.dart | 22 +- .../card_title/brn_action_card_title.dart | 36 +- .../card_title/brn_common_card_title.dart | 66 +- .../brn_doughnut_chart.dart | 35 +- .../brn_doughnut_chart_legend.dart | 15 +- .../brn_bar_chart_data.dart | 22 +- .../brn_progress_bar_chart.dart | 60 +- .../brn_progress_bar_chart_painter.dart | 145 ++- .../brn_progress_chart.dart | 16 +- .../brn_progress_chart_painter.dart | 2 + .../charts/broken_line/brn_base_painter.dart | 8 +- .../charts/broken_line/brn_broken_line.dart | 85 +- .../charts/broken_line/brn_line_data.dart | 29 +- .../charts/broken_line/brn_line_painter.dart | 297 +++---- .../broken_line/brn_line_y_painter.dart | 74 +- .../charts/broken_line/monotone_x.dart | 25 +- lib/src/components/charts/funnel_chart.dart | 161 ++-- lib/src/components/charts/radar_chart.dart | 99 +-- .../dialog/brn_content_export_dialog.dart | 38 +- lib/src/components/dialog/brn_dialog.dart | 335 +++---- .../components/dialog/brn_dialog_utils.dart | 4 +- .../dialog/brn_enhance_operation_dialog.dart | 46 +- .../dialog/brn_middle_input_diaolg.dart | 40 +- .../dialog/brn_multi_select_dialog.dart | 152 ++-- .../dialog/brn_scrollable_text_dialog.dart | 37 +- .../components/dialog/brn_share_dialog.dart | 52 +- .../components/dialog/brn_single_select.dart | 66 +- .../components/empty/brn_empty_status.dart | 106 +-- .../form/base/brn_form_item_type.dart | 78 +- .../form/base/input_item_interface.dart | 5 +- .../general/brn_multi_choice_input_item.dart | 111 +-- .../brn_multi_choice_portrait_input_item.dart | 113 +-- .../general/brn_quick_select_input_item.dart | 133 ++- .../items/general/brn_radio_input_item.dart | 125 ++- .../brn_radio_portrait_input_item.dart | 83 +- .../items/general/brn_range_input_item.dart | 101 +-- .../items/general/brn_ratio_input_item.dart | 60 +- .../items/general/brn_star_input_item.dart | 52 +- .../items/general/brn_step_input_item.dart | 136 ++- .../general/brn_text_block_input_item.dart | 76 +- .../items/general/brn_text_input_item.dart | 79 +- .../items/general/brn_text_select_item.dart | 82 +- .../general/brn_title_select_input_item.dart | 134 +-- .../group}/brn_expandable_group.dart | 48 +- ...=> brn_expandable_group_with_opreate.dart} | 44 +- .../form/items/group/brn_normal_group.dart | 62 +- .../group}/brn_portrait_radio_group.dart | 105 ++- .../items/group/element_expand_widget.dart | 53 +- .../form/items/misc/brn_add_label_item.dart | 24 +- .../form/items/misc/brn_title_item.dart | 50 +- .../form/items/title/brn_base_title_item.dart | 50 +- .../title/brn_select_all_title_item.dart | 67 +- .../components/form/utils/brn_form_util.dart | 158 ++-- .../config/brn_basic_gallery_config.dart | 22 +- .../gallery/config/brn_bottom_card.dart | 44 +- .../gallery/config/brn_controller.dart | 3 +- .../config/brn_photo_gallery_config.dart | 88 +- .../gallery/page/brn_gallery_detail_page.dart | 189 ++-- .../page/brn_gallery_summary_page.dart | 58 +- .../guide/brn_delay_rendered_widget.dart | 10 +- .../components/guide/brn_flutter_guide.dart | 74 +- .../components/guide/brn_pulse_widget.dart | 9 +- .../guide/brn_step_widget_builder.dart | 9 +- .../guide/brn_step_widget_params.dart | 20 +- lib/src/components/guide/brn_throttling.dart | 6 +- lib/src/components/guide/brn_tip_widget.dart | 58 +- lib/src/components/input/brn_input_text.dart | 36 +- lib/src/components/line/brn_dashed_line.dart | 96 +- lib/src/components/line/brn_line.dart | 11 +- lib/src/components/loading/brn_loading.dart | 22 +- lib/src/components/navbar/brn_appbar.dart | 137 +-- .../components/navbar/brn_appbar_theme.dart | 4 +- .../components/navbar/brn_empty_appbar.dart | 19 - lib/src/components/navbar/brn_search_bar.dart | 91 +- .../noticebar/brn_marquee_text.dart | 37 +- .../components/noticebar/brn_notice_bar.dart | 73 +- .../noticebar/brn_notice_bar_with_button.dart | 47 +- .../components/picker/base/brn_picker.dart | 73 +- .../picker/base/brn_picker_constants.dart | 24 +- .../picker/base/brn_picker_title.dart | 40 +- .../picker/base/brn_picker_title_config.dart | 10 +- .../components/picker/brn_bottom_picker.dart | 42 +- .../picker/brn_bottom_write_picker.dart | 50 +- .../picker/brn_mulit_select_tags_picker.dart | 77 +- .../components/picker/brn_multi_picker.dart | 103 ++- .../picker/brn_picker_cliprrect.dart | 7 +- .../brn_select_tags_with_input_picker.dart | 141 +-- .../picker/brn_tags_common_picker.dart | 33 +- .../picker/brn_tags_picker_config.dart | 24 +- .../bean/brn_multi_column_picker_entity.dart | 134 ++- .../brn_multi_column_converter.dart | 35 +- .../brn_multi_column_list.dart | 116 +-- .../brn_multi_column_picker.dart | 144 ++- .../brn_multi_column_picker_util.dart | 30 +- .../btn_multi_column_picker_item.dart | 40 +- .../brn_multi_select_data.dart | 2 + .../brn_multi_select_list_picker.dart | 42 +- .../brn_date_picker_constants.dart | 19 +- .../time_picker/brn_date_time_formatter.dart | 30 +- .../date_picker/brn_date_picker.dart | 89 +- .../date_picker/brn_date_widget.dart | 106 +-- .../date_picker/brn_datetime_widget.dart | 168 ++-- .../date_picker/brn_time_widget.dart | 118 +-- .../brn_date_range_picker.dart | 91 +- .../brn_date_range_side_widget.dart | 109 +-- .../brn_date_range_widget.dart | 88 +- .../brn_time_range_side_widget.dart | 137 +-- .../brn_time_range_widget.dart | 108 ++- .../components/popup/brn_measure_size.dart | 22 +- .../components/popup/brn_overlay_window.dart | 89 +- .../components/popup/brn_popup_window.dart | 280 +++--- lib/src/components/radio/brn_checkbox.dart | 38 +- .../components/radio/brn_radio_button.dart | 37 +- lib/src/components/radio/brn_radio_core.dart | 33 +- .../components/rating/brn_rating_star.dart | 20 +- .../scroll_anchor/brn_scroll_anchor_tab.dart | 127 ++- .../components/selectcity/brn_az_common.dart | 24 +- .../selectcity/brn_az_listview.dart | 53 +- .../selectcity/brn_base_azlistview_page.dart | 30 +- .../components/selectcity/brn_index_bar.dart | 49 +- .../selectcity/brn_select_city_model.dart | 22 +- .../brn_single_select_city_page.dart | 54 +- .../selectcity/brn_suspension_view.dart | 73 +- .../selection/bean/brn_filter_entity.dart | 15 +- .../bean/brn_selection_common_entity.dart | 440 +++++----- .../selection/brn_flat_selection.dart | 122 ++- .../selection/brn_more_selection.dart | 136 ++- .../selection/brn_selection_list_entity.dart | 10 +- .../selection/brn_selection_util.dart | 77 +- .../selection/brn_selection_view.dart | 147 ++-- .../selection/brn_simple_selection.dart | 73 +- .../brn_selection_view_controller.dart | 14 +- ...selection_view_date_picker_controller.dart | 11 +- .../converter/brn_selection_converter.dart | 61 +- .../widget/brn_flat_selection_item.dart | 266 +++--- .../widget/brn_layer_more_selection_page.dart | 267 +++--- .../widget/brn_selection_animate_widget.dart | 56 +- .../brn_selection_common_item_widget.dart | 49 +- .../brn_selection_date_range_item_widget.dart | 142 ++- ...n_selection_datepicker_animate_widget.dart | 28 +- .../widget/brn_selection_list_widget.dart | 241 +++-- .../brn_selection_menu_item_widget.dart | 24 +- .../widget/brn_selection_menu_widget.dart | 408 ++++----- .../brn_selection_more_item_widget.dart | 295 +++---- ...brn_selection_range_input_item_widget.dart | 80 +- .../brn_selection_range_tag_widget.dart | 75 +- .../widget/brn_selection_range_widget.dart | 343 +++----- .../brn_selection_single_list_widget.dart | 131 ++- .../components/step/brn_horizontal_steps.dart | 372 ++++---- lib/src/components/step/brn_step_line.dart | 88 +- .../components/sugsearch/brn_search_text.dart | 85 +- .../bottom/brn_bottom_tab_bar_item.dart | 17 +- .../bottom/brn_bottom_tab_bar_main.dart | 127 +-- .../indicator/brn_custom_width_indicator.dart | 20 +- .../brn_fixed_underline_decoration.dart | 18 +- .../indicator/brn_triangle_decoration.dart | 54 +- .../tabbar/normal/brn_sub_switch_title.dart | 24 +- .../tabbar/normal/brn_switch_title.dart | 36 +- .../components/tabbar/normal/brn_tab_bar.dart | 362 ++++---- .../tabbar/normal/brn_tabbar_controller.dart | 12 +- lib/src/components/tag/brn_state_tag.dart | 12 +- lib/src/components/tag/brn_tag_custom.dart | 61 +- .../tag/tagview/brn_delete_tag.dart | 110 ++- .../tag/tagview/brn_select_tag.dart | 79 +- .../components/text/brn_expandable_text.dart | 24 +- lib/src/components/toast/brn_toast.dart | 328 ++++--- lib/src/constants/brn_asset_constants.dart | 199 ++--- lib/src/constants/brn_constants.dart | 38 +- lib/src/constants/brn_fonts_constants.dart | 10 + lib/src/constants/brn_strings_constants.dart | 5 +- lib/src/theme/base/brn_base_config.dart | 49 +- .../theme/base/brn_default_config_utils.dart | 800 +++++++++-------- lib/src/theme/base/brn_text_style.dart | 84 +- lib/src/theme/brn_initializer.dart | 17 +- lib/src/theme/brn_theme.dart | 3 +- lib/src/theme/brn_theme_configurator.dart | 57 +- .../configs/brn_abnormal_state_config.dart | 245 ++++-- .../configs/brn_action_sheet_config.dart | 378 ++++---- lib/src/theme/configs/brn_all_config.dart | 303 +++++-- lib/src/theme/configs/brn_appbar_config.dart | 382 ++++---- lib/src/theme/configs/brn_button_config.dart | 144 +-- .../theme/configs/brn_card_title_config.dart | 278 +++--- lib/src/theme/configs/brn_common_config.dart | 827 +++++++++++------ lib/src/theme/configs/brn_dialog_config.dart | 666 ++++++++------ .../brn_enhance_number_card_config.dart | 126 +-- lib/src/theme/configs/brn_form_config.dart | 544 +++++++----- .../configs/brn_gallery_detail_config.dart | 479 +++++----- .../theme/configs/brn_pair_info_config.dart | 352 +++++--- lib/src/theme/configs/brn_picker_config.dart | 342 +++++--- .../theme/configs/brn_selection_config.dart | 829 +++++++++++------- lib/src/theme/configs/brn_tabbar_config.dart | 359 +++++--- lib/src/theme/configs/brn_tag_config.dart | 209 +++-- .../theme/img/brn_theme_default_utils.dart | 69 -- lib/src/theme/img/brn_theme_img_utils.dart | 17 - lib/src/utils/brn_event_bus.dart | 56 +- lib/src/utils/brn_multi_click_util.dart | 10 +- lib/src/utils/brn_rich_text.dart | 108 +-- lib/src/utils/brn_text_util.dart | 12 +- lib/src/utils/brn_tools.dart | 89 +- lib/src/utils/css/brn_core_funtion.dart | 130 +-- lib/src/utils/css/brn_css_2_text.dart | 38 +- lib/src/utils/css/brn_util.dart | 39 +- lib/src/utils/font/brn_font.dart | 13 - lib/src/utils/i18n/brn_date_picker_i18n.dart | 54 +- lib/src/utils/i18n/brn_strings_zh_cn.dart | 66 +- pubspec.yaml | 2 +- 384 files changed, 14113 insertions(+), 12763 deletions(-) delete mode 100644 assets/icons/icon_uparrow.png delete mode 100644 example/lib/sample/components/form/phote_picker_example/photo_preview_page.dart create mode 100644 lib/src/components/appraise/brn_appraise_config.dart create mode 100644 lib/src/components/appraise/brn_appraise_interface.dart rename lib/src/components/form/{undetermined => items/group}/brn_expandable_group.dart (88%) rename lib/src/components/form/items/group/{brn_expand_group.dart => brn_expandable_group_with_opreate.dart} (79%) rename lib/src/components/form/{undetermined => items/group}/brn_portrait_radio_group.dart (74%) delete mode 100644 lib/src/components/navbar/brn_empty_appbar.dart create mode 100644 lib/src/constants/brn_fonts_constants.dart delete mode 100644 lib/src/theme/img/brn_theme_default_utils.dart delete mode 100644 lib/src/theme/img/brn_theme_img_utils.dart delete mode 100644 lib/src/utils/font/brn_font.dart diff --git a/.gitignore b/.gitignore index 8c47502d..19f097df 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,6 @@ build/ !**/ios/**/default.perspectivev3 !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages pubspec.lock + +# FVM +.fvm diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b3e551d..70537f23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,44 @@ -## [1.0.0] - first publish adapter flutter sdk 1.22.4 -## [2.0.0] - adapter flutter sdk 2.2.2 + +## [2.1.0-Beta] - 2022-2-15 +### Changed + +#### base + +- **Breaking change**: Sound null safety support, thanks to @leftcoding #39#33 @donywan #20 @laiiihz #80#64#59#32#14 @kalifun #36 @jojinshallar #81#75#65#62#56#42 @junlandroid #73 @Kenneth #53 @HappyImp #55 @kkkman22 #23 @AlexV525 #30 +- **Breaking change**: Refer to the dart language specification to optimized constant and enum naming. +- Replace DIN Font with Bebas Font . +- Add build test thank to **AlexV525**. + +#### components +- BrnCalendarView: add BrnCalendarView.single() and BrnCalendarView.range() constructor and had its argument startEndDateChange removed. +- BrnSelectionEntityListBean: fromMap is renamed to fromJson. +- BrnRadioButton: optimize click area [#31](https://github.com/LianjiaTech/bruno/pull/31) , thanks to **a1017480401** . +- BrnScrollableTextDialog: remove Navigator.pop(context) in onSubmit() and hand it over to external processing (user). +- BrnBubbleText: add attribute bgColor and textStyle + + + +### Fixed + +- Fix example error [#71](https://github.com/LianjiaTech/bruno/issues/71) thanks to **leftcoding** fixing this issue. +- Fix BrnPickerTitleConfig titleContent setting is invalid [#70](https://github.com/LianjiaTech/bruno/issues/70). +- Optimize BrnPopupWindow onItemClick logic [#57 ](https://github.com/LianjiaTech/bruno/issues/57) . +- Fix BrnDialog is obscured by keyboard [#7](https://github.com/LianjiaTech/bruno/issues/7) . + + + +Thanks again to **leftcoding**, **jojinshallar**, **laiiihz**, **donywan**, **kalifun**, **junlandroid**, **Kenneth**, **HappyImp**, **kkkman22** , **a1017480401** and **Alex**. + + + +## [2.0.0] - 2021-12-8 + +- Adapt flutter sdk 2.2.2 + +## [1.0.0] - 2021-12-7 + +- First publish adapt flutter sdk 1.22.4 + + diff --git a/assets/icons/icon_uparrow.png b/assets/icons/icon_uparrow.png deleted file mode 100644 index b1d4cbf3a9918c37fdba49da7c2e47f07a02a8a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 452 zcmeAS@N?(olHy`uVBq!ia0vp^x**KK1|+Sd9?b$$jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(=G?|Dm){R;N%5N({9_}y24<@x!?>=%|jbY*|R zAiIFMq=D}Oqm={uCYc$_Ubap8y6M5vZUr@|O**GbWsV=WIiD}G<)S#R0G~zTo%kDU ze`45o-A%Z^?d@I5?>E18%lj_yZ?K)AxkJi|`G!mkYb-+!mtLD6!*}VYb+wD5_lCGw zTeJ4`vhVu(#bGP^`wRQCI?U4zOZYa}Ychl}@5!i~!f-e#X3~uKlt1%$*Ltq&v~@b) zw9O-H;Y0NaE!%w3mX>nmPCa7Xa?8n>D_2qOP+RWWZBO+5{}vvYxMS|qf65}~G;j7< z^`2mMzj8n^(6p9=|L_MVM{A#~i|dy0Ka@I9cWLX_TDfa5KLR~G!Qum}fVx.MULTI_CHOICE_PORTRAIT_INPUT_TYPE | 外部可根据此字段判断表单项类型 | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.multiChoicePortraitInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发 onTip 回调。 | 否 | 备注中类型 3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为 null 时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.TYPE_NORMAL | 1. 不展示图标:BrnPrefixIconType.TYPE_NORMAL2. 展示加号图标:BrnPrefixIconType.TYPE_ADD3. 展示减号图标:BrnPrefixIconType.TYPE_REMOVE | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal2. 展示加号图标:BrnPrefixIconType.add3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示\*图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑 false:禁用 | @@ -137,7 +137,7 @@ BrnMultiChoiceInputFormItem( ```dart BrnMultiChoiceInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, error: "必填项不能为空", title: "自然到访保护期", diff --git a/docs/components/form/BrnMultiChoicePortraitInputFormItem/BrnMultiChoicePortraitInputFormItem.md b/docs/components/form/BrnMultiChoicePortraitInputFormItem/BrnMultiChoicePortraitInputFormItem.md index c19f9515..9bb04350 100644 --- a/docs/components/form/BrnMultiChoicePortraitInputFormItem/BrnMultiChoicePortraitInputFormItem.md +++ b/docs/components/form/BrnMultiChoicePortraitInputFormItem/BrnMultiChoicePortraitInputFormItem.md @@ -48,7 +48,7 @@ BrnMultiChoicePortraitInputFormItem( this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -73,11 +73,11 @@ this.themeData = BrnThemeConfigurator.instance | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.MULTI_CHOICE_PORTRAIT_INPUT_TYPE | 外部可根据此字段判断表单项类型 | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.multiChoicePortraitInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.TYPE\_NORMAL | 1. 不展示图标:BrnPrefixIconType.TYPE\_NORMAL 2. 展示加号图标:BrnPrefixIconType.TYPE\_ADD 3. 展示减号图标:BrnPrefixIconType.TYPE\_REMOVE | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | @@ -94,9 +94,9 @@ this.themeData = BrnThemeConfigurator.instance ###### BrnPrefixIconType: ```dart class BrnPrefixIconType { - static const String TYPE_NORMAL = "type_normal"; - static const String TYPE_ADD = "type_add"; - static const String TYPE_REMOVE = "type_remove"; + static const String normal = "type_normal"; + static const String add = "type_add"; + static const String remove = "type_remove"; } ``` ## 四、代码演示 @@ -138,7 +138,7 @@ BrnMultiChoicePortraitInputFormItem( ```dart BrnMultiChoicePortraitInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_REMOVE, + prefixIconType: BrnPrefixIconType.remove, isRequire: true, error: "必填项不能为空", title: "自然到访保护期", diff --git a/docs/components/form/BrnNormalFormGroup/BrnNormalFormGroup.md b/docs/components/form/BrnNormalFormGroup/BrnNormalFormGroup.md index afd9cc19..3a1d2905 100644 --- a/docs/components/form/BrnNormalFormGroup/BrnNormalFormGroup.md +++ b/docs/components/form/BrnNormalFormGroup/BrnNormalFormGroup.md @@ -60,7 +60,7 @@ BrnNormalFormGroup({ | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | String | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.NORMAL_GROUP_TYPE | 外部可用此字段判断表单类型 | +| type | String | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.normalGroupType | 外部可用此字段判断表单类型 | | title | String | 录入项标题 | 否 | 无 | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | null | 1. 若赋值为 空字符串("")时仅展示"问号"图标,2. 若赋值为非空字符串时 展示"问号图标&文案",3. 若不赋值或赋值为null时 不显示提示项 | diff --git a/docs/components/form/BrnRadioInputFormItem/BrnRadioInputFormItem.md b/docs/components/form/BrnRadioInputFormItem/BrnRadioInputFormItem.md index 83fb480e..c799bf46 100644 --- a/docs/components/form/BrnRadioInputFormItem/BrnRadioInputFormItem.md +++ b/docs/components/form/BrnRadioInputFormItem/BrnRadioInputFormItem.md @@ -51,7 +51,7 @@ BrnRadioInputFormItem( this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -78,11 +78,10 @@ BrnRadioInputFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.TYPE_NORMAL | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.TYPE_NORMAL | 1. 不展示图标:BrnPrefixIconType.TYPE_NORMAL 2. 展示加号图标:BrnPrefixIconType.TYPE_ADD3. 展示减号图标:BrnPrefixIconType.TYPE_REMOVE | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示*图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | @@ -103,10 +102,10 @@ BrnRadioInputFormItem( ```dart -class BrnPrefixIconType { - static const String TYPE_NORMAL = "type_normal"; - static const String TYPE_ADD = "type_add"; - static const String TYPE_REMOVE = "type_remove"; +class BrnPrefixIconType { + static const String normal = "type_normal"; + static const String add = "type_add"; + static const String remove = "type_remove"; } ``` ## 四、代码演示 @@ -142,7 +141,7 @@ BrnRadioInputFormItem( ![](./img/BrnRadioInputFormItemDemo2.png) ```dart BrnRadioInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, error: "必填项不能为空", title: "自然到访保护期", @@ -173,7 +172,7 @@ BrnRadioInputFormItem( ![](./img/BrnRadioInputFormItemDemo3.png) ```dart BrnRadioInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_REMOVE, + prefixIconType: BrnPrefixIconType.remove, isRequire: true, title: "自然到访保护期", subTitle: "这里是副标题", @@ -203,7 +202,7 @@ BrnRadioInputFormItem( ![](./img/BrnRadioInputFormItemDemo4.png) ```dart BrnRadioInputFormItem.autoLayout( - prefixIconType: BrnPrefixIconType.TYPE_REMOVE, + prefixIconType: BrnPrefixIconType.remove, isRequire: true, error: "必填项不能为空", title: "autoLayout", diff --git a/docs/components/form/BrnRadioPortraitInputFormItem/BrnRadioPortraitInputFormItem.md b/docs/components/form/BrnRadioPortraitInputFormItem/BrnRadioPortraitInputFormItem.md index b7f70a32..237dc555 100644 --- a/docs/components/form/BrnRadioPortraitInputFormItem/BrnRadioPortraitInputFormItem.md +++ b/docs/components/form/BrnRadioPortraitInputFormItem/BrnRadioPortraitInputFormItem.md @@ -46,7 +46,7 @@ BrnRadioPortraitInputFormItem( this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -73,11 +73,11 @@ BrnRadioPortraitInputFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | -------------- | -------------------------- | ------------------------------------------------------------------ | ------------ | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.RADIO_INPUT_TYPE | 外部可根据此字段判断表单项类型 | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.radioInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | 无 | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发 onTip 回调。 | 否 | 备注中类型 3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为 null 时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.TYPE_NORMAL | 1. 不展示图标:BrnPrefixIconType.TYPE_NORMAL2. 展示加号图标:BrnPrefixIconType.TYPE_ADD3. 展示减号图标:BrnPrefixIconType.TYPE_REMOVE | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal2. 展示加号图标:BrnPrefixIconType.add3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | 无 | | | isRequire | bool | 录入项是否为必填项(展示\*图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑 false:禁用 | @@ -96,9 +96,9 @@ BrnRadioPortraitInputFormItem( ```dart class BrnPrefixIconType { - static const String TYPE_NORMAL = "type_normal"; - static const String TYPE_ADD = "type_add"; - static const String TYPE_REMOVE = "type_remove"; + static const String normal = "type_normal"; + static const String add = "type_add"; + static const String remove = "type_remove"; } ``` @@ -138,7 +138,7 @@ BrnRadioPortraitInputFormItem( ```dart BrnRadioPortraitInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, error: "必填项不能为空", title: "自然到访保护期", diff --git a/docs/components/form/BrnRangeInputFormItem/BrnRangeInputFormItem.md b/docs/components/form/BrnRangeInputFormItem/BrnRangeInputFormItem.md index 65f5e8c0..19abd429 100644 --- a/docs/components/form/BrnRangeInputFormItem/BrnRangeInputFormItem.md +++ b/docs/components/form/BrnRangeInputFormItem/BrnRangeInputFormItem.md @@ -46,7 +46,7 @@ BrnRangeInputFormItem( this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -82,11 +82,10 @@ BrnRangeInputFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.TYPE_NORMAL | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.TYPE_NORMAL | 1. 不展示图标:BrnPrefixIconType.TYPE_NORMAL 2. 展示加号图标:BrnPrefixIconType.TYPE_ADD 3. 展示减号图标:BrnPrefixIconType.TYPE_REMOVE | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标),默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | @@ -114,25 +113,25 @@ BrnRangeInputFormItem( #### BrnPrefixIconType: ``` dart -class BrnPrefixIconType { - static const String TYPE_NORMAL = "type_normal"; - static const String TYPE_ADD = "type_add"; - static const String TYPE_REMOVE = "type_remove"; +class BrnPrefixIconType { + static const String normal = "type_normal"; + static const String add = "type_add"; + static const String remove = "type_remove"; } ``` #### BrnInputType ``` dart class BrnInputType { - static const String TEXT = "text"; - static const String MULTI_LINE = "multiline"; - static const String NUMBER = "number"; - static const String DECIMAL = "decimal"; - static const String PHONE = "phone"; - static const String DATE = "datetime"; - static const String EMAIL = "emailAddress"; - static const String URL = "url"; - static const String PWD = "visiblePassword"; + static const String text = "text"; + static const String multiLine = "multiline"; + static const String number = "number"; + static const String decimal = "decimal"; + static const String phone = "phone"; + static const String date = "datetime"; + static const String email = "emailAddress"; + static const String url = "url"; + static const String pwd = "visiblePassword"; } ``` ## 四、代码演示 @@ -178,7 +177,7 @@ BrnRangeInputFormItem( BrnRangeInputFormItem( minController: TextEditingController()..text = "10", maxController: TextEditingController()..text = "100", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, error: "必填项不能为空", title: "保护期", diff --git a/docs/components/form/BrnRatioInputFormItem/BrnRatioInputFormItem.md b/docs/components/form/BrnRatioInputFormItem/BrnRatioInputFormItem.md index c8e6d691..a6548d3f 100644 --- a/docs/components/form/BrnRatioInputFormItem/BrnRatioInputFormItem.md +++ b/docs/components/form/BrnRatioInputFormItem/BrnRatioInputFormItem.md @@ -44,7 +44,7 @@ BrnRatioInputFormItem( this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -72,11 +72,11 @@ BrnRatioInputFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.TEXT_INPUT_RATIO_TYPE | 外部可根据此字段判断表单项类型 | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.textInputRatioType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.TYPE_NORMAL | 1. 不展示图标:BrnPrefixIconType.TYPE_NORMAL 2. 展示加号图标:BrnPrefixIconType.TYPE_ADD 3. 展示减号图标:BrnPrefixIconType.TYPE_REMOVE | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑,false:禁用 | diff --git a/docs/components/form/BrnStarsFormItem/BrnStarsFormItem.md b/docs/components/form/BrnStarsFormItem/BrnStarsFormItem.md index b6a280fb..d98d3e3d 100644 --- a/docs/components/form/BrnStarsFormItem/BrnStarsFormItem.md +++ b/docs/components/form/BrnStarsFormItem/BrnStarsFormItem.md @@ -41,7 +41,7 @@ BrnStarsFormItem( this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -66,11 +66,11 @@ BrnStarsFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.STAR_INPUT_TYPE | 外部可根据此字段判断表单项类型 | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.starInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.TYPE\_NORMAL | 1. 不展示图标:BrnPrefixIconType.TYPE\_NORMAL 2. 展示加号图标:BrnPrefixIconType.TYPE\_ADD 3. 展示减号图标:BrnPrefixIconType.TYPE\_REMOVE | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | diff --git a/docs/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md b/docs/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md index f388bbd6..b97f5f2d 100644 --- a/docs/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md +++ b/docs/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md @@ -42,7 +42,7 @@ BrnStepInputFormItem( this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -69,11 +69,10 @@ BrnStepInputFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.TYPE_NORMAL | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.TYPE\_NORMAL | 1. 不展示图标:BrnPrefixIconType.TYPE\_NORMAL 2. 展示加号图标:BrnPrefixIconType.TYPE\_ADD 3. 展示减号图标:BrnPrefixIconType.TYPE\_REMOVE | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | diff --git a/docs/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md b/docs/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md index 5c764ac7..4c07ac49 100644 --- a/docs/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md +++ b/docs/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md @@ -43,11 +43,11 @@ group: BrnTextBlockInputFormItem( {Key key, this.label, - this.type: BrnInputItemType.TEXT_BLOCK_INPUT_TYPE, + this.type: BrnInputItemType.textBlockInputType, this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -77,11 +77,11 @@ BrnTextBlockInputFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.TEXT_BLOCK_INPUT_TYPE | 外部可根据此字段判断表单项类型 | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.textBlockInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.TYPE_NORMAL | 1. 不展示图标:BrnPrefixIconType.TYPE_NORMAL 2. 展示加号图标:BrnPrefixIconType.TYPE_ADD3. 展示减号图标:BrnPrefixIconType.TYPE_REMOVE | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | @@ -106,26 +106,26 @@ BrnTextBlockInputFormItem( ```dart -class BrnPrefixIconType { - static const String TYPE_NORMAL = "type_normal"; - static const String TYPE_ADD = "type_add"; - static const String TYPE_REMOVE = "type_remove"; +class BrnPrefixIconType { + static const String normal = "type_normal"; + static const String add = "type_add"; + static const String remove = "type_remove"; } ``` #### BrnInputType -```dart r +```dart class BrnInputType { - static const String TEXT = "text"; - static const String MULTI_LINE = "multiline"; - static const String NUMBER = "number"; - static const String DECIMAL = "decimal"; - static const String PHONE = "phone"; - static const String DATE = "datetime"; - static const String EMAIL = "emailAddress"; - static const String URL = "url"; - static const String PWD = "visiblePassword"; + static const String text = "text"; + static const String multiLine = "multiline"; + static const String number = "number"; + static const String decimal = "decimal"; + static const String phone = "phone"; + static const String date = "datetime"; + static const String email = "emailAddress"; + static const String url = "url"; + static const String pwd = "visiblePassword"; } ``` ## 四、代码演示 @@ -160,7 +160,7 @@ BrnTextBlockInputFormItem( ```dart BrnTextBlockInputFormItem( controller: TextEditingController()..text = "hello", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: true, error: "必填项不能为空", @@ -189,7 +189,7 @@ BrnTextBlockInputFormItem( ```dart BrnTextBlockInputFormItem( controller: TextEditingController()..text = "hello", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: true, title: "备注", @@ -217,7 +217,7 @@ BrnTextBlockInputFormItem( ```dart BrnTextBlockInputFormItem( controller: TextEditingController()..text = "hello", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: false, isPrefixIconEnabled: true, diff --git a/docs/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md b/docs/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md index ca77d8f8..284cc1ba 100644 --- a/docs/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md +++ b/docs/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md @@ -43,11 +43,11 @@ group: BrnTextInputFormItem({ Key key, this.label, - this.type: BrnInputItemType.TEXT_INPUT_TYPE, + this.type: BrnInputItemType.textInputType, this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -77,11 +77,11 @@ BrnTextInputFormItem({ | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.TEXT_INPUT_TYPE | 外部可根据此字段判断表单项类型 | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.textInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.TYPE_NORMAL | 1. 不展示图标:BrnPrefixIconType.TYPE\_NORMAL 2. 展示加号图标:BrnPrefixIconType.TYPE_ADD 3. 展示减号图标:BrnPrefixIconType.TYPE\_REMOVE | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | @@ -158,7 +158,7 @@ BrnTextInputFormItem( ```dart BrnTextInputFormItem( controller: TextEditingController()..text = "300", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: true, error: "必填项不能为空", @@ -188,7 +188,7 @@ BrnTextInputFormItem( ```dart BrnTextInputFormItem( controller: TextEditingController()..text = "300", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: true, title: "房屋总价", @@ -217,7 +217,7 @@ BrnTextInputFormItem( ```dart BrnTextInputFormItem( controller: TextEditingController()..text = "300", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: false, isPrefixIconEnabled: true, diff --git a/docs/components/form/BrnTextQuickSelectFormItem/BrnTextQuickSelectFormItem.md b/docs/components/form/BrnTextQuickSelectFormItem/BrnTextQuickSelectFormItem.md index cbc675e5..b174a09a 100644 --- a/docs/components/form/BrnTextQuickSelectFormItem/BrnTextQuickSelectFormItem.md +++ b/docs/components/form/BrnTextQuickSelectFormItem/BrnTextQuickSelectFormItem.md @@ -39,7 +39,7 @@ BrnTextQuickSelectFormItem( this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -69,14 +69,14 @@ BrnTextQuickSelectFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.TEXT_QUICK_SELECT_INPUT_TYPE | 外部可根据此字段判断表单项类型 | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.textQuickSelectInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 BrnPrefixIconType 类 | 否 | BrnPrefixIconType.TYPE\_NORMAL | 1. 不展示图标:BrnPrefixIconType.TYPE\_NORMAL2. 展示加号图标:BrnPrefixIconType.TYPE\_ADD3. 展示减号图标:BrnPrefixIconType.TYPE\_REMOVE | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 BrnPrefixIconType 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal2. 展示加号图标:BrnPrefixIconType.add3. 展示减号图标:BrnPrefixIconType.remove | | isBtnsScroll | bool | 快捷按钮是否可滑动 | 否 | 无 | true:可滚动false:不可滚动 | | btnsTxt | List | 按钮文案 | 否 | 无 | | | selectBtnList | List | 按钮是否默认选中 | 否 | 无 | true:选中false:未选中 | @@ -150,7 +150,7 @@ List options = ['选项1', '选项2', '选项3', '选项4']; List statusAllFunctionDemo = [false, false, false, false]; BrnTextQuickSelectFormItem( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, btnsTxt: options, selectBtnList: statusAllFunctionDemo, diff --git a/docs/components/form/BrnTextSelectFormItem/BrnTextSelectFormItem.md b/docs/components/form/BrnTextSelectFormItem/BrnTextSelectFormItem.md index bf41b71b..3cfee756 100644 --- a/docs/components/form/BrnTextSelectFormItem/BrnTextSelectFormItem.md +++ b/docs/components/form/BrnTextSelectFormItem/BrnTextSelectFormItem.md @@ -40,7 +40,7 @@ BrnTextSelectFormItem({ this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -68,7 +68,7 @@ BrnTextSelectFormItem({ | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.TEXT_SELECT_INPUT_TYPE | 外部可根据此字段判断表单项类型 | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.textSelectInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | @@ -92,10 +92,10 @@ BrnTextSelectFormItem({ #### BrnPrefixIconType: ```dart -class BrnPrefixIconType{ - static const String TYPE_NORMAL = "type_normal"; - static const String TYPE_ADD = "type_add"; - static const String TYPE_REMOVE = "type_remove"; +class BrnPrefixIconType { + static const String normal = "type_normal"; + static const String add = "type_add"; + static const String remove = "type_remove"; } ``` ## 四、代码演示 @@ -125,7 +125,7 @@ BrnTextSelectFormItem( ![](./img/BrnTextSelectFormItemDemo2.png) ```dart BrnTextSelectFormItem( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, error: "必填项不能为空", title: "证件类型", @@ -151,7 +151,7 @@ BrnTextSelectFormItem( ```dart BrnTextSelectFormItem( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, title: "证件类型", subTitle: "这里是副标题", @@ -176,7 +176,7 @@ BrnTextSelectFormItem( ```dart BrnTextSelectFormItem.autoLayout( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, error: "必填项不能为空", title: "证件类型", diff --git a/docs/components/form/BrnTitleFormItem/BrnTitleFormItem.md b/docs/components/form/BrnTitleFormItem/BrnTitleFormItem.md index ac2f6d85..68776bf8 100644 --- a/docs/components/form/BrnTitleFormItem/BrnTitleFormItem.md +++ b/docs/components/form/BrnTitleFormItem/BrnTitleFormItem.md @@ -32,7 +32,7 @@ BrnTitleFormItem( this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -53,11 +53,11 @@ BrnTitleFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.LABEL_TITLE | 外部可根据此字段判断表单项类型 | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.labelTitle | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.TYPE\_NORMAL | 1. 不展示图标:BrnPrefixIconType.TYPE\_NORMAL2. 展示加号图标:BrnPrefixIconType.TYPE\_ADD3. 展示减号图标:BrnPrefixIconType.TYPE\_REMOVE | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal2. 展示加号图标:BrnPrefixIconType.add3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标), 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑,false:禁用 | diff --git a/docs/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md b/docs/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md index fe8f77d6..810e1cd3 100644 --- a/docs/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md +++ b/docs/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md @@ -44,7 +44,7 @@ BrnTitleSelectInputFormItem( this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -76,11 +76,11 @@ BrnTitleSelectInputFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType
.TEXT_INPUT_TITLE_SELECT_TYPE | 外部可根据此字段判断表单项类型 | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.textInputTitleSelectType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | | subTitle | String | 录入项子标题 | 否 | 无 | | | tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.TYPE_NORMAL | 1. 不展示图标:BrnPrefixIconType.TYPE_NORMAL 2. 展示加号图标:BrnPrefixIconType.TYPE_ADD 3. 展示减号图标:BrnPrefixIconType.TYPE_REMOVE | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isPrefixIconEnabled | bool | 录入项不可编辑时(isEdit: false) "+"、"-"号是否可点击,true: 可点击回调false: 不可点击回调 | 否 | false | | @@ -104,9 +104,9 @@ BrnTitleSelectInputFormItem( ```dart class BrnPrefixIconType { - static const String TYPE_NORMAL = "type_normal"; - static const String TYPE_ADD = "type_add"; - static const String TYPE_REMOVE = "type_remove"; + static const String normal = "type_normal"; + static const String add = "type_add"; + static const String remove = "type_remove"; } ``` @@ -114,15 +114,15 @@ class BrnPrefixIconType { ```dart class BrnInputType { - static const String TEXT = "text"; - static const String MULTI_LINE = "multiline"; - static const String NUMBER = "number"; - static const String DECIMAL = "decimal"; - static const String PHONE = "phone"; - static const String DATE = "datetime"; - static const String EMAIL = "emailAddress"; - static const String URL = "url"; - static const String PWD = "visiblePassword"; + static const String text = "text"; + static const String multiLine = "multiline"; + static const String number = "number"; + static const String decimal = "decimal"; + static const String phone = "phone"; + static const String date = "datetime"; + static const String email = "emailAddress"; + static const String url = "url"; + static const String pwd = "visiblePassword"; } ``` @@ -174,7 +174,7 @@ _list.add('手机号'); _list.add('座机'); BrnTitleSelectInputFormItem( controller: TextEditingController()..text = "124", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: false, error: "必填项不能为空", diff --git a/docs/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md b/docs/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md index 23bba47b..0781a113 100644 --- a/docs/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md +++ b/docs/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md @@ -58,9 +58,9 @@ BrnMultiColumnPicker( ```dart enum PickerFilterType { - None, //未设置 - Radio, //单选项,对应 type 为 radio - Checkbox, //多选项,对应 type 为 checkbox + none, //未设置 + radio, //单选项,对应 type 为 radio + checkbox, //多选项,对应 type 为 checkbox } ``` diff --git a/docs/components/selection/BrnSelectionView/BrnSelectionView.md b/docs/components/selection/BrnSelectionView/BrnSelectionView.md index 3ce81f6d..8e84a036 100644 --- a/docs/components/selection/BrnSelectionView/BrnSelectionView.md +++ b/docs/components/selection/BrnSelectionView/BrnSelectionView.md @@ -107,40 +107,40 @@ BrnSelectionView( ```dart enum BrnSelectionFilterType { /// 未设置 - None, + none, /// 不限类型 - UnLimit, + unLimit, /// 单选列表、单选项 type 为 radio - Radio, + radio, /// 多选列表、多选项 type 为 checkbox - Checkbox, + checkbox, /// 一般的值范围自定义区间 type 为 range - Range, + range, /// 日期选择,普通筛选时使用 CalendarView 展示选择时间,更多情况下使用 DatePicker 选择时间 - Date, + date, /// 自定义选择日期区间, type 为 dateRange - DateRange, + dateRange, /// 自定义通过 Calendar 选择日期区间,type 为 dateRangeCalendar - DateRangeCalendar, + dateRangeCalendar, /// 标签筛选 type 为 customerTag - CustomHandle, + customHandle, /// 更多列表、多选项 无 type - More, + more, /// 去二级页面 - Layer, + layer, /// 去自定义二级页面 - CustomLayer, + customLayer, } ``` @@ -165,8 +165,8 @@ enum BrnSelectionFilterType { ```dart enum SelectionWindowType { - List, //列表类型筛选弹窗,使用列表展示。 - Range, //标签类型筛选弹窗,使用 Tag + Range 的方式展示 + list, //列表类型筛选弹窗,使用列表展示。 + range, //标签类型筛选弹窗,使用 Tag + Range 的方式展示 } ``` diff --git a/docs/sketch.md b/docs/sketch.md index 03d90a2f..81ef8b53 100644 --- a/docs/sketch.md +++ b/docs/sketch.md @@ -2,24 +2,24 @@ order: 4 --- -# Sketch 设计指南 +# Sketch 设计指引 阅读本章内容你将学到如何使用 Bruno 配套的 Sketch 文件快速设计页面,并通过定制化标注插件导出可识别组件的设计稿。 -在开始之前需要先从 Bruno 主页下载 [UI 资源文件](https://bruno.ke.com:3008/download/sketch),得到 Sketch 文件和定制标注插件。 +在开始之前需要先从 Bruno 主页下载 [UI 资源文件](https://bruno.ke.com/download/sketch),得到 Sketch 文件和定制标注插件。 ## 第一部分 安装插件&选取所需组件 - + ## 第二部分 关于组件的解绑与使用 - + ## 第三部分 配合 Sketch 插件导出设计稿 - + ## 第四部分 查看标注中引用的组件信息 - + diff --git a/example/ios/Podfile b/example/ios/Podfile index b30a428b..ff7ef5e8 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -10,81 +10,32 @@ project 'Runner', { 'Release' => :release, } -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches end - generated_key_values + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + target 'Runner' do use_frameworks! use_modular_headers! - - # Flutter Pod - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; - - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' - - # Plugin Pods - - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') - end + flutter_install_all_ios_pods(File.dirname(File.realpath(__FILE__))) end -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - post_install do |installer| installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end + flutter_additional_ios_build_settings(target) end end diff --git a/example/lib/main.dart b/example/lib/main.dart index 202b0652..dff77517 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,3 +1,5 @@ + + import 'package:example/sample/home/home.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/actionsheet/actionsheet_entry_page.dart b/example/lib/sample/components/actionsheet/actionsheet_entry_page.dart index c98f8c16..25b1c8c6 100644 --- a/example/lib/sample/components/actionsheet/actionsheet_entry_page.dart +++ b/example/lib/sample/components/actionsheet/actionsheet_entry_page.dart @@ -1,3 +1,5 @@ + + import 'dart:async'; import 'package:bruno/bruno.dart'; @@ -121,7 +123,7 @@ class _ActionSheetEntryPageState extends State { } void _showCommonStyle(BuildContext context) { - List actions = List(); + List actions = []; actions.add(BrnCommonActionSheetItem( '选项一(警示项)', desc: '辅助信息辅助信息辅助信息', @@ -156,7 +158,7 @@ class _ActionSheetEntryPageState extends State { } void _showCommonStylex(){ - List actions = List(); + List actions = []; // 构建标题+辅助信息的普通项 actions.add(BrnCommonActionSheetItem( '选项一(警示项)', @@ -191,7 +193,7 @@ class _ActionSheetEntryPageState extends State { } void _showCommonStyle1(BuildContext context) { - List actions = List(); + List actions = []; actions.add(BrnCommonActionSheetItem( '选项一(警示项)', actionStyle: BrnCommonActionSheetItemStyle.alert, @@ -224,7 +226,7 @@ class _ActionSheetEntryPageState extends State { } void _showCommonStyle2(BuildContext context) { - List actions = List(); + List actions = []; actions.add(BrnCommonActionSheetItem( '选项一: (010)1234567', actionStyle: BrnCommonActionSheetItemStyle.link, @@ -258,7 +260,7 @@ class _ActionSheetEntryPageState extends State { } void _showCommonCustomStyle(BuildContext context) { - List actions = List(); + List actions =[]; actions.add( BrnCommonActionSheetItem( '选项一: 自定义主标题样式', @@ -332,8 +334,8 @@ class _ActionSheetEntryPageState extends State { // 用于控制timer只加载一次 var started = false; // 计时器 - var periodTimer; - List actions = List(); + late Timer periodTimer; + List actions = []; actions.add(BrnCommonActionSheetItem( '倒计时:$countdown', actionStyle: BrnCommonActionSheetItemStyle.alert, @@ -367,7 +369,7 @@ class _ActionSheetEntryPageState extends State { actions[0].desc = '倒计时:$times'; }); } else if (countdown == 0) { - periodTimer.onCancel(); + periodTimer.cancel(); } }); } @@ -378,7 +380,7 @@ class _ActionSheetEntryPageState extends State { BrnCommonActionSheetItem actionEle, ) { // 点击后立即停止计时 - periodTimer.onCancel(); + periodTimer.cancel(); var title = actionEle.title; BrnToast.show("title: $title, index: $index", context); }, @@ -386,38 +388,38 @@ class _ActionSheetEntryPageState extends State { }); // then用来在pop折后停止timer,如果不需要在pop后进行操作,不需要使用then }).then((value) { - periodTimer.onCancel(); + periodTimer.cancel(); }); } void _showShareSevenStyle(BuildContext context) { - List firstRowList = List(); + List firstRowList = []; firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_WEIXIN, + BrnShareItemConstants.shareWeiXin, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_BROWSER, + BrnShareItemConstants.shareBrowser, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_COPY_LINK, + BrnShareItemConstants.shareCopyLink, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_FRIEND, + BrnShareItemConstants.shareFriend, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_LINK, + BrnShareItemConstants.shareLink, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_QQ, + BrnShareItemConstants.shareQQ, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_CUSTOM, + BrnShareItemConstants.shareCustom, customImage: BrunoTools.getAssetImage("images/icon_custom_share.png"), customTitle: "自定义", canClick: true, @@ -434,38 +436,38 @@ class _ActionSheetEntryPageState extends State { } void _showShareFourStyle(BuildContext context) { - List firstRowList = List(); - List secondRowList = List(); + List firstRowList = []; + List secondRowList = []; firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_QZONE, + BrnShareItemConstants.shareQZone, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_SAVE_IMAGE, + BrnShareItemConstants.shareSaveImage, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_SMS, + BrnShareItemConstants.shareSms, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_WEIBO, + BrnShareItemConstants.shareWeiBo, canClick: true, )); secondRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_QZONE, + BrnShareItemConstants.shareQZone, canClick: false, )); secondRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_SAVE_IMAGE, + BrnShareItemConstants.shareSaveImage, canClick: false, )); secondRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_SMS, + BrnShareItemConstants.shareSms, canClick: false, )); secondRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_WEIBO, + BrnShareItemConstants.shareWeiBo, canClick: false, )); BrnShareActionSheet actionSheet = new BrnShareActionSheet( @@ -488,18 +490,18 @@ class _ActionSheetEntryPageState extends State { } void _showShareThreeStyle(BuildContext context) { - List firstRowList = List(); - List secondRowList = List(); + List firstRowList = []; + List secondRowList =[]; firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_WEIXIN, + BrnShareItemConstants.shareWeiXin, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_FRIEND, + BrnShareItemConstants.shareFriend, canClick: true, )); secondRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_CUSTOM, + BrnShareItemConstants.shareCustom, customImage: BrunoTools.getAssetImage("images/icon_custom_share.png"), customTitle: "自定义", canClick: true, @@ -516,13 +518,13 @@ class _ActionSheetEntryPageState extends State { } void _showShareTwoStyle(BuildContext context) { - List firstRowList = List(); + List firstRowList = []; firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_WEIXIN, + BrnShareItemConstants.shareWeiXin, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_FRIEND, + BrnShareItemConstants.shareFriend, canClick: true, )); BrnShareActionSheet actionSheet = new BrnShareActionSheet( diff --git a/example/lib/sample/components/actionsheet/actionsheet_selected_list_custom_example.dart b/example/lib/sample/components/actionsheet/actionsheet_selected_list_custom_example.dart index d018de8a..283dc591 100644 --- a/example/lib/sample/components/actionsheet/actionsheet_selected_list_custom_example.dart +++ b/example/lib/sample/components/actionsheet/actionsheet_selected_list_custom_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -9,10 +11,10 @@ class SelectedListActionSheetCustomExamplePage extends StatefulWidget { class SelectedListActionSheetCustomExamplePageState extends State { - BrnSelectedListActionSheetController controller; + late BrnSelectedListActionSheetController controller; var _bottomActionKey = GlobalKey(); - List _data; + List? _data; @override void initState() { @@ -51,18 +53,18 @@ class SelectedListActionSheetCustomExamplePageState key: _bottomActionKey, mainButtonName: 'BrnBottomButtonPanel', mainButtonOnTap: () { - BrnToast.show('确定!sheet 的数据源长度 ${_data.length}', context); + BrnToast.show('确定!sheet 的数据源长度 ${_data!.length}', context); }, iconButtonList: [ BrnVerticalIconButton( - name: '已选(${_data.length})', + name: '已选(${_data!.length})', iconWidget: BrunoTools.getAssetImage( 'icons/grey_place_holder.png'), onTap: () { if (!controller.isHidden) { controller.dismiss(); } else { - if (_data == null || _data.length <= 0) { + if (_data == null || _data!.length <= 0) { BrnToast.show('数据为空,弹窗不展示', context); return; } @@ -70,12 +72,12 @@ class SelectedListActionSheetCustomExamplePageState context: context, isClearButtonHidden: false, isDeleteButtonHidden: true, - items: _data, + items: _data!, bottomOffset: 82, maxHeight: 400, controller: controller, title: '自定义行视图例子', - itemTitleBuilder: (int index, String entity) { + itemTitleBuilder: (int index, String? entity) { return Material( child: BrnStepInputFormItem( title: 'BrnStepInputFormItemWidget', @@ -100,7 +102,7 @@ class SelectedListActionSheetCustomExamplePageState cancel: '取消', confirm: '确定', onConfirm: () { setState(() {}); - _data.clear(); + _data!.clear(); }, onCancel: () {}); }) .showWithTargetKey( diff --git a/example/lib/sample/components/actionsheet/actionsheet_selected_list_example.dart b/example/lib/sample/components/actionsheet/actionsheet_selected_list_example.dart index e4d14f88..9dd1c195 100644 --- a/example/lib/sample/components/actionsheet/actionsheet_selected_list_example.dart +++ b/example/lib/sample/components/actionsheet/actionsheet_selected_list_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -8,21 +10,18 @@ class SelectedListActionSheetExamplePage extends StatefulWidget { class SelectedListActionSheetExamplePageState extends State { - BrnSelectedListActionSheetController controller; - List _data; + late BrnSelectedListActionSheetController controller; + List _data = [ + '1. 可以只指定要显示的文案,后边的 delete icon 是组件自带', + '2. delete icon 可以控制全部显示或者隐藏,但不支持某一行独立控制', + '3. 每一行的视图支持完全自定义', + '4. 如果要刷新列表,请调用 controller 调用 reloadData() 方法 ', + '5. 该例子中,点击最后一行的删除图表,可以更新当前行的文案' + ]; @override void initState() { - _data = [ - '1. 可以只指定要显示的文案,后边的 delete icon 是组件自带', - '2. delete icon 可以控制全部显示或者隐藏,但不支持某一行独立控制', - '3. 每一行的视图支持完全自定义', - '4. 如果要刷新列表,请调用 controller 调用 reloadData() 方法 ', - '5. 该例子中,点击最后一行的删除图表,可以更新当前行的文案' - ]; - controller = BrnSelectedListActionSheetController(); - super.initState(); } @@ -65,7 +64,7 @@ class SelectedListActionSheetExamplePageState if (!controller.isHidden) { controller.dismiss(); } else { - if (_data == null || _data.length <= 0) { + if ( _data.length <= 0) { BrnToast.show('数据为空,弹窗不展示', context); return; } @@ -90,7 +89,7 @@ class SelectedListActionSheetExamplePageState ), ), ), - itemTitleBuilder: (int index, String entity) { + itemTitleBuilder: (int index, String? entity) { return entity; }, onClear: () { diff --git a/example/lib/sample/components/appraise/appraise_example.dart b/example/lib/sample/components/appraise/appraise_example.dart index c092d228..8cb7791d 100644 --- a/example/lib/sample/components/appraise/appraise_example.dart +++ b/example/lib/sample/components/appraise/appraise_example.dart @@ -67,7 +67,7 @@ class _AppraiseExampleState extends State { BrnAppraise( title: "这里是标题文字", headerType: BrnAppraiseHeaderType.center, - type: BrnAppraiseType.Star, + type: BrnAppraiseType.star, tags: tags, inputHintText: '这里是文本输入的组件', iconDescriptions: [ @@ -80,6 +80,7 @@ class _AppraiseExampleState extends State { config: BrnAppraiseConfig( showConfirmButton: false, starAppraiseHint: '星星未选择时的文案', + inputDefaultText: '这是一段默认文字', inputTextChangeCallback: (input) { BrnToast.show('输入的内容为' + input, context); }, @@ -171,7 +172,7 @@ class _AppraiseExampleState extends State { }, ///必须传入5个字符串,没有的位置传'' - type: BrnAppraiseType.Emoji, + type: BrnAppraiseType.emoji, iconDescriptions: ['很差', '', '可以', '', '非常好'], config: BrnAppraiseConfig( indexes: [0, 2, 4], titleMaxLines: 3), @@ -205,7 +206,7 @@ class _AppraiseExampleState extends State { showToast(index, list, input, context); Navigator.pop(context); }, - type: BrnAppraiseType.Star, + type: BrnAppraiseType.star, iconDescriptions: ['很差', '不行', '可以', '好'], config: BrnAppraiseConfig( showTextInput: false, @@ -228,10 +229,10 @@ class _AppraiseExampleState extends State { void showToast(int index, List selectedTags, String input, BuildContext context) { String str = '选中的评价为$index'; - if (selectedTags?.isNotEmpty ?? false) { + if (selectedTags.isNotEmpty) { str = str + ',选中的标签为:' + selectedTags.toString(); } - if (input?.isNotEmpty ?? false) { + if (input.isNotEmpty) { str = str + ',输入的内容为:' + input; } BrnToast.show(str, context); diff --git a/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart b/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart index c63100a0..5cadf9f9 100644 --- a/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart +++ b/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -23,7 +25,7 @@ class BottomTabbarExampleState extends State with SingleTic int _selectedIndexTest3 = 0; /// 未读消息数量 - String badgeNo1; + String badgeNo1 = '100'; /// title数组 var titles = ['One', 'Two', 'Three', 'Four', 'Five', 'Six']; @@ -38,14 +40,6 @@ class BottomTabbarExampleState extends State with SingleTic Icons.star ]; - @override - void initState() { - super.initState(); - - /// 初始化某个未读消息的数量 - badgeNo1 = '100'; - } - /// 选中状态时state设置 void _onItemSelected(int index) { setState(() { diff --git a/example/lib/sample/components/button/common_collection_example.dart b/example/lib/sample/components/button/common_collection_example.dart index 249d6bd0..da249615 100644 --- a/example/lib/sample/components/button/common_collection_example.dart +++ b/example/lib/sample/components/button/common_collection_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -250,7 +252,7 @@ class BrnCommonBottomExample extends StatelessWidget { ], ), Text( - '异常案例:按钮文本长为0', + '异常案例:按钮文本长为空串', style: TextStyle( color: Color(0xFF222222), fontSize: 28, diff --git a/example/lib/sample/components/button/selection_collection_example.dart b/example/lib/sample/components/button/selection_collection_example.dart index 40bcbe64..42723669 100644 --- a/example/lib/sample/components/button/selection_collection_example.dart +++ b/example/lib/sample/components/button/selection_collection_example.dart @@ -7,13 +7,8 @@ class BrnSelectionBottomButtonExample extends StatefulWidget { } class _BrnSelectionBottomButtonExampleState extends State { - BrnMultipleBottomController controller; - @override - void initState() { - super.initState(); - controller = BrnMultipleBottomController(); - } + BrnMultipleBottomController controller = BrnMultipleBottomController(); @override Widget build(BuildContext context) { diff --git a/example/lib/sample/components/calendar/calendarview_example.dart b/example/lib/sample/components/calendar/calendarview_example.dart index 26e4178e..25e9f568 100644 --- a/example/lib/sample/components/calendar/calendarview_example.dart +++ b/example/lib/sample/components/calendar/calendarview_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -56,69 +58,66 @@ class TagViewExamplePageState extends State { } Widget _calendarViewWeekNocontroll(context) { - return BrnCalendarView( - displayMode: DisplayMode.Week, - selectMode: SelectMode.SINGLE, + return BrnCalendarView.single( + displayMode: DisplayMode.week, showControllerBar: false, - startEndDateChange: (startDate, endDate) { - BrnToast.show('开始时间: $startDate , 结束时间:$endDate', context); + dateChange: (date) { + BrnToast.show('选中的时间: $date', context); }, ); } Widget _calendarViewWeekNocontrollCustomWeekName(context) { - return BrnCalendarView( - displayMode: DisplayMode.Week, - selectMode: SelectMode.SINGLE, + return BrnCalendarView.single( + displayMode: DisplayMode.week, showControllerBar: false, weekNames: ['星期天', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'], - startEndDateChange: (startDate, endDate) { - BrnToast.show('开始时间: $startDate , 结束时间:$endDate', context); + dateChange: (date) { + BrnToast.show('选中的时间: $date', context); }, ); } Widget _calendarViewWeek(context) { - return BrnCalendarView( - displayMode: DisplayMode.Week, + return BrnCalendarView.single( + displayMode: DisplayMode.week, initDisplayDate: DateTime.parse('2020-06-01'), minDate: DateTime(2020), maxDate: DateTime(2021), - startEndDateChange: (startDate, endDate) { - BrnToast.show('开始时间: $startDate , 结束时间:$endDate', context); + dateChange: (date) { + BrnToast.show('选中的时间: $date', context); }, ); } Widget _calendarViewWeekRange(context) { - return BrnCalendarView( - displayMode: DisplayMode.Week, - selectMode: SelectMode.RANGE, - startEndDateChange: (startDate, endDate) { - BrnToast.show('开始时间: $startDate , 结束时间:$endDate', context); + return BrnCalendarView.range( + displayMode: DisplayMode.week, + rangeDateChange: (rangeDate) { + BrnToast.show( + '开始时间: ${rangeDate.start} , 结束时间:${rangeDate.end}', context); }, ); } Widget _calendarViewMonth(context) { - return BrnCalendarView( - selectMode: SelectMode.SINGLE, + return BrnCalendarView.single( initDisplayDate: DateTime.parse('2020-06-01'), minDate: DateTime(2020), maxDate: DateTime(2021), - startEndDateChange: (startDate, endDate) { - BrnToast.show('开始时间: $startDate , 结束时间:$endDate', context); + dateChange: (date) { + BrnToast.show('选中的时间: $date', context); }, ); } Widget _calendarViewMonthRange(context) { - return BrnCalendarView( - selectMode: SelectMode.RANGE, + return BrnCalendarView.range( minDate: DateTime(2020), maxDate: DateTime(2023), - startEndDateChange: (startDate, endDate) { - BrnToast.show('开始时间: $startDate , 结束时间:$endDate', context); + rangeDateChange: (rangeDate) { + BrnToast.show( + '开始时间: ${rangeDate.start} , 结束时间:${rangeDate.end}', context); }, ); } diff --git a/example/lib/sample/components/card/brn_shadow_example.dart b/example/lib/sample/components/card/brn_shadow_example.dart index 679166c7..8579a95a 100644 --- a/example/lib/sample/components/card/brn_shadow_example.dart +++ b/example/lib/sample/components/card/brn_shadow_example.dart @@ -1,3 +1,5 @@ + + import 'dart:math'; import 'package:bruno/bruno.dart'; @@ -9,14 +11,6 @@ class BrnShadowExample extends StatefulWidget { } class _BrnShadowExampleState extends State { - int count; - - @override - void initState() { - super.initState(); - count = 0; - } - @override Widget build(BuildContext context) { return Scaffold( diff --git a/example/lib/sample/components/card/bubble/brn_expanded_bubble_example.dart b/example/lib/sample/components/card/bubble/brn_expanded_bubble_example.dart index 1c8754c0..46b50a47 100644 --- a/example/lib/sample/components/card/bubble/brn_expanded_bubble_example.dart +++ b/example/lib/sample/components/card/bubble/brn_expanded_bubble_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -38,7 +40,7 @@ class BrnBubbleExample2 extends StatelessWidget { maxLines: 2, text: '推荐理由:“满五唯一”“临近地铁”“首付低”,多出折行显示,文字展开的样式文式文文字展开的样式文式文。问我', onExpanded: (isExpanded){ - String str = isExpanded?"展开了":"收起了"; + String str = isExpanded ? "展开了" : "收起了"; BrnToast.show("我$str", context); }, ), diff --git a/example/lib/sample/components/card/bubble/bubble_entry_page.dart b/example/lib/sample/components/card/bubble/bubble_entry_page.dart index 550304cc..66346dcd 100644 --- a/example/lib/sample/components/card/bubble/bubble_entry_page.dart +++ b/example/lib/sample/components/card/bubble/bubble_entry_page.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/components/card/bubble/common_bubble_example.dart'; import 'package:example/sample/components/card/bubble/brn_expanded_bubble_example.dart'; diff --git a/example/lib/sample/components/card/bubble/common_bubble_example.dart b/example/lib/sample/components/card/bubble/common_bubble_example.dart index 86532787..0468c77a 100644 --- a/example/lib/sample/components/card/bubble/common_bubble_example.dart +++ b/example/lib/sample/components/card/bubble/common_bubble_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/card/content/brn_two_rich_content_example.dart b/example/lib/sample/components/card/content/brn_two_rich_content_example.dart index fc9c112d..36f082ef 100644 --- a/example/lib/sample/components/card/content/brn_two_rich_content_example.dart +++ b/example/lib/sample/components/card/content/brn_two_rich_content_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/card/content/brn_two_text_content_example.dart b/example/lib/sample/components/card/content/brn_two_text_content_example.dart index 3f011d6e..19ecbdff 100644 --- a/example/lib/sample/components/card/content/brn_two_text_content_example.dart +++ b/example/lib/sample/components/card/content/brn_two_text_content_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/card/content/keyvalue_align_content_example.dart b/example/lib/sample/components/card/content/keyvalue_align_content_example.dart index 57527374..d959c039 100644 --- a/example/lib/sample/components/card/content/keyvalue_align_content_example.dart +++ b/example/lib/sample/components/card/content/keyvalue_align_content_example.dart @@ -1,3 +1,5 @@ + + import 'dart:math'; import 'package:bruno/bruno.dart'; @@ -9,7 +11,7 @@ class TextContentExample extends StatefulWidget { } class _TextContentExampleState extends State { - List list; + late List list; @override void initState() { @@ -23,7 +25,7 @@ class _TextContentExampleState extends State { BrnInfoModal(keyPart: "名称名称名:", valuePart: "内容内容内容内容内容"), BrnInfoModal(keyPart: "名称名称名称名称:", valuePart: "内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容"), BrnInfoModal.valueLastClickInfo("名称名:", '内容内容内容内容内容', '可点击内容', clickCallback: (text) { - BrnToast.show(text, context); + BrnToast.show(text!, context); }) ]; } @@ -231,7 +233,7 @@ class _TextContentExampleState extends State { keyPart: "名称名称名称名称:", valuePart: "内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容"), BrnInfoModal.valueLastClickInfo("名称名:", '11111111', '22222222', clickCallback: (text) { - BrnToast.show(text, context); + BrnToast.show(text!, context); }), ], ), @@ -257,7 +259,7 @@ class _TextContentExampleState extends State { keyPart: "名称名称名称名称:", valuePart: "内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容"), BrnInfoModal.valueLastClickInfo("名称名:", '内容内容内容内容内容', '可点击内容', clickCallback: (text) { - BrnToast.show(text, context); + BrnToast.show(text!, context); }), ], ), @@ -301,7 +303,7 @@ class _TextContentExampleState extends State { ), Transform.rotate( angle: pi, - child: BrunoTools.getAssetImage('icons/icon_uparrow.png')), + child: BrunoTools.getAssetImage('icons/icon_up_arrow.png')), ], ), decoration: BoxDecoration( @@ -381,7 +383,7 @@ class _TextContentExampleState extends State { BrnInfoModal(keyPart: "名称名称名:", valuePart: "内容内容内容内容内容"), BrnInfoModal.valueLastClickInfo("名称十分的长名称十分的长名称十分的长名称十分的长:", '内容内容内容内容内容', '可点击内容', clickCallback: (text) { - BrnToast.show(text, context); + BrnToast.show(text!, context); }), ], ), @@ -401,7 +403,7 @@ class _TextContentExampleState extends State { BrnInfoModal.valueLastClickInfo( "名称十分的长名称十分的长名称十分的长名称十分的长:", '内容内容内容内容内容', '可点击内容可点击内容可点击内容可点击内容可点击内容可点击内容', clickCallback: (text) { - BrnToast.show(text, context); + BrnToast.show(text!, context); }), ], ), diff --git a/example/lib/sample/components/card/content/keyvalue_close_content_example.dart b/example/lib/sample/components/card/content/keyvalue_close_content_example.dart index acf2022c..2d6d8053 100644 --- a/example/lib/sample/components/card/content/keyvalue_close_content_example.dart +++ b/example/lib/sample/components/card/content/keyvalue_close_content_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -62,7 +64,7 @@ class _KeyTextCloseContentExampleState extends State BrnInfoModal(keyPart: "名称名称名:", valuePart: "内容内容内容内容内容"), BrnInfoModal.valueLastClickInfo("名称名:", '内容内容内容内容内容', '可点击内容', clickCallback: (text) { - BrnToast.show(text, context); + BrnToast.show(text!, context); }), ], ), @@ -132,12 +134,12 @@ class _KeyTextCloseContentExampleState extends State "内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内"), BrnInfoModal.valueLastClickInfo("名称十分的长名:", '内容内容内容内容内容', '可点击内容可点击内容可点击内容可点击内容', clickCallback: (text) { - BrnToast.show(text, context); + BrnToast.show(text!, context); }), BrnInfoModal.valueLastClickInfo( "名称十分的长名:", '内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容', '可点击内容可点击内容可点击内容可点击内容', clickCallback: (text) { - BrnToast.show(text, context); + BrnToast.show(text!, context); }), ], ), diff --git a/example/lib/sample/components/card/content/number_item_example.dart b/example/lib/sample/components/card/content/number_item_example.dart index 552ee602..f1a4df94 100644 --- a/example/lib/sample/components/card/content/number_item_example.dart +++ b/example/lib/sample/components/card/content/number_item_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -60,7 +62,7 @@ class _NumberItemRowExampleState extends State { number: '3', preDesc: '前', lastDesc: '后', - numberInfoIcon: BrnNumberInfoIcon.ARROW, + numberInfoIcon: BrnNumberInfoIcon.arrow, iconTapCallBack: (data) {}), ], ), @@ -79,9 +81,9 @@ class _NumberItemRowExampleState extends State { number: '3', preDesc: '前', lastDesc: '后', - numberInfoIcon: BrnNumberInfoIcon.ARROW, + numberInfoIcon: BrnNumberInfoIcon.arrow, iconTapCallBack: (data) { - BrnToast.show(data.title, context); + BrnToast.show(data.title!, context); }), BrnNumberInfoItemModel( title: '数字信息数字信息数字信息数字信息数字信息数字信息', diff --git a/example/lib/sample/components/card/content/text_content_entry_page.dart b/example/lib/sample/components/card/content/text_content_entry_page.dart index 2a3dfe12..e16e0aec 100644 --- a/example/lib/sample/components/card/content/text_content_entry_page.dart +++ b/example/lib/sample/components/card/content/text_content_entry_page.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/components/card/content/keyvalue_align_content_example.dart'; import 'package:example/sample/components/card/content/keyvalue_close_content_example.dart'; diff --git a/example/lib/sample/components/card/content/text_value_arrow_example.dart b/example/lib/sample/components/card/content/text_value_arrow_example.dart index 56d52af9..e902465a 100644 --- a/example/lib/sample/components/card/content/text_value_arrow_example.dart +++ b/example/lib/sample/components/card/content/text_value_arrow_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -66,7 +68,7 @@ class _TextValueArrowContentExampleState extends State { children: [ Text( '规则', - style: TextStyle(color: Color(0xFF222222), fontSize: 28, fontWeight: FontWeight.bold), + style: TextStyle( + color: Color(0xFF222222), + fontSize: 28, + fontWeight: FontWeight.bold), ), BrnBubbleText( maxLines: 4, diff --git a/example/lib/sample/components/card_title/title_example.dart b/example/lib/sample/components/card_title/title_example.dart index 66b73224..084cce7a 100644 --- a/example/lib/sample/components/card_title/title_example.dart +++ b/example/lib/sample/components/card_title/title_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/components/card_title/brn_action_title_example.dart'; import 'package:example/sample/components/card_title/brn_common_title_example.dart'; diff --git a/example/lib/sample/components/charts/chart_entry_example.dart b/example/lib/sample/components/charts/chart_entry_example.dart index d66f5f19..64dd6ea0 100644 --- a/example/lib/sample/components/charts/chart_entry_example.dart +++ b/example/lib/sample/components/charts/chart_entry_example.dart @@ -1,3 +1,5 @@ + + import 'dart:math'; import 'package:bruno/bruno.dart'; @@ -18,21 +20,21 @@ class FunnelChartExamplePage extends StatelessWidget { } class FunnelChartExample extends StatefulWidget { - FunnelChartExample({Key key}) : super(key: key); + FunnelChartExample({Key? key}) : super(key: key); @override _FunnelChartExampleState createState() => _FunnelChartExampleState(); } class _FunnelChartExampleState extends State { - double maxLayerWidth; - double minLayerWidth; - double layerMargin; - double layerHeight; - double offsetX; - double offsetY; - MarkerAlignment alignment; - FunnelShape shape; + late double maxLayerWidth; + late double minLayerWidth; + late double layerMargin; + late double layerHeight; + late double offsetX; + late double offsetY; + late MarkerAlignment alignment; + FunnelShape? shape; bool defaultStyle = false; @override @@ -53,7 +55,7 @@ class _FunnelChartExampleState extends State { child: Column( children: [ BrnFunnelChart( - shape: FunnelShape.LeftOrRight, + shape: FunnelShape.leftOrRight, alignment: MarkerAlignment.right, maxLayerWidth: maxLayerWidth, minLayerWidth: minLayerWidth, @@ -82,7 +84,7 @@ class _FunnelChartExampleState extends State { height: 10, ), BrnFunnelChart( - shape: FunnelShape.LeftAndRight, + shape: FunnelShape.leftAndRight, alignment: alignment, maxLayerWidth: maxLayerWidth, minLayerWidth: minLayerWidth, @@ -359,7 +361,7 @@ class _FunnelChartExampleState extends State { padding: EdgeInsets.only(left: 20), child: Text('标签位置'), ), - FlatButton( + TextButton( onPressed: () { setState(() { alignment = MarkerAlignment.left; @@ -367,7 +369,7 @@ class _FunnelChartExampleState extends State { }, child: Text('居左'), ), - FlatButton( + TextButton( onPressed: () { setState(() { alignment = MarkerAlignment.center; @@ -375,7 +377,7 @@ class _FunnelChartExampleState extends State { }, child: Text('居中'), ), - FlatButton( + TextButton( onPressed: () { setState(() { alignment = MarkerAlignment.right; @@ -413,16 +415,16 @@ class RadarChartExample extends StatefulWidget { } class _RadarChartExampleState extends State with SingleTickerProviderStateMixin { - double radius; - int sideCount; - double angle; - double padding; + late double radius; + int? sideCount; + double? angle; + late double padding; Map> dataList1 = Map(); Map> dataList2 = Map(); - AnimationController controller; - Animation animation; + late AnimationController controller; + late Animation animation; bool defaultStyle = false; @override @@ -433,8 +435,8 @@ class _RadarChartExampleState extends State with SingleTicker padding = 4; angle = 0; for (int i = 3; i <= 8; i++) { - List data1 = List(); - List data2 = List(); + List data1 = []; + List data2 = []; for (int j = 0; j < i; j++) { data1.add(Random().nextDouble() * 10); @@ -461,18 +463,18 @@ class _RadarChartExampleState extends State with SingleTicker radius: radius, sidesCount: 5, markerMargin: padding, - rotateAngle: angle * 2 * pi / 360, - data: [dataList1[sideCount.toString()], dataList2[sideCount.toString()]], + rotateAngle: angle! * 2 * pi / 360, + data: [dataList1[sideCount.toString()]!, dataList2[sideCount.toString()]!], tagNames: ['合作共赢诚实守信', '合作共赢诚实守信', '合作共赢诚实守信', '合作共赢诚实守信', '合作共赢诚实守信'], ); } else { return BrnRadarChart( radius: radius, provider: RadarProvider(sideCount, dataList1, dataList2), - sidesCount: sideCount, + sidesCount: sideCount!, markerMargin: padding, crossedAxisLine: true, - rotateAngle: angle * 2 * pi / 360, + rotateAngle: angle! * 2 * pi / 360, animateProgress: animation.value, builder: (index) { return Text( @@ -560,7 +562,7 @@ class _RadarChartExampleState extends State with SingleTicker ), Expanded( child: Slider( - value: sideCount.toDouble(), + value: sideCount!.toDouble(), divisions: 6, onChanged: (data) { if (data.toInt() != sideCount) { @@ -577,9 +579,9 @@ class _RadarChartExampleState extends State with SingleTicker onChangeEnd: (data) { debugPrint('end:$data'); }, - min: defaultStyle ? sideCount.toDouble() : 3, - max: defaultStyle ? sideCount.toDouble() : 8, - label: '${sideCount.toStringAsFixed(0)}', + min: defaultStyle ? sideCount!.toDouble() : 3, + max: defaultStyle ? sideCount!.toDouble() : 8, + label: '${sideCount!.toStringAsFixed(0)}', activeColor: Colors.green, inactiveColor: Colors.grey, semanticFormatterCallback: (double newValue) { @@ -597,7 +599,7 @@ class _RadarChartExampleState extends State with SingleTicker ), Expanded( child: Slider( - value: angle.toDouble(), + value: angle!.toDouble(), divisions: 360, onChanged: (data) { if (data.toDouble() != angle) { @@ -616,7 +618,7 @@ class _RadarChartExampleState extends State with SingleTicker }, min: 0, max: 360, - label: '${angle.toStringAsFixed(0)}', + label: '${angle!.toStringAsFixed(0)}', activeColor: Colors.green, inactiveColor: Colors.grey, semanticFormatterCallback: (double newValue) { @@ -645,7 +647,7 @@ class RadarProvider extends BrnRadarChartDataProvider { final Map> dataList2; - final int sideCount; + final int? sideCount; RadarProvider(this.sideCount, this.dataList1, this.dataList2); @@ -686,10 +688,10 @@ class RadarProvider extends BrnRadarChartDataProvider { List getRadarValues(int radarIndex) { switch (radarIndex) { case 0: - return dataList1[sideCount.toString()]; + return dataList1[sideCount.toString()]!; case 1: - return dataList2[sideCount.toString()]; + return dataList2[sideCount.toString()]!; } - return dataList1[sideCount.toString()]; + return dataList1[sideCount.toString()]!; } } diff --git a/example/lib/sample/components/charts/doughnut_chart_example.dart b/example/lib/sample/components/charts/doughnut_chart_example.dart index 49d6c6dd..b653326a 100644 --- a/example/lib/sample/components/charts/doughnut_chart_example.dart +++ b/example/lib/sample/components/charts/doughnut_chart_example.dart @@ -1,3 +1,5 @@ + + import 'dart:math'; import 'package:bruno/bruno.dart'; @@ -11,9 +13,9 @@ class DoughnutChartExample extends StatefulWidget { } class DoughnutChartExampleState extends State { - BrnDoughnutDataItem selectedItem; + BrnDoughnutDataItem? selectedItem; - List dataList = List(); + List dataList = []; List preinstallColors = [ Color(0xffFF862D), Color(0xff26BB7D), @@ -55,7 +57,7 @@ class DoughnutChartExampleState extends State { data: dataList, selectedItem: selectedItem, showTitleWhenSelected: true, - selectCallback: (BrnDoughnutDataItem selectedItem) { + selectCallback: (BrnDoughnutDataItem? selectedItem) { setState(() { this.selectedItem = selectedItem; }); diff --git a/example/lib/sample/components/charts/line/brn_broken_line_example.dart b/example/lib/sample/components/charts/line/brn_broken_line_example.dart index fe4b71b2..46cce542 100644 --- a/example/lib/sample/components/charts/line/brn_broken_line_example.dart +++ b/example/lib/sample/components/charts/line/brn_broken_line_example.dart @@ -1,3 +1,5 @@ + + import 'dart:math'; import 'package:bruno/bruno.dart'; @@ -98,7 +100,7 @@ class _BrokenLineExampleState extends State { .map((_) => BrnPointData( pointText: _.value, x: brokenData.indexOf(_).toDouble(), - y: double.parse(_.value), + y: double.parse(_.value!), lineTouchData: BrnLineTouchData( tipWindowSize: Size(60, 40), @@ -129,17 +131,17 @@ class _BrokenLineExampleState extends State { } double _getMinValueForExample1(List brokenData) { - double minValue = double.tryParse(brokenData[0]?.value) ?? 0; + double minValue = double.tryParse(brokenData[0].value!) ?? 0; for (DBDataNodeModel point in brokenData) { - minValue = min(double.tryParse(point.value) ?? 0, minValue); + minValue = min(double.tryParse(point.value!) ?? 0, minValue); } return minValue; } double _getMaxValueForExample1(List brokenData) { - double maxValue = double.tryParse(brokenData[0]?.value) ?? 0; + double maxValue = double.tryParse(brokenData[0].value!) ?? 0; for (DBDataNodeModel point in brokenData) { - maxValue = max(double.tryParse(point.value) ?? 0, maxValue); + maxValue = max(double.tryParse(point.value!) ?? 0, maxValue); } return maxValue; } @@ -190,7 +192,7 @@ class _BrokenLineExampleState extends State { List _linesForExample2() { BrnPointsLine _pointsLine; BrnPointsLine _pointsLine1; - List pointsLineList = List(); + List pointsLineList = []; _pointsLine = BrnPointsLine( isShowPointText: true, isShowXDial: true, @@ -420,7 +422,7 @@ class _BrokenLineExampleState extends State { List _getPointsLinesForExample3() { BrnPointsLine pointsLine, _pointsLine2; - List pointsLineList = List(); + List pointsLineList = []; pointsLine = BrnPointsLine( isShowXDial: true, lineWidth: 3, @@ -486,13 +488,13 @@ class _BrokenLineExampleState extends State { ], ), ); - })), + }, tipWindowSize:Size(60, 40) )), BrnPointData( pointText: '20', y: 20, x: 3, lineTouchData: BrnLineTouchData( - + tipWindowSize: Size(60, 40), onTouch: () { return '20'; })), @@ -501,7 +503,7 @@ class _BrokenLineExampleState extends State { y: 67, x: 4, lineTouchData: BrnLineTouchData( - + tipWindowSize:Size(60, 40), onTouch: () { return '66'; })), @@ -661,7 +663,7 @@ class _BrokenLineExampleState extends State { y: 66, x: 8, lineTouchData: BrnLineTouchData( - + tipWindowSize: Size(60, 40), onTouch: () { return '66'; })), @@ -790,7 +792,7 @@ class _BrokenLineExampleState extends State { List _getPointsLinesForExample4() { BrnPointsLine pointsLine, _pointsLine2; - List pointsLineList = List(); + List pointsLineList = []; pointsLine = BrnPointsLine( isShowXDial: true, lineWidth: 3, @@ -834,7 +836,7 @@ class _BrokenLineExampleState extends State { y: 80, x: 2, lineTouchData: BrnLineTouchData( - + tipWindowSize: Size(60, 40), onTouch: () { return Container( padding: EdgeInsets.only(left: 10, right: 10, top: 8, bottom: 8), @@ -862,7 +864,7 @@ class _BrokenLineExampleState extends State { y: 20, x: 3, lineTouchData: BrnLineTouchData( - + tipWindowSize: Size(60, 40), onTouch: () { return '20'; })), @@ -871,7 +873,7 @@ class _BrokenLineExampleState extends State { y: 67, x: 4, lineTouchData: BrnLineTouchData( - + tipWindowSize: Size(60, 40), onTouch: () { return '66'; })), @@ -1031,7 +1033,7 @@ class _BrokenLineExampleState extends State { y: 66, x: 8, lineTouchData: BrnLineTouchData( - + tipWindowSize: Size(60, 40), onTouch: () { return '66'; })), @@ -1193,7 +1195,7 @@ class _BrokenLineExampleState extends State { List _getPointsLineListWithShowPointText() { BrnPointsLine pointsLine, _pointsLine2; - List pointsLineList = List(); + List pointsLineList = []; pointsLine = BrnPointsLine( isShowXDial: true, lineWidth: 3, @@ -1247,7 +1249,7 @@ class _BrokenLineExampleState extends State { y: 80, x: 2, lineTouchData: BrnLineTouchData( - + tipWindowSize: Size(60, 40), onTouch: () { return Container( padding: EdgeInsets.only(left: 10, right: 10, top: 8, bottom: 8), @@ -1285,7 +1287,7 @@ class _BrokenLineExampleState extends State { y: 67, x: 4, lineTouchData: BrnLineTouchData( - + tipWindowSize: Size(60, 40), onTouch: () { return '66'; })), @@ -1490,7 +1492,7 @@ class _BrokenLineExampleState extends State { } Widget _buildIdentificationList() { - List widgetList = List(); + List widgetList = []; for (BrnPointsLine bean in _getPointsLinesForExample3()) { Widget widget = Row(children: [ Container( diff --git a/example/lib/sample/components/charts/line/db_data_node_model.dart b/example/lib/sample/components/charts/line/db_data_node_model.dart index 7e0464e4..fc5928b8 100644 --- a/example/lib/sample/components/charts/line/db_data_node_model.dart +++ b/example/lib/sample/components/charts/line/db_data_node_model.dart @@ -1,34 +1,35 @@ /// @desc 看板卡片中用于描述数据指标的模型,也能用于数据块的定义,内部嵌套了一个itemList + + class DBDataNodeModel { - String key; - String name; - String value; - String unit; - String percent; - String order; + String? key; + String? name; + String? value; + String? unit; + String? percent; + String? order; /// If tip.isNullOrEmpty == false, a question icon will be displayed on right of the label. /// A tip pop window would be displayed when icon was clicked. - String tipTitle; + String? tipTitle; - List tipList; + List? tipList; /// 1: up direction, green label, green arrow /// 0: gray label, no arrow /// -1: down direction, red label, red arrow - int trend; + int? trend; - List itemList; + List? itemList; /// section data field - String url; - DBDataNodeModel total; - + String? url; + DBDataNodeModel? total; DBDataNodeModel(); - factory DBDataNodeModel.fromJson(Map json) { - if (json == null) return null; + factory DBDataNodeModel.fromJson(Map? json) { + if (json == null) return DBDataNodeModel(); DBDataNodeModel entity = DBDataNodeModel(); entity.name = json['name'] ?? ""; entity.key = json['key'] ?? ""; diff --git a/example/lib/sample/components/charts/progress_bar_chart_example.dart b/example/lib/sample/components/charts/progress_bar_chart_example.dart index 0b6c98c4..b0563676 100644 --- a/example/lib/sample/components/charts/progress_bar_chart_example.dart +++ b/example/lib/sample/components/charts/progress_bar_chart_example.dart @@ -1,3 +1,5 @@ + + import 'dart:math'; import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/charts/progress_chart_entry_page.dart b/example/lib/sample/components/charts/progress_chart_entry_page.dart index bb0b34c9..6d71c9dc 100644 --- a/example/lib/sample/components/charts/progress_chart_entry_page.dart +++ b/example/lib/sample/components/charts/progress_chart_entry_page.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/dialog/dialog_entry_page.dart b/example/lib/sample/components/dialog/dialog_entry_page.dart index ff961be6..f53999bf 100644 --- a/example/lib/sample/components/dialog/dialog_entry_page.dart +++ b/example/lib/sample/components/dialog/dialog_entry_page.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/home/list_item.dart'; import 'package:flutter/material.dart'; @@ -299,7 +301,7 @@ class DialogEntryPage extends StatelessWidget { //光标圆角弧度 cursorRadius: Radius.circular(2.0), style: TextStyle(fontSize: 14, color: Color(0xFF222222)), - maxLengthEnforced: true, + maxLengthEnforcement: MaxLengthEnforcement.enforced, onChanged: (value) {}, decoration: InputDecoration( contentPadding: EdgeInsets.all(8.0), @@ -326,7 +328,7 @@ class DialogEntryPage extends StatelessWidget { state(() {}); }, onSubmitClick: (data) { - BrnToast.show(data, context); + BrnToast.show(data!, context); }); }, )); @@ -334,7 +336,7 @@ class DialogEntryPage extends StatelessWidget { ///多选弹框 void _showMiddleMultiSelectDialog(BuildContext context) { - List data = new List(); + List data = []; data.add(new MultiSelectItem("100", "感兴趣待跟进")); data.add(new MultiSelectItem("101", "感兴趣但对本商圈没兴趣", isChecked: true)); data.add(new MultiSelectItem("102", "接通后挂断/不感兴趣", isChecked: true)); @@ -361,7 +363,7 @@ class DialogEntryPage extends StatelessWidget { void _showMiddleMultiSelectWithMessageWidgetDialog(BuildContext context) { String hintText = "感兴趣待跟进"; - List data = new List(); + List data = []; data.add(new MultiSelectItem("100", "感兴趣待跟进")); data.add(new MultiSelectItem("101", "感兴趣但对本商圈没兴趣", isChecked: true)); data.add(new MultiSelectItem("102", "接通后挂断/不感兴趣", isChecked: true)); @@ -392,7 +394,7 @@ class DialogEntryPage extends StatelessWidget { //光标圆角弧度 cursorRadius: Radius.circular(2.0), style: TextStyle(fontSize: 14, color: Color(0xFF222222)), - maxLengthEnforced: true, + maxLengthEnforcement: MaxLengthEnforcement.enforced, onChanged: (value) {}, decoration: InputDecoration( contentPadding: EdgeInsets.all(8.0), @@ -413,7 +415,7 @@ class DialogEntryPage extends StatelessWidget { )), ), ), - onItemClick: (BuildContext contex, int index) { + onItemClick: (BuildContext context, int index) { hintText = data[index].content; state(() {}); }, @@ -430,7 +432,7 @@ class DialogEntryPage extends StatelessWidget { ///多选弹框 void _showMiddleMultiSelectWithMessageDialog(BuildContext context) { - List data = new List(); + List data = []; data.add(new MultiSelectItem("100", "感兴趣待跟进")); data.add(new MultiSelectItem("101", "感兴趣但对本商圈没兴趣", isChecked: true)); data.add(new MultiSelectItem("102", "接通后挂断/不感兴趣", isChecked: true)); @@ -467,7 +469,7 @@ class DialogEntryPage extends StatelessWidget { padding: const EdgeInsets.only(top: 6, left: 24, right: 24), child: BrnCSS2Text.toTextView( "这是一条增使用标签修改文字颜色的example\我是带颜色的文字," - "这是颜色标签后边的文字", linksCallback: (String text, String linkUrl) { + "这是颜色标签后边的文字", linksCallback: (String? text, String? linkUrl) { BrnToast.show('$text clicked! Url is $linkUrl', context); }), ), @@ -721,7 +723,7 @@ class DialogEntryPage extends StatelessWidget { ///对话框样式九:标准的对话框:有标题、双按钮、有警示文案和辅助信息 void _showStyle9_1Dialog(BuildContext context) { - bool status = false; + bool? status = false; BrnDialogManager.showConfirmDialog(context, title: "标题内容?", cancel: '取消', @@ -730,7 +732,7 @@ class DialogEntryPage extends StatelessWidget { return Row(children: [ Checkbox( value: status, - onChanged: (bool aaa) { + onChanged: (bool? aaa) { status = aaa; setState(() {}); }, @@ -762,9 +764,9 @@ class DialogEntryPage extends StatelessWidget { BrnShareDialog brnShareDialog = new BrnShareDialog( context: context, shareChannels: [ - BrnShareItemConstants.SHARE_WEIXIN, - BrnShareItemConstants.SHARE_LINK, - BrnShareItemConstants.SHARE_CUSTOM + BrnShareItemConstants.shareWeiXin, + BrnShareItemConstants.shareLink, + BrnShareItemConstants.shareCustom ], titleText: "测试标题", descText: "测试辅助信息测试辅助信息测试辅助信息测试辅助信息测试辅助信息", @@ -792,11 +794,11 @@ class DialogEntryPage extends StatelessWidget { BrnShareDialog brnShareDialog = new BrnShareDialog( context: context, shareChannels: [ - BrnShareItemConstants.SHARE_WEIXIN, - BrnShareItemConstants.SHARE_CUSTOM, - BrnShareItemConstants.SHARE_CUSTOM, - BrnShareItemConstants.SHARE_LINK, - BrnShareItemConstants.SHARE_CUSTOM + BrnShareItemConstants.shareWeiXin, + BrnShareItemConstants.shareCustom, + BrnShareItemConstants.shareCustom, + BrnShareItemConstants.shareLink, + BrnShareItemConstants.shareCustom ], titleText: "测试标题", descText: "测试辅助信息测试辅助信息测试辅助信息测试辅助信息测试辅助信息", @@ -831,7 +833,7 @@ class DialogEntryPage extends StatelessWidget { void _showBrnTwoVerticalButtonDialogDialog(BuildContext context) { BrnEnhanceOperationDialog brnShareDialog = new BrnEnhanceOperationDialog( context: context, - iconType: BrnDialogConstants.ICON_ALERT, + iconType: BrnDialogConstants.iconAlert, titleText: "强提示文案", descText: "这里是文案这里是文案这里是文案这里是文案这里是文案这里是文案这里是文案这里是文案", mainButtonText: "主要按钮", @@ -848,7 +850,7 @@ class DialogEntryPage extends StatelessWidget { void _showBrnOneVerticalButtonDialogDialog(BuildContext context) { BrnEnhanceOperationDialog brnShareDialog = new BrnEnhanceOperationDialog( - iconType: BrnDialogConstants.ICON_WARNING, + iconType: BrnDialogConstants.iconWarning, context: context, titleText: "强提示文案", descText: "这里是文案这里是文案这里是文案这里是文案这里是文案这里是文案这里是文案这里是文案", @@ -878,8 +880,8 @@ class DialogEntryPage extends StatelessWidget { "文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文" "呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表", submitText: "提交", - linksCallback: (String text, String url) { - BrnToast.show(text, context); + linksCallback: (String? text, String? url) { + BrnToast.show(text!, context); }, onSubmitClick: () { BrnToast.show("点击了纯文本弹框", context); diff --git a/example/lib/sample/components/empty/abnormal_entry_page.dart b/example/lib/sample/components/empty/abnormal_entry_page.dart index a0fa3ffa..3cfddc66 100644 --- a/example/lib/sample/components/empty/abnormal_entry_page.dart +++ b/example/lib/sample/components/empty/abnormal_entry_page.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/components/empty/abnormal_state_example.dart'; import 'package:example/sample/home/list_item.dart'; diff --git a/example/lib/sample/components/empty/abnormal_state_example.dart b/example/lib/sample/components/empty/abnormal_state_example.dart index 8fa335fc..9ec98bd5 100644 --- a/example/lib/sample/components/empty/abnormal_state_example.dart +++ b/example/lib/sample/components/empty/abnormal_state_example.dart @@ -1,8 +1,10 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; class AbnomalStateExample extends StatelessWidget { - final int caseIndex; + final int? caseIndex; AbnomalStateExample({this.caseIndex}); @@ -15,8 +17,8 @@ class AbnomalStateExample extends StatelessWidget { body: _buildEmpty(caseIndex, context)); } - Widget _buildEmpty(int index, BuildContext context) { - Widget widget; + Widget? _buildEmpty(int? index, BuildContext context) { + Widget? widget; switch (index) { case 0: widget = BrnAbnormalStateWidget( @@ -27,7 +29,7 @@ class AbnomalStateExample extends StatelessWidget { isCenterVertical: true, title: BrnStrings.getDateFailed, operateTexts: [BrnStrings.clickPageRetry], - operateAreaType: OperateAreaType.TextButton, + operateAreaType: OperateAreaType.textButton, action: (index) { BrnToast.show(BrnStrings.getDateFailed, context); }, @@ -69,7 +71,7 @@ class AbnomalStateExample extends StatelessWidget { ), title: "这是副标题内容这是副标题内容这是副标", content: '您的门店暂无用户', - operateAreaType: OperateAreaType.SingleButton, + operateAreaType: OperateAreaType.singleButton, operateTexts: ["切换账号"], action: (_) { BrnToast.show("第$_个按钮被点击了", context); @@ -84,7 +86,7 @@ class AbnomalStateExample extends StatelessWidget { ), title: "暂无", content: '您还没有在维护的信息哦', - operateAreaType: OperateAreaType.DoubleButton, + operateAreaType: OperateAreaType.doubleButton, operateTexts: ['去添加', '去修改'], action: (_) { BrnToast.show("第$_个按钮被点击了", context); diff --git a/example/lib/sample/components/form/all_item_style_example.dart b/example/lib/sample/components/form/all_item_style_example.dart index ab695efd..6084e42f 100644 --- a/example/lib/sample/components/form/all_item_style_example.dart +++ b/example/lib/sample/components/form/all_item_style_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/components/form/group_example/expansion_group_example.dart'; import 'package:example/sample/components/form/group_example/group_add_example.dart'; diff --git a/example/lib/sample/components/form/form_item_entry_example.dart b/example/lib/sample/components/form/form_item_entry_example.dart index 25b63537..d655dda2 100644 --- a/example/lib/sample/components/form/form_item_entry_example.dart +++ b/example/lib/sample/components/form/form_item_entry_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/components/form/all_item_style_example.dart'; import 'package:example/sample/components/form/form_page_example.dart'; diff --git a/example/lib/sample/components/form/form_page_example.dart b/example/lib/sample/components/form/form_page_example.dart index aa46c4bb..b55967d0 100644 --- a/example/lib/sample/components/form/form_page_example.dart +++ b/example/lib/sample/components/form/form_page_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; /// 退回订单 页面展示 @@ -9,13 +11,14 @@ class FormPageExample extends StatefulWidget { } class _FormPageExampleState extends State { - List selectedOptions = List(); - String commentStr; - BrnPortraitRadioGroupOption selectedValue; + List selectedOptions = []; + String? commentStr; + late BrnPortraitRadioGroupOption selectedValue; @override void initState() { super.initState(); + selectedValue = BrnPortraitRadioGroupOption(); } @override @@ -43,10 +46,10 @@ class _FormPageExampleState extends State { '$index 不在我服务范围', '$index 其他' ], - selectedOption: selectedValue?.title, - onChanged: (BrnPortraitRadioGroupOption old, + selectedOption: selectedValue.title ?? '', + onChanged: (BrnPortraitRadioGroupOption? old, BrnPortraitRadioGroupOption newList) { - BrnToast.show(newList.title, context); + BrnToast.show(newList.title!, context); selectedValue = newList; commentStr = ''; setState(() {}); @@ -69,9 +72,9 @@ class _FormPageExampleState extends State { subTitle: 'subtitlesubtn你好 哈哈哈哈哈哈啊哈哈哈哈哈子标题哈哈哈 子标题子标题'); }), selectedOption: selectedValue, - onChanged: (BrnPortraitRadioGroupOption old, + onChanged: (BrnPortraitRadioGroupOption? old, BrnPortraitRadioGroupOption newList) { - BrnToast.show(newList.title, context); + BrnToast.show(newList.title!, context); selectedValue = newList; commentStr = ''; setState(() {}); diff --git a/example/lib/sample/components/form/group_example/expansion_group_example.dart b/example/lib/sample/components/form/group_example/expansion_group_example.dart index 248937bb..9d2f2d98 100644 --- a/example/lib/sample/components/form/group_example/expansion_group_example.dart +++ b/example/lib/sample/components/form/group_example/expansion_group_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/form/group_example/group_add_example.dart b/example/lib/sample/components/form/group_example/group_add_example.dart index 7516c930..2e810ecf 100644 --- a/example/lib/sample/components/form/group_example/group_add_example.dart +++ b/example/lib/sample/components/form/group_example/group_add_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/form/group_example/normal_group_example.dart b/example/lib/sample/components/form/group_example/normal_group_example.dart index 8edefddd..5b4b133a 100644 --- a/example/lib/sample/components/form/group_example/normal_group_example.dart +++ b/example/lib/sample/components/form/group_example/normal_group_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/form/items_example/base_title_example.dart b/example/lib/sample/components/form/items_example/base_title_example.dart index f251cb35..b2e8b9d7 100644 --- a/example/lib/sample/components/form/items_example/base_title_example.dart +++ b/example/lib/sample/components/form/items_example/base_title_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/form/items_example/multi_choice_example.dart b/example/lib/sample/components/form/items_example/multi_choice_example.dart index bae807bf..204e8f4b 100644 --- a/example/lib/sample/components/form/items_example/multi_choice_example.dart +++ b/example/lib/sample/components/form/items_example/multi_choice_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -40,9 +42,9 @@ class MultiChoiceInputExamplePage extends StatelessWidget { onRemoveTap: () { BrnToast.show("点击触发onRemoveTap回调", context); }, - onChanged: (List oldValue, List newValue) { + onChanged: (List oldValue, List? newValue) { BrnToast.show( - "点击触发onChanged回调${oldValue.length}_${newValue.length}_onChanged", context); + "点击触发onChanged回调${oldValue.length}_${newValue!.length}_onChanged", context); }, ), Container( @@ -56,7 +58,7 @@ class MultiChoiceInputExamplePage extends StatelessWidget { ), ), BrnMultiChoiceInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, error: "必填项不能为空", title: "自然", @@ -79,9 +81,9 @@ class MultiChoiceInputExamplePage extends StatelessWidget { onRemoveTap: () { BrnToast.show("点击触发onRemoveTap回调", context); }, - onChanged: (List oldValue, List newValue) { + onChanged: (List oldValue, List? newValue) { BrnToast.show( - "点击触发onChanged回调${oldValue.length}_${newValue.length}_onChanged", context); + "点击触发onChanged回调${oldValue.length}_${newValue!.length}_onChanged", context); }, ), Container( @@ -95,7 +97,7 @@ class MultiChoiceInputExamplePage extends StatelessWidget { ), ), BrnMultiChoiceInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_REMOVE, + prefixIconType: BrnPrefixIconType.remove, isRequire: true, title: "自然到", subTitle: "这里是副标题", diff --git a/example/lib/sample/components/form/items_example/multi_choice_protrait_example.dart b/example/lib/sample/components/form/items_example/multi_choice_protrait_example.dart index 9621128e..e74e91aa 100644 --- a/example/lib/sample/components/form/items_example/multi_choice_protrait_example.dart +++ b/example/lib/sample/components/form/items_example/multi_choice_protrait_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -60,7 +62,7 @@ class MultiChoicePortraitInputExamplePage extends StatelessWidget { ), ), BrnMultiChoicePortraitInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_REMOVE, + prefixIconType: BrnPrefixIconType.remove, isRequire: true, error: "必填项不能为空", title: "自然到访保护期", @@ -101,7 +103,7 @@ class MultiChoicePortraitInputExamplePage extends StatelessWidget { ), ), BrnMultiChoicePortraitInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_REMOVE, + prefixIconType: BrnPrefixIconType.remove, isRequire: true, title: "自然到访保护期", subTitle: "这里是副标题", diff --git a/example/lib/sample/components/form/items_example/radio_input_example.dart b/example/lib/sample/components/form/items_example/radio_input_example.dart index cf2045dd..f05edb6e 100644 --- a/example/lib/sample/components/form/items_example/radio_input_example.dart +++ b/example/lib/sample/components/form/items_example/radio_input_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -55,7 +57,7 @@ class RadioInputExamplePage extends StatelessWidget { ), ), BrnRadioInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, error: "必填项不能为空", title: "自然到访保护期", @@ -90,7 +92,7 @@ class RadioInputExamplePage extends StatelessWidget { ), ), BrnRadioInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_REMOVE, + prefixIconType: BrnPrefixIconType.remove, isRequire: true, title: "自然到访保护期", subTitle: "这里是副标题", @@ -124,7 +126,7 @@ class RadioInputExamplePage extends StatelessWidget { ), ), BrnRadioInputFormItem.autoLayout( - prefixIconType: BrnPrefixIconType.TYPE_REMOVE, + prefixIconType: BrnPrefixIconType.remove, isRequire: true, error: "必填项不能为空", title: "autoLayout", diff --git a/example/lib/sample/components/form/items_example/radio_protrait_example.dart b/example/lib/sample/components/form/items_example/radio_protrait_example.dart index 27b60220..b4c3949d 100644 --- a/example/lib/sample/components/form/items_example/radio_protrait_example.dart +++ b/example/lib/sample/components/form/items_example/radio_protrait_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -56,7 +58,7 @@ class RadioPortraitInputExamplePage extends StatelessWidget { ), ), BrnRadioPortraitInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, error: "必填项不能为空", title: "自然到访保护期", @@ -93,7 +95,7 @@ class RadioPortraitInputExamplePage extends StatelessWidget { ), ), BrnRadioPortraitInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_REMOVE, + prefixIconType: BrnPrefixIconType.remove, isRequire: true, title: "自然到访保护期", subTitle: "这里是副标题", diff --git a/example/lib/sample/components/form/items_example/range_input_example.dart b/example/lib/sample/components/form/items_example/range_input_example.dart index b04a42d9..0e207851 100644 --- a/example/lib/sample/components/form/items_example/range_input_example.dart +++ b/example/lib/sample/components/form/items_example/range_input_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -34,7 +36,7 @@ class RangeInputExamplePage extends StatelessWidget { maxUnit: "天", leftMaxCount: 1, rightMaxCount: 3, - inputType: BrnInputType.NUMBER, + inputType: BrnInputType.number, onTip: () { BrnToast.show("点击触发onTip回调", context); }, @@ -64,7 +66,7 @@ class RangeInputExamplePage extends StatelessWidget { BrnRangeInputFormItem( minController: TextEditingController()..text = "10", maxController: TextEditingController()..text = "100", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, error: "必填项不能为空", title: "保护期", @@ -77,7 +79,7 @@ class RangeInputExamplePage extends StatelessWidget { maxUnit: "天", leftMaxCount: 1, rightMaxCount: 3, - inputType: BrnInputType.NUMBER, + inputType: BrnInputType.number, onTip: () { BrnToast.show("点击触发onTip回调", context); }, @@ -107,7 +109,7 @@ class RangeInputExamplePage extends StatelessWidget { BrnRangeInputFormItem( minController: TextEditingController()..text = "10", maxController: TextEditingController()..text = "100", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, title: "保护期", subTitle: "这里是副标题", @@ -119,7 +121,7 @@ class RangeInputExamplePage extends StatelessWidget { maxUnit: "天", leftMaxCount: 2, rightMaxCount: 3, - inputType: BrnInputType.NUMBER, + inputType: BrnInputType.number, onTip: () { BrnToast.show("点击触发onTip回调", context); }, @@ -149,7 +151,7 @@ class RangeInputExamplePage extends StatelessWidget { BrnRangeInputFormItem( minController: TextEditingController()..text = "10", maxController: TextEditingController()..text = "100", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, title: "保护期", subTitle: "这里是副标题", @@ -162,7 +164,7 @@ class RangeInputExamplePage extends StatelessWidget { maxUnit: "天", leftMaxCount: 2, rightMaxCount: 3, - inputType: BrnInputType.NUMBER, + inputType: BrnInputType.number, onTip: () { BrnToast.show("点击触发onTip回调", context); }, diff --git a/example/lib/sample/components/form/items_example/ratio_input_example.dart b/example/lib/sample/components/form/items_example/ratio_input_example.dart index 72f19a93..5d374d59 100644 --- a/example/lib/sample/components/form/items_example/ratio_input_example.dart +++ b/example/lib/sample/components/form/items_example/ratio_input_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -52,7 +54,7 @@ class RatioInputExamplePage extends StatelessWidget { ), BrnRatioInputFormItem( controller: TextEditingController()..text = "1.6", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: true, error: "必填项不能为空", @@ -84,7 +86,7 @@ class RatioInputExamplePage extends StatelessWidget { ), BrnRatioInputFormItem( controller: TextEditingController()..text = "1.6", - prefixIconType: BrnPrefixIconType.TYPE_REMOVE, + prefixIconType: BrnPrefixIconType.remove, isRequire: true, isEdit: true, title: "车位比", @@ -115,7 +117,7 @@ class RatioInputExamplePage extends StatelessWidget { ), BrnRatioInputFormItem( controller: TextEditingController()..text = "1.6", - prefixIconType: BrnPrefixIconType.TYPE_REMOVE, + prefixIconType: BrnPrefixIconType.remove, isRequire: true, isEdit: false, isPrefixIconEnabled: true, diff --git a/example/lib/sample/components/form/items_example/select_all_title_example.dart b/example/lib/sample/components/form/items_example/select_all_title_example.dart index 2b2d991d..78507285 100644 --- a/example/lib/sample/components/form/items_example/select_all_title_example.dart +++ b/example/lib/sample/components/form/items_example/select_all_title_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/form/items_example/star_example.dart b/example/lib/sample/components/form/items_example/star_example.dart index 484bc0a4..d9f2f43f 100644 --- a/example/lib/sample/components/form/items_example/star_example.dart +++ b/example/lib/sample/components/form/items_example/star_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -52,7 +54,7 @@ class StarInputExamplePage extends StatelessWidget { ), ), BrnStarsFormItem( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: true, error: "必填项不能为空", @@ -85,7 +87,7 @@ class StarInputExamplePage extends StatelessWidget { ), ), BrnStarsFormItem( - prefixIconType: BrnPrefixIconType.TYPE_REMOVE, + prefixIconType: BrnPrefixIconType.remove, isRequire: true, isEdit: true, title: "自然到访保护期", diff --git a/example/lib/sample/components/form/items_example/step_input_example.dart b/example/lib/sample/components/form/items_example/step_input_example.dart index ca1ea523..07a92d2f 100644 --- a/example/lib/sample/components/form/items_example/step_input_example.dart +++ b/example/lib/sample/components/form/items_example/step_input_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -54,14 +56,13 @@ class StepInputExamplePage extends StatelessWidget { ), ), BrnStepInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: true, error: "必填项不能为空", title: "自然到访保护期", subTitle: "这里是副标题", tipLabel: "标签", - value: 0, maxLimit: 5, minLimit: 1, onTip: () { @@ -88,13 +89,12 @@ class StepInputExamplePage extends StatelessWidget { ), ), BrnStepInputFormItem( - prefixIconType: BrnPrefixIconType.TYPE_REMOVE, + prefixIconType: BrnPrefixIconType.remove, isRequire: true, isEdit: true, title: "自然到访保护期", subTitle: "这里是副标题", tipLabel: "标签", - value: 0, maxLimit: 5, minLimit: 1, onTip: () { diff --git a/example/lib/sample/components/form/items_example/text_block_input_example.dart b/example/lib/sample/components/form/items_example/text_block_input_example.dart index bd15cc0a..9d05ba9f 100644 --- a/example/lib/sample/components/form/items_example/text_block_input_example.dart +++ b/example/lib/sample/components/form/items_example/text_block_input_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -55,7 +57,7 @@ class TextBlockInputExamplePage extends StatelessWidget { ), BrnTextBlockInputFormItem( controller: TextEditingController()..text = "hello", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: true, error: "必填项不能为空", @@ -88,7 +90,7 @@ class TextBlockInputExamplePage extends StatelessWidget { ), BrnTextBlockInputFormItem( controller: TextEditingController()..text = "hello", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: true, title: "备注", @@ -120,7 +122,7 @@ class TextBlockInputExamplePage extends StatelessWidget { ), BrnTextBlockInputFormItem( controller: TextEditingController()..text = "hello", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: false, isPrefixIconEnabled: true, diff --git a/example/lib/sample/components/form/items_example/text_input_example.dart b/example/lib/sample/components/form/items_example/text_input_example.dart index 401b42dc..2e3037d8 100644 --- a/example/lib/sample/components/form/items_example/text_input_example.dart +++ b/example/lib/sample/components/form/items_example/text_input_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -54,7 +56,7 @@ class TextInputExamplePage extends StatelessWidget { ), BrnTextInputFormItem( controller: TextEditingController()..text = "300", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: true, error: "必填项不能为空", @@ -88,7 +90,7 @@ class TextInputExamplePage extends StatelessWidget { ), BrnTextInputFormItem( controller: TextEditingController()..text = "300", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: true, title: "房屋总价", @@ -121,7 +123,7 @@ class TextInputExamplePage extends StatelessWidget { ), BrnTextInputFormItem( controller: TextEditingController()..text = "300", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: false, isPrefixIconEnabled: true, diff --git a/example/lib/sample/components/form/items_example/text_quick_select_input_example.dart b/example/lib/sample/components/form/items_example/text_quick_select_input_example.dart index 8703111f..28698733 100644 --- a/example/lib/sample/components/form/items_example/text_quick_select_input_example.dart +++ b/example/lib/sample/components/form/items_example/text_quick_select_input_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; @@ -19,8 +21,8 @@ class _TextQuickSelectInputExamplePageState String selectedStr = ''; String selectedStrAllFunctionExample = ''; List options = ['选项1', '选项2', '选项3', '选项4', '选项5', '选项6', '选项7']; - List status; - List statusAllFunctionExample; + late List status; + List? statusAllFunctionExample; _TextQuickSelectInputExamplePageState(this._title); @@ -92,7 +94,7 @@ class _TextQuickSelectInputExamplePageState ), ), BrnTextQuickSelectFormItem( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, btnsTxt: options, selectBtnList: statusAllFunctionExample, @@ -103,8 +105,8 @@ class _TextQuickSelectInputExamplePageState subTitle: "这里是副标题", tipLabel: "标签", onBtnSelectChanged: (index) { - statusAllFunctionExample[index] = !statusAllFunctionExample[index]; - if (statusAllFunctionExample[index]) { + statusAllFunctionExample![index] = !statusAllFunctionExample![index]; + if (statusAllFunctionExample![index]) { selectedStrAllFunctionExample += '${options[index]} '; } else if (selectedStrAllFunctionExample.contains(options[index])) { selectedStrAllFunctionExample = selectedStrAllFunctionExample.replaceFirst('${options[index]} ', ''); diff --git a/example/lib/sample/components/form/items_example/text_select_example.dart b/example/lib/sample/components/form/items_example/text_select_example.dart index 3e8de41a..7a689bbd 100644 --- a/example/lib/sample/components/form/items_example/text_select_example.dart +++ b/example/lib/sample/components/form/items_example/text_select_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; @@ -51,7 +53,7 @@ class TextSelectInputExamplePage extends StatelessWidget { ), ), BrnTextSelectFormItem( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, error: "必填项不能为空", title: "证件类型", @@ -81,7 +83,7 @@ class TextSelectInputExamplePage extends StatelessWidget { ), ), BrnTextSelectFormItem( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, title: "证件类型", subTitle: "这里是副标题", @@ -110,7 +112,7 @@ class TextSelectInputExamplePage extends StatelessWidget { ), ), BrnTextSelectFormItem.autoLayout( - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, error: "必填项不能为空", title: "证件类型", diff --git a/example/lib/sample/components/form/items_example/title_example.dart b/example/lib/sample/components/form/items_example/title_example.dart index 227cd61a..8bcd8bb2 100644 --- a/example/lib/sample/components/form/items_example/title_example.dart +++ b/example/lib/sample/components/form/items_example/title_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/form/items_example/title_select_example.dart b/example/lib/sample/components/form/items_example/title_select_example.dart index 698237bf..afaff9d7 100644 --- a/example/lib/sample/components/form/items_example/title_select_example.dart +++ b/example/lib/sample/components/form/items_example/title_select_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -14,13 +16,13 @@ class TitleSelectInputExamplePage extends StatefulWidget { } class TitleSelectInputState extends State { - List _list; + late List _list; TextEditingController controller = TextEditingController()..text = '123456'; @override void initState() { super.initState(); - _list = List(); + _list = []; _list.add('手机号'); _list.add('座机'); } @@ -47,7 +49,7 @@ class TitleSelectInputState extends State { title: _list[0], hint: "请输入", controller: controller, - inputFormatters: [FilteringTextInputFormatter(RegExp('[0-9"]'))], + inputFormatters: [FilteringTextInputFormatter.digitsOnly], selectedIndex: -1, selectList: _list, onTip: () { @@ -81,7 +83,7 @@ class TitleSelectInputState extends State { ), BrnTitleSelectInputFormItem( controller: TextEditingController()..text = "124", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: false, error: "必填项不能为空", @@ -119,7 +121,7 @@ class TitleSelectInputState extends State { ), BrnTitleSelectInputFormItem( controller: TextEditingController()..text = "124", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: false, subTitle: "这里是副标题", @@ -156,7 +158,7 @@ class TitleSelectInputState extends State { ), BrnTitleSelectInputFormItem( controller: TextEditingController()..text = "不可编辑时+ -号可点击", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: false, isPrefixIconEnabled: false, @@ -195,7 +197,7 @@ class TitleSelectInputState extends State { ), BrnTitleSelectInputFormItem( controller: TextEditingController()..text = "不可编辑时+ -号可点击", - prefixIconType: BrnPrefixIconType.TYPE_ADD, + prefixIconType: BrnPrefixIconType.add, isRequire: true, isEdit: false, isPrefixIconEnabled: true, diff --git a/example/lib/sample/components/form/phote_picker_example/photo_preview_page.dart b/example/lib/sample/components/form/phote_picker_example/photo_preview_page.dart deleted file mode 100644 index 5cd8fa5b..00000000 --- a/example/lib/sample/components/form/phote_picker_example/photo_preview_page.dart +++ /dev/null @@ -1,69 +0,0 @@ -import 'dart:io'; -import 'package:bruno/bruno.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_swiper/flutter_swiper.dart'; - -/// @des:图片预览页面 -/// - -// ignore: must_be_immutable -class PhotoPreviewPage extends StatefulWidget { - /// 图片地址 - List picUrl; - - /// 初始化角标 - int initialIndex; - - PhotoPreviewPage({@required this.picUrl, this.initialIndex: 0}); - - @override - _PhotoPreviewPageState createState() => _PhotoPreviewPageState(); -} - -class _PhotoPreviewPageState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: _buildAppBar(context), - body: _buildBody(context), - ); - } - - /// - /// 标题栏 - /// - Widget _buildAppBar(BuildContext context) { - return BrnAppBar( - title: "图片详情", - backLeadCallback: () { - Navigator.pop(context); - }, - ); - } - - /// - /// 轮播图 - /// - Widget _buildBody(BuildContext context) { - return Swiper( - itemCount: widget.picUrl.length, - itemBuilder: (BuildContext context, int index) { - String picUrl = widget.picUrl[index]; - if (picUrl.startsWith("http") || picUrl.startsWith("https")) { - return FadeInImage.assetNetwork( - placeholder: "packages/bruno/assets/" + "images/icon_alert", - image: widget.picUrl[index], - fit: BoxFit.fill, - ); - } else { - File file = File(picUrl); - Image image = Image.file(file, fit: BoxFit.fill); - return image; - } - }, - index: widget.initialIndex, - control: new SwiperControl(), - loop: false, - ); - } -} diff --git a/example/lib/sample/components/gallery/gallery_detail_example.dart b/example/lib/sample/components/gallery/gallery_detail_example.dart index 9680766f..1219679d 100644 --- a/example/lib/sample/components/gallery/gallery_detail_example.dart +++ b/example/lib/sample/components/gallery/gallery_detail_example.dart @@ -1,10 +1,12 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; enum PhotoGalleryTheme { dark, light } class GalleryDetailExamplePage extends StatefulWidget { - final String title; + final String? title; final PhotoGalleryTheme photoGalleryTheme; GalleryDetailExamplePage({this.title, this.photoGalleryTheme = PhotoGalleryTheme.dark}); @@ -16,8 +18,8 @@ class GalleryDetailExamplePage extends StatefulWidget { } class GalleryDetailExamplePageState extends State { - List allConfig; - BrnGalleryController controller; + late List allConfig; + late BrnGalleryController controller; @override void initState() { @@ -171,8 +173,8 @@ class GalleryDetailExamplePageState extends State { BrnToast.show("点击了$i $j", context); // 移除第二组的最后一个配置,跳转到 第二组的第一张图 if (allConfig.length > 1) { - if (allConfig[1].configList.length > 0) { - allConfig[1].configList.removeLast(); + if (allConfig[1].configList!.length > 0) { + allConfig[1].configList!.removeLast(); controller.refresh(1, 0); } else { allConfig.removeAt(1); diff --git a/example/lib/sample/components/gallery/gallery_detail_page_theme_example.dart b/example/lib/sample/components/gallery/gallery_detail_page_theme_example.dart index b47d65c6..88ea69ac 100644 --- a/example/lib/sample/components/gallery/gallery_detail_page_theme_example.dart +++ b/example/lib/sample/components/gallery/gallery_detail_page_theme_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/components/gallery/gallery_detail_example.dart'; import 'package:example/sample/home/list_item.dart'; diff --git a/example/lib/sample/components/gallery/gallery_example.dart b/example/lib/sample/components/gallery/gallery_example.dart index 1df173bf..fe88e811 100644 --- a/example/lib/sample/components/gallery/gallery_example.dart +++ b/example/lib/sample/components/gallery/gallery_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/components/gallery/gallery_detail_page_theme_example.dart'; import 'package:example/sample/home/list_item.dart'; @@ -88,7 +90,7 @@ class GalleryExample extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: BrnAppBar( - title: "步骤条示例", + title: "Gallery 图片", ),body: ListView(children: [ ListItem( title: "图片选择控件", diff --git a/example/lib/sample/components/guide/force_guide_example.dart b/example/lib/sample/components/guide/force_guide_example.dart index 0803c653..e3e6b3c5 100644 --- a/example/lib/sample/components/guide/force_guide_example.dart +++ b/example/lib/sample/components/guide/force_guide_example.dart @@ -1,17 +1,19 @@ + + import 'dart:async'; import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; /// @desc 强引导example class ForceGuideExample extends StatefulWidget { - ForceGuideExample({Key key}) : super(key: key); + ForceGuideExample({Key? key}) : super(key: key); @override _ForceGuideExampleState createState() => _ForceGuideExampleState(); } class _ForceGuideExampleState extends State { - BrnGuide intro; + late BrnGuide intro; _ForceGuideExampleState() { /// init Guide diff --git a/example/lib/sample/components/guide/guide_entry_page.dart b/example/lib/sample/components/guide/guide_entry_page.dart index a48c0515..f15dc4b7 100644 --- a/example/lib/sample/components/guide/guide_entry_page.dart +++ b/example/lib/sample/components/guide/guide_entry_page.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/components/guide/force_guide_example.dart'; import 'package:example/sample/components/guide/soft_intro_example.dart'; diff --git a/example/lib/sample/components/guide/soft_intro_example.dart b/example/lib/sample/components/guide/soft_intro_example.dart index 2fed63f6..fcb0a12f 100644 --- a/example/lib/sample/components/guide/soft_intro_example.dart +++ b/example/lib/sample/components/guide/soft_intro_example.dart @@ -1,3 +1,5 @@ + + import 'dart:async'; import 'package:bruno/bruno.dart'; @@ -5,14 +7,14 @@ import 'package:flutter/material.dart'; /// @desc 弱引导example class SoftGuideExample extends StatefulWidget { - SoftGuideExample({Key key}) : super(key: key); + SoftGuideExample({Key? key}) : super(key: key); @override _SoftGuideExampleState createState() => _SoftGuideExampleState(); } class _SoftGuideExampleState extends State { - BrnGuide intro; + late BrnGuide intro; _SoftGuideExampleState() { /// init Guide diff --git a/example/lib/sample/components/input/input_example.dart b/example/lib/sample/components/input/input_example.dart index a6e654b9..0aceb62b 100644 --- a/example/lib/sample/components/input/input_example.dart +++ b/example/lib/sample/components/input/input_example.dart @@ -1,9 +1,11 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; class TextModel { - String text; + String? text; } class BrnInputTextExample extends StatefulWidget { @@ -46,8 +48,8 @@ class _BrnInputTextExampleState extends State { minHeight: 30, minLines: 1, maxLength: 10, - bgColor: Colors.grey[200], - textString: model.text, + bgColor: Colors.grey[200]!, + textString: model.text ?? '', textInputAction: TextInputAction.newline, maxHintLines: 20, hint: 'input动态算高input动态算高input动态算高input动态算高input动态算高', diff --git a/example/lib/sample/components/line/dashed_line_example.dart b/example/lib/sample/components/line/dashed_line_example.dart index 8ffd30a6..08cf4ff7 100644 --- a/example/lib/sample/components/line/dashed_line_example.dart +++ b/example/lib/sample/components/line/dashed_line_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -33,7 +35,7 @@ class _DashedLineExampleState extends State { axis: Axis.vertical, color: Colors.red, dashedOffset: 20, - position: BrnDashedLinePosition.DashedLineLeading, + position: BrnDashedLinePosition.leading, contentWidget: Container( margin: EdgeInsets.only(left: 60, right: 20, top: 10, bottom: 10), child: @@ -54,7 +56,7 @@ class _DashedLineExampleState extends State { axis: Axis.horizontal, color: Colors.green, dashedOffset: 20, - position: BrnDashedLinePosition.DashedLineLeading, + position: BrnDashedLinePosition.leading, contentWidget: Container( width: 200, height: 100, @@ -75,7 +77,10 @@ class _DashedLineExampleState extends State { color: Colors.red, child: BrnDashedLine( axis: Axis.horizontal, - dashedOffset: 10, + dashedOffset: 10, contentWidget: Container( + width: 200, + height: 100, + ), ), ), ], diff --git a/example/lib/sample/components/loading/loading_widget_example.dart b/example/lib/sample/components/loading/loading_widget_example.dart index f1f64c84..53b9aa05 100644 --- a/example/lib/sample/components/loading/loading_widget_example.dart +++ b/example/lib/sample/components/loading/loading_widget_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/navbar/appbar_entry_page.dart b/example/lib/sample/components/navbar/appbar_entry_page.dart index 31f4f747..b800a595 100644 --- a/example/lib/sample/components/navbar/appbar_entry_page.dart +++ b/example/lib/sample/components/navbar/appbar_entry_page.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/home/list_item.dart'; import 'package:example/sample/components/navbar/nav_bar_example_page.dart'; diff --git a/example/lib/sample/components/navbar/nav_bar_example_page.dart b/example/lib/sample/components/navbar/nav_bar_example_page.dart index fa51a1ef..d0870d2a 100644 --- a/example/lib/sample/components/navbar/nav_bar_example_page.dart +++ b/example/lib/sample/components/navbar/nav_bar_example_page.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -12,25 +14,25 @@ class NavBarPage extends StatefulWidget { } class _NavBarPageState extends State with TickerProviderStateMixin { - TextEditingController textEditingController; + TextEditingController? textEditingController; - TextStyle selectedHeiStyle; - TextStyle unSelectedHeiStyle; - TextStyle commonHeiStyle; + TextStyle? selectedHeiStyle; + TextStyle? unSelectedHeiStyle; + TextStyle? commonHeiStyle; - TextStyle selectedBaiStyle; - TextStyle unSelectedBaiStyle; - TextStyle commonBaiStyle; + TextStyle? selectedBaiStyle; + TextStyle? unSelectedBaiStyle; + TextStyle? commonBaiStyle; int currentIndex = 0; - ValueNotifier valueNotifier; - FocusNode focusNode; + late ValueNotifier valueNotifier; + FocusNode? focusNode; - TabController tabController; + TabController? tabController; - var keyleading = GlobalKey(); + GlobalKey keyLeading = GlobalKey(); - var actionKey = GlobalKey(); + GlobalKey actionKey = GlobalKey(); @override void initState() { @@ -52,8 +54,8 @@ class _NavBarPageState extends State with TickerProviderStateMixin { commonBaiStyle = TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xFF222222)); focusNode = FocusNode(); - focusNode.addListener(() { - if (focusNode.hasFocus) { + focusNode!.addListener(() { + if (focusNode!.hasFocus) { valueNotifier.value = true; } }); @@ -69,8 +71,8 @@ class _NavBarPageState extends State with TickerProviderStateMixin { ); } - PreferredSizeWidget buildBarByIndex(BuildContext context) { - PreferredSizeWidget appBar; + PreferredSizeWidget? buildBarByIndex(BuildContext context) { + PreferredSizeWidget? appBar; switch (widget.index) { case 0: //2个文字模块切换 左右两个icon hei @@ -142,8 +144,8 @@ class _NavBarPageState extends State with TickerProviderStateMixin { return appBar; } - Widget buildContentByIndex(BuildContext context) { - Widget widget; + Widget? buildContentByIndex(BuildContext context) { + Widget? widget; switch (this.widget.index) { case 0: widget = @@ -475,7 +477,7 @@ class _NavBarPageState extends State with TickerProviderStateMixin { leading: Padding( padding: const EdgeInsets.only(right: 16), child: Row( - key: keyleading, + key: keyLeading, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( @@ -501,7 +503,7 @@ class _NavBarPageState extends State with TickerProviderStateMixin { //update 是setState方法的方法命,update() 就可以刷新输入框 BrnPopupListWindow.showPopListWindow( context, - keyleading, + keyLeading, data: ["aaaa", "bbbbb"], ); }, @@ -538,7 +540,7 @@ class _NavBarPageState extends State with TickerProviderStateMixin { leading: Padding( padding: const EdgeInsets.only(right: 16), child: Row( - key: keyleading, + key: keyLeading, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( @@ -561,7 +563,7 @@ class _NavBarPageState extends State with TickerProviderStateMixin { leadClickCallback: (controller, update) { //controller 是文本控制器,通过controller 可以拿到输入的内容 以及 对输入的内容更改 //update 是setState方法的方法命,update() 就可以刷新输入框 - BrnPopupListWindow.showPopListWindow(context, keyleading, data: ["aaaa", "bbbbb"]); + BrnPopupListWindow.showPopListWindow(context, keyLeading, data: ["aaaa", "bbbbb"]); }, //输入框 文本内容变化的监听 searchBarInputChangeCallback: (input) { diff --git a/example/lib/sample/components/noticebar/brn_notice_bar_example.dart b/example/lib/sample/components/noticebar/brn_notice_bar_example.dart index fa7c06b2..94eec187 100644 --- a/example/lib/sample/components/noticebar/brn_notice_bar_example.dart +++ b/example/lib/sample/components/noticebar/brn_notice_bar_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/home/list_item.dart'; import 'package:example/sample/components/noticebar/notice_bar_example.dart'; diff --git a/example/lib/sample/components/noticebar/notice_bar_example.dart b/example/lib/sample/components/noticebar/notice_bar_example.dart index 438dc52a..073ac2c4 100644 --- a/example/lib/sample/components/noticebar/notice_bar_example.dart +++ b/example/lib/sample/components/noticebar/notice_bar_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/noticebar/notice_bar_with_button_example.dart b/example/lib/sample/components/noticebar/notice_bar_with_button_example.dart index 4f710353..be11f666 100644 --- a/example/lib/sample/components/noticebar/notice_bar_with_button_example.dart +++ b/example/lib/sample/components/noticebar/notice_bar_with_button_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/picker/cutomer_bottom_picker_example.dart b/example/lib/sample/components/picker/cutomer_bottom_picker_example.dart index 144f9981..e63e6188 100644 --- a/example/lib/sample/components/picker/cutomer_bottom_picker_example.dart +++ b/example/lib/sample/components/picker/cutomer_bottom_picker_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/home/list_item.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/picker/date_picker_example.dart b/example/lib/sample/components/picker/date_picker_example.dart index 46408e2b..ece9492a 100644 --- a/example/lib/sample/components/picker/date_picker_example.dart +++ b/example/lib/sample/components/picker/date_picker_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/home/list_item.dart'; import 'package:flutter/material.dart'; @@ -154,7 +156,7 @@ class DatePickerExamplePage extends StatelessWidget { format = 'HH时:mm分'; BrnPickerTitleConfig timePickerTheme = BrnPickerTitleConfig( title: BrnPickerTitleConfig.Default.title, - showTitle: PICKER_SHOW_TITLE_DEFAULT, + showTitle: pickerShowTitleDefault, titleContent: "选择时间范围"); BrnDateRangePicker.showDatePicker(context, minDateTime: DateTime.parse(MIN_DATETIME), diff --git a/example/lib/sample/components/picker/multi_picker_example.dart b/example/lib/sample/components/picker/multi_picker_example.dart index 00ff73c3..b1aa2b87 100644 --- a/example/lib/sample/components/picker/multi_picker_example.dart +++ b/example/lib/sample/components/picker/multi_picker_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/home/list_item.dart'; import 'package:flutter/material.dart'; @@ -180,7 +182,7 @@ class Brn1RowDelegate implements BrnMultiDataPickerDelegate { } @override - double rowHeightForComponent(int component) { + double? rowHeightForComponent(int component) { return null; } @@ -247,7 +249,7 @@ class Brn2RowDelegate implements BrnMultiDataPickerDelegate { } @override - double rowHeightForComponent(int component) { + double? rowHeightForComponent(int component) { return null; } @@ -324,7 +326,7 @@ class Brn3RowDelegate implements BrnMultiDataPickerDelegate { } @override - double rowHeightForComponent(int component) { + double? rowHeightForComponent(int component) { return null; } @@ -384,7 +386,7 @@ class Brn2RowCustomDelegate implements BrnMultiDataPickerDelegate { } @override - double rowHeightForComponent(int component) { + double? rowHeightForComponent(int component) { return null; } diff --git a/example/lib/sample/components/picker/picker_entry_page.dart b/example/lib/sample/components/picker/picker_entry_page.dart index 508db7ca..33b907a5 100644 --- a/example/lib/sample/components/picker/picker_entry_page.dart +++ b/example/lib/sample/components/picker/picker_entry_page.dart @@ -1,3 +1,5 @@ + + import 'dart:convert'; import 'package:bruno/bruno.dart'; @@ -11,7 +13,7 @@ import 'multi_picker_example.dart'; class PickerEntryPage extends StatelessWidget { final String _title; - List dataList = List(); + List dataList = []; PickerEntryPage(this._title); @@ -80,11 +82,11 @@ class PickerEntryPage extends StatelessWidget { describe: "底部级联选择框", onPressed: () { rootBundle.loadString('assets/list_picker.json').then((data) { - List _selectionData = List() - ..addAll((JsonDecoder().convert(data)["data"]['list'] as List ?? []) + List _selectionData = [] + ..addAll((JsonDecoder().convert(data)["data"]['list'] as List? ?? []) .map((o) => BrnPickerEntity.fromMap(o))); - if (_selectionData != null && _selectionData.length > 0) { - _selectionData?.forEach((f) => f.configChild()); + if ( _selectionData.length > 0) { + _selectionData.forEach((f) => f.configChild()); if (dataList.length == 0) { dataList.addAll(_selectionData); } @@ -98,11 +100,11 @@ class PickerEntryPage extends StatelessWidget { describe: "底部级联选择框(Title 动态改变)", onPressed: () { rootBundle.loadString('assets/list_picker.json').then((data) { - List _selectionData = List() - ..addAll((JsonDecoder().convert(data)["data"]['list'] as List ?? []) + List _selectionData = [] + ..addAll((JsonDecoder().convert(data)["data"]['list'] as List? ?? []) .map((o) => BrnPickerEntity.fromMap(o))); - if (_selectionData != null && _selectionData.length > 0) { - _selectionData?.forEach((f) => f.configChild()); + if (_selectionData.length > 0) { + _selectionData.forEach((f) => f.configChild()); if (dataList.length == 0) { dataList.addAll(_selectionData); } @@ -129,7 +131,7 @@ class PickerEntryPage extends StatelessWidget { ///多选弹框 void _showBottomMultiSelectPicker(BuildContext context) { - List items = new List(); + List items = []; items.add(new BrnMultiSelectBottomPickerItem("100", "这里是标题1")); items.add(new BrnMultiSelectBottomPickerItem("101", "这里是标题2")); items.add(new BrnMultiSelectBottomPickerItem("102", "这里是标题3", isChecked: true)); @@ -153,7 +155,7 @@ class PickerEntryPage extends StatelessWidget { /// 实现限制选择数量的情况 void _showCountLimitBottomMultiSelectPicker(BuildContext context) { - List items = new List(); + List items = []; items.add(new BrnMultiSelectBottomPickerItem("100", "这里是标题1")); items.add(new BrnMultiSelectBottomPickerItem("101", "这里是标题2")); items.add(new BrnMultiSelectBottomPickerItem("102", "这里是标题3", isChecked: true)); @@ -201,7 +203,7 @@ class PickerEntryPage extends StatelessWidget { cancelDismiss: true, confirmDismiss: false, onConfirm: (context, string) { - BrnToast.show(string, context); + BrnToast.show(string ?? '', context); return; }, onCancel: (_) { @@ -213,15 +215,15 @@ class PickerEntryPage extends StatelessWidget { } void _showRangePicker(BuildContext context, List _selectionData) { - _selectionData?.forEach((f) => f.configChild()); + _selectionData.forEach((f) => f.configChild()); var selectionMenuView = BrnMultiColumnPicker( entity: _selectionData[3], defaultFocusedIndexes: [0, -1, -1], - onConfirm: (Map> result, int firstIndex, - int secondIndex, int thirdIndex) { - List pickResult = List(); + onConfirm: (Map> result, int? firstIndex, + int? secondIndex, int? thirdIndex) { + List pickResult = []; result.forEach((key, val) { - List tmp = List(); + List tmp = []; val.forEach((item) { tmp.add(item.name); }); @@ -243,7 +245,7 @@ class PickerEntryPage extends StatelessWidget { } void _showRangePicker1(BuildContext context, List _selectionData) { - _selectionData?.forEach((f) => f.configChild()); + _selectionData.forEach((f) => f.configChild()); String titleName = "测试标题"; showModalBottomSheet( context: context, @@ -253,11 +255,11 @@ class PickerEntryPage extends StatelessWidget { pickerTitleConfig: BrnPickerTitleConfig(titleContent: titleName), entity: _selectionData[3], defaultFocusedIndexes: [0, -1, -1], - onConfirm: (Map> result, int firstIndex, - int secondIndex, int thirdIndex) { - List pickResult = List(); + onConfirm: (Map> result, int? firstIndex, + int? secondIndex, int? thirdIndex) { + List pickResult = []; result.forEach((key, val) { - List tmp = List(); + List tmp = []; val.forEach((item) { tmp.add(item.name); }); @@ -291,7 +293,7 @@ class PickerEntryPage extends StatelessWidget { '可爱多池', ]; - List items = List(); + List items = []; for (int i = 0; i < tags.length; i++) { String it = tags[i]; BrnTagItemBean item = BrnTagItemBean(name: it, code: it, index: i); @@ -348,10 +350,10 @@ class PickerEntryPage extends StatelessWidget { '我是可选择的标签1', ]; - List items = List(); + List items = []; for (int i = 0; i < tags.length; i++) { String it = tags[i]; - BrnTagInputItemBean item = BrnTagInputItemBean(name: it, index: i, needExplane: (i % 2 == 0)); + BrnTagInputItemBean item = BrnTagInputItemBean(name: it, index: i, needExpend: (i % 2 == 0)); items.add(item); } @@ -369,8 +371,8 @@ class PickerEntryPage extends StatelessWidget { tagItemSource: items, tagTitleFontSize: 12, tagTitleColor: Color(0xff222222), - tagBackgroudColor: Color(0xffF8F8F8), - selectedTagBackgroudColor: Color(0x140984F9), + tagBackgroundColor: Color(0xffF8F8F8), + selectedTagBackgroundColor: Color(0x140984F9), selectedTagTitleColor: Color(0xFF0984F9), ), onTagValueGetter: (choice) { diff --git a/example/lib/sample/components/popup/overlay_window_example.dart b/example/lib/sample/components/popup/overlay_window_example.dart index cad07a2c..458ba188 100644 --- a/example/lib/sample/components/popup/overlay_window_example.dart +++ b/example/lib/sample/components/popup/overlay_window_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -11,9 +13,9 @@ class OverlayWindowExample extends StatefulWidget { } class OverlayWindowExamplePageState extends State { - BrnOverlayController _overlayController; - var _focusNode = FocusNode(); - var _searchBarKey = GlobalKey(); + BrnOverlayController? _overlayController; + FocusNode _focusNode = FocusNode(); + GlobalKey _searchBarKey = GlobalKey(); @override void initState() { @@ -66,7 +68,7 @@ class OverlayWindowExamplePageState extends State { _overlayController?.removeOverlay(); return; } - if (_overlayController == null || _overlayController.isOverlayShowing == false) { + if (_overlayController == null || _overlayController!.isOverlayShowing == false) { _overlayController = BrnOverlayWindow.showOverlayWindow(context, _searchBarKey, content: _sugListView(), autoDismissOnTouchOutSide: true, diff --git a/example/lib/sample/components/popup/popwindow_example.dart b/example/lib/sample/components/popup/popwindow_example.dart index cb01d1d6..0645716f 100644 --- a/example/lib/sample/components/popup/popwindow_example.dart +++ b/example/lib/sample/components/popup/popwindow_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -11,19 +13,19 @@ class PopWindowExamplePage extends StatefulWidget { } class PopWindowExamplePageState extends State { - GlobalKey _leftKeylist0; - GlobalKey _leftKeylist1; - GlobalKey _leftKeylist2; - GlobalKey _leftKey; - GlobalKey _leftKey1; - GlobalKey _leftKey2; - GlobalKey _leftKey3; - GlobalKey _leftKey4; - GlobalKey _leftKey5; - GlobalKey _leftKey6; - GlobalKey _leftKey7; + GlobalKey? _leftKeylist0; + GlobalKey? _leftKeylist1; + GlobalKey? _leftKeylist2; + GlobalKey? _leftKey; + GlobalKey? _leftKey1; + GlobalKey? _leftKey2; + GlobalKey? _leftKey3; + GlobalKey? _leftKey4; + GlobalKey? _leftKey5; + GlobalKey? _leftKey6; + GlobalKey? _leftKey7; - BrnOverlayController overlayController; + BrnOverlayController? overlayController; @override void initState() { @@ -43,7 +45,6 @@ class PopWindowExamplePageState extends State { @override Widget build(BuildContext context) { - double top = MediaQuery.of(context).padding.top ?? 0; return Scaffold( appBar: BrnAppBar( title: widget._title, @@ -57,7 +58,7 @@ class PopWindowExamplePageState extends State { child: RaisedButton( key: _leftKey, onPressed: () { - BrnPopupWindow.showPopWindow(context, "提示内容", _leftKey, + BrnPopupWindow.showPopWindow(context, "提示内容", _leftKey!, hasCloseIcon: true); }, child: Text("左侧带关闭Tips"), @@ -68,7 +69,7 @@ class PopWindowExamplePageState extends State { child: RaisedButton( key: _leftKey1, onPressed: () { - BrnPopupWindow.showPopWindow(context, "提示内容提示内容提示内容提示内容提示内容提示内容提示内容提示内容", _leftKey1, + BrnPopupWindow.showPopWindow(context, "提示内容提示内容提示内容提示内容提示内容提示内容提示内容提示内容", _leftKey1!, hasCloseIcon: false); }, child: Text("左侧带无关闭Tips"), @@ -79,7 +80,7 @@ class PopWindowExamplePageState extends State { child: RaisedButton( key: _leftKey2, onPressed: () { - BrnPopupWindow.showPopWindow(context, "提示内容提示内容提示内容提示内容提示内容提示内容提示内容提示内容提示内容", _leftKey2, + BrnPopupWindow.showPopWindow(context, "提示内容提示内容提示内容提示内容提示内容提示内容提示内容提示内容提示内容", _leftKey2!, popDirection: BrnPopupDirection.top, hasCloseIcon: true); }, child: Text("左侧带关闭,箭头朝下Tips"), @@ -90,7 +91,7 @@ class PopWindowExamplePageState extends State { child: RaisedButton( key: _leftKey3, onPressed: () { - BrnPopupWindow.showPopWindow(context, "提示内容提示内容提示内容提示内容提示内容提示内容提示内容提示内容", _leftKey3, + BrnPopupWindow.showPopWindow(context, "提示内容提示内容提示内容提示内容提示内容提示内容提示内容提示内容", _leftKey3!, dismissCallback: () {}, popDirection: BrnPopupDirection.top); }, child: Text("左侧无关闭,箭头朝下Tips"), @@ -101,7 +102,7 @@ class PopWindowExamplePageState extends State { child: RaisedButton( key: _leftKey4, onPressed: () { - BrnPopupWindow.showPopWindow(context, "提示内容提示内容提示内容提示内容提示内容提示内容提示内容提示内容", _leftKey4, + BrnPopupWindow.showPopWindow(context, "提示内容提示内容提示内容提示内容提示内容提示内容提示内容提示内容", _leftKey4!, hasCloseIcon: true, dismissCallback: () {}, popDirection: BrnPopupDirection.bottom); @@ -114,7 +115,7 @@ class PopWindowExamplePageState extends State { child: RaisedButton( key: _leftKey5, onPressed: () { - BrnPopupWindow.showPopWindow(context, "提示内容提示内容提示内容提示内容", _leftKey5, + BrnPopupWindow.showPopWindow(context, "提示内容提示内容提示内容提示内容", _leftKey5!, hasCloseIcon: false, dismissCallback: () {}, popDirection: BrnPopupDirection.bottom); @@ -127,7 +128,7 @@ class PopWindowExamplePageState extends State { child: RaisedButton( key: _leftKey6, onPressed: () { - BrnPopupWindow.showPopWindow(context, "提示内容提示内容提示内容提示内容提示内容提示内容", _leftKey6, + BrnPopupWindow.showPopWindow(context, "提示内容提示内容提示内容提示内容提示内容提示内容", _leftKey6!, hasCloseIcon: true, canWrap: false, dismissCallback: () {}, @@ -141,7 +142,7 @@ class PopWindowExamplePageState extends State { child: RaisedButton( key: _leftKey7, onPressed: () { - BrnPopupWindow.showPopWindow(context, "提示内容提示内容提示内容提示内容提示内容提示内容", _leftKey7, + BrnPopupWindow.showPopWindow(context, "提示内容提示内容提示内容提示内容提示内容提示内容", _leftKey7!, hasCloseIcon: false, dismissCallback: () {}, popDirection: BrnPopupDirection.top); diff --git a/example/lib/sample/components/rating/rating_example.dart b/example/lib/sample/components/rating/rating_example.dart index 4c1addfc..61acdb71 100644 --- a/example/lib/sample/components/rating/rating_example.dart +++ b/example/lib/sample/components/rating/rating_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -72,12 +74,12 @@ class _RatingExampleState extends State { Widget _buildRating(RatingState state) { switch (state) { case RatingState.select: - return BrunoTools.getAssetSizeImage(BrnAsset.ICON_STAR, 16, 16, color: Color(0xFF3571DC)); + return BrunoTools.getAssetSizeImage(BrnAsset.iconStar, 16, 16, color: Color(0xFF3571DC)); case RatingState.half: - return BrunoTools.getAssetSizeImage(BrnAsset.ICON_STAR_HALF, 16, 16); + return BrunoTools.getAssetSizeImage(BrnAsset.iconStarHalf, 16, 16); case RatingState.unselect: default: - return BrunoTools.getAssetSizeImage(BrnAsset.ICON_STAR, 16, 16, color: Color(0xFFF0F0F0)); + return BrunoTools.getAssetSizeImage(BrnAsset.iconStar, 16, 16, color: Color(0xFFF0F0F0)); } } } diff --git a/example/lib/sample/components/scroll_anchor/scroll_actor_tab_example.dart b/example/lib/sample/components/scroll_anchor/scroll_actor_tab_example.dart index 9060636a..ffba733b 100644 --- a/example/lib/sample/components/scroll_anchor/scroll_actor_tab_example.dart +++ b/example/lib/sample/components/scroll_anchor/scroll_actor_tab_example.dart @@ -1,3 +1,5 @@ + + import 'dart:math'; import 'package:bruno/bruno.dart'; diff --git a/example/lib/sample/components/selectcity/selected_city_example.dart b/example/lib/sample/components/selectcity/selected_city_example.dart index 9082bd77..0f6fdfb6 100644 --- a/example/lib/sample/components/selectcity/selected_city_example.dart +++ b/example/lib/sample/components/selectcity/selected_city_example.dart @@ -1,3 +1,5 @@ + + import 'dart:convert'; import 'package:bruno/bruno.dart'; @@ -13,8 +15,8 @@ class CitySelectRoute extends StatefulWidget { } class _CitySelectRouteState extends State { - List _cityList = List(); - List _hotCityList = List(); + List _cityList = []; + List _hotCityList = []; int _suspensionHeight = 40; int _itemHeight = 50; @@ -44,7 +46,7 @@ class _CitySelectRouteState extends State { } void _handleList(List list) { - if (list == null || list.isEmpty) return; + if (list.isEmpty) return; for (int i = 0, length = list.length; i < length; i++) { String pinyin = PinyinHelper.getPinyinE(list[i].name); String tag = pinyin.substring(0, 1).toUpperCase(); @@ -132,7 +134,7 @@ class _CitySelectRouteState extends State { flex: 1, child: AzListView( data: _cityList, - itemBuilder: (context, model) => _buildListItem(model), + itemBuilder: (context, model) => _buildListItem(model as BrnSelectCityModel), suspensionWidget: _buildSusWidget(_suspensionTag), isUseRealIndex: true, itemHeight: _itemHeight, diff --git a/example/lib/sample/components/selection/filter_entity.dart b/example/lib/sample/components/selection/filter_entity.dart index 23f2d8e5..50d19dfb 100644 --- a/example/lib/sample/components/selection/filter_entity.dart +++ b/example/lib/sample/components/selection/filter_entity.dart @@ -1,17 +1,17 @@ + + import 'package:bruno/bruno.dart'; class BrnFilterEntity { - String key; - String name; - String defaultValue; - List children; + String? key; + late String name; + String? defaultValue; + late List children; BrnFilterEntity.fromJson(Map map) { - if (map == null) return; - key = map['key'] ?? ""; - name = map['title'] ?? ""; - defaultValue = map['defaultValue'] ?? ""; - children = List() - ..addAll((map['children'] as List ?? []).map((o) => ItemEntity.fromJson(o))); + key = map['key'] ?? ''; + name = map['title'] ?? ''; + defaultValue = map['defaultValue'] ?? ''; + children = []..addAll((map['children'] as List? ?? []).map((o) => ItemEntity.fromJson(o))); } } diff --git a/example/lib/sample/components/selection/flat_selection_five_tags_example.dart b/example/lib/sample/components/selection/flat_selection_five_tags_example.dart index e4e7f2e6..6cd63d43 100644 --- a/example/lib/sample/components/selection/flat_selection_five_tags_example.dart +++ b/example/lib/sample/components/selection/flat_selection_five_tags_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -12,11 +14,11 @@ class NewSelectionViewExamplePage23 extends StatefulWidget { } class _SelectionViewExamplePageState extends State { - BrnSelectionEntity entity; + BrnSelectionEntity? entity; - BrnFlatSelectionController controller; + BrnFlatSelectionController? controller; - var selectionKey = GlobalKey(); + GlobalKey selectionKey = GlobalKey(); bool _isShow = true; @@ -29,7 +31,7 @@ class _SelectionViewExamplePageState extends State { - BrnSelectionEntity entity; + BrnSelectionEntity? entity; - BrnFlatSelectionController controller; + BrnFlatSelectionController? controller; var selectionKey = GlobalKey(); @@ -29,7 +31,7 @@ class _SelectionViewExamplePageState extends State @override void dispose() { - controller.dispose(); + controller!.dispose(); controller = null; super.dispose(); } @@ -109,7 +111,7 @@ class _SelectionViewExamplePageState extends State ), onTap: () { if (controller != null) { - controller.resetSelectedOptions(); + controller!.resetSelectedOptions(); } }, ), @@ -122,7 +124,7 @@ class _SelectionViewExamplePageState extends State title: "取消", onTap: () { if (controller != null) { - controller.cancelSelectedOptions(); + controller!.cancelSelectedOptions(); setState(() { _isShow = false; }); @@ -136,7 +138,7 @@ class _SelectionViewExamplePageState extends State title: "确定", onTap: () { if (controller != null) { - controller.confirmSelectedOptions(); + controller!.confirmSelectedOptions(); setState(() { _isShow = false; }); diff --git a/example/lib/sample/components/selection/flat_selection_three_tags_example.dart b/example/lib/sample/components/selection/flat_selection_three_tags_example.dart index 16de0f0a..73f60dbc 100644 --- a/example/lib/sample/components/selection/flat_selection_three_tags_example.dart +++ b/example/lib/sample/components/selection/flat_selection_three_tags_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -12,9 +14,9 @@ class FlatSelectionThreeTagsExample extends StatefulWidget { } class _SelectionViewExamplePageState extends State { - BrnSelectionEntity entity; + BrnSelectionEntity? entity; - BrnFlatSelectionController controller; + BrnFlatSelectionController? controller; var selectionKey = GlobalKey(); @@ -29,7 +31,7 @@ class _SelectionViewExamplePageState extends State 0) { @@ -56,7 +58,7 @@ class FlatSelectionEntryPage extends StatelessWidget { onPressed: () { rootBundle.loadString('assets/flat_selection_filter.json').then((data) { var datas = - BrnSelectionEntityListBean.fromMap(JsonDecoder().convert(data)["data"]).list; + BrnSelectionEntityListBean.fromJson(JsonDecoder().convert(data)["data"])!.list!; void _configMaxSelectedCount(BrnSelectionEntity entity, int maxCount) { entity.maxSelectedCount = maxCount; if (entity.children != null && entity.children.length > 0) { @@ -81,7 +83,7 @@ class FlatSelectionEntryPage extends StatelessWidget { onPressed: () { rootBundle.loadString('assets/flat_selection_filter.json').then((data) { var datas = - BrnSelectionEntityListBean.fromMap(JsonDecoder().convert(data)["data"]).list; + BrnSelectionEntityListBean.fromJson(JsonDecoder().convert(data)["data"])!.list!; void _configMaxSelectedCount(BrnSelectionEntity entity, int maxCount) { entity.maxSelectedCount = maxCount; if (entity.children != null && entity.children.length > 0) { diff --git a/example/lib/sample/components/selection/selectionview_custom_floating_layer_example.dart b/example/lib/sample/components/selection/selectionview_custom_floating_layer_example.dart index 016d6571..e01167c2 100644 --- a/example/lib/sample/components/selection/selectionview_custom_floating_layer_example.dart +++ b/example/lib/sample/components/selection/selectionview_custom_floating_layer_example.dart @@ -1,10 +1,12 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/components/card/bubble/common_bubble_example.dart'; import 'package:flutter/material.dart'; class SelectionViewMoreCustomFloatLayerExamplePage extends StatefulWidget { final String _title; - final List _filterData; + final List? _filterData; SelectionViewMoreCustomFloatLayerExamplePage(this._title, this._filterData); @@ -13,9 +15,9 @@ class SelectionViewMoreCustomFloatLayerExamplePage extends StatefulWidget { } class _SelectionViewExamplePageState extends State { - List items; + List? items; - BrnSelectionViewController controller; + BrnSelectionViewController? controller; var selectionKey = GlobalKey(); @@ -44,14 +46,14 @@ class _SelectionViewExamplePageState extends State result = Map(); result['Key1'] = 'Value1'; result['Key2'] = 'Value2'; - List resultEntity = List(); - result?.forEach((userId, userName) { + List resultEntity = []; + result.forEach((userId, userName) { resultEntity.add(BrnSelectionEntity( value: userId, title: userName, isSelected: true, type: 'radio')); }); diff --git a/example/lib/sample/components/selection/selectionview_customhandle_filter_example_page.dart b/example/lib/sample/components/selection/selectionview_customhandle_filter_example_page.dart index ae7f7681..7e122c0b 100644 --- a/example/lib/sample/components/selection/selectionview_customhandle_filter_example_page.dart +++ b/example/lib/sample/components/selection/selectionview_customhandle_filter_example_page.dart @@ -1,9 +1,11 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; class SelectionViewCustomHandleFilterExamplePage extends StatefulWidget { final String _title; - final List _filters; + final List? _filters; SelectionViewCustomHandleFilterExamplePage(this._title, this._filters); @@ -26,7 +28,7 @@ class _SelectionViewExamplePageState extends State[ BrnSelectionView( - originalSelectionData: widget._filters, + originalSelectionData: widget._filters!, onCustomSelectionMenuClick: (int index, BrnSelectionEntity customMenuItem, BrnSetCustomSelectionParams customHandleCallBack) { /// 用户操作一段时间之后,将自定义参数回传,触发 onSelectionChanged回调。 @@ -40,7 +42,7 @@ class _SelectionViewExamplePageState extends State filterParams, Map customParams, BrnSetCustomSelectionMenuTitle setCustomTitleFunction) { - if (menuIndex == 1 && setCustomTitleFunction != null) { + if (menuIndex == 1) { setCustomTitleFunction( menuTitle: BrunoTools.isEmpty(customParams) ? "" : customParams['CKey'] ?? "", isMenuTitleHighLight: !BrunoTools.isEmpty(customParams['CKey'])); diff --git a/example/lib/sample/components/selection/selectionview_customview_example_page.dart b/example/lib/sample/components/selection/selectionview_customview_example_page.dart index d2e9475a..e84b04ef 100644 --- a/example/lib/sample/components/selection/selectionview_customview_example_page.dart +++ b/example/lib/sample/components/selection/selectionview_customview_example_page.dart @@ -1,9 +1,11 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; class SelectionViewCustomViewExamplePage extends StatefulWidget { final String _title; - final List _filters; + final List? _filters; SelectionViewCustomViewExamplePage(this._title, this._filters); @@ -12,11 +14,11 @@ class SelectionViewCustomViewExamplePage extends StatefulWidget { } class _SelectionViewExamplePageState extends State { - List _filterData; + List? _filterData; var selectionKey = GlobalKey(); bool isCustomFilterViewShow = false; - OverlayEntry filterViewEntry; + OverlayEntry? filterViewEntry; /// 筛选组件的回调函数,用于把用户选中的参数回传给筛选组件,同意在 onSelectionChanged 回调处理。 参数在 customParams 中存储 var _customHandleCallBack; @@ -25,13 +27,13 @@ class _SelectionViewExamplePageState extends State _currentCalendarSelectedDate; + late ValueNotifier _currentCalendarSelectedDate; String _dateForamt = 'yyyy-MM-dd HH:mm:ss'; - _SelectionViewExamplePageState(List filters) { + _SelectionViewExamplePageState(List? filters) { _filterData = filters; } @@ -58,14 +60,14 @@ class _SelectionViewExamplePageState extends State[ ValueListenableBuilder( valueListenable: _currentCalendarSelectedDate, - builder: (context, value, widget) { - return BrnCalendarView( + builder: (context, dynamic value, widget) { + return BrnCalendarView.single( initStartSelectedDate: _currentCalendarSelectedDate.value, initEndSelectedDate: _currentCalendarSelectedDate.value, - startEndDateChange: (_, __) { + dateChange: (_){ _currentCalendarSelectedDate.value = _; }); }, @@ -186,7 +188,7 @@ class _SelectionViewExamplePageState extends State() - : {'date': _currentCalendarSelectedDate.value.toString() ?? ''}); + : {'date': _currentCalendarSelectedDate.value.toString()}); _filterSelectedDate = _currentCalendarSelectedDate.value?.toString(); closeCustomFilterView(); }, @@ -199,8 +201,8 @@ class _SelectionViewExamplePageState extends State { - List _filterData; + late List _filterData; _SelectionViewExamplePageState(List filters) { _filterData = filters; diff --git a/example/lib/sample/components/selection/selectionview_date_range_example_page.dart b/example/lib/sample/components/selection/selectionview_date_range_example_page.dart index dbec59e6..25979345 100644 --- a/example/lib/sample/components/selection/selectionview_date_range_example_page.dart +++ b/example/lib/sample/components/selection/selectionview_date_range_example_page.dart @@ -1,9 +1,11 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; class SelectionViewDateRangeExamplePage extends StatefulWidget { final String _title; - final List _filterData; + final List? _filterData; SelectionViewDateRangeExamplePage(this._title, this._filterData); @@ -12,9 +14,9 @@ class SelectionViewDateRangeExamplePage extends StatefulWidget { } class _SelectionViewExamplePageState extends State { - List items; + List? items; - BrnSelectionViewController controller; + BrnSelectionViewController? controller; @override void initState() { @@ -41,13 +43,13 @@ class _SelectionViewExamplePageState extends State filterParams, Map customParams, @@ -56,9 +58,9 @@ class _SelectionViewExamplePageState extends State _filterData; + final List? _filterData; SelectionViewCloseOrInterceptorExamplePage(this._title, this._filterData); @@ -12,9 +14,9 @@ class SelectionViewCloseOrInterceptorExamplePage extends StatefulWidget { } class _SelectionViewExamplePageState extends State { - List items; + List? items; - BrnSelectionViewController controller; + BrnSelectionViewController? controller; @override void initState() { @@ -36,7 +38,7 @@ class _SelectionViewExamplePageState extends State filterParams, Map customParams, BrnSetCustomSelectionMenuTitle setCustomTitleFunction) { - BrnToast.show(filterParams.toString(), context); + BrnToast.show('选中 ${filterParams.toString()},但筛选条件被清除了', context); if (menuIndex == 1 && filterParams != null && filterParams['two_list_key'] != null) { - widget._filterData[1].clearChildSelection(); - widget._filterData[1].configRelationshipAndDefaultValue(); - controller.refreshSelectionTitle(); + widget._filterData![1].clearChildSelection(); + widget._filterData![1].configRelationshipAndDefaultValue(); + controller!.refreshSelectionTitle(); } }, onMenuClickInterceptor: (index) { diff --git a/example/lib/sample/components/selection/selectionview_limit_max_selected_count_example.dart b/example/lib/sample/components/selection/selectionview_limit_max_selected_count_example.dart index d70a16b2..acf53e3a 100644 --- a/example/lib/sample/components/selection/selectionview_limit_max_selected_count_example.dart +++ b/example/lib/sample/components/selection/selectionview_limit_max_selected_count_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -12,9 +14,9 @@ class SelectionViewLimitMaxSelectedCountExamplePage extends StatefulWidget { } class _SelectionViewExamplePageState extends State { - List items; + List? items; - BrnSelectionViewController controller; + BrnSelectionViewController? controller; @override void initState() { @@ -41,7 +43,7 @@ class _SelectionViewExamplePageState extends State _filters; + final List? _filters; SelectionViewMoreFilterExamplePage(this._title, this._filters); @@ -27,7 +29,7 @@ class _SelectionViewExamplePageState extends State[ BrnSelectionView( - originalSelectionData: widget._filters, + originalSelectionData: widget._filters!, onMoreSelectionMenuClick: (int index, BrnOpenMorePage openMore) { openMore(updateData: false); }, diff --git a/example/lib/sample/components/selection/selectionview_multi_list_example_page.dart b/example/lib/sample/components/selection/selectionview_multi_list_example_page.dart index 3d3c6172..bb5937fa 100644 --- a/example/lib/sample/components/selection/selectionview_multi_list_example_page.dart +++ b/example/lib/sample/components/selection/selectionview_multi_list_example_page.dart @@ -1,9 +1,11 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; class SelectionViewMultiListExamplePage extends StatefulWidget { final String _title; - final List _filterData; + final List? _filterData; SelectionViewMultiListExamplePage(this._title, this._filterData); @@ -12,7 +14,7 @@ class SelectionViewMultiListExamplePage extends StatefulWidget { } class _SelectionViewExamplePageState extends State { - List items; + List? items; @override void initState() { @@ -26,7 +28,7 @@ class _SelectionViewExamplePageState extends State[ BrnSelectionView( - originalSelectionData: widget._filterData, + originalSelectionData: widget._filterData!, onSelectionChanged: (int menuIndex, Map filterParams, Map customParams, diff --git a/example/lib/sample/components/selection/selectionview_multi_range_example_page.dart b/example/lib/sample/components/selection/selectionview_multi_range_example_page.dart index bd5555de..f9594e28 100644 --- a/example/lib/sample/components/selection/selectionview_multi_range_example_page.dart +++ b/example/lib/sample/components/selection/selectionview_multi_range_example_page.dart @@ -1,9 +1,11 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; class SelectionViewMultiRangeExamplePage extends StatefulWidget { final String _title; - final List _filters; + final List? _filters; SelectionViewMultiRangeExamplePage(this._title, this._filters); @@ -12,7 +14,7 @@ class SelectionViewMultiRangeExamplePage extends StatefulWidget { } class _SelectionViewExamplePageState extends State { - List titles; + List? titles; @override void initState() { @@ -26,7 +28,7 @@ class _SelectionViewExamplePageState extends State[ BrnSelectionView( - originalSelectionData: widget._filters, + originalSelectionData: widget._filters!, onSelectionChanged: (int menuIndex, Map filterParams, Map customParams, @@ -35,9 +37,9 @@ class _SelectionViewExamplePageState extends State { - List items; + List? items; @override void initState() { @@ -28,7 +30,7 @@ class _SelectionViewExamplePageState extends State[ BrnSimpleSelection.checkbox( menuName: widget._filterData.name, - menuKey: widget._filterData.key ?? defaultMenuKey, + menuKey: widget._filterData.key ?? 'defaultMenuKey', items: widget._filterData.children, maxSelectedCount: 4, defaultValue: widget._filterData.defaultValue, diff --git a/example/lib/sample/components/selection/selectionview_simple_single_list_example_page.dart b/example/lib/sample/components/selection/selectionview_simple_single_list_example_page.dart index b05f00ef..3ef33f9e 100755 --- a/example/lib/sample/components/selection/selectionview_simple_single_list_example_page.dart +++ b/example/lib/sample/components/selection/selectionview_simple_single_list_example_page.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/components/selection/filter_entity.dart'; import 'package:flutter/material.dart'; @@ -13,7 +15,7 @@ class SelectionViewSimpleSingleListExamplePage extends StatefulWidget { } class _SelectionViewExamplePageState extends State { - List items; + List? items; @override void initState() { @@ -28,7 +30,7 @@ class _SelectionViewExamplePageState extends State[ BrnSimpleSelection.radio( menuName: widget._filterData.name, - menuKey: widget._filterData.key ?? defaultMenuKey, + menuKey: widget._filterData.key ?? 'defaultMenuKey', items: widget._filterData.children, defaultValue: widget._filterData.defaultValue, onSimpleSelectionChanged: ( diff --git a/example/lib/sample/components/step/brn_horizontal_step_example.dart b/example/lib/sample/components/step/brn_horizontal_step_example.dart index 5f92beb6..f65c31de 100644 --- a/example/lib/sample/components/step/brn_horizontal_step_example.dart +++ b/example/lib/sample/components/step/brn_horizontal_step_example.dart @@ -4,7 +4,8 @@ import 'package:flutter/material.dart'; class BrnHorizontalStepExamplePage extends StatefulWidget { final String title; - BrnHorizontalStepExamplePage({this.title}); + const BrnHorizontalStepExamplePage({Key? key, required this.title}) + : super(key: key); @override State createState() { @@ -12,49 +13,164 @@ class BrnHorizontalStepExamplePage extends StatefulWidget { } } -class BrnHorizontalStepExamplePageState extends State { - int _index; - BrnHorizontalStepsManager _stepsManager = BrnHorizontalStepsManager(); +class BrnHorizontalStepExamplePageState + extends State { + late int _index; + double sliderValue = 2; + late BrnStepsController _controller; + late ValueNotifier valueNotifier; @override void initState() { - _index = 1; super.initState(); + _index = 0; + _controller = BrnStepsController(currentIndex: _index); + valueNotifier = ValueNotifier(sliderValue); } @override Widget build(BuildContext context) { return Scaffold( - appBar: BrnAppBar( - title: widget.title, - actions: controlSteps(context), - ), - body: _stepsManager.buildSteps(currentIndex: _index, isCompleted: false, steps: [ - BrunoStep( - stepContentText: "文案步骤", + appBar: BrnAppBar(title: widget.title), + body: Column( + children: [ + SliverBrnHorizontalStep( + controller: _controller, + valueNotifier: valueNotifier, ), - BrunoStep( - stepContentText: "文案步骤", + const Text('步骤个数:'), + SliderWidget( + initValue: sliderValue, + valueNotifier: valueNotifier, ), - BrunoStep( - stepContentText: "文案步骤", + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + ElevatedButton( + child: const Text('上一步'), + onPressed: () { + _controller.backStep(); + }, + ), + ElevatedButton( + child: const Text('下一步'), + onPressed: () { + _controller.forwardStep(); + }, + ), + ], ), - BrunoStep( - stepContentText: "文案步骤", + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + ElevatedButton( + child: const Text('跳至第3步'), + onPressed: () { + _controller.setCurrentIndex(2); + }, + ), + ElevatedButton( + child: const Text('完成'), + onPressed: () { + _controller.setCompleted(); + }, + ), + ], ), - ])); + ], + ), + ); } +} + +/// 自定义 widget +class SliderWidget extends StatefulWidget { + const SliderWidget({ + Key? key, + required this.initValue, + required this.valueNotifier, + }) : super(key: key); + final double initValue; + final ValueNotifier valueNotifier; + + @override + _SliderWidgetState createState() => _SliderWidgetState(); +} + +class _SliderWidgetState extends State { + late double sliderValue; + + @override + void initState() { + super.initState(); + sliderValue = widget.initValue; + } + + @override + Widget build(BuildContext context) { + return Slider( + value: sliderValue, + min: 2, + max: 5, + divisions: 3, + onChanged: (value) { + setState(() { + sliderValue = value; + widget.valueNotifier.value = value; + }); + }, + ); + } +} - List controlSteps(BuildContext context) { - List result = List(); +/// 自定义 widget +class SliverBrnHorizontalStep extends StatefulWidget { + const SliverBrnHorizontalStep({ + Key? key, + required this.controller, + required this.valueNotifier, + }) : super(key: key); + final BrnStepsController controller; + final ValueNotifier valueNotifier; - result.add(BrnTextAction("上一步", iconPressed: () { - _stepsManager.backStep(); - })); + @override + _SliverBrnHorizontalStepsState createState() => _SliverBrnHorizontalStepsState(); +} + +class _SliverBrnHorizontalStepsState extends State { + List brunoSteps() { + final List _list = []; + final int value = widget.valueNotifier.value.toInt(); + for (int i = 0; i < value; i++) { + _list.add(BrunoStep(stepContentText: ('第你好11${i + 1}步'))); + } + return _list; + } + + void _onChange() { + setState(() { + brunoSteps(); + widget.controller.setCurrentIndex(0); + }); + } + + @override + void initState() { + super.initState(); + widget.valueNotifier.addListener(_onChange); + } + + @override + void dispose() { + widget.valueNotifier.removeListener(_onChange); + super.dispose(); + } - result.add(BrnTextAction("下一步", iconPressed: () { - _stepsManager.forwardStep(); - })); - return result; + @override + Widget build(BuildContext context) { + return BrnHorizontalSteps( + steps: brunoSteps(), + controller: widget.controller, + ); } } diff --git a/example/lib/sample/components/step/step_example.dart b/example/lib/sample/components/step/step_example.dart index b07eee16..9d493417 100644 --- a/example/lib/sample/components/step/step_example.dart +++ b/example/lib/sample/components/step/step_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/components/step/brn_horizontal_step_example.dart'; import 'package:example/sample/components/step/step_line_example.dart'; diff --git a/example/lib/sample/components/step/step_line_example.dart b/example/lib/sample/components/step/step_line_example.dart index 7e2ad87f..d189385c 100644 --- a/example/lib/sample/components/step/step_line_example.dart +++ b/example/lib/sample/components/step/step_line_example.dart @@ -1,15 +1,19 @@ + + import 'dart:math'; import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; class StepLineExample extends StatefulWidget { + const StepLineExample({Key? key}) : super(key: key); + @override _StepLineExampleState createState() => _StepLineExampleState(); } class _StepLineExampleState extends State { - int count; + int? count; @override void initState() { @@ -32,24 +36,30 @@ class _StepLineExampleState extends State { Text( '规则', style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, fontSize: 28, fontWeight: FontWeight.bold), ), - BrnBubbleText( + const BrnBubbleText( maxLines: 2, text: '头部icon需要显示主题相关的icon,线条需要时圆头\n,' '线条的高度随着左侧内容变化而改变,线宽2'), Text( '第一个高亮', style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, fontSize: 16, ), ), ListView.builder( - padding: EdgeInsets.only(top: 20), - physics: NeverScrollableScrollPhysics(), + padding: const EdgeInsets.only(top: 20), + physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: 3, itemBuilder: (context, index) { @@ -57,10 +67,12 @@ class _StepLineExampleState extends State { lineWidth: 1, //非第一个是灰色 isGrey: index != 0, + iconTopPadding: 20, //最后一个的线条为透明色 做到不显示的效果 - lineColor: index == 2 ? Colors.transparent : Color(0xffeeeeee), + lineColor: + index == 2 ? Colors.transparent : const Color(0xffeeeeee), contentWidget: Container( - padding: EdgeInsets.only(left: 8), + padding: const EdgeInsets.only(left: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -97,13 +109,16 @@ class _StepLineExampleState extends State { Text( '最后一个灰色', style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, fontSize: 16, ), ), ListView.builder( - padding: EdgeInsets.only(top: 20), - physics: NeverScrollableScrollPhysics(), + padding: const EdgeInsets.only(top: 20), + physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: 3, itemBuilder: (context, index) { @@ -113,10 +128,12 @@ class _StepLineExampleState extends State { isGrey: index == 2, //最后一个的线条为透明色 做到不显示的效果 lineColor: index == 2 ? Colors.transparent : null, - highlightColor: - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + highlightColor: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, contentWidget: Container( - padding: EdgeInsets.only(left: 8), + padding: const EdgeInsets.only(left: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -153,74 +170,86 @@ class _StepLineExampleState extends State { Text( '颜色线条变化', style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, - fontSize: 16, - ), - ), -ListView.builder( - padding: EdgeInsets.only(top: 20), - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: 3, - itemBuilder: (context, index) { - return BrnStepLine( - lineWidth: 1, - //最后一个的线条为透明色 做到不显示的效果 - lineColor: index == 2 - ? Colors.transparent - : (index == 1 - ? [ - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, - Colors.red - ] - : null), - highlightColor: index == 2 - ? Colors.red - : BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, - contentWidget: Container( - padding: EdgeInsets.only(left: 8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '步骤${index + 1}', - style: TextStyle( - height: 0.9, color: BrnThemeConfigurator.instance .getConfig() .commonConfig - .colorTextBase, + .brandPrimary, fontSize: 16, ), ), - Padding( - padding: const EdgeInsets.only(top: 20, bottom: 20), - child: Text( - '辅助信息', - style: TextStyle( - color: BrnThemeConfigurator.instance + ListView.builder( + padding: const EdgeInsets.only(top: 20), + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: 3, + itemBuilder: (context, index) { + return BrnStepLine( + lineWidth: 1, + //最后一个的线条为透明色 做到不显示的效果 + lineColor: index == 2 + ? Colors.transparent + : (index == 1 + ? [ + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, + Colors.red + ] + : null), + highlightColor: index == 2 + ? Colors.red + : BrnThemeConfigurator.instance .getConfig() .commonConfig - .colorTextSecondary, - fontSize: 14, - ), - ), - ) - ], - ), - ), - ); - }, -), + .brandPrimary, + contentWidget: Container( + padding: const EdgeInsets.only(left: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '步骤${index + 1}', + style: TextStyle( + height: 0.9, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, + fontSize: 16, + ), + ), + Padding( + padding: const EdgeInsets.only(top: 20, bottom: 20), + child: Text( + '辅助信息', + style: TextStyle( + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextSecondary, + fontSize: 14, + ), + ), + ) + ], + ), + ), + ); + }, + ), Text( '全灰色', style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, fontSize: 16, ), ), ListView.builder( - physics: NeverScrollableScrollPhysics(), + physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: 5, itemBuilder: (context, index) { @@ -237,13 +266,16 @@ ListView.builder( Text( '最后一条不显示', style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, fontSize: 16, ), ), ListView.builder( shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), + physics: const NeverScrollableScrollPhysics(), itemCount: 5, itemBuilder: (context, index) { if (index == 4) { @@ -268,20 +300,26 @@ ListView.builder( Text( '线条颜色有变化', style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, fontSize: 16, ), ), ListView.builder( shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), + physics: const NeverScrollableScrollPhysics(), itemCount: 5, itemBuilder: (context, index) { if (index == 4) { return BrnStepLine( lineWidth: 1, lineColor: [ - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, Colors.red, ], contentWidget: Container( @@ -302,19 +340,25 @@ ListView.builder( Text( '虚线显示', style: TextStyle( - color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, fontSize: 16, ), ), ListView.builder( shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), + physics: const NeverScrollableScrollPhysics(), itemCount: 5, itemBuilder: (context, index) { return BrnStepLine( lineWidth: 1, lineColor: [ - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, Colors.red, ], isDashLine: true, @@ -334,12 +378,15 @@ ListView.builder( dynamic getLineColor(int index) { return index == 1 - ? [BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, Colors.red] - : (index == 2 ? Colors.transparent : Color(0xffeeeeee)); + ? [ + BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + Colors.red + ] + : (index == 2 ? Colors.transparent : const Color(0xffeeeeee)); } Color getRandomColor() { - return Color.fromARGB( - Random().nextInt(255), Random().nextInt(255), Random().nextInt(255), Random().nextInt(255)); + return Color.fromARGB(Random().nextInt(255), Random().nextInt(255), + Random().nextInt(255), Random().nextInt(255)); } } diff --git a/example/lib/sample/components/sugsearch/search_text_example.dart b/example/lib/sample/components/sugsearch/search_text_example.dart index d29ebe20..1347faff 100644 --- a/example/lib/sample/components/sugsearch/search_text_example.dart +++ b/example/lib/sample/components/sugsearch/search_text_example.dart @@ -1,3 +1,4 @@ + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/switch/checkbox_example.dart b/example/lib/sample/components/switch/checkbox_example.dart index 33894921..d7ad41ba 100644 --- a/example/lib/sample/components/switch/checkbox_example.dart +++ b/example/lib/sample/components/switch/checkbox_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/switch/radio_example.dart b/example/lib/sample/components/switch/radio_example.dart index a07db2f1..08fb1ce2 100644 --- a/example/lib/sample/components/switch/radio_example.dart +++ b/example/lib/sample/components/switch/radio_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/tabbar/brn_switch_title_example.dart b/example/lib/sample/components/tabbar/brn_switch_title_example.dart index 55b826c9..73658682 100644 --- a/example/lib/sample/components/tabbar/brn_switch_title_example.dart +++ b/example/lib/sample/components/tabbar/brn_switch_title_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -7,7 +9,7 @@ class BrnSwitchTitleExample extends StatefulWidget { } class _BrnSwitchTitleExampleState extends State with TickerProviderStateMixin { - TabController _controller; + late TabController _controller; @override void initState() { diff --git a/example/lib/sample/components/tabbar/brn_tab_example.dart b/example/lib/sample/components/tabbar/brn_tab_example.dart index dd05f85f..a75c263c 100644 --- a/example/lib/sample/components/tabbar/brn_tab_example.dart +++ b/example/lib/sample/components/tabbar/brn_tab_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/home/list_item.dart'; import 'package:flutter/material.dart'; @@ -10,7 +12,7 @@ class BrnTabExample extends StatefulWidget { } class _BrnTabExampleState extends State with TickerProviderStateMixin { - BrnCloseWindowController closeWindowController; + BrnCloseWindowController? closeWindowController; @override void initState() { @@ -35,7 +37,7 @@ class _BrnTabExampleState extends State with TickerProviderStateM ), Divider(), Center( - child: OutlineButton( + child: OutlinedButton( onPressed: () { Navigator.of(context).push(new MaterialPageRoute(builder: (context) { return BrnTabbarStickyExample(); @@ -69,8 +71,8 @@ class _BrnTabExampleState extends State with TickerProviderStateM ), ), onWillPop: () { - if (closeWindowController.isShow) { - closeWindowController.closeMoreWindow(); + if (closeWindowController!.isShow) { + closeWindowController!.closeMoreWindow(); return Future.value(false); } return Future.value(true); @@ -78,7 +80,7 @@ class _BrnTabExampleState extends State with TickerProviderStateM } _createExpandedMoreTabbarWidgets() { - var tabs = List(); + var tabs = []; tabs.add(BadgeTab(text: "业务一")); tabs.add(BadgeTab(text: "业务二")); tabs.add(BadgeTab(text: "业务三")); @@ -98,7 +100,7 @@ class _BrnTabExampleState extends State with TickerProviderStateM } _createStableTabbar4Widgets() { - var tabs = List(); + var tabs = []; tabs.add(BadgeTab(text: "业务一")); tabs.add(BadgeTab(text: "业务二")); tabs.add(BadgeTab(text: "业务三")); @@ -114,7 +116,7 @@ class _BrnTabExampleState extends State with TickerProviderStateM } _createStableTabbarWidgets() { - var tabs = List(); + var tabs = []; tabs.add(BadgeTab(text: "特殊业务详情一", badgeText: "新")); tabs.add(BadgeTab(text: "业务二", badgeNum: 22)); tabs.add(BadgeTab(text: "业务三", badgeNum: 11)); @@ -140,7 +142,7 @@ class _BrnTabExampleState extends State with TickerProviderStateM } _createTabbarBadgeWidgets() { - var tabs = List(); + var tabs = []; tabs.add(BadgeTab(text: "业务一", badgeText: "新")); tabs.add(BadgeTab(text: "业务二", badgeNum: 22)); tabs.add(BadgeTab(text: "业务三", badgeNum: 11)); @@ -161,7 +163,7 @@ class _BrnTabExampleState extends State with TickerProviderStateM } _createStableTabbarBadgeWidgets() { - var tabs = List(); + var tabs = []; tabs.add(BadgeTab(text: "业务一", badgeNum: 100)); tabs.add(BadgeTab(text: "业务二", badgeNum: 22)); tabs.add(BadgeTab(text: "业务三", badgeNum: 11)); @@ -177,7 +179,7 @@ class _BrnTabExampleState extends State with TickerProviderStateM } _createDividerTabbarWidgets() { - var tabs = List(); + var tabs = []; tabs.add(BadgeTab(text: "业务一", topText: "1")); tabs.add(BadgeTab(text: "业务二", topText: "2")); tabs.add(BadgeTab(text: "业务三", topText: "3")); @@ -197,7 +199,7 @@ class _BrnTabExampleState extends State with TickerProviderStateM /// 自定义Tab宽度,如果tab宽度之和大于屏幕宽度,默认能左右滚动 /// _createCustomTabbarWidgets() { - var tabs = List(); + var tabs = []; tabs.add(BadgeTab(text: "业务一", badgeNum: 2)); tabs.add(BadgeTab(text: "业务二")); tabs.add(BadgeTab(text: "业务三", badgeNum: 33)); @@ -213,7 +215,7 @@ class _BrnTabExampleState extends State with TickerProviderStateM } _createTopTabbarWidgets() { - var tabs = List(); + var tabs = []; tabs.add(BadgeTab(text: "08月09日", topText: "今天")); tabs.add(BadgeTab(text: "08月10日", topText: "明天")); tabs.add(BadgeTab(text: "08月11日", topText: "周三")); @@ -232,7 +234,7 @@ class _BrnTabExampleState extends State with TickerProviderStateM } _createTopTabbarCountWidgets() { - var tabs = List(); + var tabs = []; tabs.add(BadgeTab(text: "08月09日", topText: "今天")); tabs.add(BadgeTab(text: "08月10日", topText: "明天")); tabs.add(BadgeTab(text: "08月11日", topText: "周三")); @@ -249,7 +251,7 @@ class _BrnTabExampleState extends State with TickerProviderStateM } _createOriginWidgets() { - var tabs = List(); + var tabs = []; tabs.add(BadgeTab(text: "业务一", badgeText: "新")); tabs.add(BadgeTab(text: "业务二", badgeNum: 22)); tabs.add(BadgeTab(text: "业务三", badgeNum: 11)); diff --git a/example/lib/sample/components/tabbar/brn_tabbar_sticky_example.dart b/example/lib/sample/components/tabbar/brn_tabbar_sticky_example.dart index 886dd88b..a12d990d 100644 --- a/example/lib/sample/components/tabbar/brn_tabbar_sticky_example.dart +++ b/example/lib/sample/components/tabbar/brn_tabbar_sticky_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -8,14 +10,14 @@ class BrnTabbarStickyExample extends StatefulWidget { class _BrnTabbarStickyExampleState extends State with SingleTickerProviderStateMixin { - TabController tabController; + TabController? tabController; GlobalKey globalKey = GlobalKey(); ScrollController scrollController = ScrollController(); - BrnCloseWindowController closeWindowController; - var tabs = List(); + BrnCloseWindowController? closeWindowController; + List tabs = []; @override void initState() { @@ -29,7 +31,7 @@ class _BrnTabbarStickyExampleState extends State tabController = TabController(length: tabs.length, vsync: this); closeWindowController = BrnCloseWindowController(); scrollController.addListener(() { - closeWindowController.closeMoreWindow(); + closeWindowController!.closeMoreWindow(); }); } @@ -64,7 +66,7 @@ class _BrnTabbarStickyExampleState extends State moreWindowText: "Tabs描述", onTap: (state, index) { state.refreshBadgeState(index); - scrollController.animateTo(globalKey.currentContext.size.height, + scrollController.animateTo(globalKey.currentContext!.size!.height, duration: Duration(milliseconds: 200), curve: Curves.linear); }, onMorePop: () {}, @@ -88,8 +90,8 @@ class _BrnTabbarStickyExampleState extends State ), ), onWillPop: () { - if (closeWindowController.isShow) { - closeWindowController.closeMoreWindow(); + if (closeWindowController!.isShow) { + closeWindowController!.closeMoreWindow(); return Future.value(false); } return Future.value(true); @@ -112,7 +114,7 @@ class _BrnTabbarStickyExampleState extends State class StickyTabBarDelegate extends SliverPersistentHeaderDelegate { final BrnTabBar child; - StickyTabBarDelegate({@required this.child}); + StickyTabBarDelegate({required this.child}); @override Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { @@ -120,10 +122,10 @@ class StickyTabBarDelegate extends SliverPersistentHeaderDelegate { } @override - double get maxExtent => this.child.tabHeight; + double get maxExtent => this.child.tabHeight!; @override - double get minExtent => this.child.tabHeight; + double get minExtent => this.child.tabHeight!; @override bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) { diff --git a/example/lib/sample/components/tabbar/sub_switch_title_example.dart b/example/lib/sample/components/tabbar/sub_switch_title_example.dart index 4c870862..83ee38b7 100644 --- a/example/lib/sample/components/tabbar/sub_switch_title_example.dart +++ b/example/lib/sample/components/tabbar/sub_switch_title_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -8,7 +10,7 @@ class SubSwitchTitleExample extends StatefulWidget { class _SubSwitchTitleExampleState extends State with TickerProviderStateMixin { - TabController _controller; + late TabController _controller; @override void initState() { diff --git a/example/lib/sample/components/tag/border_tag_example.dart b/example/lib/sample/components/tag/border_tag_example.dart index aff03ec1..e37b580f 100644 --- a/example/lib/sample/components/tag/border_tag_example.dart +++ b/example/lib/sample/components/tag/border_tag_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/tag/custom_tag_example.dart b/example/lib/sample/components/tag/custom_tag_example.dart index db9f8083..8b5d425d 100644 --- a/example/lib/sample/components/tag/custom_tag_example.dart +++ b/example/lib/sample/components/tag/custom_tag_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/tag/delete_tag_example.dart b/example/lib/sample/components/tag/delete_tag_example.dart index 8a4a657e..969007a8 100644 --- a/example/lib/sample/components/tag/delete_tag_example.dart +++ b/example/lib/sample/components/tag/delete_tag_example.dart @@ -37,28 +37,37 @@ class TagViewExamplePageState extends State { } Widget _buildDeleteWidget() { - BrnDeleteTagController controller = BrnDeleteTagController( - initTags: ['这是一条很长很长很长很长很长很长很长很长很长很长的标签', '标签信息', '标签信息标签信息', '标签信息', '标签信息标签信息标签信息标签信息']); + BrnDeleteTagController controller = BrnDeleteTagController(initTags: [ + '这是一条很长很长很长很长很长很长很长很长很长很长的标签', + '标签信息', + '标签信息标签信息', + '标签信息', + '标签信息标签信息标签信息标签信息' + ]); return Container( margin: EdgeInsets.only(top: 20), color: Colors.white, child: Column( children: [ -BrnDeleteTag( - controller: controller, - onTagDelete: (tags, tag, index) { - BrnToast.show('剩余的标签为:${tags.toString()},删除了的标签为:$tag ,删除的标签index为$index', context); - }, -), -BrnDeleteTag( - controller: controller, - tagTextStyle: TextStyle(color: Colors.blue, fontSize: 20), - deleteIconSize: Size(16, 16), - onTagDelete: (tags, tag, index) { - BrnToast.show('剩余的标签为:${tags.toString()},删除了的标签为:$tag ,删除的标签index为$index', context); - }, -), + BrnDeleteTag( + controller: controller, + onTagDelete: (tags, tag, index) { + BrnToast.show( + '剩余的标签为:${tags.toString()},删除了的标签为:$tag ,删除的标签index为$index', + context); + }, + ), + BrnDeleteTag( + controller: controller, + tagTextStyle: TextStyle(color: Colors.blue, fontSize: 20), + deleteIconSize: Size(16, 16), + onTagDelete: (tags, tag, index) { + BrnToast.show( + '剩余的标签为:${tags.toString()},删除了的标签为:$tag ,删除的标签index为$index', + context); + }, + ), BrnDeleteTag( controller: controller, tagTextStyle: TextStyle(color: Colors.yellow), @@ -66,7 +75,9 @@ BrnDeleteTag( deleteIconColor: Colors.red, softWrap: false, onTagDelete: (tags, tag, index) { - BrnToast.show('剩余的标签为:${tags.toString()},删除了的标签为:$tag ,删除的标签index为$index', context); + BrnToast.show( + '剩余的标签为:${tags.toString()},删除了的标签为:$tag ,删除的标签index为$index', + context); }, ), Row( diff --git a/example/lib/sample/components/tag/select_tag_example.dart b/example/lib/sample/components/tag/select_tag_example.dart index 56f56e24..03122e59 100644 --- a/example/lib/sample/components/tag/select_tag_example.dart +++ b/example/lib/sample/components/tag/select_tag_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -152,8 +154,7 @@ class SelectTagExamplePageState extends State { double _getTagWidth(context, {int rowCount: 4}) { double leftRightPadding = 40; double rowSpace = 12; - return MediaQuery.of(context).size.width - - leftRightPadding - - rowSpace * (rowCount - 1) / rowCount; + return (MediaQuery.of(context).size.width - leftRightPadding - rowSpace * (rowCount - 1)) / + rowCount; } } diff --git a/example/lib/sample/components/tag/state_tag_example.dart b/example/lib/sample/components/tag/state_tag_example.dart index 3363d57a..70b3facc 100644 --- a/example/lib/sample/components/tag/state_tag_example.dart +++ b/example/lib/sample/components/tag/state_tag_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/tag/tag_example.dart b/example/lib/sample/components/tag/tag_example.dart index 60aca84c..c7222e94 100644 --- a/example/lib/sample/components/tag/tag_example.dart +++ b/example/lib/sample/components/tag/tag_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/components/tag/border_tag_example.dart'; import 'package:example/sample/components/tag/custom_tag_example.dart'; diff --git a/example/lib/sample/components/tag/tag_row_example.dart b/example/lib/sample/components/tag/tag_row_example.dart index ed035494..510eec30 100644 --- a/example/lib/sample/components/tag/tag_row_example.dart +++ b/example/lib/sample/components/tag/tag_row_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/example/lib/sample/components/toast/toast_example.dart b/example/lib/sample/components/toast/toast_example.dart index d7ade587..50821aff 100644 --- a/example/lib/sample/components/toast/toast_example.dart +++ b/example/lib/sample/components/toast/toast_example.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -6,7 +8,8 @@ class ToastExample extends StatefulWidget { _ToastExampleState createState() => _ToastExampleState(); } -class _ToastExampleState extends State with TickerProviderStateMixin { +class _ToastExampleState extends State + with TickerProviderStateMixin { @override Widget build(BuildContext context) { return Scaffold( @@ -14,54 +17,75 @@ class _ToastExampleState extends State with TickerProviderStateMix title: 'BrnToast示例', ), body: SingleChildScrollView( - child: Column( - children: [ - Padding( - padding: EdgeInsets.only(top: 50, bottom: 50), - child: Center( - child: RaisedButton( - onPressed: () { - BrnToast.show("普通长Toast", context, duration: BrnToast.LENGTH_LONG, gravity: 1); - }, - child: Text("普通长Toast"), - ), + child: Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ElevatedButton( + onPressed: () { + BrnToast.show( + "普通长Toast", + context, + duration: BrnDuration.long, + gravity: BrnToastGravity.center, + ); + }, + child: Text("普通长Toast"), + ), + ElevatedButton( + onPressed: () { + BrnToast.show( + "失败图标Toast", + context, + preIcon: Image.asset( + "assets/image/icon_toast_fail.png", + width: 24, + height: 24, + ), + duration: BrnDuration.short, + ); + }, + child: Text("失败图标Toast"), + ), + ElevatedButton( + onPressed: () { + BrnToast.show( + "成功图标Toast", + context, + preIcon: Image.asset( + "assets/image/icon_toast_success.png", + width: 24, + height: 24, + ), + duration: BrnDuration.short, + ); + }, + child: Text("成功图标Toast"), ), - ), - Padding( - padding: EdgeInsets.only(top: 50, bottom: 50), - child: Center( - child: RaisedButton( - onPressed: () { - BrnToast.show("失败图标Toast", context, - preIcon: Image.asset( - "assets/image/icon_toast_fail.png", - width: 24, - height: 24, - ), - duration: BrnToast.LENGTH_SHORT); - }, - child: Text("失败图标Toast"), - ), + ElevatedButton( + onPressed: () { + BrnToast.show( + "自定义位置Toast", + context, + duration: BrnDuration.short, + verticalOffset: 100, + gravity: BrnToastGravity.bottom + ); + }, + child: Text("自定义位置Toast"), ), - ), - Padding( - padding: EdgeInsets.only(top: 50, bottom: 50), - child: Center( - child: RaisedButton( - onPressed: () { - BrnToast.show("成功图标Toast", context, - preIcon: Image.asset( - "assets/image/icon_toast_success.png", - width: 24, - height: 24, - ), - duration: BrnToast.LENGTH_SHORT); - }, - child: Text("成功图标Toast"), - ), + ElevatedButton( + onPressed: () { + BrnToast.show( + "自定义时长Toast", + context, + duration: Duration(seconds: 5), + ); + }, + child: Text("自定义时长Toast(5s)"), ), - ) - ], + ], + ), ), ), ); diff --git a/example/lib/sample/home/card_data_config.dart b/example/lib/sample/home/card_data_config.dart index 99e7684f..aa94ddfe 100644 --- a/example/lib/sample/home/card_data_config.dart +++ b/example/lib/sample/home/card_data_config.dart @@ -1,3 +1,5 @@ + + import 'dart:convert'; import 'package:bruno/bruno.dart'; @@ -47,7 +49,7 @@ import 'package:flutter/services.dart'; /// 卡片信息 class GroupInfo { /// 唯一ID - int groupId; + int? groupId; /// 组名称 String groupName; @@ -62,10 +64,10 @@ class GroupInfo { bool isSupportTheme; /// 子Widget - List children; + List? children; /// 跳转到下一个页面 - Function(BuildContext context) navigatorPage; + Function(BuildContext context)? navigatorPage; GroupInfo( {this.groupId, @@ -81,7 +83,7 @@ class GroupInfo { class CardDataConfig { /// 全部 static List getAllGroup() { - List list = List(); + List list = []; list.add(_getChartGroup()); list.add(_getDataInputGroup()); list.add(_getOperateGroup()); @@ -93,14 +95,14 @@ class CardDataConfig { /// 数据图表 static GroupInfo _getChartGroup() { - List children = List(); + List children = []; children.add(GroupInfo( groupName: "BrokenLine 折线图 ", desc: "数据折线图", navigatorPage: (BuildContext context) { rootBundle.loadString('assets/brokenline_data.json').then((data) { - var brokenData = List() - ..addAll(((JsonDecoder().convert(data) as List) ?? []) + var brokenData = [] + ..addAll(((JsonDecoder().convert(data) as List?) ?? []) .map((o) => DBDataNodeModel.fromJson(o))); Navigator.push(context, MaterialPageRoute( builder: (BuildContext context) { @@ -165,7 +167,7 @@ class CardDataConfig { /// 数据录入 static GroupInfo _getDataInputGroup() { - List children = List(); + List children = []; children.add(GroupInfo( groupName: "Form 表单项", desc: "各种表单项", @@ -213,7 +215,7 @@ class CardDataConfig { /// 操作反馈类 static GroupInfo _getOperateGroup() { - List children = List(); + List children = []; children.add(GroupInfo( groupName: "Dialog 弹窗", desc: "Dialog多种类型展示", @@ -271,7 +273,7 @@ class CardDataConfig { /// 导航类 static GroupInfo _getNavigatorGroup() { - List children = List(); + List children = []; children.add(GroupInfo( groupName: "Appbar 导航栏", desc: "Appbar 导航栏", @@ -359,7 +361,7 @@ class CardDataConfig { /// 按钮 static GroupInfo _getButtonGroup() { - List children = List(); + List children = []; children.add(GroupInfo( groupName: "NormalButton 普通按钮", desc: "主按钮、次按钮、按钮集合", @@ -426,7 +428,7 @@ class CardDataConfig { /// 内容 static GroupInfo _getContentGroup() { - List children = List(); + List children =[]; children.add(GroupInfo( groupName: "Tag 标签", desc: "标签多种样式", @@ -556,7 +558,7 @@ class CardDataConfig { /// 城市选择 static Widget _buildSingleSelectCityPage() { - List hotCityList = List(); + List hotCityList = []; hotCityList.addAll([ BrnSelectCityModel(name: "北京市"), BrnSelectCityModel(name: "广州市"), diff --git a/example/lib/sample/home/expandable_container_widget.dart b/example/lib/sample/home/expandable_container_widget.dart index 517d15c6..d8264175 100644 --- a/example/lib/sample/home/expandable_container_widget.dart +++ b/example/lib/sample/home/expandable_container_widget.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. + + import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; @@ -21,21 +23,20 @@ import 'package:flutter/widgets.dart'; /// * The "Expand/collapse" section of class BrnExpandableContainerWidget extends StatefulWidget { - final Widget Function(BuildContext context) headerBuilder; + final Widget Function(BuildContext context)? headerBuilder; /// Creates a single-line [ListTile] with a trailing button that expands or collapses /// the tile to reveal or hide the [children]. The [initiallyExpanded] property must /// be non-null. const BrnExpandableContainerWidget({ - Key key, + Key? key, this.onExpansionChanged, this.headerBuilder, this.child, this.initiallyExpanded = false, this.animationDuration, this.expandableController, - }) : assert(initiallyExpanded != null), - super(key: key); + }) : super(key: key); /// A widget to display before the title. /// @@ -45,19 +46,19 @@ class BrnExpandableContainerWidget extends StatefulWidget { /// When the tile starts expanding, this function is called with the value /// true. When the tile starts collapsing, this function is called with /// the value false. - final ValueChanged onExpansionChanged; + final ValueChanged? onExpansionChanged; /// The widgets that are displayed when the tile expands. /// /// Typically [ListTile] widgets. - final Widget child; + final Widget? child; /// Specifies if the list tile is initially expanded (true) or collapsed (false, the default). final bool initiallyExpanded; - final Duration animationDuration; + final Duration? animationDuration; - final BrnExpandableContainerController expandableController; + final BrnExpandableContainerController? expandableController; @override _BrnExpansionContainerElementState createState() => _BrnExpansionContainerElementState(); @@ -67,13 +68,13 @@ class _BrnExpansionContainerElementState extends State _easeInTween = CurveTween(curve: Curves.easeIn); - BrnExpandableContainerController _expandableController; - AnimationController _animationController; - Animation _heightFactor; + BrnExpandableContainerController? _expandableController; + AnimationController? _animationController; + late Animation _heightFactor; bool _isExpanded = false; - Widget arrowIcon; + Widget? arrowIcon; @override void initState() { @@ -82,21 +83,21 @@ class _BrnExpansionContainerElementState extends State with SingleTickerProviderStateMixin { static final Animatable _easeInTween = CurveTween(curve: Curves.easeIn); static final Animatable _halfTween = Tween(begin: 0.0, end: 0.5); - BrnExpandableContainerController _controller; - Widget _arrowIcon; - Animation _iconTurns; - bool _initExpand; - AnimationController _animationController; + BrnExpandableContainerController? _controller; + Widget? _arrowIcon; + late Animation _iconTurns; + late bool _initExpand; + AnimationController? _animationController; @override void initState() { super.initState(); _controller = BrnExpandableContainerController(); _animationController = AnimationController(duration: Duration(milliseconds: 200), vsync: this); - _initExpand = widget.groupInfo.isExpand; - _iconTurns = _animationController.drive(_halfTween.chain(_easeInTween)); + _initExpand = widget.groupInfo!.isExpand; + _iconTurns = _animationController!.drive(_halfTween.chain(_easeInTween)); if (_initExpand) { _arrowIcon = Icon(Icons.keyboard_arrow_up); } else { @@ -62,7 +64,7 @@ class GroupCardState extends State with SingleTickerProviderStateMixi } else { _arrowIcon = Icon(Icons.keyboard_arrow_down); } - widget.groupInfo.isExpand = isExpand; + widget.groupInfo!.isExpand = isExpand; }, headerBuilder: (_) { return GestureDetector( @@ -76,7 +78,7 @@ class GroupCardState extends State with SingleTickerProviderStateMixi children: [ Expanded( child: Text( - widget.groupInfo.groupName, + widget.groupInfo!.groupName, style: TextStyle(color: Color(0xFF222222), fontSize: 18), )), RotationTransition( @@ -94,6 +96,9 @@ class GroupCardState extends State with SingleTickerProviderStateMixi } Widget _getContentWidget() { + if(widget.groupInfo == null || widget.groupInfo!.children == null){ + return SizedBox.shrink(); + } return ListView.builder( physics: new NeverScrollableScrollPhysics(), shrinkWrap: true, @@ -102,14 +107,14 @@ class GroupCardState extends State with SingleTickerProviderStateMixi return Container( color: Colors.white, child: ListItem( - isSupportTheme: widget.groupInfo?.children[index]?.isSupportTheme, + isSupportTheme: widget.groupInfo?.children![index].isSupportTheme ?? false, isShowLine: !(index == 0), - title: widget.groupInfo?.children[index].groupName, - describe: widget.groupInfo?.children[index].desc, + title: widget.groupInfo?.children![index].groupName ?? '', + describe: widget.groupInfo?.children![index].desc ?? '', onPressed: () { if (widget.groupInfo?.children != null && - widget.groupInfo?.children[index].navigatorPage != null) { - widget.groupInfo?.children[index].navigatorPage(context); + widget.groupInfo?.children![index].navigatorPage != null) { + widget.groupInfo?.children![index].navigatorPage!(context); } }, ), diff --git a/example/lib/sample/home/home.dart b/example/lib/sample/home/home.dart index 9b3abc45..cf745500 100644 --- a/example/lib/sample/home/home.dart +++ b/example/lib/sample/home/home.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/bruno.dart'; import 'package:example/sample/home/card_data_config.dart'; import 'package:example/sample/home/group_card.dart'; @@ -25,7 +27,7 @@ class HomePage extends StatelessWidget { padding: EdgeInsets.fromLTRB(16, 10, 16, 0), child: ListView.builder( shrinkWrap: true, - itemCount: list?.length, + itemCount: list.length, itemBuilder: (BuildContext context, int index) { return Container( padding: EdgeInsets.only(top: 10), diff --git a/example/lib/sample/home/list_item.dart b/example/lib/sample/home/list_item.dart index 616f1729..81fd2cc2 100644 --- a/example/lib/sample/home/list_item.dart +++ b/example/lib/sample/home/list_item.dart @@ -1,35 +1,37 @@ + + import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; /// 列表项 class ListItem extends StatefulWidget { /// 点击事件 - final VoidCallback onPressed; + final VoidCallback? onPressed; /// 标题 final String title; - final double titleFontSize; - final Color titleColor; - final String imgPath; + final double? titleFontSize; + final Color? titleColor; + final String? imgPath; /// 描述 final String describe; final Color describeColor; /// 右侧控件 - final Widget rightWidget; + final Widget? rightWidget; final bool isSupportTheme; final bool isShowLine; /// 构造函数 ListItem({ - Key key, + Key? key, this.onPressed, this.title = "", this.titleFontSize, this.titleColor, this.describe = "", - this.describeColor: Colors.grey, + this.describeColor = const Color(0xFF999999), this.rightWidget, this.imgPath, this.isSupportTheme = false, @@ -91,7 +93,7 @@ class _ListItemState extends State { Padding(padding: EdgeInsets.all(2)), Text( widget.describe, - style: TextStyle(color: widget.describeColor ?? Color(0xFF999999), fontSize: 12), + style: TextStyle(color: widget.describeColor, fontSize: 12), ), BrnLine( height: 14, diff --git a/example/lib/sample/theme/config_test_utils.dart b/example/lib/sample/theme/config_test_utils.dart index 7837353d..a9256ce8 100644 --- a/example/lib/sample/theme/config_test_utils.dart +++ b/example/lib/sample/theme/config_test_utils.dart @@ -1,3 +1,5 @@ + + import 'dart:ui'; import 'package:bruno/bruno.dart'; @@ -158,16 +160,6 @@ class TestConfigUtils { titleMaxLength: 20, titleStyle: BrnTextStyle(color: Color(0xff222222), fontWeight: FontWeight.w600, fontSize: 24), actionsStyle: BrnTextStyle(color: Color(0xFF3072F6), fontWeight: FontWeight.w600, fontSize: 18), - flexibleSpace: Container( - width: double.infinity, - height: MediaQueryData.fromWindow(window).padding.top + 57, - decoration: BoxDecoration( - gradient: LinearGradient(colors: [ - Color(0xfffafafa), - Color(0xfff5f5f5), - ], begin: Alignment.topCenter, end: Alignment.bottomCenter), - ), - ), ); static BrnButtonConfig defaultButtonConfig = BrnButtonConfig( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 1d71f15b..ffb77c08 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -14,7 +14,7 @@ description: A new Flutter project. version: 1.0.0+1 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: @@ -24,20 +24,18 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 bruno: path: ../ flutter_easyrefresh: ^2.2.1 http: any badges: ^2.0.2 - flutter_swiper: 1.1.6 dev_dependencies: flutter_test: sdk: flutter dependency_overrides: - intl: 0.16.0 + intl: ^0.17.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/lib/bruno.dart b/lib/bruno.dart index b2b13bea..8ca380d3 100644 --- a/lib/bruno.dart +++ b/lib/bruno.dart @@ -74,8 +74,6 @@ export 'src/components/tabbar/normal/brn_tabbar_controller.dart'; export 'src/components/tabbar/indicator/brn_fixed_underline_decoration.dart'; export 'src/components/tabbar/indicator/brn_triangle_decoration.dart'; -//分割线 - //空页面 export 'src/components/empty/brn_empty_status.dart'; @@ -84,7 +82,6 @@ export 'src/components/loading/brn_loading.dart'; //导航栏 export 'src/components/navbar/brn_appbar.dart'; -export 'src/components/navbar/brn_empty_appbar.dart'; //搜索bar export 'src/components/navbar/brn_search_bar.dart'; @@ -125,9 +122,9 @@ export 'src/components/form/items/general/brn_title_select_input_item.dart'; export 'src/components/form/items/misc/brn_title_item.dart'; export 'src/components/form/items/misc/brn_add_label_item.dart'; export 'src/components/form/items/group/brn_normal_group.dart'; -export 'src/components/form/undetermined/brn_expandable_group.dart'; -export 'src/components/form/undetermined/brn_portrait_radio_group.dart'; -export 'src/components/form/items/group/brn_expand_group.dart'; +export 'src/components/form/items/group/brn_expandable_group.dart'; +export 'src/components/form/items/group/brn_portrait_radio_group.dart'; +export 'src/components/form/items/group/brn_expandable_group_with_opreate.dart'; // 新增表单项 export 'src/components/form/items/title/brn_base_title_item.dart'; @@ -151,6 +148,8 @@ export 'src/components/appraise/brn_appraise_bottom_picker.dart'; export 'src/components/appraise/brn_appraise_emoji_list_view.dart'; export 'src/components/appraise/brn_appraise_header.dart'; export 'src/components/appraise/brn_appraise.dart'; +export 'src/components/appraise/brn_appraise_config.dart'; +export 'src/components/appraise/brn_appraise_interface.dart'; export 'src/components/appraise/brn_appraise_star_list_view.dart'; //大图预览 diff --git a/lib/src/components/actionsheet/brn_common_action_sheet.dart b/lib/src/components/actionsheet/brn_common_action_sheet.dart index 42a8bf32..ab18f617 100644 --- a/lib/src/components/actionsheet/brn_common_action_sheet.dart +++ b/lib/src/components/actionsheet/brn_common_action_sheet.dart @@ -26,16 +26,16 @@ class BrnCommonActionSheetItem { String title; /// 辅助信息 - String desc; + String? desc; /// 样式 [BrnActionSheetActionStyle] final BrnCommonActionSheetItemStyle actionStyle; /// 主标题文本样式 - final TextStyle titleStyle; + final TextStyle? titleStyle; /// 辅助信息文本样式 - final TextStyle descStyle; + final TextStyle? descStyle; BrnCommonActionSheetItem( this.title, { @@ -55,19 +55,19 @@ class BrnCommonActionSheet extends StatelessWidget { final List actions; /// ActionSheet 标题 - final String title; + final String? title; /// title区域widget, 与 title 字段互斥,当 titleWidget 不为 null 时优先使用 titleWidget。 - final Widget titleWidget; + final Widget? titleWidget; /// Action 之间分割线颜色,默认值 Color(0xfff0f0f0) - final Color separatorLineColor; + final Color? separatorLineColor; /// 取消按钮与 Action 之间的分割线的颜色,默认值 Color(0xfff8f8f8) final Color spaceColor; /// 取消按钮文本 - final String cancelTitle; + final String? cancelTitle; /// 标题最大行数,默认为2 final int maxTitleLines; @@ -77,16 +77,16 @@ class BrnCommonActionSheet extends StatelessWidget { final double maxSheetHeight; /// Action Item 的点击事件 - final BrnCommonActionSheetItemClickCallBack clickCallBack; + final BrnCommonActionSheetItemClickCallBack? clickCallBack; /// Action Item 点击事件拦截回调 - final BrnCommonActionSheetItemClickInterceptor onItemClickInterceptor; + final BrnCommonActionSheetItemClickInterceptor? onItemClickInterceptor; /// 主题定制 - BrnActionSheetConfig themeData; + BrnActionSheetConfig? themeData; BrnCommonActionSheet({ - @required this.actions, + required this.actions, this.title, this.titleWidget, this.cancelTitle, @@ -97,10 +97,10 @@ class BrnCommonActionSheet extends StatelessWidget { this.maxSheetHeight = 0, this.onItemClickInterceptor, this.themeData, - }) : assert(actions != null) { + }) { themeData ??= BrnActionSheetConfig(); themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) + .getConfig(configId: themeData!.configId) .actionSheetConfig .merge(themeData); } @@ -122,8 +122,8 @@ class BrnCommonActionSheet extends StatelessWidget { color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( - topLeft: Radius.circular(themeData.topRadius), - topRight: Radius.circular(themeData.topRadius), + topLeft: Radius.circular(themeData!.topRadius), + topRight: Radius.circular(themeData!.topRadius), ), ), ), @@ -135,11 +135,11 @@ class BrnCommonActionSheet extends StatelessWidget { /// 构建actionSheet的按钮 Widget _configActionWidgets(BuildContext context, double _maxSheetHeight) { - List widgets = List(); + List widgets = []; // 构建整体标题 if (titleWidget != null) { // 如果传入了则直接使用 - widgets.add(titleWidget); + widgets.add(titleWidget!); } else if (title != null && title.toString().trim() != "") { // 如果只传入title则根据文案构建默认title widgets.add(_configTitleActions()); @@ -147,7 +147,7 @@ class BrnCommonActionSheet extends StatelessWidget { widgets.add(_configListActions(context)); // 添加间隔 widgets.add(Divider( - color: spaceColor ?? Color(0xfff8f8f8), + color: spaceColor, thickness: 8, height: 8, )); @@ -168,13 +168,13 @@ class BrnCommonActionSheet extends StatelessWidget { return Column( children: [ Container( - padding: themeData.titlePadding, + padding: themeData!.titlePadding, child: Center( child: Text( - title, + title!, textAlign: TextAlign.center, maxLines: maxTitleLines, - style: themeData.titleStyle.generateTextStyle(), + style: themeData!.titleStyle.generateTextStyle(), ), ), ), @@ -182,7 +182,7 @@ class BrnCommonActionSheet extends StatelessWidget { //有标题则添加分割线 thickness: 1, height: 1, - color: separatorLineColor ?? themeData.commonConfig.dividerColorBase, + color: separatorLineColor ?? themeData!.commonConfig.dividerColorBase, ), ], ); @@ -190,22 +190,22 @@ class BrnCommonActionSheet extends StatelessWidget { /// 构建列表widget Widget _configListActions(BuildContext context) { - List tiles = List(); + List tiles = []; //构建列表内容 for (int index = 0; index < actions.length; index++) { tiles.add( GestureDetector( behavior: HitTestBehavior.opaque, child: Container( - padding: themeData.contentPadding, + padding: themeData!.contentPadding, child: _configTile(actions[index]), ), onTap: () { if (onItemClickInterceptor == null || - !onItemClickInterceptor(index, actions[index])) { + !onItemClickInterceptor!(index, actions[index])) { // 推荐使用回调方法处理点击事件!!!!!!!!!! if (clickCallBack != null) { - clickCallBack(index, actions[index]); + clickCallBack!(index, actions[index]); } // 如果未拦截,则pop掉当前页面,并且携带信息(不建议使用此信息进行点击时间处理) Navigator.of(context).pop([index, actions[index]]); @@ -216,7 +216,7 @@ class BrnCommonActionSheet extends StatelessWidget { tiles.add(Divider( thickness: 1, height: 1, - color: separatorLineColor ?? themeData.commonConfig.dividerColorBase, + color: separatorLineColor ?? themeData!.commonConfig.dividerColorBase, )); } return Flexible( @@ -231,7 +231,7 @@ class BrnCommonActionSheet extends StatelessWidget { // 配置每个选项内部信息 // action 每个item配置项 [BrnCommonActionSheetItem] Widget _configTile(BrnCommonActionSheetItem action) { - List tileElements = List(); + List tileElements = []; bool hasTitle = false; // 如果有标题则添加标题 if (action.title != null) { @@ -241,10 +241,10 @@ class BrnCommonActionSheet extends StatelessWidget { maxLines: 1, style: action.titleStyle ?? (action.actionStyle == BrnCommonActionSheetItemStyle.alert - ? this.themeData.itemTitleStyleAlert.generateTextStyle() + ? this.themeData!.itemTitleStyleAlert.generateTextStyle() : (action.actionStyle == BrnCommonActionSheetItemStyle.link - ? this.themeData.itemTitleStyleLink.generateTextStyle() - : this.themeData.itemTitleStyle.generateTextStyle())), + ? this.themeData!.itemTitleStyleLink.generateTextStyle() + : this.themeData!.itemTitleStyle.generateTextStyle())), ), )); hasTitle = true; @@ -260,15 +260,15 @@ class BrnCommonActionSheet extends StatelessWidget { tileElements.add( Center( child: Text( - action.desc, + action.desc!, textAlign: TextAlign.center, maxLines: 1, style: action.descStyle ?? (action.actionStyle == BrnCommonActionSheetItemStyle.alert - ? this.themeData.itemDescStyleAlert.generateTextStyle() + ? this.themeData!.itemDescStyleAlert.generateTextStyle() : (action.actionStyle == BrnCommonActionSheetItemStyle.link - ? this.themeData.itemDescStyleLink.generateTextStyle() - : this.themeData.itemDescStyle.generateTextStyle())), + ? this.themeData!.itemDescStyleLink.generateTextStyle() + : this.themeData!.itemDescStyle.generateTextStyle())), ), ), ); @@ -292,8 +292,8 @@ class BrnCommonActionSheet extends StatelessWidget { padding: EdgeInsets.only(top: 12, bottom: 12), child: Center( child: Text( - (cancelTitle != null) ? cancelTitle : "取消", - style: this.themeData.cancelStyle.generateTextStyle(), + cancelTitle ?? "取消", + style: this.themeData!.cancelStyle.generateTextStyle(), ), ), ), diff --git a/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart b/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart index 2b0dd36e..06bf0ef7 100644 --- a/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart +++ b/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart @@ -45,19 +45,16 @@ class BrnSelectedListActionSheetController extends ChangeNotifier { /// 自动与 globalKey 绑定的组件左右对齐,并从其顶部弹出。clear /// 2. 外界需要自己监听 Android 上的系统返回事件,并且调用组件的 [dismiss] 方法!否则,组件不能正常关闭。 class BrnSelectedListActionSheet { - @required final BuildContext context; /// 数据源列表 - @required final List items; /// 获取对应 index 行内容的回调。类型必须为 String 或者自定义的 widget.自定义 widget 时,左边的 icon 会自动隐藏,自定义widget填充整行。 - @required final dynamic Function(int index, T entity) itemTitleBuilder; /// 控制视图隐藏/刷新列表等方法 - final BrnSelectedListActionSheetController controller; + final BrnSelectedListActionSheetController? controller; /// 视图的最大高度。默认值 290,列表的内容的高度=maxHeight-65 final double maxHeight; @@ -75,10 +72,10 @@ class BrnSelectedListActionSheet { /// fontWeight: FontWeight.w600, /// decoration: TextDecoration.none) /// ``` - final String title; + final String? title; /// 自定义标题视图。默认外层有 `const EdgeInsets.fromLTRB(20, 20, 20, 15)` 的 padding,且优先级比 [title] 高 - final Widget titleWidget; + final Widget? titleWidget; /// 清空按钮是否显示,默认为 false final bool isClearButtonHidden; @@ -87,33 +84,33 @@ class BrnSelectedListActionSheet { final bool isDeleteButtonHidden; /// 每一行前边的 icon,可不传。如果该 image 没有设置,并且 itemTitleBuilder 返回的是自定义 widget,则该 widget 自动填充整行区域 - final Image itemIconImage; + final Image? itemIconImage; /// 点击清空按钮后的回调,如果没有实现该回调,则会显示默认弹窗。如果要关闭已选列表,请调用 dismiss()。 - final VoidCallback onClear; + final VoidCallback? onClear; /// 清空按钮点击显示默认确认弹窗之后,`确定` 按钮的点击回调 - final VoidCallback onClearConfirmed; + final VoidCallback? onClearConfirmed; /// 清空按钮点击显示默认确认弹窗之后,`取消` 按钮的点击回调 - final VoidCallback onClearCanceled; + final VoidCallback? onClearCanceled; /// 每一行删除按钮的点击回调。返回值:是否要删除该 entity,如果该 handler 没有实现或者返回 true,则删除 - final bool Function(int deleteIdx, T deleteEntity) onItemDelete; + final bool Function(int deleteIdx, T deleteEntity)? onItemDelete; /// 视图显示时的回调 - final VoidCallback onListShowed; + final VoidCallback? onListShowed; /// 视图隐藏时的回调,会把是否是清空按钮触发的销毁视图回传 - final void Function(bool isClosedByClearButton) onListDismissed; + final void Function(bool isClosedByClearButton)? onListDismissed; - OverlayEntry _overlayEntry; - double _leftOffset; + OverlayEntry? _overlayEntry; + double? _leftOffset; double _bottomKeyOffset = 0; - double _maxWidth; + double? _maxWidth; BrnSelectedListActionSheet( - {this.context, + {required this.context, this.maxHeight = 290, this.bottomOffset = 82, this.title, @@ -121,8 +118,8 @@ class BrnSelectedListActionSheet { this.isClearButtonHidden = false, this.isDeleteButtonHidden = false, this.itemIconImage, - this.items, - this.itemTitleBuilder, + required this.items, + required this.itemTitleBuilder, this.onClear, this.onClearConfirmed, this.onClearCanceled, @@ -133,21 +130,21 @@ class BrnSelectedListActionSheet { void _dismissHandler(bool isClear) { if (onListDismissed != null) { - onListDismissed(isClear); + onListDismissed!(isClear); } if (_overlayEntry != null) { - _overlayEntry.remove(); + _overlayEntry!.remove(); _overlayEntry = null; } } /// bottomWidgetKey: 已选列表下边操作区域绑定的 GlobalKey,已选列表会自动与操作区域左右对齐,且从操作区域的顶部滑出 - void showWithTargetKey({GlobalKey bottomWidgetKey}) { - assert(bottomWidgetKey != null); - RenderBox renderBox = bottomWidgetKey?.currentContext?.findRenderObject(); + void showWithTargetKey({required GlobalKey bottomWidgetKey}) { + RenderBox? renderBox = + bottomWidgetKey.currentContext?.findRenderObject() as RenderBox?; var offset = renderBox?.localToGlobal(Offset.zero); _leftOffset = offset?.dx ?? 0; - _maxWidth = renderBox?.size?.width ?? MediaQuery.of(context).size.width; + _maxWidth = renderBox?.size.width ?? MediaQuery.of(context).size.width; _bottomKeyOffset = MediaQuery.of(context).size.height - (offset?.dy ?? 0); this._innerShow(true); } @@ -160,7 +157,7 @@ class BrnSelectedListActionSheet { if (_overlayEntry != null) { return; } - BrnSelectedListActionSheetController tempCcontroller = controller; + BrnSelectedListActionSheetController? tempCcontroller = controller; if (tempCcontroller == null) { tempCcontroller = BrnSelectedListActionSheetController(); tempCcontroller._isHidden = false; @@ -186,7 +183,7 @@ class BrnSelectedListActionSheet { return Positioned( top: MediaQuery.of(context).viewInsets.top, left: _leftOffset, - bottom: (showByKey ?? false) + bottom: (showByKey) ? _bottomKeyOffset : (bottomOffset + MediaQuery.of(context).padding.bottom + @@ -196,11 +193,11 @@ class BrnSelectedListActionSheet { child: content, )); }); - content._overlayState.insert(overlayEntry); + content._overlayState!.insert(overlayEntry); _overlayEntry = overlayEntry; if (onListShowed != null) { - onListShowed(); + onListShowed!(); } } } @@ -208,25 +205,25 @@ class BrnSelectedListActionSheet { // ignore: must_be_immutable class _BrnActionSheetSelectedItemListContentWidget extends StatefulWidget { final BrnSelectedListActionSheet itemWidget; - final void Function(bool isClear) onDismiss; + final void Function(bool isClear)? onDismiss; final dynamic Function(int index, T entity) itemTitleBuilder; - final bool Function(int deleteIdx, T deleteEntity) onItemDelete; - final BrnSelectedListActionSheetController controller; + final bool Function(int deleteIdx, T deleteEntity)? onItemDelete; + final BrnSelectedListActionSheetController? controller; - OverlayState _overlayState; + OverlayState? _overlayState; // 位置动画 - Animation _yAnimation; + late Animation _yAnimation; // 背景透明度动画 - Animation _alphaAnimation; - AnimationController _yAnimationController; - AnimationController _alphaAnimationController; + late Animation _alphaAnimation; + late AnimationController _yAnimationController; + late AnimationController _alphaAnimationController; _BrnActionSheetSelectedItemListContentWidget( - {this.itemWidget, + {required this.itemWidget, this.onDismiss, - this.itemTitleBuilder, + required this.itemTitleBuilder, this.onItemDelete, this.controller}); @@ -245,10 +242,10 @@ class _BrnActionSheetSelectedItemListContentWidget extends StatefulWidget { } class _BrnActionSheetSelectedItemListState - extends State<_BrnActionSheetSelectedItemListContentWidget> + extends State<_BrnActionSheetSelectedItemListContentWidget> with TickerProviderStateMixin { bool _isClosedByClear = false; - BrnSelectedListActionSheetController _controller; + BrnSelectedListActionSheetController? _controller; @override initState() { @@ -263,26 +260,22 @@ class _BrnActionSheetSelectedItemListState @override dispose() { //路由销毁时需要释放动画资源 - if (widget._yAnimationController != null) { - widget._yAnimationController.dispose(); - } - if (widget._alphaAnimationController != null) { - widget._alphaAnimationController.dispose(); - } + widget._yAnimationController.dispose(); + widget._alphaAnimationController.dispose(); _controller?.removeListener(_onListenHandler); _controller = null; super.dispose(); } void _onListenHandler() { - if (_controller.isShouldReloadData) { + if (_controller!.isShouldReloadData) { if (mounted) { setState(() {}); } - _controller.isShouldReloadData = false; - } else if (_controller.isSelectedListDismissed) { + _controller!.isShouldReloadData = false; + } else if (_controller!.isSelectedListDismissed) { widget.dismissWithAnimation(); - _controller.isSelectedListDismissed = false; + _controller!.isSelectedListDismissed = false; } } @@ -293,21 +286,21 @@ class _BrnActionSheetSelectedItemListState AnimationController alphaAnimationController = AnimationController( duration: const Duration(milliseconds: 200), vsync: this); widget._alphaAnimationController = alphaAnimationController; - Animation yAnimation = Tween(begin: 65.0, end: this.getContentHeight()) + Animation yAnimation = Tween(begin: 65.0, end: this.getContentHeight()) .animate(yAnimationController) - ..addListener(() { - setState(() => {}); - }) - ..addStatusListener((status) { - if (status == AnimationStatus.dismissed) { - widget.onDismiss(_isClosedByClear); - } - }); - widget._yAnimation = yAnimation; + ..addListener(() { + setState(() => {}); + }) + ..addStatusListener((status) { + if (status == AnimationStatus.dismissed) { + widget.onDismiss!(_isClosedByClear); + } + }); + widget._yAnimation = yAnimation as Animation; Animation alphaAnimation = Tween(begin: 0.0, end: 0.7) .animate(alphaAnimationController) - ..addListener(() {}); - widget._alphaAnimation = alphaAnimation; + ..addListener(() {}); + widget._alphaAnimation = alphaAnimation as Animation; yAnimationController.forward(); alphaAnimationController.forward(); } @@ -328,25 +321,21 @@ class _BrnActionSheetSelectedItemListState BrnDialogManager.showConfirmDialog(context, title: "确定要清空已选列表吗?", cancel: '取消', confirm: '确定', onConfirm: () { if (widget.itemWidget.onClearConfirmed != null) { - widget.itemWidget.onClearConfirmed(); - } - if (widget.itemWidget.items != null) { - widget.itemWidget.items - .removeRange(0, widget.itemWidget.items.length); + widget.itemWidget.onClearConfirmed!(); } + widget.itemWidget.items.removeRange(0, widget.itemWidget.items.length); }, onCancel: () { if (widget.itemWidget.onClearCanceled != null) { - widget.itemWidget.onClearCanceled(); + widget.itemWidget.onClearCanceled!(); } }); } else { - widget.itemWidget.onClear(); + widget.itemWidget.onClear!(); } } void onDeleteItemAction(int idx) { - if (widget.itemWidget.items == null || - idx >= widget.itemWidget.items.length) { + if (idx >= widget.itemWidget.items.length) { debugPrint( 'idx:$idx out of range of selectedModelList:${widget.itemWidget.items.length}!!!'); return; @@ -354,7 +343,7 @@ class _BrnActionSheetSelectedItemListState bool shouldDelete = true; if (widget.onItemDelete != null) { - shouldDelete = widget.onItemDelete(idx, widget.itemWidget.items[idx]); + shouldDelete = widget.onItemDelete!(idx, widget.itemWidget.items[idx]); } if (shouldDelete) { setState(() { @@ -367,8 +356,8 @@ class _BrnActionSheetSelectedItemListState Widget build(BuildContext context) { // 顶部标题处理 String title = - (widget.itemWidget.title != null && widget.itemWidget.title.length > 0) - ? widget.itemWidget.title + (widget.itemWidget.title != null && widget.itemWidget.title!.length > 0) + ? widget.itemWidget.title! : '已选列表'; TextStyle titleStyle = const TextStyle( fontSize: 18, @@ -384,10 +373,9 @@ class _BrnActionSheetSelectedItemListState style: titleStyle, ), )); - List topWidgetList = List(); + List topWidgetList = []; topWidgetList.add(topTitle); - if (widget.itemWidget.isClearButtonHidden != null && - !widget.itemWidget.isClearButtonHidden) { + if (!widget.itemWidget.isClearButtonHidden) { Widget clearWidget = GestureDetector( onTap: () { this.onClearAction(); @@ -456,16 +444,13 @@ class _BrnActionSheetSelectedItemListState Expanded( child: ListView.builder( padding: EdgeInsets.zero, - itemCount: widget.itemWidget.items != null - ? widget.itemWidget.items.length - : 0, + itemCount: widget.itemWidget.items.length, itemBuilder: (BuildContext context, int index) { // 是否展示左侧的图标 bool shouldHideIcon = false; // 获取标题 Widget content = Container(color: Colors.white); - if (widget.itemWidget.items != null && - index < widget.itemWidget.items.length) { + if (index < widget.itemWidget.items.length) { var item = widget.itemTitleBuilder( index, widget.itemWidget.items[index]); if (item is String) { @@ -511,7 +496,7 @@ class _BrnActionSheetSelectedItemListState padding: const EdgeInsets.only( left: 5, right: 20), child: BrunoTools.getAssetImage( - BrnAsset.ICON_TRASH_BIN)), + BrnAsset.iconTrashBin)), ), ), ], diff --git a/lib/src/components/actionsheet/brn_share_action_sheet.dart b/lib/src/components/actionsheet/brn_share_action_sheet.dart index d547ebf4..6cfc6e62 100644 --- a/lib/src/components/actionsheet/brn_share_action_sheet.dart +++ b/lib/src/components/actionsheet/brn_share_action_sheet.dart @@ -19,10 +19,10 @@ class BrnShareItem extends Object { int shareType; /// 自定义标题 - String customTitle; + String? customTitle; /// 自定义图标 - Widget customImage; + Widget? customImage; /// 是否可点击(如果为预设类型,设置为不可点击后会变为相应的置灰图标)默认为true bool canClick; @@ -38,16 +38,16 @@ class BrnShareItem extends Object { // ignore: must_be_immutable class BrnShareActionSheet extends StatelessWidget { /// 第一行渠道列表 - final List firstShareChannels; + final List? firstShareChannels; /// 第二行渠道列表 - final List secondShareChannels; + final List? secondShareChannels; /// 列表标题 - final String mainTitle; + final String? mainTitle; /// 取消按钮名称 - final String cancelTitle; + final String? cancelTitle; /// 取消按钮的文本颜色,默认值为 Color(0xff222222) final Color textColor; @@ -56,10 +56,10 @@ class BrnShareActionSheet extends StatelessWidget { final Color shareTextColor; /// 点击事件回调 - final BrnShareActionSheetItemClickCallBack clickCallBack; + final BrnShareActionSheetItemClickCallBack? clickCallBack; /// 点击事件拦截回调(如果配置了此项,返回值为是否拦截,如果为true,则进行拦截,不进行默认回调) - final BrnShareActionSheetOnItemClickInterceptor clickInterceptor; + final BrnShareActionSheetOnItemClickInterceptor? clickInterceptor; BrnShareActionSheet({ this.firstShareChannels, @@ -97,13 +97,13 @@ class BrnShareActionSheet extends StatelessWidget { } /// 构建单个分享渠道 - Widget _configChannelWidget(BuildContext context, int section, int index) { + Widget? _configChannelWidget(BuildContext context, int section, int index) { // 分享类型 BrnShareItem channel; // 渠道名称 - String title; + String? title; // 图片 - Widget image; + Widget? image; // 元素宽度(图片边长也是48) double itemsWidth = 48; // 元素间隔为20写死 @@ -112,16 +112,16 @@ class BrnShareActionSheet extends StatelessWidget { image = null; // 判断区域 if (section == 0) { - channel = firstShareChannels[index]; + channel = firstShareChannels![index]; } else { - channel = secondShareChannels[index]; + channel = secondShareChannels![index]; } // 判断是否为自定义标题 - title = (channel.shareType == BrnShareItemConstants.SHARE_CUSTOM) + title = (channel.shareType == BrnShareItemConstants.shareCustom) ? (channel.customTitle ?? "") : BrnShareItemConstants.shareItemTitleList[channel.shareType]; // 判断是否为自定义,如果不是自定义图标,则判断是否可点击(决定是否使用置灰图标) - image = (channel.shareType == BrnShareItemConstants.SHARE_CUSTOM) + image = (channel.shareType == BrnShareItemConstants.shareCustom) ? channel.customImage : (channel.canClick ? BrunoTools.getAssetImage( @@ -129,7 +129,7 @@ class BrnShareActionSheet extends StatelessWidget { : BrunoTools.getAssetImage(BrnShareItemConstants .disableShareItemImagePathList[channel.shareType])); //如果没图或没文字则不显示 - if (title == null || image == null) { + if (image == null) { return null; } @@ -160,10 +160,10 @@ class BrnShareActionSheet extends StatelessWidget { ), onTap: () { if (clickInterceptor == null || - !clickInterceptor(section, index, channel)) { + !clickInterceptor!(section, index, channel)) { // 推荐使用回调方法处理点击事件!!!!!!!!!! if (clickCallBack != null && channel.canClick) { - clickCallBack(section, index, channel); + clickCallBack!(section, index, channel); // 如果未拦截并且可点击,则pop掉当前页面 Navigator.of(context).pop(); } @@ -174,11 +174,11 @@ class BrnShareActionSheet extends StatelessWidget { /// 构建actionSheet的按钮 Widget _configActionWidgets(BuildContext context) { - List tiles = List(); + List tiles = []; // 预设分享渠道 - List firstSectionItems = List(); + List firstSectionItems = []; // 自定义分享渠道 - List secondSectionItems = List(); + List secondSectionItems = []; // 容器左侧留白 double leftGap = 10; // 容器上方留白 @@ -187,8 +187,8 @@ class BrnShareActionSheet extends StatelessWidget { double bottomGap = 20; // 构建第一行 if (firstShareChannels != null) { - for (int index = 0; index < firstShareChannels.length; index++) { - Widget item = _configChannelWidget(context, 0, index); + for (int index = 0; index < firstShareChannels!.length; index++) { + Widget? item = _configChannelWidget(context, 0, index); if (item != null) { firstSectionItems.add(item); } @@ -196,8 +196,8 @@ class BrnShareActionSheet extends StatelessWidget { } // 构建第二行 if (secondShareChannels != null) { - for (int index = 0; index < secondShareChannels.length; index++) { - Widget item = _configChannelWidget(context, 1, index); + for (int index = 0; index < secondShareChannels!.length; index++) { + Widget? item = _configChannelWidget(context, 1, index); if (item != null) { secondSectionItems.add(item); } @@ -268,7 +268,7 @@ class BrnShareActionSheet extends StatelessWidget { padding: EdgeInsets.only(left: 61, right: 61, top: 12, bottom: 12), child: Center( child: Text( - (cancelTitle != null) ? cancelTitle : "取消", + cancelTitle ?? "取消", style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: textColor), ), diff --git a/lib/src/components/appraise/brn_appraise.dart b/lib/src/components/appraise/brn_appraise.dart index c396c807..96963656 100644 --- a/lib/src/components/appraise/brn_appraise.dart +++ b/lib/src/components/appraise/brn_appraise.dart @@ -5,25 +5,9 @@ import 'package:bruno/src/components/appraise/brn_mulit_select_tags.dart'; import 'package:bruno/src/components/button/brn_big_main_button.dart'; import 'package:bruno/src/components/input/brn_input_text.dart'; import 'package:bruno/src/components/picker/brn_tags_picker_config.dart'; +import 'package:bruno/src/components/appraise/brn_appraise_config.dart'; import 'package:flutter/material.dart'; - -/// 点击表情或者星星时的回调 -/// index 点击的表情或者星星的index -typedef BrnAppraiseIconClick = void Function(int index); - -/// 点击tag的回调 -/// selectedTags 所有选中标签的集合 -typedef BrnAppraiseTagClick = void Function(List selectedTags); - -/// 提交按钮点击事件回调 -/// index 选中的表情或者星星的index -/// selectedTags 所有选中标签的集合 -/// input 自定义输入的内容 -typedef BrnAppraiseConfirmClick = void Function( - int index, List selectedTags, String input); - -/// 点击关闭的回掉 -typedef BrnAppraiseCloseClickCallBack = void Function(BuildContext context); +import 'package:bruno/src/components/appraise/brn_appraise_interface.dart'; /// /// /// /// /// /// /// /// /// / /// 描述: 评价组件 @@ -57,13 +41,13 @@ class BrnAppraise extends StatefulWidget { final List iconDescriptions; /// 标签 - final List tags; + final List? tags; ///输入框允许提示文案 final String inputHintText; /// 提交按钮的点击回调 - final BrnAppraiseConfirmClick onConfirm; + final BrnAppraiseConfirmClick? onConfirm; /// 评价组件的配置项 final BrnAppraiseConfig config; @@ -77,16 +61,17 @@ class BrnAppraise extends StatefulWidget { '超惊喜' ]; - BrnAppraise({ - this.title, - this.headerType = BrnAppraiseHeaderType.spaceBetween, - this.type = BrnAppraiseType.Star, - this.iconDescriptions = _defaultIconDescriptions, - this.tags, - this.inputHintText, - this.onConfirm, - this.config = cConfig, - }); + BrnAppraise( + {Key? key, + this.title = '', + this.headerType = BrnAppraiseHeaderType.spaceBetween, + this.type = BrnAppraiseType.star, + this.iconDescriptions = _defaultIconDescriptions, + this.tags, + this.inputHintText = '', + this.onConfirm, + this.config = cConfig}) + : super(key: key); @override _BrnAppraiseState createState() => _BrnAppraiseState(); @@ -94,19 +79,19 @@ class BrnAppraise extends StatefulWidget { class _BrnAppraiseState extends State { int _appraiseIndex = -1; - bool _enable; - String _inputText; - List _selectedTag; + bool? _enable; + String? _inputText; + List _selectedTag = []; @override void initState() { - _enable = widget.config?.isConfirmButtonEnabled; + _enable = widget.config.isConfirmButtonEnabled; super.initState(); } @override void didUpdateWidget(BrnAppraise oldWidget) { - _enable = widget.config?.isConfirmButtonEnabled; + _enable = widget.config.isConfirmButtonEnabled; super.didUpdateWidget(oldWidget); } @@ -149,41 +134,41 @@ class _BrnAppraiseState extends State { ? EdgeInsets.only(top: 20, bottom: 20) : EdgeInsets.only(left: 20, top: 16, right: 16, bottom: 20); return BrnAppraiseHeader( - showHeader: widget.config?.showHeader ?? true, - headerType: widget.headerType ?? BrnAppraiseHeaderType.spaceBetween, - title: widget.title ?? '', - maxLines: widget.config?.titleMaxLines ?? 1, - headPadding: widget.config?.headerPadding ?? defaultPadding, - cancelCallBack: widget.config?.onCancel, + showHeader: widget.config.showHeader, + headerType: widget.headerType, + title: widget.title, + maxLines: widget.config.titleMaxLines, + headPadding: widget.config.headerPadding ?? defaultPadding, + cancelCallBack: widget.config.onCancel, ); } /// 获取评分组件 Widget _getIconWidget() { - if (widget.type == BrnAppraiseType.Emoji) { + if (widget.type == BrnAppraiseType.emoji) { return BrnAppraiseEmojiListView( - indexes: widget.config?.indexes, + indexes: widget.config.indexes, titles: widget.iconDescriptions, onTap: (index) { setState(() { _appraiseIndex = index; }); - if (widget.config?.iconClickCallback != null) { - widget.config.iconClickCallback(index); + if (widget.config.iconClickCallback != null) { + widget.config.iconClickCallback!(index); } }, ); } else { return BrnAppraiseStarListView( - count: widget.config?.count ?? 5, + count: widget.config.count, titles: widget.iconDescriptions, - hint: widget.config?.starAppraiseHint, + hint: widget.config.starAppraiseHint, onTap: (index) { setState(() { _appraiseIndex = index; }); - if (widget.config?.iconClickCallback != null) { - widget.config.iconClickCallback(index); + if (widget.config.iconClickCallback != null) { + widget.config.iconClickCallback!(index); } }, ); @@ -207,12 +192,12 @@ class _BrnAppraiseState extends State { return choice.name; }, // tagStyle: BrnMultiSelectStyle.auto, - multiSelect: widget.config?.multiSelect ?? true, - brnCrossAxisCount: widget.config?.tagCountEachRow ?? 2, + multiSelect: widget.config.multiSelect, + brnCrossAxisCount: widget.config.tagCountEachRow, selectedTagsCallback: (list) { _selectedTag = tag2String(list); - if (widget.config?.tagSelectCallback != null) { - widget.config.tagSelectCallback(_selectedTag); + if (widget.config.tagSelectCallback != null) { + widget.config.tagSelectCallback!(_selectedTag); } }, ), @@ -221,22 +206,22 @@ class _BrnAppraiseState extends State { /// 输入框 Widget _inputArea() { - if (widget.config?.showTextInput ?? true) { + if (widget.config.showTextInput) { return Padding( padding: EdgeInsets.only(top: 24), child: BrnInputText( - maxLength: widget.config?.maxLength ?? 100, + maxLength: widget.config.maxLength, bgColor: Color(0xfff8f8f8), - hint: widget.inputHintText ?? '', - textString: _inputText ?? '', - maxHeight: widget.config?.inputMaxHeight ?? 120, + hint: widget.inputHintText, + textString: (_inputText ?? widget.config.inputDefaultText) ?? '', + maxHeight: widget.config.inputMaxHeight, minHeight: 40, - maxHintLines: widget.config?.maxHintLines ?? 1, + maxHintLines: widget.config.maxHintLines, padding: EdgeInsets.all(12), onTextChange: (input) { _inputText = input; - if (widget.config?.inputTextChangeCallback != null) { - widget.config.inputTextChangeCallback(input); + if (widget.config.inputTextChangeCallback != null) { + widget.config.inputTextChangeCallback!(input); } }, ), @@ -247,16 +232,17 @@ class _BrnAppraiseState extends State { /// 提交按钮 Widget _confirmButton() { - if (widget.config?.showConfirmButton ?? true) { + if (widget.config.showConfirmButton) { return Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: BrnBigMainButton( - title: widget.config?.confirmButtonText ?? '提交', + title: widget.config.confirmButtonText, isEnable: _enable ?? _appraiseIndex != -1, onTap: () { if (_enable ?? _appraiseIndex != -1) { if (widget.onConfirm != null) { - widget.onConfirm(_appraiseIndex, _selectedTag, _inputText); + widget.onConfirm!( + _appraiseIndex, _selectedTag, _inputText ?? ''); } } }, @@ -267,10 +253,10 @@ class _BrnAppraiseState extends State { return Container(); } - List string2Tag(List tags) { - List items = List(); + List string2Tag(List? tags) { + List items = []; if (tags?.isNotEmpty ?? false) { - for (int i = 0; i < tags.length; i++) { + for (int i = 0; i < tags!.length; i++) { items.add(BrnTagItemBean(name: tags[i], code: tags[i], index: i)); } } @@ -278,104 +264,10 @@ class _BrnAppraiseState extends State { } List tag2String(List tags) { - List result = List(); - tags?.forEach((item) { + List result = []; + tags.forEach((item) { result.add(item.name); }); return result; } } - -class BrnAppraiseConfig { - /// 是否显示标题和关闭 - final bool showHeader; - - /// 标题的padding - final EdgeInsets headerPadding; - - /// 标题的最大行数 - final int titleMaxLines; - - /// 取消的回调 - final BrnAppraiseCloseClickCallBack onCancel; - - /// 所需表情包的index列表,index最大值为4 - final List indexes; - - /// 展示的星星的数目 - final int count; - - /// 展示星星时的默认提示 - final String starAppraiseHint; - - /// 标签是否支持多选,默认为 true - final bool multiSelect; - - /// 每行能显示的tag数目,默认为 2 - final int tagCountEachRow; - - ///是否显示输入框,默认为 true - final bool showTextInput; - - ///输入框允许输入的最大长度,默认为 100 - final int maxLength; - - ///提示文案的最大行数,默认为1 - final int maxHintLines; - - /// 输入框默认输入文案 - final String inputDefaultText; - - /// 输入框的最大高度,默认为 120 - final double inputMaxHeight; - - /// 是否显示确认按钮 - final bool showConfirmButton; - - /// 确认按钮的文案 - final String confirmButtonText; - - /// 外部控制提交button的enable状态,null有效,不设置默认值 - final bool isConfirmButtonEnabled; - - /// 点击icon的回调 - final BrnAppraiseIconClick iconClickCallback; - - /// 输入框改变的回调 - final BrnInputTextChangeCallback inputTextChangeCallback; - - /// 选择标签的回调 - final BrnAppraiseTagClick tagSelectCallback; - - const BrnAppraiseConfig({ - this.showHeader = true, - this.headerPadding, - this.titleMaxLines = 1, - this.onCancel, - this.indexes = const [0, 1, 2, 3, 4], - this.count = 5, - this.starAppraiseHint = '', - this.multiSelect = true, - this.tagCountEachRow = 2, - this.showTextInput = true, - this.maxLength = 100, - this.maxHintLines = 1, - this.inputDefaultText, - this.inputMaxHeight = 120, - this.showConfirmButton = true, - this.confirmButtonText = '提交', - this.isConfirmButtonEnabled, - this.iconClickCallback, - this.inputTextChangeCallback, - this.tagSelectCallback, - }); -} - -/// 评价组件类型 -enum BrnAppraiseType { - /// 表情包评价组件 - Emoji, - - /// 星星评价组件 - Star, -} diff --git a/lib/src/components/appraise/brn_appraise_bottom_picker.dart b/lib/src/components/appraise/brn_appraise_bottom_picker.dart index 2701efef..9d6d18da 100644 --- a/lib/src/components/appraise/brn_appraise_bottom_picker.dart +++ b/lib/src/components/appraise/brn_appraise_bottom_picker.dart @@ -1,6 +1,8 @@ import 'package:bruno/src/components/appraise/brn_appraise.dart'; import 'package:bruno/src/components/appraise/brn_appraise_header.dart'; +import 'package:bruno/src/components/appraise/brn_appraise_config.dart'; import 'package:flutter/material.dart'; +import 'package:bruno/src/components/appraise/brn_appraise_interface.dart'; /// 描述: 评价组件bottom picker, /// 对BrnAppraise做了一层封装,可直接使用在showDialog里面 @@ -21,13 +23,13 @@ class BrnAppraiseBottomPicker extends StatefulWidget { final List iconDescriptions; /// 标签 - final List tags; + final List? tags; ///输入框允许提示文案 final String inputHintText; /// 提交按钮的点击回调 - final BrnAppraiseConfirmClick onConfirm; + final BrnAppraiseConfirmClick? onConfirm; /// 评价组件的配置项 final BrnAppraiseConfig config; @@ -42,15 +44,16 @@ class BrnAppraiseBottomPicker extends StatefulWidget { ]; BrnAppraiseBottomPicker({ - this.title, + Key? key, + this.title = '', this.headerType = BrnAppraiseHeaderType.spaceBetween, - this.type = BrnAppraiseType.Star, + this.type = BrnAppraiseType.star, this.iconDescriptions = _defaultIconDescriptions, this.tags, - this.inputHintText, + this.inputHintText = '', this.onConfirm, - this.config, - }); + this.config = const BrnAppraiseConfig(), + }) : super(key: key); @override _BrnAppraiseBottomPickerState createState() => @@ -74,7 +77,7 @@ class _BrnAppraiseBottomPickerState extends State { inputHintText: widget.inputHintText, onConfirm: (index, list, input) { if (widget.onConfirm != null) { - widget.onConfirm(index, list, input); + widget.onConfirm!(index, list, input); } }, config: widget.config, diff --git a/lib/src/components/appraise/brn_appraise_config.dart b/lib/src/components/appraise/brn_appraise_config.dart new file mode 100644 index 00000000..5309e308 --- /dev/null +++ b/lib/src/components/appraise/brn_appraise_config.dart @@ -0,0 +1,97 @@ +import 'package:flutter/material.dart'; +import 'package:bruno/src/components/input/brn_input_text.dart'; +import 'package:bruno/src/components/appraise/brn_appraise_interface.dart'; + +class BrnAppraiseConfig { + /// 是否显示标题和关闭 + final bool showHeader; + + /// 标题的padding + final EdgeInsets? headerPadding; + + /// 标题的最大行数 + final int titleMaxLines; + + /// 取消的回调 + final BrnAppraiseCloseClickCallBack? onCancel; + + /// 所需表情包的index列表,index最大值为4 + final List indexes; + + /// 展示的星星的数目 + final int count; + + /// 展示星星时的默认提示 + final String starAppraiseHint; + + /// 标签是否支持多选,默认为 true + final bool multiSelect; + + /// 每行能显示的tag数目,默认为 2 + final int tagCountEachRow; + + ///是否显示输入框,默认为 true + final bool showTextInput; + + ///输入框允许输入的最大长度,默认为 100 + final int maxLength; + + ///提示文案的最大行数,默认为1 + final int maxHintLines; + + /// 输入框默认输入文案 + final String? inputDefaultText; + + /// 输入框的最大高度,默认为 120 + final double inputMaxHeight; + + /// 是否显示确认按钮 + final bool showConfirmButton; + + /// 确认按钮的文案,默认 '提交' + final String confirmButtonText; + + /// 外部控制提交button的enable状态,null有效,不设置默认值 + final bool? isConfirmButtonEnabled; + + /// 点击icon的回调 + final BrnAppraiseIconClick? iconClickCallback; + + /// 输入框改变的回调 + final BrnInputTextChangeCallback? inputTextChangeCallback; + + /// 选择标签的回调 + final BrnAppraiseTagClick? tagSelectCallback; + + const BrnAppraiseConfig({ + this.showHeader = true, + this.headerPadding, + this.titleMaxLines = 1, + this.onCancel, + this.indexes = const [0, 1, 2, 3, 4], + this.count = 5, + this.starAppraiseHint = '', + this.multiSelect = true, + this.tagCountEachRow = 2, + this.showTextInput = true, + this.maxLength = 100, + this.maxHintLines = 1, + this.inputDefaultText, + this.inputMaxHeight = 120, + this.showConfirmButton = true, + this.confirmButtonText = '提交', + this.isConfirmButtonEnabled, + this.iconClickCallback, + this.inputTextChangeCallback, + this.tagSelectCallback, + }); +} + +/// 评价组件类型 +enum BrnAppraiseType { + /// 表情包评价组件 + emoji, + + /// 星星评价组件 + star, +} diff --git a/lib/src/components/appraise/brn_appraise_emoji_item.dart b/lib/src/components/appraise/brn_appraise_emoji_item.dart index b3867c82..e6e19e0e 100644 --- a/lib/src/components/appraise/brn_appraise_emoji_item.dart +++ b/lib/src/components/appraise/brn_appraise_emoji_item.dart @@ -18,34 +18,36 @@ class BrnAppraiseEmojiItem extends StatefulWidget { /// 默认图片,传入asserts/image 全路径 final String defaultName; - /// 表情所在的index + /// 表情所在的 index final int index; - /// 选中的的index + /// 选中的的 index final int selectedIndex; /// 表情图片下面的说明 - final String title; + final String? title; - /// 加载的gif图帧数 + /// 加载的 gif 图帧数,默认 24 final double frameCount; /// 点击的回调 - final BrnAppraiseEmojiClickCallback onTap; + final BrnAppraiseEmojiClickCallback? onTap; - /// item的padding + /// item的padding,默认 EdgeInsets.only(horizontal: 7) final EdgeInsets padding; BrnAppraiseEmojiItem( - {this.selectedName, - this.unselectedName, - this.defaultName, - this.index, - this.selectedIndex, + {Key? key, + required this.selectedName, + required this.unselectedName, + required this.defaultName, + this.index = 0, + this.selectedIndex = -1, this.title, this.frameCount = 24, this.onTap, - this.padding}); + this.padding = const EdgeInsets.symmetric(horizontal: 7)}) + : super(key: key); @override _BrnAppraiseEmojiItemState createState() => _BrnAppraiseEmojiItemState(); @@ -53,11 +55,11 @@ class BrnAppraiseEmojiItem extends StatefulWidget { class _BrnAppraiseEmojiItemState extends State with SingleTickerProviderStateMixin { - AnimationController _controller; + late AnimationController _controller; - int _selectedIndex; + int _selectedIndex = -1; - GifImage _gif; + late GifImage _gif; @override void initState() { @@ -94,7 +96,7 @@ class _BrnAppraiseEmojiItemState extends State Widget build(BuildContext context) { return GestureDetector( child: Padding( - padding: widget.padding ?? EdgeInsets.only(left: 7, right: 7), + padding: widget.padding, child: Column( mainAxisSize: MainAxisSize.min, children: [ @@ -118,7 +120,7 @@ class _BrnAppraiseEmojiItemState extends State onTap: () { if (_selectedIndex != widget.index) { if (widget.onTap != null) { - widget.onTap(widget.index); + widget.onTap!(widget.index); } _selectedIndex = widget.index; _reset(); diff --git a/lib/src/components/appraise/brn_appraise_emoji_list_view.dart b/lib/src/components/appraise/brn_appraise_emoji_list_view.dart index 52c1cf75..93ef8d1d 100644 --- a/lib/src/components/appraise/brn_appraise_emoji_list_view.dart +++ b/lib/src/components/appraise/brn_appraise_emoji_list_view.dart @@ -1,7 +1,7 @@ -import 'package:bruno/src/components/appraise/brn_appraise.dart'; import 'package:bruno/src/components/appraise/brn_appraise_emoji_item.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:flutter/material.dart'; +import 'package:bruno/src/components/appraise/brn_appraise_interface.dart'; /// 描述: 表情评价列表 /// 最多支持5个表情,默认也是5个,支持选择任意个数, @@ -15,16 +15,18 @@ class BrnAppraiseEmojiListView extends StatefulWidget { final List titles; /// 点击回调 - final BrnAppraiseIconClick onTap; + final BrnAppraiseIconClick? onTap; static const List _defaultTitles = ['不好', '还行', '满意', '很棒', '超惊喜']; BrnAppraiseEmojiListView( - {this.indexes = const [0, 1, 2, 3, 4], + {Key? key, + this.indexes = const [0, 1, 2, 3, 4], this.titles = _defaultTitles, this.onTap}) - : assert((indexes?.length ?? 0) > 0), - assert(titles?.length == 5); + : assert(indexes.length > 0), + assert(titles.length == 5), + super(key: key); @override _BrnAppraiseEmojiListViewState createState() => @@ -34,40 +36,40 @@ class BrnAppraiseEmojiListView extends StatefulWidget { class _BrnAppraiseEmojiListViewState extends State { /// 未选中表情,灰色 List _unselectedIcons = [ - BrnAsset.ICON_APPRAISE_BAD_UNSELECTED, - BrnAsset.ICON_APPRAISE_NOT_GOOD_UNSELECTED, - BrnAsset.ICON_APPRAISE_OK_UNSELECTED, - BrnAsset.ICON_APPRAISE_GOOD_UNSELECTED, - BrnAsset.ICON_APPRAISE_SURPRISE_UNSELECTED, + BrnAsset.iconAppraiseBadUnselected, + BrnAsset.iconAppraiseNotGoodUnselected, + BrnAsset.iconAppraiseOkUnselected, + BrnAsset.iconAppraiseGoodUnselected, + BrnAsset.iconAppraiseSurpriseUnselected, ]; /// 默认表情,黄色 List _defaultIcons = [ - BrnAsset.ICON_APPRAISE_BAD_DEFAULT, - BrnAsset.ICON_APPRAISE_NOT_GOOD_DEFAULT, - BrnAsset.ICON_APPRAISE_OK_DEFAULT, - BrnAsset.ICON_APPRAISE_GOOD_DEFAULT, - BrnAsset.ICON_APPRAISE_SURPRISE_DEFAULT, + BrnAsset.iconAppraiseBadDefault, + BrnAsset.iconAppraiseNotGoodDefault, + BrnAsset.iconAppraiseOkDefault, + BrnAsset.iconAppraiseGoodDefault, + BrnAsset.iconAppraiseSurpriseDefault, ]; /// 选中表情,gif List _selectedIcons = [ - BrnAsset.ICON_APPRAISE_BAD_SELECTED, - BrnAsset.ICON_APPRAISE_NOT_GOOD_SELECTED, - BrnAsset.ICON_APPRAISE_OK_SELECTED, - BrnAsset.ICON_APPRAISE_GOOD_SELECTED, - BrnAsset.ICON_APPRAISE_SURPRISE_SELECTED, + BrnAsset.iconAppraiseBadSelected, + BrnAsset.iconAppraiseNotGoodSelected, + BrnAsset.iconAppraiseOkSelected, + BrnAsset.iconAppraiseGoodSelected, + BrnAsset.iconAppraiseSurpriseSelected, ]; int _selectedIndex = -1; @override Widget build(BuildContext context) { - if (widget.indexes?.isEmpty ?? true) { + if (widget.indexes.isEmpty) { return Container(); } - List list = List(); + List list = []; for (int i = 0; i < widget.indexes.length; i++) { list.add(BrnAppraiseEmojiItem( selectedName: _selectedIcons[widget.indexes[i]], @@ -81,7 +83,7 @@ class _BrnAppraiseEmojiListViewState extends State { onTap: (index) { _selectedIndex = index; if (widget.onTap != null) { - widget.onTap(index); + widget.onTap!(_selectedIndex); } }, )); diff --git a/lib/src/components/appraise/brn_appraise_header.dart b/lib/src/components/appraise/brn_appraise_header.dart index 065962a4..252a0344 100644 --- a/lib/src/components/appraise/brn_appraise_header.dart +++ b/lib/src/components/appraise/brn_appraise_header.dart @@ -1,37 +1,39 @@ -import 'package:bruno/src/components/appraise/brn_appraise.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; +import 'package:bruno/src/components/appraise/brn_appraise_interface.dart'; /// 描述: 评价组件title - class BrnAppraiseHeader extends StatelessWidget { - /// 是否显示标题 + /// 是否显示标题,默认为 true,显示 final bool showHeader; - /// 标题文字 + /// 标题文字,默认 '' final String title; - /// 标题最大行数 + /// 标题最大行数,默认为 1 final int maxLines; - /// 标题类型 + /// 标题类型,默认 [BrnAppraiseHeaderType.spaceBetween] final BrnAppraiseHeaderType headerType; - /// 标题的padding - final EdgeInsets headPadding; + /// 标题的 padding,为 null 时为默认 padding。 + /// headerType 为 spaceBetween 时默认为 EdgeInsets.only(left: 20, top: 16, right: 16, bottom: 20) + /// headerType 为 center 时默认为 EdgeInsets.only(top: 20, bottom: 20) + final EdgeInsets? headPadding; /// 点击关闭的回掉 - final BrnAppraiseCloseClickCallBack cancelCallBack; + final BrnAppraiseCloseClickCallBack? cancelCallBack; BrnAppraiseHeader( - {this.showHeader = true, + {Key? key, + this.showHeader = true, this.title = '', this.maxLines = 1, this.headerType = BrnAppraiseHeaderType.spaceBetween, this.headPadding, - this.cancelCallBack}); + this.cancelCallBack}) : super(key: key); @override Widget build(BuildContext context) { @@ -42,16 +44,16 @@ class BrnAppraiseHeader extends StatelessWidget { return _centerHeader(); } } - return Container(); + return SizedBox.shrink(); } Widget _centerHeader() { return Container( color: Colors.white, - padding: headPadding ?? EdgeInsets.only(top: 20, bottom: 20), + padding: headPadding ?? const EdgeInsets.only(top: 20, bottom: 20), child: Text( - title ?? '', - maxLines: maxLines ?? 1, + title, + maxLines: maxLines, style: TextStyle( color: BrnThemeConfigurator.instance .getConfig() @@ -67,7 +69,7 @@ class BrnAppraiseHeader extends StatelessWidget { Widget _spaceHeader(BuildContext context) { return Container( color: Colors.white, - height: 38 + (maxLines ?? 1) * 22.0, + height: 38 + maxLines * 22.0, child: Padding( padding: headPadding ?? EdgeInsets.only(left: 20, top: 16, right: 16, bottom: 20), @@ -79,8 +81,8 @@ class BrnAppraiseHeader extends StatelessWidget { child: Padding( padding: EdgeInsets.only(top: 4, right: 12), child: Text( - title ?? '', - maxLines: maxLines ?? 1, + title, + maxLines: maxLines, style: TextStyle( color: BrnThemeConfigurator.instance .getConfig() @@ -96,11 +98,11 @@ class BrnAppraiseHeader extends StatelessWidget { InkWell( onTap: () { if (cancelCallBack != null) { - cancelCallBack(context); + cancelCallBack!(context); } Navigator.of(context).pop(); }, - child: BrunoTools.getAssetImage(BrnAsset.ICON_PICKER_CLOSE), + child: BrunoTools.getAssetImage(BrnAsset.iconPickerClose), ), ], ), diff --git a/lib/src/components/appraise/brn_appraise_interface.dart b/lib/src/components/appraise/brn_appraise_interface.dart new file mode 100644 index 00000000..f3b70cb2 --- /dev/null +++ b/lib/src/components/appraise/brn_appraise_interface.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +/// 点击表情或者星星时的回调 +/// index 点击的表情或者星星的index +typedef BrnAppraiseIconClick = void Function(int index); + +/// 点击tag的回调 +/// selectedTags 所有选中标签的集合 +typedef BrnAppraiseTagClick = void Function(List selectedTags); + +/// 提交按钮点击事件回调 +/// index 选中的表情或者星星的index +/// selectedTags 所有选中标签的集合 +/// input 自定义输入的内容 +typedef BrnAppraiseConfirmClick = void Function( + int index, List selectedTags, String input); + +/// 点击关闭的回掉 +typedef BrnAppraiseCloseClickCallBack = void Function(BuildContext context); \ No newline at end of file diff --git a/lib/src/components/appraise/brn_appraise_star_list_view.dart b/lib/src/components/appraise/brn_appraise_star_list_view.dart index c4aef940..9859a9ee 100644 --- a/lib/src/components/appraise/brn_appraise_star_list_view.dart +++ b/lib/src/components/appraise/brn_appraise_star_list_view.dart @@ -1,4 +1,3 @@ -import 'package:bruno/src/components/appraise/brn_appraise.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/utils/brn_tools.dart'; @@ -11,17 +10,19 @@ class BrnAppraiseStarListView extends StatefulWidget { final int count; /// 未选中时的提示 - final String hint; + final String? hint; /// 星星下面的文案,点击对应的星星会显示相应index的文案,titles长度不能比count小 final List titles; /// 点击回调 - final BrnAppraiseIconClick onTap; + final ValueChanged? onTap; - BrnAppraiseStarListView({this.count = 5, this.titles, this.hint, this.onTap}) + BrnAppraiseStarListView( + {Key? key, this.count = 5, required this.titles, this.hint, this.onTap}) : assert(count > 0 && count <= 5), - assert(titles == null || titles.length >= count); + assert(titles.length >= count), + super(key: key); @override _BrnAppraiseStarListViewState createState() => @@ -39,11 +40,11 @@ class _BrnAppraiseStarListViewState extends State { @override Widget build(BuildContext context) { - if (widget.titles?.isEmpty ?? true) { + if (widget.titles.isEmpty) { return _buildStars(); } else { Widget subWidget = Container(); - String subTitle = widget.hint; + String? subTitle = widget.hint; if (_selectedIndex >= 0 && _selectedIndex < widget.titles.length) { subTitle = widget.titles[_selectedIndex]; } @@ -72,7 +73,7 @@ class _BrnAppraiseStarListViewState extends State { } Widget _buildStars() { - List list = List(); + List list = []; for (int i = 0; i < widget.count; i++) { Widget item = GestureDetector( child: Padding( @@ -81,7 +82,7 @@ class _BrnAppraiseStarListViewState extends State { ), onTap: () { if (widget.onTap != null) { - widget.onTap(i); + widget.onTap!(i); } _selectedIndex = i; }, diff --git a/lib/src/components/appraise/brn_flutter_gif_image.dart b/lib/src/components/appraise/brn_flutter_gif_image.dart index efa21010..cd624bba 100644 --- a/lib/src/components/appraise/brn_flutter_gif_image.dart +++ b/lib/src/components/appraise/brn_flutter_gif_image.dart @@ -1,7 +1,6 @@ import 'dart:ui' as ui show Codec; import 'dart:ui'; -import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; /// 描述: 用于加载gif图, @@ -9,26 +8,26 @@ import 'package:flutter/widgets.dart'; /// 感谢 Jpeng class GifImage extends StatefulWidget { - final VoidCallback onFetchCompleted; + final VoidCallback? onFetchCompleted; final AnimationController controller; final ImageProvider image; - final double width; - final double height; - final Color color; - final BlendMode colorBlendMode; - final BoxFit fit; + final double? width; + final double? height; + final Color? color; + final BlendMode? colorBlendMode; + final BoxFit? fit; final AlignmentGeometry alignment; final ImageRepeat repeat; - final Rect centerSlice; + final Rect? centerSlice; final bool matchTextDirection; final bool gaplessPlayback; - final String semanticLabel; + final String? semanticLabel; final bool excludeFromSemantics; - final Widget defaultImage; + final Widget? defaultImage; GifImage({ - @required this.image, - @required this.controller, + required this.image, + required this.controller, this.semanticLabel, this.excludeFromSemantics = false, this.width, @@ -50,8 +49,7 @@ class GifImage extends StatefulWidget { } class GifImageState extends State { - ValueNotifier> _images = - ValueNotifier>(List()); + ValueNotifier> _images = ValueNotifier>([]); double _curValue = 0.0; @override @@ -80,7 +78,7 @@ class GifImageState extends State { return ValueListenableBuilder( ///数据发生变化时回调 builder: (context, value, child) { - return _buildImage(value); + return _buildImage(value as List); }, ///监听的数据 @@ -88,19 +86,19 @@ class GifImageState extends State { ); } - Widget _buildImage(List imageInfo) { + Widget _buildImage(List? imageInfo) { int length = (imageInfo?.length ?? 0); int _curIndex = (_curValue * length).toInt(); int index = -1; if (length > 0) { index = length == _curIndex ? length - 1 : _curIndex; } - if (index != -1 && imageInfo[index]?.image != null) { + if (index != -1 && imageInfo?[index].image != null) { RawImage _image = RawImage( - image: imageInfo[index].image, + image: imageInfo?[index].image, width: widget.width, height: widget.height, - scale: imageInfo[index]?.scale ?? 1.0, + scale: imageInfo?[index].scale ?? 1.0, color: widget.color, colorBlendMode: widget.colorBlendMode, fit: widget.fit, @@ -124,17 +122,17 @@ class GifImageState extends State { } Future fetchGif(ImageProvider provider) async { - List infos = List(); - dynamic data; - - AssetBundleImageKey key = await provider.obtainKey(ImageConfiguration()); - data = await key.bundle.load(key.name); - - ui.Codec codec = await PaintingBinding.instance - .instantiateImageCodec(data.buffer.asUint8List()); - for (int i = 0; i < codec.frameCount; i++) { - FrameInfo frameInfo = await codec.getNextFrame(); - infos.add(ImageInfo(image: frameInfo.image)); + List infos = []; + if (provider is AssetImage) { + dynamic data; + AssetBundleImageKey key = await provider.obtainKey(ImageConfiguration()); + data = await key.bundle.load(key.name); + ui.Codec codec = await PaintingBinding.instance! + .instantiateImageCodec(data.buffer.asUint8List()); + for (int i = 0; i < codec.frameCount; i++) { + FrameInfo frameInfo = await codec.getNextFrame(); + infos.add(ImageInfo(image: frameInfo.image)); + } } _images.value = infos; } diff --git a/lib/src/components/appraise/brn_mulit_select_tags.dart b/lib/src/components/appraise/brn_mulit_select_tags.dart index 3d463c82..495db92f 100644 --- a/lib/src/components/appraise/brn_mulit_select_tags.dart +++ b/lib/src/components/appraise/brn_mulit_select_tags.dart @@ -23,12 +23,12 @@ typedef BrnMultiSelectedTagsCallback = void Function( class BrnMultiSelectTags extends StatefulWidget { ///当点击到最大数目时的点击事件 - final VoidCallback onMaxSelectClick; + final VoidCallback? onMaxSelectClick; - ///一行多少个数据 + ///一行多少个数据,默认 2 final int brnCrossAxisCount; - ///最多选择多少个item - 默认可以无限选 + ///最多选择多少个item - 默认0,可以无限选 final int maxSelectItemCount; /// 本类属性 @@ -38,12 +38,12 @@ class BrnMultiSelectTags extends StatefulWidget { final BrnMultiSelectTagText tagText; /// 已选中列表 - final BrnMultiSelectedTagsCallback selectedTagsCallback; + final BrnMultiSelectedTagsCallback? selectedTagsCallback; /// 没有数据时的样式 - final Widget emptyWidget; + final Widget? emptyWidget; - /// 没有数据时的样式 + /// 没有数据时的样式,如果为 null,默认 EdgeInsets.only(top: 0.0, left: 20.0, right: 20.0, bottom: 0.0) final EdgeInsets padding; ///是等分样式还是流式布局样式 默认等分 @@ -53,25 +53,26 @@ class BrnMultiSelectTags extends StatefulWidget { final bool multiSelect; /// 滑动选项 - final ScrollPhysics physics; + final ScrollPhysics? physics; - /// 最小宽度 + /// 最小宽度,默认 75 final double minWidth; BrnMultiSelectTags({ - @required this.tagPickerBean, - @required this.tagText, + Key? key, + required this.tagPickerBean, + required this.tagText, this.onMaxSelectClick, this.maxSelectItemCount = 0, - this.brnCrossAxisCount, + this.brnCrossAxisCount = 2, this.tagStyle = BrnMultiSelectStyle.average, this.selectedTagsCallback, this.emptyWidget, - this.padding, + this.padding = const EdgeInsets.symmetric(horizontal: 20), this.multiSelect = true, this.physics, - this.minWidth, - }); + this.minWidth = 75, + }) : super(key: key); @override _BrnMultiSelectTagsState createState() => _BrnMultiSelectTagsState(); @@ -79,8 +80,8 @@ class BrnMultiSelectTags extends StatefulWidget { class _BrnMultiSelectTagsState extends State { /// 操作类型属性 - List _selectedTags; - List _sourceTags; + List _selectedTags = []; + List _sourceTags = []; @override void initState() { @@ -90,7 +91,7 @@ class _BrnMultiSelectTagsState extends State { @override Widget build(BuildContext context) { - if (widget.tagPickerBean?.tagItemSource?.isNotEmpty ?? false) { + if (widget.tagPickerBean.tagItemSource.isNotEmpty) { return _buildContent(context); } else { return widget.emptyWidget ?? @@ -113,7 +114,7 @@ class _BrnMultiSelectTagsState extends State { ///等宽度的布局 Widget _buildGridViewWidget(BuildContext context) { - int brnCrossAxisCount = widget.brnCrossAxisCount ?? 2; + int brnCrossAxisCount = widget.brnCrossAxisCount; double width = (MediaQuery.of(context).size.width - (brnCrossAxisCount - 1) * 12 - 40) / @@ -122,8 +123,7 @@ class _BrnMultiSelectTagsState extends State { double brnChildAspectRatio = width / 34.0; return Container( - padding: widget.padding ?? - EdgeInsets.only(top: 0.0, left: 20.0, right: 20.0, bottom: 0.0), + padding: widget.padding, constraints: BoxConstraints(maxHeight: 322, minHeight: 120), child: GridView.count( shrinkWrap: true, @@ -146,7 +146,7 @@ class _BrnMultiSelectTagsState extends State { ///流式布局 Widget _buildWrapViewWidget(BuildContext context) { return Container( - padding: widget.padding ?? EdgeInsets.symmetric(horizontal: 20), + padding: widget.padding, child: Wrap( spacing: 12, runSpacing: 12, @@ -158,8 +158,8 @@ class _BrnMultiSelectTagsState extends State { } void _dataSetup() { - List tagItems = List(); - List tagSelectItems = List(); + List tagItems = []; + List tagSelectItems = []; for (BrnTagItemBean item in widget.tagPickerBean.tagItemSource) { tagItems.add(item); //选中的按钮 @@ -176,14 +176,14 @@ class _BrnMultiSelectTagsState extends State { void _clickTag(bool selected, BrnTagItemBean tagName) { if (!widget.multiSelect) { /// 单选 - _sourceTags?.forEach((tag) { + _sourceTags.forEach((tag) { tag.isSelect = false; }); - _selectedTags?.clear(); + _selectedTags.clear(); tagName.isSelect = true; _selectedTags.add(tagName); if (widget.selectedTagsCallback != null) { - widget.selectedTagsCallback(_selectedTags); + widget.selectedTagsCallback!(_selectedTags); } } else { /// 多选 @@ -195,7 +195,7 @@ class _BrnMultiSelectTagsState extends State { _selectedTags.remove(tagName); } if (widget.selectedTagsCallback != null) { - widget.selectedTagsCallback(_selectedTags); + widget.selectedTagsCallback!(_selectedTags); } } } @@ -226,7 +226,7 @@ class _BrnMultiSelectTagsState extends State { setState(() {}); }, child: Container( - constraints: BoxConstraints(minWidth: widget.minWidth ?? 75), + constraints: BoxConstraints(minWidth: widget.minWidth), decoration: BoxDecoration( color: bgColor, borderRadius: BorderRadius.circular(3.0)), padding: padding, diff --git a/lib/src/components/button/brn_big_ghost_button.dart b/lib/src/components/button/brn_big_ghost_button.dart index 9722e302..c75d2369 100644 --- a/lib/src/components/button/brn_big_ghost_button.dart +++ b/lib/src/components/button/brn_big_ghost_button.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/button/brn_normal_button.dart'; import 'package:bruno/src/theme/brn_theme.dart'; import 'package:flutter/material.dart'; @@ -17,31 +19,25 @@ import 'package:flutter/material.dart'; /// * [BrnBigMainButton], 大主色调按钮 /// * [BrnBigOutlineButton], 大边框按钮 -/// 默认水平间距 -const double _BHorizontalPadding = 16; - -/// 默认垂直间距 -const double _BVerticalPadding = 8; - class BrnBigGhostButton extends StatelessWidget { ///按钮文案,默认'确认' final String title; ///文案颜色 - final Color titleColor; + final Color? titleColor; ///按钮背景颜色 - final Color bgColor; + final Color? bgColor; ///点击回调 - final VoidCallback onTap; + final VoidCallback? onTap; ///默认父布局可用空间 - final double width; - final BrnButtonConfig themeData; + final double? width; + final BrnButtonConfig? themeData; const BrnBigGhostButton({ - Key key, + Key? key, this.title = '确认', this.titleColor, this.bgColor, @@ -55,8 +51,7 @@ class BrnBigGhostButton extends StatelessWidget { BrnButtonConfig defaultThemeConfig = themeData ?? BrnButtonConfig(); defaultThemeConfig = BrnThemeConfigurator.instance .getConfig(configId: defaultThemeConfig.configId) - .buttonConfig - .merge(defaultThemeConfig); + .buttonConfig.merge(defaultThemeConfig); return BrnNormalButton( borderRadius: BorderRadius.circular(defaultThemeConfig.bigButtonRadius), @@ -67,11 +62,9 @@ class BrnBigGhostButton extends StatelessWidget { defaultThemeConfig.commonConfig.brandPrimary.withOpacity(0.05), onTap: onTap, alignment: Alignment.center, - text: title ?? '确认', + text: title, textColor: titleColor ?? defaultThemeConfig.commonConfig.brandPrimary, fontSize: defaultThemeConfig.bigButtonFontSize, - insertPadding: EdgeInsets.symmetric( - vertical: _BVerticalPadding, horizontal: _BHorizontalPadding), ); } } diff --git a/lib/src/components/button/brn_big_main_button.dart b/lib/src/components/button/brn_big_main_button.dart index 3077bc6d..26e5b8cd 100644 --- a/lib/src/components/button/brn_big_main_button.dart +++ b/lib/src/components/button/brn_big_main_button.dart @@ -1,6 +1,6 @@ -import 'package:bruno/bruno.dart'; import 'package:bruno/src/theme/brn_theme.dart'; import 'package:flutter/material.dart'; +import 'brn_normal_button.dart'; /// 页面中的主按钮,支持动态设置背景颜色,置灰 /// @@ -27,12 +27,6 @@ import 'package:flutter/material.dart'; /// * [BrnBigGhostButton], 大主色调的幽灵按钮 /// * [BrnBigOutlineButton], 大边框按钮 -/// 默认水平间距 -const double _BHorizontalPadding = 16; - -/// 默认垂直间距 -const double _BVerticalPadding = 8; - class BrnBigMainButton extends StatelessWidget { ///按钮显示文案,默认'确认' final String title; @@ -41,18 +35,18 @@ class BrnBigMainButton extends StatelessWidget { final bool isEnable; ///点击回调 - final VoidCallback onTap; + final VoidCallback? onTap; ///默认父布局可用空间 - final double width; + final double? width; ///背景颜色 - final Color bgColor; + final Color? bgColor; - final BrnButtonConfig themeData; + final BrnButtonConfig? themeData; const BrnBigMainButton({ - Key key, + Key? key, this.title = '确认', this.width, this.isEnable = true, @@ -67,24 +61,21 @@ class BrnBigMainButton extends StatelessWidget { defaultThemeConfig = BrnThemeConfigurator.instance .getConfig(configId: defaultThemeConfig.configId) - .buttonConfig - .merge(defaultThemeConfig); + .buttonConfig.merge(defaultThemeConfig); return BrnNormalButton( constraints: BoxConstraints.tightFor( width: width ?? double.infinity, height: defaultThemeConfig.bigButtonHeight), alignment: Alignment.center, - isEnable: isEnable ?? true, - text: title ?? '确认', + isEnable: isEnable, + text: title, backgroundColor: bgColor ?? defaultThemeConfig.commonConfig.brandPrimary, disableBackgroundColor: Color(0xFFCCCCCC), onTap: onTap, textColor: Colors.white, disableTextColor: defaultThemeConfig.commonConfig.colorTextBaseInverse.withOpacity(0.7), - insertPadding: EdgeInsets.symmetric( - horizontal: _BHorizontalPadding, vertical: _BVerticalPadding), ); } } diff --git a/lib/src/components/button/brn_big_outline_button.dart b/lib/src/components/button/brn_big_outline_button.dart index 9940fe9d..b6b6804d 100644 --- a/lib/src/components/button/brn_big_outline_button.dart +++ b/lib/src/components/button/brn_big_outline_button.dart @@ -1,7 +1,8 @@ + + import 'package:bruno/src/components/button/brn_big_ghost_button.dart'; import 'package:bruno/src/components/button/brn_normal_button.dart'; import 'package:bruno/src/theme/brn_theme.dart'; -import 'package:bruno/src/utils/brn_multi_click_util.dart'; import 'package:flutter/material.dart'; /// 页面的边框按钮,没有背景颜色,占据父节点分配的最大空间 @@ -27,12 +28,6 @@ import 'package:flutter/material.dart'; /// * [BrnBigGhostButton], 大幽灵按钮 /// -/// 默认水平间距 -const double _BHorizontalPadding = 16; - -/// 默认垂直间距 -const double _BVerticalPadding = 8; - /// 默认线宽 const double _BBorderWith = 1; @@ -41,23 +36,23 @@ class BrnBigOutlineButton extends StatelessWidget { final String title; ///边框的颜色 - final Color lineColor; + final Color? lineColor; ///点击回调 - final VoidCallback onTap; + final VoidCallback? onTap; ///显示的文案的颜色 - final Color textColor; + final Color? textColor; ///是否可用,默认为true。false为不可用:置灰、不可点击。 final bool isEnable; ///默认父布局可用空间 - final double width; - final BrnButtonConfig themeData; + final double? width; + final BrnButtonConfig? themeData; const BrnBigOutlineButton({ - Key key, + Key? key, this.title = '确认', this.lineColor, this.textColor, @@ -73,16 +68,15 @@ class BrnBigOutlineButton extends StatelessWidget { defaultThemeConfig = BrnThemeConfigurator.instance .getConfig(configId: defaultThemeConfig.configId) - .buttonConfig - .merge(defaultThemeConfig); + .buttonConfig.merge(defaultThemeConfig); - Color _lineColor = + Color? _lineColor = lineColor ?? defaultThemeConfig.commonConfig.borderColorBase; return BrnNormalButton.outline( borderWith: _BBorderWith, radius: defaultThemeConfig.bigButtonRadius, - text: title ?? "", + text: title, disableLineColor: _lineColor, lineColor: _lineColor, textColor: textColor ?? defaultThemeConfig.commonConfig.colorTextBase, @@ -95,8 +89,6 @@ class BrnBigOutlineButton extends StatelessWidget { width: width ?? double.infinity, height: defaultThemeConfig.bigButtonHeight), onTap: onTap, - insertPadding: EdgeInsets.symmetric( - vertical: _BVerticalPadding, horizontal: _BHorizontalPadding), backgroundColor: Colors.white, disableBackgroundColor: Color(0xffcccccc).withOpacity(0.1), ); diff --git a/lib/src/components/button/brn_icon_button.dart b/lib/src/components/button/brn_icon_button.dart index e834a3df..57894d43 100644 --- a/lib/src/components/button/brn_icon_button.dart +++ b/lib/src/components/button/brn_icon_button.dart @@ -25,10 +25,10 @@ class BrnIconButton extends StatefulWidget { final String name; /// 需要传的icon - final Widget iconWidget; + final Widget? iconWidget; /// 点击的回调 - final VoidCallback onTap; + final VoidCallback? onTap; /// 文字相对于图片的位置 final Direction direction; @@ -43,7 +43,7 @@ class BrnIconButton extends StatefulWidget { final double fontSize; /// 文字样式 - final TextStyle style; + final TextStyle? style; /// 图文组合的宽度,默认 80 final double widgetWidth; @@ -58,8 +58,8 @@ class BrnIconButton extends StatefulWidget { final MainAxisAlignment mainAxisAlignment; const BrnIconButton({ - Key key, - @required this.name, + Key? key, + required this.name, this.iconWidget, this.onTap, this.iconWidth = 24, @@ -71,7 +71,7 @@ class BrnIconButton extends StatefulWidget { this.padding = 4, this.style, this.mainAxisAlignment = MainAxisAlignment.center, - }); + }): super(key: key); @override _BrnIconButtonState createState() => _BrnIconButtonState(); @@ -85,17 +85,15 @@ class _BrnIconButtonState extends State { // Left、文字在左 icon在右 right、文字在右 icon在左 if (widget.direction == Direction.bottom) { ctn = Container( - height: widget.widgetHeight ?? 80, - width: widget.widgetWidth ?? 80, + height: widget.widgetHeight, + width: widget.widgetWidth, child: Column( mainAxisAlignment: widget.mainAxisAlignment, mainAxisSize: MainAxisSize.min, children: [ // 图片 Container( - height: widget.iconHeight, - width: widget.iconWidth, - child: widget.iconWidget), + height: widget.iconHeight, width: widget.iconWidth, child: widget.iconWidget), Padding( padding: EdgeInsets.only(top: widget.padding), child: Text( @@ -113,16 +111,19 @@ class _BrnIconButtonState extends State { ) ], )); - } else if (widget.direction == Direction.top) { + } else if (widget.direction == Direction.left) { ctn = Container( - height: widget.widgetHeight ?? 80, - width: widget.widgetWidth ?? 80, - child: Column( + height: widget.widgetHeight, + width: widget.widgetWidth, + child: Row( mainAxisAlignment: widget.mainAxisAlignment, mainAxisSize: MainAxisSize.min, children: [ + // 图片 + Container( + height: widget.iconHeight, width: widget.iconWidth, child: widget.iconWidget), Padding( - padding: EdgeInsets.only(bottom: widget.padding), + padding: EdgeInsets.only(left: widget.padding), child: Text( widget.name, style: widget.style ?? @@ -135,31 +136,19 @@ class _BrnIconButtonState extends State { ), overflow: TextOverflow.ellipsis, ), - ), - - // 图片 - Container( - child: widget.iconWidget, - height: widget.iconHeight, - width: widget.iconWidth, - ), + ) ], )); - } else if (widget.direction == Direction.left) { + } else if (widget.direction == Direction.right) { ctn = Container( - height: widget.widgetHeight ?? 80, - width: widget.widgetWidth ?? 80, + height: widget.widgetHeight, + width: widget.widgetWidth, child: Row( mainAxisAlignment: widget.mainAxisAlignment, mainAxisSize: MainAxisSize.min, children: [ - // 图片 - Container( - height: widget.iconHeight, - width: widget.iconWidth, - child: widget.iconWidget), Padding( - padding: EdgeInsets.only(left: widget.padding), + padding: EdgeInsets.only(right: widget.padding), child: Text( widget.name, style: widget.style ?? @@ -172,19 +161,22 @@ class _BrnIconButtonState extends State { ), overflow: TextOverflow.ellipsis, ), - ) + ), + // 图片 + Container( + height: widget.iconHeight, width: widget.iconWidth, child: widget.iconWidget), ], )); - } else if (widget.direction == Direction.right) { + } else { ctn = Container( - height: widget.widgetHeight ?? 80, - width: widget.widgetWidth ?? 80, - child: Row( + height: widget.widgetHeight, + width: widget.widgetWidth, + child: Column( mainAxisAlignment: widget.mainAxisAlignment, mainAxisSize: MainAxisSize.min, children: [ Padding( - padding: EdgeInsets.only(right: widget.padding), + padding: EdgeInsets.only(bottom: widget.padding), child: Text( widget.name, style: widget.style ?? @@ -198,11 +190,13 @@ class _BrnIconButtonState extends State { overflow: TextOverflow.ellipsis, ), ), + // 图片 Container( - height: widget.iconHeight, - width: widget.iconWidth, - child: widget.iconWidget), + child: widget.iconWidget, + height: widget.iconHeight, + width: widget.iconWidth, + ), ], )); } @@ -211,7 +205,7 @@ class _BrnIconButtonState extends State { return GestureDetector( child: ctn, onTap: () { - widget?.onTap(); + widget.onTap!(); }, ); } diff --git a/lib/src/components/button/brn_normal_button.dart b/lib/src/components/button/brn_normal_button.dart index 4cdef410..a5dc4e91 100644 --- a/lib/src/components/button/brn_normal_button.dart +++ b/lib/src/components/button/brn_normal_button.dart @@ -1,4 +1,4 @@ -import 'package:bruno/bruno.dart'; +import 'package:bruno/src/constants/brn_constants.dart'; import 'package:bruno/src/utils/brn_multi_click_util.dart'; import 'package:flutter/material.dart'; @@ -8,8 +8,6 @@ const Color _BBackgroundColor = Color(0xFF0984F9); const Color _BDisableBackgroundColor = Color(0xFFCCCCCC); const FontWeight _BFontWeight = FontWeight.bold; const double _BRadius = 6; -const double _BHorizontalPadding = 16; -const double _BVerticalPadding = 8; /// 通用按钮,支持用户设置背景色、是否可用等属性 /// 若[BrnBigMainButton]、[BrnSmallMainButton]、[BrnBigOutlineButton]不能满足用户需要 @@ -75,7 +73,7 @@ class BrnNormalButton extends StatelessWidget { final bool isEnable; /// 按钮点击的回调 - final VoidCallback onTap; + final VoidCallback? onTap; /// 按钮显示的文案 final String text; @@ -87,25 +85,25 @@ class BrnNormalButton extends StatelessWidget { final double fontSize; /// 按钮不可用的文字颜色 - final Color disableTextColor; - - /// 按钮不可用背景色 默认[_BDisableBackgroundColor] - final Color disableBackgroundColor; + final Color? disableTextColor; /// 按钮背景色 默认[_BBackgroundColor] final Color backgroundColor; + /// 按钮不可用背景色 默认[_BDisableBackgroundColor] + final Color disableBackgroundColor; + /// 按钮内边距 默认水平[_BHorizontalPadding] 垂直[_BVerticalPadding] final EdgeInsetsGeometry insertPadding; /// 按钮的修饰 默认实色背景 - final Decoration decoration; + final Decoration? decoration; /// 按钮的显示子节点 优先级高于[text] - final Widget child; + final Widget? child; /// 按钮的文本显示样式 优先级高于[textColor]等属性 - final TextStyle textStyle; + final TextStyle? textStyle; /// 按钮的文本Weight 默认是[FontWeight.bold] final FontWeight fontWeight; @@ -114,78 +112,82 @@ class BrnNormalButton extends StatelessWidget { final BoxConstraints constraints; /// 按钮的内部对齐 默认为null - final Alignment alignment; + final Alignment? alignment; /// 按钮圆角大小 final BorderRadiusGeometry borderRadius; - BrnNormalButton( - {@required this.text, - this.backgroundColor, - this.isEnable = true, - this.onTap, - this.insertPadding, - this.decoration, - this.child, - this.textStyle, - this.fontWeight, - this.fontSize, - this.textColor, - this.disableTextColor, - this.disableBackgroundColor, - this.constraints, - this.borderRadius, - this.alignment}); + BrnNormalButton({ + Key? key, + required this.text, + this.backgroundColor = _BBackgroundColor, + this.isEnable = true, + this.onTap, + this.insertPadding = const EdgeInsets.symmetric( + vertical: BrnButtonConstant.verticalPadding, + horizontal: BrnButtonConstant.horizontalPadding), + this.decoration, + this.child, + this.textStyle, + this.fontWeight = _BFontWeight, + this.fontSize = _BFontSize, + this.textColor = _BTextColor, + this.disableTextColor, + this.disableBackgroundColor = _BDisableBackgroundColor, + this.constraints = const BoxConstraints.tightFor(), + this.borderRadius = const BorderRadius.all(Radius.circular(_BRadius)), + this.alignment, + }) : super(key: key); BrnNormalButton.outline({ - Color disableLineColor, - Color lineColor, + Key? key, + Color? disableLineColor, + Color? lineColor, double radius = 6, double borderWith = 1.0, - @required this.text, + required this.text, this.isEnable = true, - this.backgroundColor, - this.disableBackgroundColor, + this.backgroundColor = _BBackgroundColor, + this.disableBackgroundColor = _BDisableBackgroundColor, this.alignment, this.child, this.onTap, - this.textColor, - this.fontSize, + this.textColor = _BTextColor, + this.fontWeight = _BFontWeight, + this.fontSize = _BFontSize, this.disableTextColor, - this.insertPadding, + this.insertPadding = const EdgeInsets.symmetric( + vertical: BrnButtonConstant.verticalPadding, + horizontal: BrnButtonConstant.horizontalPadding), this.textStyle, - this.fontWeight, - this.constraints, - this.borderRadius, - }) : decoration = _OutlineBoxDecorationCreator.createOutlineBoxDecoration( + this.constraints = const BoxConstraints.tightFor(), + this.borderRadius = const BorderRadius.all(Radius.circular(_BRadius)), + }) : decoration = _OutlineBoxDecorationCreator.createOutlineBoxDecoration( isEnable: isEnable, disableBackgroundColor: disableBackgroundColor, disableLineColor: disableLineColor, lineColor: lineColor, backgroundColor: backgroundColor, radius: radius, - borderWith: borderWith); + borderWith: borderWith), + super(key: key); @override Widget build(BuildContext context) { - Color bgColor = _getBackgroundColor(); - return GestureDetector( onTap: () { if (BrnMultiClickUtils.isMultiClick()) { return; } if (isEnable && onTap != null) { - onTap(); + onTap!(); } }, child: Container( alignment: alignment, - decoration: decoration ?? _getBoxDecoration(bgColor), - constraints: constraints ?? BoxConstraints.tightFor(), - padding: insertPadding ?? - EdgeInsets.symmetric( - vertical: _BVerticalPadding, horizontal: _BHorizontalPadding), + decoration: decoration ?? _getBoxDecoration(_getBackgroundColor()), + constraints: constraints, + padding: insertPadding, child: child ?? Text( text, @@ -199,62 +201,45 @@ class BrnNormalButton extends StatelessWidget { TextStyle _getTextStyle() { if (textStyle != null) { - return textStyle; + return textStyle!; } Color textColor; if (isEnable) { textColor = this.textColor; - if (textColor == null) { - textColor = _BTextColor; - } } else { - textColor = this.disableTextColor; - if (textColor == null) { - textColor = (this.textColor ?? _BTextColor).withOpacity(0.7); - } + textColor = this.disableTextColor ?? (this.textColor).withOpacity(0.7); } return TextStyle( - fontSize: fontSize ?? _BFontSize, + fontSize: fontSize, color: textColor, - fontWeight: fontWeight ?? _BFontWeight, + fontWeight: fontWeight, ); } Color _getBackgroundColor() { - Color bgColor; - if (isEnable) { - bgColor = backgroundColor; - if (bgColor == null) { - bgColor = _BBackgroundColor; - } - } else { - bgColor = disableBackgroundColor; - if (bgColor == null) { - bgColor = _BDisableBackgroundColor; - } - } - return bgColor; + return isEnable ? backgroundColor : disableBackgroundColor; } - BoxDecoration _getBoxDecoration(Color bgColor) { + BoxDecoration _getBoxDecoration(Color? bgColor) { return BoxDecoration( color: bgColor, - borderRadius: borderRadius ?? BorderRadius.all(Radius.circular(_BRadius)), + borderRadius: borderRadius, ); } } class _OutlineBoxDecorationCreator { - static BoxDecoration createOutlineBoxDecoration( - {bool isEnable, - Color disableLineColor, - Color lineColor, - Color disableBackgroundColor, - Color backgroundColor, - double radius = 6, - double borderWith = 1.0}) { - Color _lineColor = isEnable ? lineColor : disableLineColor; + static BoxDecoration createOutlineBoxDecoration({ + required bool isEnable, + Color? disableLineColor, + Color? lineColor, + required Color backgroundColor, + required Color disableBackgroundColor, + double radius = 6, + double borderWith = 1.0, + }) { + Color _lineColor = isEnable ? lineColor! : disableLineColor!; Color _bgColor = isEnable ? backgroundColor : disableBackgroundColor; return BoxDecoration( diff --git a/lib/src/components/button/brn_small_main_button.dart b/lib/src/components/button/brn_small_main_button.dart index 93801488..4bb05cec 100644 --- a/lib/src/components/button/brn_small_main_button.dart +++ b/lib/src/components/button/brn_small_main_button.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:bruno/src/components/button/brn_normal_button.dart'; +import 'package:bruno/src/constants/brn_constants.dart'; import 'package:bruno/src/theme/brn_theme.dart'; import 'package:flutter/material.dart'; @@ -20,12 +21,6 @@ import 'package:flutter/material.dart'; /// /// -/// 默认水平间距 -const double _BHorizontalPadding = 6; - -/// 默认垂直间距 -const double _BVerticalPadding = 8; - /// 默认最小宽度 const double _BMinWidth = 84; @@ -34,63 +29,63 @@ class BrnSmallMainButton extends StatelessWidget { final String title; ///点击回调 - final VoidCallback onTap; + final VoidCallback? onTap; ///是否可用,默认为true。false为不可用:置灰、不可点击。 final bool isEnable; + final Color? bgColor; final Color textColor; - final Color bgColor; - final double radius; final FontWeight fontWeight; - final double fontSize; - final double maxWidth; - final double width; + final double? fontSize; + final double? radius; + final double? maxWidth; + final double? width; /// 配置样式 - final BrnButtonConfig themeData; + final BrnButtonConfig? themeData; /// 传入属性优先级最高,未传入的走默认配置,更多请看[BrnSmallMainButtonConfig.defaultConfig] const BrnSmallMainButton({ + Key? key, this.title = '确认', this.onTap, this.isEnable = true, - this.textColor, this.bgColor, - this.fontWeight, + this.textColor = Colors.white, + this.fontWeight = FontWeight.w600, this.fontSize, this.radius, this.maxWidth, this.width, this.themeData, - }); + }): super(key: key); @override Widget build(BuildContext context) { BrnButtonConfig defaultThemeConfig = themeData ?? BrnButtonConfig(); - defaultThemeConfig = defaultThemeConfig.merge(BrnButtonConfig( - smallButtonFontSize: fontSize, smallButtonRadius: radius)); + defaultThemeConfig = defaultThemeConfig + .merge(BrnButtonConfig(smallButtonFontSize: fontSize, smallButtonRadius: radius)); defaultThemeConfig = BrnThemeConfigurator.instance .getConfig(configId: defaultThemeConfig.configId) .buttonConfig .merge(defaultThemeConfig); - TextPainter textPainter = - TextPainter(textScaleFactor: MediaQuery.of(context).textScaleFactor); + TextPainter textPainter = TextPainter(textScaleFactor: MediaQuery.of(context).textScaleFactor); return LayoutBuilder( builder: (_, con) { TextStyle style = TextStyle( fontSize: defaultThemeConfig.smallButtonFontSize, - fontWeight: fontWeight ?? FontWeight.w600, - color: textColor ?? Colors.white, + fontWeight: fontWeight, + color: textColor, ); textPainter.textDirection = TextDirection.ltr; textPainter.text = TextSpan(text: title, style: style); textPainter.layout(maxWidth: con.maxWidth); double textWidth = textPainter.width; //按钮本身大小 - double _maxWidth = textWidth + _BHorizontalPadding * 2; + double _maxWidth = textWidth + BrnButtonConstant.horizontalPadding * 2; double _minWidth = min(_BMinWidth, con.maxWidth); //保证最小宽度是 (84、可用空间)的最小值 @@ -99,8 +94,8 @@ class BrnSmallMainButton extends StatelessWidget { } else { //外部要求最大宽度 if (maxWidth != null) { - if (_maxWidth > maxWidth) { - _maxWidth = maxWidth; + if (_maxWidth > maxWidth!) { + _maxWidth = maxWidth!; } } } @@ -110,22 +105,18 @@ class BrnSmallMainButton extends StatelessWidget { } return BrnNormalButton( - isEnable: isEnable ?? true, + isEnable: isEnable, constraints: BoxConstraints( minWidth: this.width ?? _minWidth, maxWidth: this.width ?? _maxWidth, ), alignment: Alignment.center, - text: title ?? '确认', - backgroundColor: - bgColor ?? defaultThemeConfig.commonConfig.brandPrimary, + text: title, + backgroundColor: bgColor ?? defaultThemeConfig.commonConfig.brandPrimary, disableBackgroundColor: Color(0xFFCCCCCC), - borderRadius: BorderRadius.all( - Radius.circular(defaultThemeConfig.smallButtonRadius)), + borderRadius: BorderRadius.all(Radius.circular(defaultThemeConfig.smallButtonRadius)), onTap: onTap, textStyle: style, - insertPadding: EdgeInsets.symmetric( - vertical: _BVerticalPadding, horizontal: _BHorizontalPadding), ); }, ); diff --git a/lib/src/components/button/brn_small_outline_button.dart b/lib/src/components/button/brn_small_outline_button.dart index bfda7d0b..e415ec20 100644 --- a/lib/src/components/button/brn_small_outline_button.dart +++ b/lib/src/components/button/brn_small_outline_button.dart @@ -1,14 +1,14 @@ + + import 'dart:math'; import 'package:bruno/src/components/button/brn_normal_button.dart'; +import 'package:bruno/src/constants/brn_constants.dart'; import 'package:bruno/src/theme/brn_theme.dart'; import 'package:flutter/material.dart'; /// 边框 小、次按钮,小灰框,默认按钮确认,支持自定义边框、文字颜色 -Color greyColor = Color(0xffD7D7D7); -Color normalColor = Color(0xffF0F0F0); - /// 小的边框按钮 /// 该按钮有一个最小的宽度84,在此基础上,宽度随着文本内容的多少变更 /// @@ -19,12 +19,6 @@ Color normalColor = Color(0xffF0F0F0); /// 其他按钮如下: /// * [BrnSmallMainButton], 小主色调按钮 -/// 默认水平间距 -const double _BHorizontalPadding = 6; - -/// 默认垂直间距 -const double _BVerticalPadding = 8; - /// 默认最小宽度 const double _BMinWidth = 84; @@ -32,26 +26,26 @@ const double _BMinWidth = 84; const double _BBorderWith = 1; class BrnSmallOutlineButton extends StatelessWidget { - /// 按钮显示文案,默认'确认' + /// 按钮显示文案,默认'确认 final String title; /// 点击的回调 - final VoidCallback onTap; + final VoidCallback? onTap; ///是否可用,默认为true。false为不可用:置灰、不可点击。 final bool isEnable; /// 边框的颜色,边框颜色, - final Color lineColor; + final Color? lineColor; /// 文字颜色 - final Color textColor; + final Color? textColor; ///圆角 - final double radius; + final double? radius; ///宽度 - final double width; + final double? width; ///字体weigh final FontWeight fontWeight; @@ -60,10 +54,11 @@ class BrnSmallOutlineButton extends StatelessWidget { final double fontSize; /// 配置样式 - final BrnButtonConfig themeData; + final BrnButtonConfig? themeData; /// 传入属性优先级最高,未传入的走默认配置,更多请看[BrnSmallSecondaryOutlineButtonConfig.defaultConfig] const BrnSmallOutlineButton({ + Key? key, this.title = '确认', this.onTap, this.isEnable = true, @@ -72,9 +67,9 @@ class BrnSmallOutlineButton extends StatelessWidget { this.radius, this.width, this.fontSize = 14, - this.fontWeight, + this.fontWeight = FontWeight.w600, this.themeData, - }); + }): super(key: key); @override Widget build(BuildContext context) { @@ -86,8 +81,7 @@ class BrnSmallOutlineButton extends StatelessWidget { )); defaultThemeConfig = BrnThemeConfigurator.instance .getConfig(configId: defaultThemeConfig.configId) - .buttonConfig - .merge(defaultThemeConfig); + .buttonConfig.merge(defaultThemeConfig); TextPainter textPainter = TextPainter(textScaleFactor: MediaQuery.of(context).textScaleFactor); @@ -96,7 +90,7 @@ class BrnSmallOutlineButton extends StatelessWidget { builder: (_, con) { TextStyle style = TextStyle( fontSize: defaultThemeConfig.smallButtonFontSize, - fontWeight: fontWeight ?? FontWeight.w600, + fontWeight: fontWeight, ); textPainter.textDirection = TextDirection.ltr; @@ -104,7 +98,7 @@ class BrnSmallOutlineButton extends StatelessWidget { textPainter.layout(maxWidth: con.maxWidth); double textWidth = textPainter.width; double _maxWidth = - textWidth + _BHorizontalPadding * 2 + 2 * _BBorderWith; + textWidth + BrnButtonConstant.horizontalPadding * 2 + 2 * _BBorderWith; double _minWidth = min(_BMinWidth, con.maxWidth); if (_maxWidth <= _minWidth) { @@ -121,7 +115,7 @@ class BrnSmallOutlineButton extends StatelessWidget { ), borderWith: _BBorderWith, radius: defaultThemeConfig.smallButtonRadius, - text: title ?? "", + text: title, disableLineColor: defaultThemeConfig.commonConfig.borderColorBase, lineColor: defaultThemeConfig.commonConfig.borderColorBase, textColor: textColor ?? defaultThemeConfig.commonConfig.colorTextBase, @@ -131,8 +125,6 @@ class BrnSmallOutlineButton extends StatelessWidget { fontWeight: FontWeight.bold, fontSize: defaultThemeConfig.smallButtonFontSize, onTap: onTap, - insertPadding: EdgeInsets.symmetric( - vertical: _BVerticalPadding, horizontal: _BHorizontalPadding), backgroundColor: Colors.white, disableBackgroundColor: Color(0xffcccccc).withOpacity(0.1), ); diff --git a/lib/src/components/button/brn_vertical_icon_button.dart b/lib/src/components/button/brn_vertical_icon_button.dart index 02d1be17..5576c4e9 100644 --- a/lib/src/components/button/brn_vertical_icon_button.dart +++ b/lib/src/components/button/brn_vertical_icon_button.dart @@ -33,11 +33,14 @@ class BrnVerticalIconButton extends StatelessWidget { final Widget iconWidget; /// 按钮点击的回调 - final VoidCallback onTap; + final VoidCallback? onTap; - const BrnVerticalIconButton( - {Key key, @required this.name, @required this.iconWidget, this.onTap}) - : super(key: key); + const BrnVerticalIconButton({ + Key? key, + required this.name, + required this.iconWidget, + this.onTap, + }) : super(key: key); @override Widget build(BuildContext context) { diff --git a/lib/src/components/button/collection/brn_bottom_button_panel.dart b/lib/src/components/button/collection/brn_bottom_button_panel.dart index 05f9486a..70f670f7 100644 --- a/lib/src/components/button/collection/brn_bottom_button_panel.dart +++ b/lib/src/components/button/collection/brn_bottom_button_panel.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/button/brn_vertical_icon_button.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:flutter/material.dart'; @@ -64,13 +66,13 @@ class BrnBottomButtonPanel extends StatelessWidget { final VoidCallback mainButtonOnTap; /// 次按钮的文案 - final String secondaryButtonName; + final String? secondaryButtonName; /// 次按钮的点击回调 - final VoidCallback secondaryButtonOnTap; + final VoidCallback? secondaryButtonOnTap; /// icon按钮的集合 - final List iconButtonList; + final List? iconButtonList; /// 主按钮是否可用 默认可用 /// 如果设置为false,按钮置灰且不响应[mainButtonOnTap] @@ -81,9 +83,9 @@ class BrnBottomButtonPanel extends StatelessWidget { final bool enableSecondaryButton; const BrnBottomButtonPanel( - {Key key, - @required this.mainButtonName, - @required this.mainButtonOnTap, + {Key? key, + required this.mainButtonName, + required this.mainButtonOnTap, this.secondaryButtonName, this.secondaryButtonOnTap, this.enableMainButton = true, @@ -102,16 +104,13 @@ class BrnBottomButtonPanel extends StatelessWidget { /// secondaryButtonOnTap 次按钮的点击事件 /// iconButtonList icon按钮 static Widget createByList(List buttonTitleList, - {VoidCallback mainButtonOnTap, - VoidCallback secondaryButtonOnTap, + {VoidCallback? mainButtonOnTap, + VoidCallback? secondaryButtonOnTap, bool enableMainButton = true, - List iconButtonList}) { - if ((buttonTitleList == null || buttonTitleList.isEmpty) && + List? iconButtonList}) { + if ((buttonTitleList.isEmpty) && iconButtonList == null) { - return Container( - height: 0, - width: 0, - ); + return SizedBox.shrink(); } if (buttonTitleList.length >= 2) { return BrnBottomButtonPanel( @@ -144,15 +143,12 @@ class BrnBottomButtonPanel extends StatelessWidget { iconButtonList: iconButtonList, ); } - return Container( - height: 0, - width: 0, - ); + return SizedBox.shrink(); } @override Widget build(BuildContext context) { - List rowChildren = List(); + List rowChildren = []; if (null != iconButtonList) { Widget iconListWidget = _iconWidgetListWidget(); rowChildren.add(iconListWidget); @@ -171,7 +167,7 @@ class BrnBottomButtonPanel extends StatelessWidget { } Widget _buttonListWidget() { - List btnList = List(); + List btnList = []; Widget mBtn = _mainButtonWidget(); btnList.add(mBtn); if (secondaryButtonName != null) { @@ -187,7 +183,7 @@ class BrnBottomButtonPanel extends StatelessWidget { } Widget _iconWidgetListWidget() { - List finalIconList = iconButtonList.map((wdt) { + List finalIconList = iconButtonList!.map((wdt) { return Padding(padding: EdgeInsets.only(left: 0), child: wdt); }).toList(); return Row( @@ -203,7 +199,7 @@ class BrnBottomButtonPanel extends StatelessWidget { child: GestureDetector( onTap: () { if (secondaryButtonOnTap != null && enableSecondaryButton) { - secondaryButtonOnTap(); + secondaryButtonOnTap!(); } }, child: Container( @@ -213,8 +209,7 @@ class BrnBottomButtonPanel extends StatelessWidget { color: enableSecondaryButton ? BrnThemeConfigurator.instance .getConfig() - .commonConfig - .brandAuxiliary + .commonConfig.brandAuxiliary : Color(0xFFCCCCCC), borderRadius: BorderRadius.all(Radius.circular(6.0)), ), @@ -231,9 +226,7 @@ class BrnBottomButtonPanel extends StatelessWidget { ? Colors.white : BrnThemeConfigurator.instance .getConfig() - .commonConfig - .colorTextBaseInverse - .withOpacity(0.7), + .commonConfig.colorTextBaseInverse.withOpacity(0.7), ), ), )), @@ -245,7 +238,7 @@ class BrnBottomButtonPanel extends StatelessWidget { Widget _mainButtonWidget() { Widget mainWidget = GestureDetector( onTap: () { - if (mainButtonOnTap != null && enableMainButton) { + if (enableMainButton) { mainButtonOnTap(); } }, @@ -256,14 +249,13 @@ class BrnBottomButtonPanel extends StatelessWidget { color: enableMainButton ? BrnThemeConfigurator.instance .getConfig() - .commonConfig - .brandPrimary + .commonConfig.brandPrimary : Color(0xFFCCCCCC), borderRadius: BorderRadius.all(Radius.circular(6.0)), ), child: Center( child: Text( - mainButtonName ?? "", + mainButtonName, textAlign: TextAlign.center, maxLines: 1, overflow: TextOverflow.ellipsis, @@ -274,9 +266,7 @@ class BrnBottomButtonPanel extends StatelessWidget { ? Colors.white : BrnThemeConfigurator.instance .getConfig() - .commonConfig - .colorTextBaseInverse - .withOpacity(0.7), + .commonConfig.colorTextBaseInverse.withOpacity(0.7), ), ), )), @@ -292,7 +282,7 @@ class BrnBottomButtonPanel extends StatelessWidget { } bool _isEmptyIcon() { - return iconButtonList == null || iconButtonList.isEmpty; + return iconButtonList == null || iconButtonList!.isEmpty; } bool _isEmptySecondary() { diff --git a/lib/src/components/button/collection/brn_button_panel.dart b/lib/src/components/button/collection/brn_button_panel.dart index 3ec50256..8d2442c4 100644 --- a/lib/src/components/button/collection/brn_button_panel.dart +++ b/lib/src/components/button/collection/brn_button_panel.dart @@ -5,7 +5,6 @@ import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// 描述: 主次按钮组成的横向面板 /// 主按钮和边框按钮组成的集合 @@ -28,13 +27,13 @@ class BrnButtonPanel extends StatefulWidget { final bool isMainBtnEnable; /// 默认状态下,次按钮的文案集合。如果需要改变按钮的可用状态,请使用 [secondaryButtonList] 初始化。 - final List secondaryButtonNameList; + final List? secondaryButtonNameList; /// 包含config状态的次按钮,默认状态的话直接传[secondaryButtonNameList]即可 - final List secondaryButtonList; + final List? secondaryButtonList; /// 次按钮的点击回调 - final void Function(int) secondaryButtonOnTap; + final void Function(int)? secondaryButtonOnTap; /// 控件的左右的padding /// 默认值为20 @@ -44,9 +43,9 @@ class BrnButtonPanel extends StatefulWidget { final BrnPopupDirection popDirection; const BrnButtonPanel( - {Key key, - @required this.mainButtonName, - @required this.mainButtonOnTap, + {Key? key, + required this.mainButtonName, + required this.mainButtonOnTap, this.isMainBtnEnable = true, this.secondaryButtonNameList, this.secondaryButtonOnTap, @@ -60,9 +59,9 @@ class BrnButtonPanel extends StatefulWidget { } class _BrnButtonPanelState extends State { - GlobalKey _popWindowKey; + late GlobalKey _popWindowKey; - List _secondaryButtonList = List(); + List _secondaryButtonList = []; @override void initState() { @@ -79,20 +78,19 @@ class _BrnButtonPanelState extends State { /// 初始化次按钮列表 void initSecondaryButton() { - _secondaryButtonList = List(); + _secondaryButtonList = []; if (widget.secondaryButtonList?.isNotEmpty ?? false) { - _secondaryButtonList = widget.secondaryButtonList; + _secondaryButtonList = widget.secondaryButtonList!; } else if (widget.secondaryButtonNameList?.isNotEmpty ?? false) { - widget.secondaryButtonNameList.forEach((name) { - _secondaryButtonList - .add(BrnButtonPanelConfig(name: name, isEnable: true)); + widget.secondaryButtonNameList!.forEach((name) { + _secondaryButtonList.add(BrnButtonPanelConfig(name: name, isEnable: true)); }); } } @override Widget build(BuildContext context) { - List list = List(); + List list = []; if (_secondaryButtonList.length > 2) { //次按钮两个以上特殊处理,所有button等分 @@ -140,8 +138,7 @@ class _BrnButtonPanelState extends State { } return Padding( - padding: EdgeInsets.fromLTRB( - widget.horizontalPadding ?? 20, 0, widget.horizontalPadding ?? 20, 0), + padding: EdgeInsets.fromLTRB(widget.horizontalPadding, 0, widget.horizontalPadding, 0), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: list, @@ -153,19 +150,18 @@ class _BrnButtonPanelState extends State { return BrnSmallMainButton( title: widget.mainButtonName, onTap: widget.mainButtonOnTap, - isEnable: widget.isMainBtnEnable ?? true, + isEnable: widget.isMainBtnEnable, maxWidth: 132, ); } Widget _secondaryButton(int btnIndex) { - String name = _secondaryButtonList[btnIndex].name; BrnSmallOutlineButton button = BrnSmallOutlineButton( - title: name, - isEnable: _secondaryButtonList[btnIndex].isEnable ?? true, + title:_secondaryButtonList[btnIndex].name, + isEnable: _secondaryButtonList[btnIndex].isEnable, onTap: () { if (widget.secondaryButtonOnTap != null) { - widget.secondaryButtonOnTap(btnIndex); + widget.secondaryButtonOnTap!(btnIndex); } }, ); @@ -177,8 +173,8 @@ class _BrnButtonPanelState extends State { /// 更多按钮 Widget _moreButton() { - if (null != _secondaryButtonList && _secondaryButtonList.length > 2) { - List list = List(); + if (_secondaryButtonList.length > 2) { + List list = []; for (int i = 2; i < _secondaryButtonList.length; i++) { list.add(_secondaryButtonList[i].name); } @@ -199,14 +195,8 @@ class _BrnButtonPanelState extends State { maxLines: 1, style: TextStyle( color: _secondaryButtonList[index + 2].isEnable - ? BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .colorTextBase - : BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .colorTextHint, + ? BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase + : BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextHint, fontSize: 16)); }, popDirection: widget.popDirection, @@ -214,7 +204,7 @@ class _BrnButtonPanelState extends State { // 按钮不可用的时候,点击无响应; if (widget.secondaryButtonOnTap != null) { if (_secondaryButtonList[index + 2].isEnable) { - widget.secondaryButtonOnTap(index + 2); + widget.secondaryButtonOnTap!(index + 2); return false; } else { return true; @@ -239,7 +229,7 @@ class BrnButtonPanelConfig { final bool isEnable; BrnButtonPanelConfig({ - this.name, + required this.name, this.isEnable = true, }); } diff --git a/lib/src/components/button/collection/brn_multiple_bottom_button.dart b/lib/src/components/button/collection/brn_multiple_bottom_button.dart index 61ca51b7..367553c2 100644 --- a/lib/src/components/button/collection/brn_multiple_bottom_button.dart +++ b/lib/src/components/button/collection/brn_multiple_bottom_button.dart @@ -1,5 +1,6 @@ + + import 'package:bruno/src/components/radio/brn_checkbox.dart'; -import 'package:bruno/src/components/radio/brn_radio_core.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/utils/brn_tools.dart'; @@ -24,31 +25,31 @@ enum BrnMultipleButtonArrowState { /// 支持 **[全选]+[选中状态]+[次要按钮]+[主要按钮]** 的组合(中括号代表可选) class BrnMultipleBottomButton extends StatefulWidget { /// 全选的点击回调,不传则不展示多选按钮,回传参数 true 表示选中全选,false 表示取消全选 - final void Function(bool) onSelectAll; + final void Function(bool?)? onSelectAll; /// selectedButtonOnTap, 点击已选的回调,存在三种状态:-1:不可展开(当 value 为 0 的时候),0:收起,1:展开 - final void Function(BrnMultipleButtonArrowState) onSelectedButtonTap; + final void Function(BrnMultipleButtonArrowState)? onSelectedButtonTap; - /// 主按钮的文案,默认为主题色 可以传入自定义 Widget,不传则不展示 + /// 主按钮的文案,默认为主题色 可以传入自定义 Widget 以及 String 类型的文案,不传则不展示 final dynamic mainButton; - /// 次按钮的文案可以传入自定义 Widget,不传则不展示 + /// 次按钮的文案可以传入自定义 Widget 以及 String 类型的文案,不传则不展示 final dynamic subButton; /// 主按钮点击回调 - final VoidCallback onMainButtonTap; + final VoidCallback? onMainButtonTap; /// 次按钮点击回调 - final VoidCallback onSubButtonTap; + final VoidCallback? onSubButtonTap; /// 已选后面是否需要带小箭头。默认 false final bool hasArrow; /// 暴露给外界设置多选状态的控制器 - final BrnMultipleBottomController bottomController; + final BrnMultipleBottomController? bottomController; const BrnMultipleBottomButton( - {Key key, + {Key? key, this.mainButton, this.subButton, this.onMainButtonTap, @@ -65,7 +66,7 @@ class BrnMultipleBottomButton extends StatefulWidget { } class _BrnMultipleBottomButtonState extends State { - BrnMultipleBottomController _controller; + late BrnMultipleBottomController _controller; bool _unfoldState = false; @override @@ -76,7 +77,7 @@ class _BrnMultipleBottomButtonState extends State { @override Widget build(BuildContext context) { - List rowChildren = List() + List rowChildren = [] ..add(_allSelectedWidget()) ..add(_selectedCountWidget()) ..add(_buttonArea()); @@ -99,7 +100,7 @@ class _BrnMultipleBottomButtonState extends State { bool currentState = !_controller.valueNotifier.value.selectAllState; _controller.setState(selectAllState: currentState); - if (widget.onSelectAll != null) widget.onSelectAll(currentState); + if (widget.onSelectAll != null) widget.onSelectAll!(currentState); }, behavior: HitTestBehavior.opaque, child: Row( @@ -118,7 +119,7 @@ class _BrnMultipleBottomButtonState extends State { //同步到外界的当前的全选状态 _controller.setState(selectAllState: value); if (widget.onSelectAll != null) - widget.onSelectAll(value); + widget.onSelectAll!(value); }, key: Key(DateTime.now().toString()), ); @@ -140,14 +141,13 @@ class _BrnMultipleBottomButtonState extends State { Widget _selectedCountWidget() { Image unfoldWidget = BrunoTools.getAssetImageWithColor( - BrnAsset.ICON_SELECTED_UP_TRIANGLE, + BrnAsset.iconSelectedUpTriangle, BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary); - Image foldWidget = - BrunoTools.getAssetImage(BrnAsset.ICON_UNSELECT_DOWN_TRIANGLE); + BrunoTools.getAssetImage(BrnAsset.iconUnSelectDownTriangle); Image cantFoldWidget = BrunoTools.getAssetImageWithColor( - BrnAsset.ICON_UNSELECT_DOWN_TRIANGLE, Color(0XCCCCCCCC)); + BrnAsset.iconUnSelectDownTriangle, Color(0XCCCCCCCC)); return GestureDetector( onTap: () { @@ -156,14 +156,14 @@ class _BrnMultipleBottomButtonState extends State { if (_controller.valueNotifier.value.selectedCount == 0) { _unfoldState = false; widget - .onSelectedButtonTap(BrnMultipleButtonArrowState.cantUnfold); + .onSelectedButtonTap!(BrnMultipleButtonArrowState.cantUnfold); return; } _unfoldState = !_unfoldState; if (_unfoldState) { - widget.onSelectedButtonTap(BrnMultipleButtonArrowState.unfold); + widget.onSelectedButtonTap!(BrnMultipleButtonArrowState.unfold); } else { - widget.onSelectedButtonTap(BrnMultipleButtonArrowState.fold); + widget.onSelectedButtonTap!(BrnMultipleButtonArrowState.fold); } } }); @@ -179,15 +179,14 @@ class _BrnMultipleBottomButtonState extends State { ValueListenableBuilder( valueListenable: _controller.valueNotifier, builder: (context, value, _) { - List rowChildren = List(); + List rowChildren = []; rowChildren.add(Text( '(${value.selectedCount})', style: TextStyle( color: value.selectedCount != 0 ? BrnThemeConfigurator.instance .getConfig() - .commonConfig - .brandPrimary + .commonConfig.brandPrimary : Color(0x99999999), fontSize: 16), )); @@ -196,8 +195,8 @@ class _BrnMultipleBottomButtonState extends State { if (value.arrowStatus != BrnMultipleButtonArrowState.defaultStatus) { //使用方主动设置箭头状态的时候 - Widget arrow; - switch (value.arrowStatus) { + Widget? arrow; + switch (value.arrowStatus!) { case BrnMultipleButtonArrowState.cantUnfold: arrow = cantFoldWidget; break; @@ -264,7 +263,7 @@ class _BrnMultipleBottomButtonState extends State { ? Expanded( child: GestureDetector( onTap: () { - if (widget.onMainButtonTap != null) widget.onMainButtonTap(); + if (widget.onMainButtonTap != null) widget.onMainButtonTap!(); }, child: ValueListenableBuilder( valueListenable: _controller.valueNotifier, @@ -274,19 +273,16 @@ class _BrnMultipleBottomButtonState extends State { padding: EdgeInsets.only(left: 10, right: 10), decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(4)), - color: value.mainButtonState - ? BrnThemeConfigurator.instance + color: value.mainButtonState? BrnThemeConfigurator.instance .getConfig() - .commonConfig - .brandPrimary + .commonConfig.brandPrimary : Color(0xFFCCCCCC)), child: widget.mainButton is String ? Center( child: Text( widget.mainButton, style: TextStyle( - color: value.mainButtonState - ? Colors.white + color: value.mainButtonState? Colors.white : Color(0xAAFFFFFF), fontSize: 16, fontWeight: FontWeight.w600), @@ -307,7 +303,7 @@ class _BrnMultipleBottomButtonState extends State { ? Expanded( child: GestureDetector( onTap: () { - if (widget.onSubButtonTap != null) widget.onSubButtonTap(); + if (widget.onSubButtonTap != null) widget.onSubButtonTap!(); }, child: ValueListenableBuilder( valueListenable: _controller.valueNotifier, @@ -317,19 +313,16 @@ class _BrnMultipleBottomButtonState extends State { padding: EdgeInsets.only(left: 10, right: 10), decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(4)), - color: value.subButtonState - ? BrnThemeConfigurator.instance + color: value.subButtonState? BrnThemeConfigurator.instance .getConfig() - .commonConfig - .brandAuxiliary + .commonConfig.brandAuxiliary : Color(0xFFCCCCCC)), child: widget.subButton is String ? Center( child: Text( widget.subButton, style: TextStyle( - color: value.subButtonState - ? Colors.white + color: value.subButtonState? Colors.white : Color(0xAAFFFFFF), fontSize: 16, fontWeight: FontWeight.w600), @@ -352,9 +345,9 @@ class BrnMultipleBottomController { valueNotifier = ValueNotifier(initMultiSelectState ?? MultiSelectState()); } - final MultiSelectState initMultiSelectState; + final MultiSelectState? initMultiSelectState; - ValueNotifier valueNotifier; + late ValueNotifier valueNotifier; /// 设置按钮的状态,当主按钮或者此按钮置灰的时候,对应的点击任然会回调,控件只做按钮置灰 /// [selectedCount] 已选括号中的数目 @@ -363,18 +356,18 @@ class BrnMultipleBottomController { /// [subButtonState] 次按钮是否置灰 /// [arrowStatus] 控制箭头的状态 void setState( - {int selectedCount, - bool selectAllState, - bool mainButtonState, - bool subButtonState, - BrnMultipleButtonArrowState arrowStatus}) { + {int? selectedCount, + bool? selectAllState, + bool? mainButtonState, + bool? subButtonState, + BrnMultipleButtonArrowState? arrowStatus}) { MultiSelectState data = MultiSelectState( - selectedCount: selectedCount ?? valueNotifier?.value?.selectedCount, - selectAllState: selectAllState ?? valueNotifier?.value?.selectAllState, + selectedCount: selectedCount ?? valueNotifier.value.selectedCount, + selectAllState: selectAllState ?? valueNotifier.value.selectAllState, mainButtonState: - mainButtonState ?? valueNotifier?.value?.mainButtonState, - subButtonState: subButtonState ?? valueNotifier?.value?.subButtonState, - arrowStatus: arrowStatus ?? valueNotifier?.value?.arrowStatus); + mainButtonState ?? valueNotifier.value.mainButtonState, + subButtonState: subButtonState ?? valueNotifier.value.subButtonState, + arrowStatus: arrowStatus ?? valueNotifier.value.arrowStatus); valueNotifier.value = data; } } @@ -393,7 +386,7 @@ class MultiSelectState { bool subButtonState; /// 控制箭头的状态 - BrnMultipleButtonArrowState arrowStatus; + BrnMultipleButtonArrowState? arrowStatus; MultiSelectState( {this.selectedCount = 0, diff --git a/lib/src/components/button/collection/brn_text_button_panel.dart b/lib/src/components/button/collection/brn_text_button_panel.dart index 64b324d1..93e2f582 100644 --- a/lib/src/components/button/collection/brn_text_button_panel.dart +++ b/lib/src/components/button/collection/brn_text_button_panel.dart @@ -17,26 +17,26 @@ class BrnTextButtonPanel extends StatefulWidget { final List nameList; /// 点击某个文本按钮的回调 - final void Function(int index) onTap; + final void Function(int index)? onTap; /// popUpWindow位于targetView的方向 /// 取[BrnPopupDirection]里面的值 /// 默认值为PopDirection.bottom final BrnPopupDirection popDirection; - const BrnTextButtonPanel( - {Key key, - @required this.nameList, - this.onTap, - this.popDirection = BrnPopupDirection.bottom}) - : super(key: key); + const BrnTextButtonPanel({ + Key? key, + required this.nameList, + this.onTap, + this.popDirection = BrnPopupDirection.bottom, + }) : super(key: key); @override _BrnTextButtonPanelState createState() => _BrnTextButtonPanelState(); } class _BrnTextButtonPanelState extends State { - GlobalKey _popWindowKey; + GlobalKey _popWindowKey = GlobalKey(); /// 更多按钮的展开收起状态 bool _isExpanded = false; @@ -44,21 +44,9 @@ class _BrnTextButtonPanelState extends State { /// 展示的文本按钮的最大数目,超过这个数目时展示更多 int _maxNum = 4; - @override - void initState() { - super.initState(); - _popWindowKey = GlobalKey(); - } - - @override - void didUpdateWidget(covariant BrnTextButtonPanel oldWidget) { - super.didUpdateWidget(oldWidget); - _popWindowKey = GlobalKey(); - } - @override Widget build(BuildContext context) { - if (widget.nameList != null && widget.nameList.length > 0) { + if (widget.nameList.length > 0) { Row row = Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceAround, @@ -70,22 +58,20 @@ class _BrnTextButtonPanelState extends State { } List _textOperationWidgetList(context) { - List widgetList = List(); + List widgetList = []; //文本按钮不超过4个,就全不显示 //超过4个的话,就只显示3个,剩下的显示在更多里 - int length = widget.nameList.length <= _maxNum - ? widget.nameList.length - : _maxNum - 1; + int length = widget.nameList.length <= _maxNum ? widget.nameList.length : _maxNum - 1; for (int textIndex = 0; textIndex < length; textIndex++) { Widget operationWidget = _operationWidgetAtIndex(textIndex); widgetList.add(operationWidget); } - if (widget.nameList != null && widget.nameList.length > _maxNum) { + if (widget.nameList.length > _maxNum) { widgetList.add(_moreButton()); } - List showWidget = List(); + List showWidget = []; for (int i = 0, n = widgetList.length; i < n; ++i) { showWidget.add(Expanded( child: Center( @@ -113,10 +99,7 @@ class _BrnTextButtonPanelState extends State { style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, - color: BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .brandPrimary), + color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary), ); return GestureDetector( @@ -129,15 +112,15 @@ class _BrnTextButtonPanelState extends State { return; } if (null != widget.onTap) { - widget.onTap(index); + widget.onTap!(index); } }); } /// 更多按钮 Widget _moreButton() { - if (widget.nameList != null && widget.nameList.length > _maxNum) { - List list = List(); + if (widget.nameList.length > _maxNum) { + List list = []; for (int i = _maxNum - 1; i < widget.nameList.length; i++) { list.add(widget.nameList[i]); } @@ -153,8 +136,8 @@ class _BrnTextButtonPanelState extends State { ); Widget imageWidget = _isExpanded - ? BrunoTools.getAssetImage(BrnAsset.ICON_UP_ARROW) - : BrunoTools.getAssetImage(BrnAsset.ICON_DOWN_ARROW); + ? BrunoTools.getAssetImage(BrnAsset.iconUpArrow) + : BrunoTools.getAssetImage(BrnAsset.iconDownArrow); return GestureDetector( child: Row( @@ -174,7 +157,7 @@ class _BrnTextButtonPanelState extends State { popDirection: widget.popDirection, data: list, onItemClick: (index, item) { if (widget.onTap != null) { - widget.onTap(index + 3); + widget.onTap!(index + 3); } }, onDismiss: () { setState(() { @@ -186,7 +169,7 @@ class _BrnTextButtonPanelState extends State { }); }); } else { - return Container(); + return SizedBox.shrink(); } } } diff --git a/lib/src/components/calendar/brn_calendar_view.dart b/lib/src/components/calendar/brn_calendar_view.dart index 93bcb87e..3f5feb97 100644 --- a/lib/src/components/calendar/brn_calendar_view.dart +++ b/lib/src/components/calendar/brn_calendar_view.dart @@ -1,15 +1,20 @@ -import 'package:bruno/bruno.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +///单选日期回调函数 +typedef CalendarDateChange = Function(DateTime date); + +///范围选择日期回调函数 +typedef CalendarRangeDateChange = Function(DateTimeRange range); + /// 展示模式,周视图模式,月视图模式 -enum DisplayMode { Week, Month } +enum DisplayMode { week, month } /// 时间选择模式,单个时间,时间范围 -enum SelectMode { SINGLE, RANGE } +enum SelectMode { single, range } const List _defaultWeekNames = ['日', '一', '二', '三', '四', '五', '六']; @@ -18,18 +23,54 @@ const List _defaultWeekNames = ['日', '一', '二', '三', '四', '五' /// 2、日历组件支持时间范围展示,仅展示范围内的日历视图,范围外日期置灰不可点击。日期范围边界后不可再翻页。 class BrnCalendarView extends StatefulWidget { const BrnCalendarView( - {Key key, - this.selectMode = SelectMode.SINGLE, - this.displayMode = DisplayMode.Month, + {Key? key, + this.selectMode = SelectMode.single, + this.displayMode = DisplayMode.month, this.weekNames = _defaultWeekNames, this.showControllerBar = true, this.initStartSelectedDate, this.initEndSelectedDate, this.initDisplayDate, - this.startEndDateChange, + this.dateChange, + this.rangeDateChange, this.minDate, this.maxDate}) - : assert(weekNames != null && weekNames.length > 0), + : assert(weekNames.length == 7), + assert( + selectMode == SelectMode.single && dateChange != null || + selectMode == SelectMode.range && rangeDateChange != null), + super(key: key); + + const BrnCalendarView.single( + {Key? key, + this.displayMode = DisplayMode.month, + this.weekNames = _defaultWeekNames, + this.showControllerBar = true, + this.initStartSelectedDate, + this.initEndSelectedDate, + this.initDisplayDate, + required this.dateChange, + this.minDate, + this.maxDate}) + : this.selectMode = SelectMode.single, + this.rangeDateChange = null, + assert(weekNames.length == 7), + super(key: key); + + const BrnCalendarView.range( + {Key? key, + this.displayMode = DisplayMode.month, + this.weekNames = _defaultWeekNames, + this.showControllerBar = true, + this.initStartSelectedDate, + this.initEndSelectedDate, + this.initDisplayDate, + required this.rangeDateChange, + this.minDate, + this.maxDate}) + : this.selectMode = SelectMode.range, + this.dateChange = null, + assert(weekNames.length == 7), super(key: key); /// 展示模式, Week, Month @@ -39,16 +80,20 @@ class BrnCalendarView extends StatefulWidget { final SelectMode selectMode; /// 日历日期选择范围最小值 - final DateTime minDate; + /// + /// 默认 `DateTime(1970)` + final DateTime? minDate; /// 日历日期选择范围最大值 - final DateTime maxDate; + /// + /// 默认 `DateTime(2100)` + final DateTime? maxDate; /// 日历日期初始选中最小值 - final DateTime initStartSelectedDate; + final DateTime? initStartSelectedDate; /// 日历日期初始选中最大值 - final DateTime initEndSelectedDate; + final DateTime? initEndSelectedDate; /// 是否展示顶部控制按钮 final bool showControllerBar; @@ -57,10 +102,15 @@ class BrnCalendarView extends StatefulWidget { final List weekNames; /// 初始展示月份 - final DateTime initDisplayDate; + /// + /// 默认当前时间 + final DateTime? initDisplayDate; + + /// single 类型选择日期回调 + final CalendarDateChange? dateChange; - final Function(DateTime startSelectedDate, DateTime endSelectedDate) - startEndDateChange; + /// range 类型选择日期回调 + final CalendarRangeDateChange? rangeDateChange; @override _CustomCalendarViewState createState() => _CustomCalendarViewState(); @@ -68,12 +118,10 @@ class BrnCalendarView extends StatefulWidget { class _CustomCalendarViewState extends State { List dateList = []; - DateTime _currentDate; - DisplayMode _displayMode; - DateTime _minDate, - _maxDate, - _currentStartSelectedDate, - _currentEndSelectedDate; + late DateTime _currentDate; + late DisplayMode _displayMode; + late DateTime _minDate, _maxDate; + DateTime? _currentStartSelectedDate, _currentEndSelectedDate; @override void initState() { @@ -84,22 +132,17 @@ class _CustomCalendarViewState extends State { _currentStartSelectedDate = widget.initStartSelectedDate; _currentEndSelectedDate = widget.initEndSelectedDate; - if (_displayMode == DisplayMode.Month) { + if (_displayMode == DisplayMode.month) { _setListOfMonthDate(_currentDate); - } else if (_displayMode == DisplayMode.Week) { + } else if (_displayMode == DisplayMode.week) { _setListOfWeekDate(_currentDate); } super.initState(); } - @override - void dispose() { - super.dispose(); - } - void _setListOfWeekDate(DateTime weekDate) { dateList.clear(); - List tmpDateList = List(); + List tmpDateList = []; int previousDay = weekDate.weekday % 7; for (int i = 0; i < weekDate.weekday; i++) { tmpDateList.add(weekDate.subtract(Duration(days: previousDay - i))); @@ -114,7 +157,7 @@ class _CustomCalendarViewState extends State { void _setListOfMonthDate(DateTime monthDate) { dateList.clear(); - List tmpDateList = List(); + List tmpDateList = []; final DateTime newDate = DateTime(monthDate.year, monthDate.month, 0); int previousMonthDay = (newDate.weekday + 1) % 7; for (int i = 1; i <= previousMonthDay; i++) { @@ -159,11 +202,11 @@ class _CustomCalendarViewState extends State { onTap: () { if (!isPreIconEnable) return; setState(() { - if (_displayMode == DisplayMode.Month) { + if (_displayMode == DisplayMode.month) { _currentDate = DateTime(_currentDate.year, _currentDate.month, 0); _setListOfMonthDate(_currentDate); - } else if (_displayMode == DisplayMode.Week) { + } else if (_displayMode == DisplayMode.week) { _currentDate = _currentDate.subtract(Duration(days: 7)); _setListOfWeekDate(_currentDate); } @@ -175,9 +218,9 @@ class _CustomCalendarViewState extends State { color: Colors.transparent, padding: EdgeInsets.only(left: 15), child: isPreIconEnable - ? BrunoTools.getAssetImage(BrnAsset.ICON_CALENDAR_PRE_MONTH) + ? BrunoTools.getAssetImage(BrnAsset.iconCalendarPreMonth) : BrunoTools.getAssetImageWithColor( - BrnAsset.ICON_CALENDAR_PRE_MONTH, Color(0xFFCCCCCC)), + BrnAsset.iconCalendarPreMonth, Color(0xFFCCCCCC)), alignment: Alignment.center, ), ), @@ -199,11 +242,11 @@ class _CustomCalendarViewState extends State { onTap: () { if (!isNextIconEnable) return; setState(() { - if (_displayMode == DisplayMode.Month) { + if (_displayMode == DisplayMode.month) { _currentDate = DateTime(_currentDate.year, _currentDate.month + 2, 0); _setListOfMonthDate(_currentDate); - } else if (_displayMode == DisplayMode.Week) { + } else if (_displayMode == DisplayMode.week) { _currentDate = _currentDate.add(Duration(days: 7)); _setListOfWeekDate(_currentDate); } @@ -215,10 +258,9 @@ class _CustomCalendarViewState extends State { color: Colors.transparent, padding: EdgeInsets.only(right: 15), child: isNextIconEnable - ? BrunoTools.getAssetImage( - BrnAsset.ICON_CALENDAR_NEXT_MONTH) + ? BrunoTools.getAssetImage(BrnAsset.iconCalendarNextMonth) : BrunoTools.getAssetImageWithColor( - BrnAsset.ICON_CALENDAR_NEXT_MONTH, Color(0xFFCCCCCC)), + BrnAsset.iconCalendarNextMonth, Color(0xFFCCCCCC)), alignment: Alignment.center, ), ) @@ -226,10 +268,7 @@ class _CustomCalendarViewState extends State { ), ); } - return Container( - height: 0, - width: 0, - ); + return SizedBox.shrink(); } bool _isIconEnable(bool isPre) { @@ -238,7 +277,7 @@ class _CustomCalendarViewState extends State { return false; } if (dateList[0].year == _minDate.year) { - if (_displayMode == DisplayMode.Week) { + if (_displayMode == DisplayMode.week) { if (dateList[0].month < _minDate.month) { return false; } @@ -260,7 +299,7 @@ class _CustomCalendarViewState extends State { return false; } if (dateList.last.year == _maxDate.year) { - if (_displayMode == DisplayMode.Week) { + if (_displayMode == DisplayMode.week) { if (dateList.last.month > _maxDate.month) { return false; } @@ -339,17 +378,11 @@ class _CustomCalendarViewState extends State { .withOpacity(0.14) : Colors.transparent) : Colors.transparent, - borderRadius: BorderRadius.only( - bottomLeft: _isStartDateRadius(date) - ? const Radius.circular(24.0) - : const Radius.circular(0.0), - topLeft: _isStartDateRadius(date) + borderRadius: BorderRadius.horizontal( + left: _isStartDateRadius(date) ? const Radius.circular(24.0) : const Radius.circular(0.0), - topRight: _isEndDateRadius(date) - ? const Radius.circular(24.0) - : const Radius.circular(0.0), - bottomRight: _isEndDateRadius(date) + right: _isEndDateRadius(date) ? const Radius.circular(24.0) : const Radius.circular(0.0), ), @@ -394,12 +427,12 @@ class _CustomCalendarViewState extends State { if (date.isAfter(newMinimumDate) && date.isBefore(newMaximumDate)) { _currentDate = date; - if (_displayMode == DisplayMode.Week) { + if (_displayMode == DisplayMode.week) { _setListOfWeekDate(_currentDate); - } else if (_displayMode == DisplayMode.Month) { + } else if (_displayMode == DisplayMode.month) { _setListOfMonthDate(_currentDate); } - if (widget.selectMode == SelectMode.SINGLE) { + if (widget.selectMode == SelectMode.single) { _onSingleDateClick(date); } else { _onRangeDateClick(date); @@ -407,13 +440,13 @@ class _CustomCalendarViewState extends State { } }, child: Padding( - padding: const EdgeInsets.all(0), + padding: EdgeInsets.zero, child: Container( child: Center( child: Text( date.day > 9 ? '${date.day}' : '0${date.day}', style: TextStyle( - color: _displayMode == DisplayMode.Month + color: _displayMode == DisplayMode.month ? (_getIsItStartAndEndDate(date) ? Colors.white : _currentDate.month == @@ -491,8 +524,8 @@ class _CustomCalendarViewState extends State { bool _getIsInRange(DateTime date) { if (_currentStartSelectedDate != null && _currentEndSelectedDate != null) { - if (date.isAfter(_currentStartSelectedDate) && - date.isBefore(_currentEndSelectedDate)) { + if (date.isAfter(_currentStartSelectedDate!) && + date.isBefore(_currentEndSelectedDate!)) { return true; } else { return false; @@ -504,14 +537,14 @@ class _CustomCalendarViewState extends State { bool _getIsItStartAndEndDate(DateTime date) { if (_currentStartSelectedDate != null && - _currentStartSelectedDate.day == date.day && - _currentStartSelectedDate.month == date.month && - _currentStartSelectedDate.year == date.year) { + _currentStartSelectedDate!.day == date.day && + _currentStartSelectedDate!.month == date.month && + _currentStartSelectedDate!.year == date.year) { return true; } else if (_currentEndSelectedDate != null && - _currentEndSelectedDate.day == date.day && - _currentEndSelectedDate.month == date.month && - _currentEndSelectedDate.year == date.year) { + _currentEndSelectedDate!.day == date.day && + _currentEndSelectedDate!.month == date.month && + _currentEndSelectedDate!.year == date.year) { return true; } else { return false; @@ -520,8 +553,8 @@ class _CustomCalendarViewState extends State { bool _isStartDateRadius(DateTime date) { if (_currentStartSelectedDate != null && - _currentStartSelectedDate.day == date.day && - _currentStartSelectedDate.month == date.month) { + _currentStartSelectedDate!.day == date.day && + _currentStartSelectedDate!.month == date.month) { return true; } else if (date.weekday == 7) { return true; @@ -532,8 +565,8 @@ class _CustomCalendarViewState extends State { bool _isEndDateRadius(DateTime date) { if (_currentEndSelectedDate != null && - _currentEndSelectedDate.day == date.day && - _currentEndSelectedDate.month == date.month) { + _currentEndSelectedDate!.day == date.day && + _currentEndSelectedDate!.month == date.month) { return true; } else if (date.weekday == 6) { return true; @@ -547,8 +580,9 @@ class _CustomCalendarViewState extends State { _currentEndSelectedDate = date; setState(() { try { - widget.startEndDateChange( - _currentStartSelectedDate, _currentEndSelectedDate); + if (widget.dateChange != null) { + widget.dateChange!(date); + } } catch (_) {} }); } @@ -569,24 +603,29 @@ class _CustomCalendarViewState extends State { } if (_currentStartSelectedDate != null && _currentEndSelectedDate != null) { - if (!_currentEndSelectedDate.isAfter(_currentStartSelectedDate)) { - final DateTime d = _currentStartSelectedDate; + if (!_currentEndSelectedDate!.isAfter(_currentStartSelectedDate!)) { + final DateTime d = _currentStartSelectedDate!; _currentStartSelectedDate = _currentEndSelectedDate; _currentEndSelectedDate = d; } - if (date.isBefore(_currentStartSelectedDate)) { + if (date.isBefore(_currentStartSelectedDate!)) { _currentStartSelectedDate = date; } - if (date.isAfter(_currentEndSelectedDate)) { + if (date.isAfter(_currentEndSelectedDate!)) { _currentEndSelectedDate = date; } + setState(() { + try { + if (widget.rangeDateChange != null) { + widget.rangeDateChange!(DateTimeRange( + start: _currentStartSelectedDate!, + end: _currentEndSelectedDate!, + )); + } + } catch (_) {} + }); } - setState(() { - try { - widget.startEndDateChange( - _currentStartSelectedDate, _currentEndSelectedDate); - } catch (_) {} - }); + } String _getChinaWeekName(int weekOfDay) { diff --git a/lib/src/components/card/bubble_card/brn_bubble_text.dart b/lib/src/components/card/bubble_card/brn_bubble_text.dart index 0af90b23..e5161c5b 100644 --- a/lib/src/components/card/bubble_card/brn_bubble_text.dart +++ b/lib/src/components/card/bubble_card/brn_bubble_text.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/text/brn_expandable_text.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:flutter/material.dart'; @@ -28,26 +30,41 @@ import 'package:bruno/src/utils/brn_tools.dart'; /// * [BrnInsertInfo], 气泡背景的文本组件 /// class BrnBubbleText extends StatelessWidget { - ///显示的文本 + /// 显示的文本 final String text; - ///最多显示的行数 - final int maxLines; + /// 最多显示的行数 + final int? maxLines; - ///展开收起回调 - final TextExpandedCallback onExpanded; + /// 展开收起回调 + final TextExpandedCallback? onExpanded; - ///气泡的圆角 默认是4 + /// 气泡的圆角 默认是4 final double radius; + /// 气泡背景色 默认是 Color(0xFFF8F8F8) + final Color bgColor; + + /// 内容文本样式 + final TextStyle? textStyle; + + + const BrnBubbleText( - {Key key, this.text, this.maxLines, this.onExpanded, this.radius = 4}) + {Key? key, + this.text = '', + this.maxLines, + this.onExpanded, + this.radius = 4, + this.bgColor = const Color(0xFFF8F8F8), + this.textStyle}) : super(key: key); @override @override Widget build(BuildContext context) { - Image image = BrunoTools.getAssetImage('icons/icon_right_top_pointer.png'); + Image image = BrunoTools.getAssetImageWithColor( + 'icons/icon_right_top_pointer.png', bgColor); Widget bubbleText = Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -66,27 +83,28 @@ class BrnBubbleText extends StatelessWidget { Expanded( child: Container( decoration: BoxDecoration( - color: Color(0xFFF8F8F8), + color: bgColor, shape: BoxShape.rectangle, borderRadius: BorderRadius.only( topLeft: Radius.circular(0), - topRight: Radius.circular(radius ?? 4), - bottomLeft: Radius.circular(radius ?? 4), - bottomRight: Radius.circular(radius ?? 4))), + topRight: Radius.circular(radius), + bottomLeft: Radius.circular(radius), + bottomRight: Radius.circular(radius))), padding: EdgeInsets.only(left: 20, right: 20, top: 12, bottom: 12), child: BrnExpandableText( - text: text ?? "", + text: text, maxLines: maxLines, - color: Color(0xFFF8F8F8), + color: bgColor, onExpanded: onExpanded, - textStyle: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 14, - color: BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .colorTextBase, - ), + textStyle: textStyle ?? + TextStyle( + fontWeight: FontWeight.w500, + fontSize: 14, + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, + ), ), ), ) diff --git a/lib/src/components/card/bubble_card/brn_insert_info.dart b/lib/src/components/card/bubble_card/brn_insert_info.dart index 2a402468..a1872aa4 100644 --- a/lib/src/components/card/bubble_card/brn_insert_info.dart +++ b/lib/src/components/card/bubble_card/brn_insert_info.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; @@ -26,7 +28,7 @@ class BrnInsertInfo extends StatelessWidget { final String infoText; final int maxLines; - const BrnInsertInfo({Key key, @required this.infoText, this.maxLines = 2}) + const BrnInsertInfo({Key? key, required this.infoText, this.maxLines = 2}) : super(key: key); @override diff --git a/lib/src/components/card/content_card/brn_enhance_number_card.dart b/lib/src/components/card/content_card/brn_enhance_number_card.dart index 0081dbe2..12f683f7 100644 --- a/lib/src/components/card/content_card/brn_enhance_number_card.dart +++ b/lib/src/components/card/content_card/brn_enhance_number_card.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/constants/brn_strings_constants.dart'; import 'package:bruno/src/theme/brn_theme.dart'; @@ -55,13 +57,13 @@ import 'package:flutter/widgets.dart'; /// /// class BrnEnhanceNumberCard extends StatelessWidget { - final List itemChildren; + final List? itemChildren; ///如果超过一行,行间距则 默认为16 - final double runningSpace; + final double? runningSpace; ///Item的上半部分和下半部分的间距 默认为8 - final double itemRunningSpace; + final double? itemRunningSpace; ///每一行显示的数量 默认为3 final int rowCount; @@ -74,10 +76,10 @@ class BrnEnhanceNumberCard extends StatelessWidget { final TextAlign itemTextAlign; - final BrnEnhanceNumberCardConfig themeData; + final BrnEnhanceNumberCardConfig? themeData; BrnEnhanceNumberCard({ - Key key, + Key? key, this.itemChildren, this.rowCount = 3, this.runningSpace, @@ -100,7 +102,7 @@ class BrnEnhanceNumberCard extends StatelessWidget { .enhanceNumberCardConfig .merge(defaultConfig); - if (itemChildren == null || itemChildren.length == 0) { + if (itemChildren == null || itemChildren!.length == 0) { return Container( height: 0, width: 0, @@ -114,25 +116,25 @@ class BrnEnhanceNumberCard extends StatelessWidget { ); // 容错显示的行数 显示三行 int count = rowCount; - if (rowCount <= 0 || rowCount > itemChildren.length) { + if (rowCount <= 0 || rowCount > itemChildren!.length) { count = 3; } double width = constraints.maxWidth; double singleWidth = (width - padding.left - padding.right) / count; - if (itemChildren.length > 1) { + if (itemChildren!.length > 1) { // 平铺下来 contentWidget = Wrap( runSpacing: defaultConfig.runningSpace, spacing: 0.0, - children: itemChildren.map((data) { + children: itemChildren!.map((data) { //每行的最后一个 不显示分割线 //最后一个元素 不显示分割线 - bool condition1 = (itemChildren.indexOf(data) + 1) % count == 0; - bool condition2 = itemChildren.last == data; + bool condition1 = (itemChildren!.indexOf(data) + 1) % count == 0; + bool condition2 = itemChildren!.last == data; bool allCondition = condition1 || condition2; - bool isFirst = (itemChildren.indexOf(data) + 1) % count == 1; + bool isFirst = (itemChildren!.indexOf(data) + 1) % count == 1; return Container( width: singleWidth, child: Row( @@ -163,7 +165,7 @@ class BrnEnhanceNumberCard extends StatelessWidget { }).toList(), ); } else { - contentWidget = _buildItemWidget(itemChildren[0], defaultConfig); + contentWidget = _buildItemWidget(itemChildren![0], defaultConfig); } return Container( @@ -177,7 +179,7 @@ class BrnEnhanceNumberCard extends StatelessWidget { Widget _buildItemWidget( BrnNumberInfoItemModel model, BrnEnhanceNumberCardConfig config, - {double width}) { + {double? width}) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -194,9 +196,9 @@ class BrnEnhanceNumberCard extends StatelessWidget { Widget _buildTopWidget( BrnNumberInfoItemModel model, BrnEnhanceNumberCardConfig config, - {double width}) { + {double? width}) { if (model.topWidget != null) { - return model.topWidget; + return model.topWidget!; } return Row( mainAxisSize: MainAxisSize.min, @@ -207,7 +209,7 @@ class BrnEnhanceNumberCard extends StatelessWidget { Container( height: 26, transform: Matrix4.translationValues(0, 1, 0), - child: Text(model.number, + child: Text(model.number!, style: TextStyle( height: 1.0, textBaseline: TextBaseline.ideographic, @@ -225,9 +227,9 @@ class BrnEnhanceNumberCard extends StatelessWidget { Widget _buildBottomWidget( BrnNumberInfoItemModel model, BrnEnhanceNumberCardConfig config, - {double width}) { + {double? width}) { if (model.bottomWidget != null) { - return model.bottomWidget; + return model.bottomWidget!; } TextSpan span = TextSpan( text: model.title ?? "", @@ -247,10 +249,10 @@ class BrnEnhanceNumberCard extends StatelessWidget { ); if (model.iconTapCallBack != null) { Widget icon = - BrunoTools.getAssetSizeImage(BrnAsset.ICON_QUESTION, 14, 14); + BrunoTools.getAssetSizeImage(BrnAsset.iconQuestion, 14, 14); - if (model.numberInfoIcon == BrnNumberInfoIcon.ARROW) { - icon = BrunoTools.getAssetSizeImage(BrnAsset.ICON_RIGHT_ARROW, 14, 14); + if (model.numberInfoIcon == BrnNumberInfoIcon.arrow) { + icon = BrunoTools.getAssetSizeImage(BrnAsset.iconRightArrow, 14, 14); } debugPrint('${tp.height}'); debugPrint(model.title); @@ -268,7 +270,7 @@ class BrnEnhanceNumberCard extends StatelessWidget { ), GestureDetector( onTap: () { - model.iconTapCallBack(model); + model.iconTapCallBack!(model); }, child: icon, ) @@ -278,7 +280,7 @@ class BrnEnhanceNumberCard extends StatelessWidget { return text; } - Widget _getPreWidget(String preDesc, BrnEnhanceNumberCardConfig config) { + Widget _getPreWidget(String? preDesc, BrnEnhanceNumberCardConfig config) { if (preDesc == null || preDesc.isEmpty) { return Container( height: 0, @@ -288,7 +290,7 @@ class BrnEnhanceNumberCard extends StatelessWidget { return Padding( padding: const EdgeInsets.only(left: 1), child: Text( - preDesc ?? "", + preDesc, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( @@ -300,7 +302,7 @@ class BrnEnhanceNumberCard extends StatelessWidget { ); } - Widget _getLastWidget(String lastDesc, BrnEnhanceNumberCardConfig config) { + Widget _getLastWidget(String? lastDesc, BrnEnhanceNumberCardConfig config) { if (lastDesc == null || lastDesc.isEmpty) { return Container( height: 0, @@ -309,7 +311,7 @@ class BrnEnhanceNumberCard extends StatelessWidget { } return Padding( padding: const EdgeInsets.only(left: 1, top: 0), - child: Text(lastDesc ?? "", + child: Text(lastDesc, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( @@ -323,35 +325,35 @@ class BrnEnhanceNumberCard extends StatelessWidget { /// 用来显示强化数据的model class BrnNumberInfoItemModel { ///number必须是非中文,否则会展示异常,如果有中文信息 则设置pre和last字段 - final String number; + final String? number; ///下半部分的辅助信息 - final String title; + final String? title; ///强化信息的前面展示字段 - final String preDesc; + final String? preDesc; ///强化信息的后面展示字段 - final String lastDesc; + final String? lastDesc; ///icon的事件 - final Function(BrnNumberInfoItemModel) iconTapCallBack; + final Function(BrnNumberInfoItemModel)? iconTapCallBack; ///icon的样式 可枚举 , 默认为问号 final BrnNumberInfoIcon numberInfoIcon; ///上半部分的自定义内容 如果设置了优先级则高于 number、preDesc和lastDesc - final Widget topWidget; + final Widget? topWidget; ///下半部分的自定义内容 如果设置了优先级则高于 title - final Widget bottomWidget; + final Widget? bottomWidget; ///上部分的:(number、preDesc、lastDesc)和topWidget 必须设置一个 ///下部分的:title和title 必须设置一个 BrnNumberInfoItemModel({ this.number, this.title, - this.numberInfoIcon = BrnNumberInfoIcon.QUESTION, + this.numberInfoIcon = BrnNumberInfoIcon.question, this.iconTapCallBack, this.preDesc, this.lastDesc, @@ -362,6 +364,6 @@ class BrnNumberInfoItemModel { ///可扩展 enum BrnNumberInfoIcon { - ARROW, - QUESTION, + arrow, + question, } diff --git a/lib/src/components/card/content_card/brn_pair_info_rich_grid.dart b/lib/src/components/card/content_card/brn_pair_info_rich_grid.dart index f9c9d7fd..ca1f2666 100644 --- a/lib/src/components/card/content_card/brn_pair_info_rich_grid.dart +++ b/lib/src/components/card/content_card/brn_pair_info_rich_grid.dart @@ -1,3 +1,5 @@ + + import 'dart:ui' as ui; import 'package:bruno/src/constants/brn_asset_constants.dart'; @@ -37,27 +39,27 @@ import 'package:flutter/material.dart'; /// * [BrnPairInfoTable], 单列key-value信息集合组件 /// class BrnRichInfoGrid extends StatelessWidget { - final List pairInfoList; + final List? pairInfoList; ///行间距 纵向 - final double rowSpace; + final double? rowSpace; ///gridView 为children包裹的padding,默认是从media中获取,支持修改 ///同gridView的padding - final EdgeInsetsGeometry padding; + final EdgeInsetsGeometry? padding; ///元素间距 横向 - final double space; + final double? space; - final double itemHeight; + final double? itemHeight; /// 一共多少列 默认2列 final int crossAxisCount; - final BrnPairRichInfoGridConfig themeData; + final BrnPairRichInfoGridConfig? themeData; BrnRichInfoGrid({ - Key key, + Key? key, this.pairInfoList, this.padding, this.rowSpace, @@ -69,7 +71,7 @@ class BrnRichInfoGrid extends StatelessWidget { @override Widget build(BuildContext context) { - if (pairInfoList == null || pairInfoList.isEmpty) { + if (pairInfoList == null || pairInfoList!.isEmpty) { return Container( height: 0, width: 0, @@ -117,16 +119,16 @@ class BrnRichInfoGrid extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ _getKeyWidget( - pairInfoList[index], + pairInfoList![index], gridWidth, context, defaultConfig, ), - _getValueWidget(pairInfoList[index], defaultConfig) + _getValueWidget(pairInfoList![index], defaultConfig) ], ); }, - itemCount: (null != this.pairInfoList) ? this.pairInfoList.length : 0, + itemCount: (null != this.pairInfoList) ? this.pairInfoList!.length : 0, ); return gridView; }, @@ -135,7 +137,7 @@ class BrnRichInfoGrid extends StatelessWidget { Widget _getKeyWidget(BrnRichGridInfo info, double width, BuildContext context, BrnPairRichInfoGridConfig config) { - if (info == null || info.keyPart == null) { + if (info.keyPart == null) { return Container( height: 0, width: 0, @@ -163,12 +165,6 @@ class BrnRichInfoGrid extends StatelessWidget { Widget _getValueWidget( BrnRichGridInfo info, BrnPairRichInfoGridConfig config) { - if (info == null) { - return Container( - height: 0, - width: 0, - ); - } if (info.valuePart == null) { return Text('--', style: _getValueStyle('--', themeData: config)); } @@ -210,12 +206,12 @@ class BrnRichGridInfo { static BrnRichGridInfo valueLastClickInfo( String keyTitle, String valueTitle, { - Function(String key) keyQuestionCallback, - Function(String value) valueQuestionCallback, - String clickTitle, - Color clickColor, - Function(String clickValue) clickCallback, - BrnPairRichInfoGridConfig themeData, + Function(String key)? keyQuestionCallback, + Function(String value)? valueQuestionCallback, + String clickTitle = '', + Color? clickColor, + Function(String clickValue)? clickCallback, + BrnPairRichInfoGridConfig? themeData, }) { themeData ??= BrnPairRichInfoGridConfig(); themeData = themeData.merge(BrnPairRichInfoGridConfig( @@ -229,19 +225,19 @@ class BrnRichGridInfo { return GestureDetector( onTap: () { if (isKey) { - keyQuestionCallback(keyTitle); + keyQuestionCallback!(keyTitle); } else { - valueQuestionCallback(valueTitle); + valueQuestionCallback!(valueTitle); } }, child: Padding( padding: EdgeInsets.only(left: isKey ? 0 : 4), child: BrunoTools.getAssetSizeImage( - BrnAsset.ICON_PAIR_INFO_QUESTION, 14, 14), + BrnAsset.iconPairInfoQuestion, 14, 14), )); } - Widget _getClickValue({BrnPairRichInfoGridConfig themeData}) { + Widget _getClickValue({required BrnPairRichInfoGridConfig themeData}) { return GestureDetector( onTap: () { if (clickCallback != null) { @@ -264,10 +260,10 @@ class BrnRichGridInfo { bool isShowKeyQuestion = keyQuestionCallback != null; bool isShowValueQuestion = valueQuestionCallback != null; - bool isShowValueClick = clickTitle != null && clickTitle.isNotEmpty; + bool isShowValueClick = clickTitle.isNotEmpty; MediaQueryData mediaQuery = MediaQueryData.fromWindow(ui.window); - double screen = mediaQuery?.size?.width ?? 375; + double screen = mediaQuery.size.width; Widget key = Container( constraints: BoxConstraints( @@ -280,7 +276,7 @@ class BrnRichGridInfo { children: [ Flexible( child: Text( - keyTitle ?? "", + keyTitle, maxLines: 1, overflow: TextOverflow.ellipsis, style: _getKeyStyle(themeData: themeData), @@ -308,7 +304,7 @@ class BrnRichGridInfo { children: [ Flexible( child: Text( - valueTitle ?? "", + valueTitle, maxLines: 1, overflow: TextOverflow.ellipsis, style: _getValueStyle(valueTitle, themeData: themeData), @@ -334,13 +330,13 @@ class BrnRichGridInfo { } } -TextStyle _getKeyStyle({BrnPairRichInfoGridConfig themeData}) => - themeData.keyTextStyle?.generateTextStyle(); +TextStyle? _getKeyStyle({BrnPairRichInfoGridConfig? themeData}) => + themeData?.keyTextStyle.generateTextStyle(); -TextStyle _getClickStyle(String content, Color clickColor, - {BrnPairRichInfoGridConfig themeData}) => - themeData.linkTextStyle?.generateTextStyle(); +TextStyle? _getClickStyle(String? content, Color? clickColor, + {BrnPairRichInfoGridConfig? themeData}) => + themeData?.linkTextStyle.generateTextStyle(); -TextStyle _getValueStyle(String content, - {BrnPairRichInfoGridConfig themeData}) => - themeData?.valueTextStyle?.generateTextStyle(); +TextStyle? _getValueStyle(String content, + {BrnPairRichInfoGridConfig? themeData}) => + themeData?.valueTextStyle.generateTextStyle(); diff --git a/lib/src/components/card/content_card/brn_pair_info_table.dart b/lib/src/components/card/content_card/brn_pair_info_table.dart index 6a840977..2e7b7a4c 100644 --- a/lib/src/components/card/content_card/brn_pair_info_table.dart +++ b/lib/src/components/card/content_card/brn_pair_info_table.dart @@ -5,6 +5,7 @@ import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme.dart'; import 'package:bruno/src/utils/brn_rich_text.dart'; import 'package:bruno/src/utils/brn_tools.dart'; +import 'package:bruno/src/utils/css/brn_core_funtion.dart'; import 'package:bruno/src/utils/css/brn_css_2_text.dart'; import 'package:flutter/material.dart'; @@ -84,21 +85,21 @@ class BrnPairInfoTable extends StatefulWidget { final bool isFolded; /// 每一行的间距 默认4 - final double rowDistance; + final double? rowDistance; /// key和value的间距 默认2 - final double itemSpacing; + final double? itemSpacing; - final BrnPairInfoTableConfig themeData; + final BrnPairInfoTableConfig? themeData; ///对齐情况下,自定义的key展示规则 ///默认是最大的Key展示长度是107 ///可以参考[_MaxWrapTableWidth]实现自定义的展示规则,指定长度等 - final TableColumnWidth customKeyWidth; + final TableColumnWidth? customKeyWidth; BrnPairInfoTable({ - Key key, - @required this.children, + Key? key, + required this.children, this.isValueAlign = true, this.expandAtIndex = -1, this.rowDistance, @@ -114,27 +115,27 @@ class BrnPairInfoTable extends StatefulWidget { class _BrnPairInfoTableState extends State { //当前的展示状态 - bool _isFolded; + late bool _isFolded; //指定索引位置去具备展开功能 - int _expandAtIndex; + late int _expandAtIndex; // 收起状态显示的孩子 - List foldList; + List? foldList; // 展开状态显示的孩子 - List expandedList; + List? expandedList; // 在页面呈现的孩子 - List showList; + List? showList; // 指定位置的最原始 modal - BrnInfoModal indexModal; + BrnInfoModal? indexModal; // 是否具备展开收起功能 如果不展示则显示全部 bool canExpanded = false; - BrnPairInfoTableConfig themeData; + late BrnPairInfoTableConfig themeData; @override void initState() { @@ -166,7 +167,6 @@ class _BrnPairInfoTableState extends State { @override void didUpdateWidget(BrnPairInfoTable oldWidget) { super.didUpdateWidget(oldWidget); - themeData ??= BrnPairInfoTableConfig(); themeData = themeData.merge(BrnPairInfoTableConfig(rowSpacing: widget.rowDistance)); themeData = BrnThemeConfigurator.instance @@ -208,8 +208,8 @@ class _BrnPairInfoTableState extends State { return showWidget; } - Widget _finalValueWidget(BrnInfoModal data, {double itemSpacing}) { - Widget valueWidget; + Widget _finalValueWidget(BrnInfoModal data, {double? itemSpacing}) { + Widget? valueWidget; if (data.valuePart is String) { valueWidget = _valueTitleText(data.valuePart, @@ -222,7 +222,7 @@ class _BrnPairInfoTableState extends State { if (valueWidget == null) { valueWidget = Text( '--', - style: themeData.valueTextStyle?.generateTextStyle(), + style: themeData.valueTextStyle.generateTextStyle(), ); } } @@ -233,7 +233,7 @@ class _BrnPairInfoTableState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded(child: valueWidget), - BrunoTools.getAssetImage(BrnAsset.ICON_RIGHT_ARROW), + BrunoTools.getAssetImage(BrnAsset.iconRightArrow), ], ); } @@ -259,8 +259,8 @@ class _BrnPairInfoTableState extends State { /// 张开状态的孩子 /// 替换最后的value 为具备收起功能的 value /// 替换index的value 为原始的value - List _generateExpandedList() { - List finalChildren = List.of(widget.children); + List _generateExpandedList() { + List finalChildren = List.of(widget.children); BrnInfoModal foldRowWidget = _expandedButtonWidget(); finalChildren[_expandAtIndex] = indexModal; finalChildren[widget.children.length - 1] = foldRowWidget; @@ -268,7 +268,7 @@ class _BrnPairInfoTableState extends State { } BrnInfoModal _foldButtonWidget() { - Image img = BrunoTools.getAssetImage('icons/icon_uparrow.png'); + Image img = BrunoTools.getAssetImage(BrnAsset.iconUpArrow); Transform trsm = Transform.rotate(angle: pi, child: img); Row row = Row( children: [ @@ -310,9 +310,9 @@ class _BrnPairInfoTableState extends State { /// 将原有的value显示替换为 stack BrnInfoModal brnMetaInfoModal = BrnInfoModal( - isArrow: indexModal.isArrow, - keyPart: indexModal.keyPart, - valuePart: indexModal.valuePart, + isArrow: indexModal!.isArrow, + keyPart: indexModal!.keyPart, + valuePart: indexModal!.valuePart, ); Container stack = Container( child: Stack( @@ -327,7 +327,7 @@ class _BrnPairInfoTableState extends State { } BrnInfoModal _expandedButtonWidget() { - Image img = BrunoTools.getAssetImage('icons/icon_uparrow.png'); + Image img = BrunoTools.getAssetImage(BrnAsset.iconUpArrow); Row row = Row( children: [ Padding( @@ -388,7 +388,7 @@ class _BrnPairInfoTableState extends State { Widget _valueTitleText(String text, {bool isValueAlign = true, bool isArrow = false, - BrnPairInfoTableConfig themeData}) { + required BrnPairInfoTableConfig themeData}) { bool isSingle; if (isArrow) { isSingle = true; @@ -407,7 +407,7 @@ class _BrnPairInfoTableState extends State { show, overflow: isSingle ? TextOverflow.ellipsis : TextOverflow.clip, maxLines: isSingle ? 1 : null, - style: themeData.valueTextStyle?.generateTextStyle(), + style: themeData.valueTextStyle.generateTextStyle(), ); return keyOrValue; } @@ -417,9 +417,9 @@ mixin PairInfoPart { bool isValueAlign(); BrnPairInfoTableConfig configDefaultThemeData( - BrnPairInfoTableConfig themeData, - {double rowDistance, - double itemSpacing}) { + BrnPairInfoTableConfig? themeData, + {double? rowDistance, + double? itemSpacing}) { BrnPairInfoTableConfig defaultThemeData; defaultThemeData = themeData ?? BrnPairInfoTableConfig(); defaultThemeData = defaultThemeData.merge(BrnPairInfoTableConfig( @@ -431,8 +431,8 @@ mixin PairInfoPart { return defaultThemeData; } - Widget finalKeyWidget(BrnInfoModal data, BrnPairInfoTableConfig themeData) { - Widget keyWidget; + Widget? finalKeyWidget(BrnInfoModal data, BrnPairInfoTableConfig themeData) { + Widget? keyWidget; if (data.keyPart is String) { keyWidget = keyOrValueTitleText(true, data.keyPart.toString(), isValueAlign: isValueAlign(), @@ -445,8 +445,8 @@ mixin PairInfoPart { } Widget finalValueWidget(BrnInfoModal data, BrnPairInfoTableConfig themeData, - {double itemSpacing}) { - Widget valueWidget; + {double? itemSpacing}) { + Widget? valueWidget; if (data.valuePart is String) { valueWidget = keyOrValueTitleText(false, data.valuePart, @@ -459,7 +459,7 @@ mixin PairInfoPart { if (valueWidget == null) { valueWidget = Text( '--', - style: themeData.valueTextStyle?.generateTextStyle(), + style: themeData.valueTextStyle.generateTextStyle(), ); } } @@ -470,7 +470,7 @@ mixin PairInfoPart { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded(child: valueWidget), - BrunoTools.getAssetImage(BrnAsset.ICON_RIGHT_ARROW), + BrunoTools.getAssetImage(BrnAsset.iconRightArrow), ], ); } @@ -483,7 +483,7 @@ mixin PairInfoPart { Widget keyOrValueTitleText(bool isKey, String text, {bool isValueAlign = true, bool isArrow = false, - BrnPairInfoTableConfig themeData}) { + required BrnPairInfoTableConfig themeData}) { bool isSingle; if (isArrow) { isSingle = true; @@ -507,8 +507,8 @@ mixin PairInfoPart { overflow: isSingle ? TextOverflow.ellipsis : TextOverflow.clip, maxLines: isSingle ? 1 : null, style: isKey - ? themeData.keyTextStyle?.generateTextStyle() - : themeData.valueTextStyle?.generateTextStyle(), + ? themeData.keyTextStyle.generateTextStyle() + : themeData.valueTextStyle.generateTextStyle(), ); return keyOrValue; } @@ -516,19 +516,19 @@ mixin PairInfoPart { class BrnFollowPairInfo extends StatelessWidget with PairInfoPart { /// 待展示的文本信息集合 - final List children; + final List? children; /// 每一行的间距 - final double rowDistance; + final double? rowDistance; /// key和value的间距 - final double itemSpacing; + final double? itemSpacing; - final BrnPairInfoTableConfig themeData; + final BrnPairInfoTableConfig? themeData; BrnFollowPairInfo({ - Key key, - @required this.children, + Key? key, + required this.children, this.rowDistance, this.itemSpacing, this.themeData, @@ -550,13 +550,13 @@ class BrnFollowPairInfo extends StatelessWidget with PairInfoPart { builder: (context, constraints) { return Column( crossAxisAlignment: CrossAxisAlignment.start, - children: children.map((data) { + children: children!.map((data) { index++; return Padding( - padding: - EdgeInsets.only(top: (index == 0) ? 0 : themeData.rowSpacing), + padding: EdgeInsets.only( + top: (index == 0) ? 0 : themeData!.rowSpacing), child: _buildSingleInfo( - data, constraints.maxWidth / 2, defaultThemeConfig), + data!, constraints.maxWidth / 2, defaultThemeConfig), ); }).toList(), ); @@ -571,7 +571,7 @@ class BrnFollowPairInfo extends StatelessWidget with PairInfoPart { value = GestureDetector( onTap: () { if (infoModal.valueClickCallback != null) { - infoModal.valueClickCallback(); + infoModal.valueClickCallback!(); } }, child: value, @@ -600,20 +600,20 @@ class BrnFollowPairInfo extends StatelessWidget with PairInfoPart { class BrnAlignPairInfo extends StatelessWidget with PairInfoPart { /// 待展示的文本信息集合 - final List children; + final List? children; ///控件的背景色 默认为白色 - final Color backgroundColor; + final Color? backgroundColor; /// 每一行的间距 - final double rowDistance; + final double? rowDistance; /// key和value的间距 - final double itemSpacing; + final double? itemSpacing; - final TableColumnWidth customKeyWidth; + final TableColumnWidth? customKeyWidth; - final BrnPairInfoTableConfig themeData; + final BrnPairInfoTableConfig? themeData; BrnAlignPairInfo( {this.children, @@ -645,14 +645,14 @@ class BrnAlignPairInfo extends StatelessWidget with PairInfoPart { defaultVerticalAlignment: TableCellVerticalAlignment.baseline, textBaseline: TextBaseline.ideographic, columnWidths: { - 0: customKeyWidth ?? _MaxWrapTableWidth(maxWidth: maxWith), + 0: customKeyWidth ?? _MaxWrapTableWidth(maxWith), 1: FlexColumnWidth() }, border: TableBorder.all(color: Colors.transparent), - children: children.map((data) { + children: children!.map((data) { index++; return _buildSingleInfo( - data, index == children.length - 1, defaultThemeConfig); + data!, index == children!.length - 1, defaultThemeConfig); }).toList(), ); return table; @@ -674,14 +674,14 @@ class BrnAlignPairInfo extends StatelessWidget with PairInfoPart { value = GestureDetector( onTap: () { if (infoModal.valueClickCallback != null) { - infoModal.valueClickCallback(); + infoModal.valueClickCallback!(); } }, child: value, ); } return TableRow( - children: [finalKeyWidget(infoModal, defaultThemeConfig), value]); + children: [finalKeyWidget(infoModal, defaultThemeConfig)!, value]); } } @@ -702,7 +702,7 @@ class BrnInfoModal { final bool isArrow; /// value的点击回调 - final VoidCallback valueClickCallback; + final VoidCallback? valueClickCallback; BrnInfoModal( {this.keyPart, @@ -710,8 +710,7 @@ class BrnInfoModal { this.isArrow = false, this.valueClickCallback}) : assert(keyPart == null || keyPart is String || keyPart is Widget), - assert( - valuePart == null || valuePart is String || valuePart is Widget) {} + assert(valuePart == null || valuePart is String || valuePart is Widget); ///-----------以下静态方法为常见显示的快捷构造----------- /// value的最后一部分带有可点击的超链接 @@ -726,14 +725,14 @@ class BrnInfoModal { String keyTitle, String valueTitle, String clickValue, { - double fontSize, - double itemSpacing, - TextStyle valueTextStyle, - Function(String clickValue) clickCallback, + double? fontSize, + double? itemSpacing, + TextStyle? valueTextStyle, + Function(String? clickValue)? clickCallback, bool isArrow = false, - VoidCallback valueClickCallback, - Color linkColor, - BrnPairInfoTableConfig themeData, + VoidCallback? valueClickCallback, + Color? linkColor, + BrnPairInfoTableConfig? themeData, }) { themeData ??= BrnPairInfoTableConfig(); themeData = themeData.merge(BrnPairInfoTableConfig( @@ -759,7 +758,7 @@ class BrnInfoModal { valueTitle, overflow: TextOverflow.ellipsis, maxLines: 1, - style: themeData.valueTextStyle?.generateTextStyle(), + style: themeData.valueTextStyle.generateTextStyle(), ), ), GestureDetector( @@ -772,7 +771,7 @@ class BrnInfoModal { clickValue, overflow: TextOverflow.ellipsis, maxLines: 1, - style: themeData.linkTextStyle?.generateTextStyle(), + style: themeData.linkTextStyle.generateTextStyle(), ), ) ], @@ -781,11 +780,11 @@ class BrnInfoModal { valueWidget = BrnRichTextGenerator() .addText( valueTitle, - textStyle: themeData.valueTextStyle?.generateTextStyle(), + textStyle: themeData.valueTextStyle.generateTextStyle(), ) .addTextWithLink( clickValue, - textStyle: themeData.linkTextStyle?.generateTextStyle(), + textStyle: themeData.linkTextStyle.generateTextStyle(), richTextLinkClick: (text, url) { if (clickCallback != null) { clickCallback(text); @@ -821,15 +820,15 @@ class BrnInfoModal { String valueTitle, { bool keyShow = false, bool valueShow = true, - double fontSize, - double itemSpacing, - TextStyle keyTextStyle, - TextStyle valueTextStyle, - Function keyCallback, - Function valueCallback, + double? fontSize, + double? itemSpacing, + TextStyle? keyTextStyle, + TextStyle? valueTextStyle, + Function? keyCallback, + Function? valueCallback, bool isArrow = false, - VoidCallback valueClickCallback, - BrnPairInfoTableConfig themeData, + VoidCallback? valueClickCallback, + BrnPairInfoTableConfig? themeData, }) { themeData ??= BrnPairInfoTableConfig(); themeData = themeData.merge(BrnPairInfoTableConfig( @@ -848,7 +847,7 @@ class BrnInfoModal { if (isArrow) { MediaQueryData mediaQuery = MediaQueryData.fromWindow(ui.window); - double screen = mediaQuery?.size?.width ?? 375; + double screen = mediaQuery.size.width; if (keyShow) { keyWidget = Container( @@ -862,7 +861,7 @@ class BrnInfoModal { keyTitle, overflow: TextOverflow.ellipsis, maxLines: 1, - style: themeData.keyTextStyle?.generateTextStyle(), + style: themeData.keyTextStyle.generateTextStyle(), ), ), GestureDetector( @@ -871,13 +870,13 @@ class BrnInfoModal { keyCallback(); } }, - child: BrunoTools.getAssetImage(BrnAsset.ICON_QUESTION), + child: BrunoTools.getAssetImage(BrnAsset.iconQuestion), ), Text( ':', overflow: TextOverflow.ellipsis, maxLines: 1, - style: themeData.valueTextStyle?.generateTextStyle(), + style: themeData.valueTextStyle.generateTextStyle(), ) ], ), @@ -895,7 +894,7 @@ class BrnInfoModal { valueTitle, overflow: TextOverflow.ellipsis, maxLines: 1, - style: themeData.keyTextStyle?.generateTextStyle(), + style: themeData.keyTextStyle.generateTextStyle(), ), ), GestureDetector( @@ -904,7 +903,7 @@ class BrnInfoModal { valueCallback(); } }, - child: BrunoTools.getAssetImage(BrnAsset.ICON_QUESTION), + child: BrunoTools.getAssetImage(BrnAsset.iconQuestion), ) ], ); @@ -914,7 +913,7 @@ class BrnInfoModal { } else { BrnRichTextGenerator keyGen = BrnRichTextGenerator(); keyGen.addText(keyTitle, - textStyle: themeData.keyTextStyle?.generateTextStyle()); + textStyle: themeData.keyTextStyle.generateTextStyle()); if (keyShow) { keyGen.addIcon(GestureDetector( onTap: () { @@ -922,16 +921,16 @@ class BrnInfoModal { keyCallback(); } }, - child: BrunoTools.getAssetImage(BrnAsset.ICON_QUESTION), + child: BrunoTools.getAssetImage(BrnAsset.iconQuestion), )); keyGen.addText(':', - textStyle: themeData.keyTextStyle?.generateTextStyle()); + textStyle: themeData.keyTextStyle.generateTextStyle()); } keyWidget = keyGen.build(); BrnRichTextGenerator valueGen = BrnRichTextGenerator(); valueGen.addText(valueTitle, - textStyle: themeData.valueTextStyle?.generateTextStyle()); + textStyle: themeData.valueTextStyle.generateTextStyle()); if (valueShow) { valueGen.addIcon(GestureDetector( onTap: () { @@ -939,7 +938,7 @@ class BrnInfoModal { valueCallback(); } }, - child: BrunoTools.getAssetImage(BrnAsset.ICON_QUESTION), + child: BrunoTools.getAssetImage(BrnAsset.iconQuestion), )); } valueWidget = valueGen.build(); @@ -963,14 +962,14 @@ class BrnInfoModal { static BrnInfoModal keyHeadIconInfo( String keyTitle, String valueTitle, { - Widget headIcon, - double fontSize, - double itemSpacing, - TextStyle keyTextStyle, - TextStyle valueTextStyle, + Widget? headIcon, + double? fontSize, + double? itemSpacing, + TextStyle? keyTextStyle, + TextStyle? valueTextStyle, bool isArrow = false, - VoidCallback valueClickCallback, - BrnPairInfoTableConfig themeData, + VoidCallback? valueClickCallback, + BrnPairInfoTableConfig? themeData, }) { themeData ??= BrnPairInfoTableConfig(); themeData = themeData.merge(BrnPairInfoTableConfig( @@ -1001,7 +1000,7 @@ class BrnInfoModal { } keyGen.addText(keyTitle, - textStyle: themeData.keyTextStyle?.generateTextStyle()); + textStyle: themeData.keyTextStyle.generateTextStyle()); return BrnInfoModal( keyPart: keyGen.build(), @@ -1014,13 +1013,13 @@ class BrnInfoModal { static BrnInfoModal valueRichTextInfo( String keyTitle, String valueTitle, { - double fontSize, - double itemSpacing, - TextStyle valueTextStyle, + double? fontSize, + required double itemSpacing, + TextStyle? valueTextStyle, bool isArrow = false, - BrnRichTextLinkClick richTextLinkClick, - VoidCallback valueClickCallback, - BrnPairInfoTableConfig themeData, + BrnHyperLinkCallback? richTextLinkClick, + VoidCallback? valueClickCallback, + BrnPairInfoTableConfig? themeData, }) { themeData ??= BrnPairInfoTableConfig(); themeData = themeData.merge(BrnPairInfoTableConfig( @@ -1042,7 +1041,7 @@ class BrnInfoModal { maxLines: isArrow ? 1 : null, textOverflow: isArrow ? TextOverflow.ellipsis : TextOverflow.clip, - defaultStyle: themeData.valueTextStyle?.generateTextStyle(), + defaultStyle: themeData.valueTextStyle.generateTextStyle(), linksCallback: (text, url) { if (richTextLinkClick != null) { richTextLinkClick(text, url); @@ -1083,5 +1082,5 @@ class _MaxWrapTableWidth extends TableColumnWidth { return 0; } - _MaxWrapTableWidth({this.maxWidth}); + _MaxWrapTableWidth(this.maxWidth); } diff --git a/lib/src/components/card/shadow_card/brn_shadow_card.dart b/lib/src/components/card/shadow_card/brn_shadow_card.dart index c68fda31..e2969c82 100644 --- a/lib/src/components/card/shadow_card/brn_shadow_card.dart +++ b/lib/src/components/card/shadow_card/brn_shadow_card.dart @@ -36,10 +36,10 @@ class BrnShadowCard extends StatelessWidget { final double borderWidth; BrnShadowCard( - {@required this.child, - this.color, - this.shadowColor, - this.padding, + {required this.child, + this.color = const Color(0xfffafafa), + this.shadowColor = const Color(0xffeeeeee), + this.padding = const EdgeInsets.all(0), this.circular = 4.0, this.blurRadius = 5.0, this.spreadRadius = 0, @@ -49,18 +49,14 @@ class BrnShadowCard extends StatelessWidget { @override Widget build(BuildContext context) { double tempBorderWidth = 0; - if (this.borderWidth != null && this.borderWidth > 0) { + if (this.borderWidth > 0) { tempBorderWidth = this.borderWidth; } return Container( - padding: padding ?? EdgeInsets.all(0), - child: this.child ?? - Container( - width: 0, - height: 0, - ), + padding: padding, + child: this.child, decoration: BoxDecoration( - color: this.color ?? Color(0xfffafafa), + color: this.color, borderRadius: BorderRadius.all(Radius.circular(circular)), border: tempBorderWidth != 0 ? Border.all( @@ -72,7 +68,7 @@ class BrnShadowCard extends StatelessWidget { : Border.all(style: BorderStyle.none), boxShadow: [ BoxShadow( - color: this.shadowColor ?? Color(0xffeeeeee), + color: this.shadowColor, offset: this.offset, //阴影xy轴偏移量 blurRadius: this.blurRadius, //阴影模糊程度 spreadRadius: this.spreadRadius //阴影扩散程度 diff --git a/lib/src/components/card_title/brn_action_card_title.dart b/lib/src/components/card_title/brn_action_card_title.dart index f483e641..4cb00a2c 100644 --- a/lib/src/components/card_title/brn_action_card_title.dart +++ b/lib/src/components/card_title/brn_action_card_title.dart @@ -1,5 +1,4 @@ -import 'package:bruno/bruno.dart'; -import 'package:bruno/src/constants/brn_strings_constants.dart'; +import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_card_title_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; @@ -38,29 +37,28 @@ class BrnActionCardTitle extends StatelessWidget { final String title; ///箭头左边的文字 - final String accessoryText; + final String? accessoryText; ///标题点击 - final VoidCallback onTap; + final VoidCallback? onTap; ///标题右侧的小文字 - final String subTitle; + final String? subTitle; ///标题右侧的显示widget - final Widget subTitleWidget; + final Widget? subTitleWidget; - final BrnCardTitleConfig themeData; + final BrnCardTitleConfig? themeData; BrnActionCardTitle({ - Key key, - @required this.title, + Key? key, + required this.title, this.accessoryText, this.onTap, this.subTitle, this.subTitleWidget, this.themeData, - }) : assert(null != title), - super(key: key); + }) : super(key: key); @override Widget build(BuildContext context) { @@ -112,10 +110,10 @@ class BrnActionCardTitle extends StatelessWidget { return Container( padding: EdgeInsets.only(right: 8), child: Text( - this.title ?? "", + this.title, maxLines: 1, overflow: TextOverflow.ellipsis, - style: defaultConfig.titleTextStyle?.generateTextStyle(), + style: defaultConfig.titleTextStyle.generateTextStyle(), ), ); } @@ -123,24 +121,24 @@ class BrnActionCardTitle extends StatelessWidget { // 如果传入了subTitleWidget 则以subTitleWidget为主 Widget _sub(BrnCardTitleConfig defaultConfig) { if (subTitleWidget != null) { - return subTitleWidget; + return subTitleWidget!; } if (subTitle != null) { return Container( constraints: BoxConstraints(maxWidth: 84), - child: Text(this.subTitle, + child: Text(this.subTitle!, maxLines: 1, overflow: TextOverflow.ellipsis, style: subTextStyle(defaultConfig)), ); } - return Container(); + return SizedBox.shrink(); } Widget _arrowWidget() { - return BrunoTools.getAssetSizeImage(BrnAsset.ICON_RIGHT_ARROW, 16, 16); + return BrunoTools.getAssetSizeImage(BrnAsset.iconRightArrow, 16, 16); } Widget _accessoryTextWidget(BrnCardTitleConfig defaultConfig) { @@ -156,7 +154,7 @@ class BrnActionCardTitle extends StatelessWidget { child: Text( accessoryText ?? "", overflow: TextOverflow.ellipsis, - style: defaultConfig.accessoryTextStyle?.generateTextStyle(), + style: defaultConfig.accessoryTextStyle.generateTextStyle(), ), ), _arrowWidget() @@ -167,5 +165,5 @@ class BrnActionCardTitle extends StatelessWidget { //标题右侧的小文字 样式 TextStyle subTextStyle(BrnCardTitleConfig defaultConfig) => - defaultConfig?.subtitleTextStyle?.generateTextStyle(); + defaultConfig.subtitleTextStyle.generateTextStyle(); } diff --git a/lib/src/components/card_title/brn_common_card_title.dart b/lib/src/components/card_title/brn_common_card_title.dart index 86f0840b..cea76fdf 100644 --- a/lib/src/components/card_title/brn_common_card_title.dart +++ b/lib/src/components/card_title/brn_common_card_title.dart @@ -50,34 +50,34 @@ class BrnCommonCardTitle extends StatelessWidget { final String title; /// 最右侧的文字 - final String accessoryText; + final String? accessoryText; /// 最右侧的widget 如果两者同时存在 则以widget为主 - final Widget accessoryWidget; + final Widget? accessoryWidget; /// 整个区域点击的回调 - final VoidCallback onTap; + final VoidCallback? onTap; /// 标题右侧的显示widget - final Widget subTitleWidget; + final Widget? subTitleWidget; /// 标题下面的文字 - final String detailTextString; + final String? detailTextString; /// title的流式文本的对齐方式 - final PlaceholderAlignment alignment; + final PlaceholderAlignment? alignment; /// 标题下方文字 默认是深色的222222 - final Color detailColor; + final Color? detailColor; /// 内容的padding 默认上下16 左右0 - final EdgeInsetsGeometry padding; + final EdgeInsetsGeometry? padding; - final BrnCardTitleConfig themeData; + final BrnCardTitleConfig? themeData; BrnCommonCardTitle( - {Key key, - @required this.title, + {Key? key, + required this.title, this.accessoryText, this.accessoryWidget, this.onTap, @@ -95,7 +95,7 @@ class BrnCommonCardTitle extends StatelessWidget { defaultConfig = defaultConfig.merge(BrnCardTitleConfig( alignment: alignment, - cardTitlePadding: padding, + cardTitlePadding: padding as EdgeInsets?, detailTextStyle: BrnTextStyle(color: detailColor))); defaultConfig = BrnThemeConfigurator.instance @@ -103,27 +103,22 @@ class BrnCommonCardTitle extends StatelessWidget { .cardTitleConfig .merge(defaultConfig); + Widget titleContainer = Container( + color: defaultConfig.cardBackgroundColor, + child: _rowWidget(context, defaultConfig), + ); + if (onTap == null) return titleContainer; return GestureDetector( - onTap: () { - if (onTap != null) { - onTap(); - } - }, - child: Container( - color: defaultConfig?.cardBackgroundColor, - child: _rowWidget(context, defaultConfig), - ), + onTap: onTap, + child: titleContainer, ); } Widget _rowWidget(BuildContext context, BrnCardTitleConfig defaultConfig) { - List children = List(); + List children = []; children.add(Expanded(child: _titleWidget(context, defaultConfig))); - Widget accessory = Container( - height: 0, - width: 0, - ); + Widget accessory = SizedBox.shrink(); // 左侧的文本的行高是25,那么右侧的widget最大为25 if (this.accessoryWidget != null) { accessory = Container( @@ -151,7 +146,7 @@ class BrnCommonCardTitle extends StatelessWidget { Widget _accessoryTextWidget(BrnCardTitleConfig defaultConfig) { Text tx = Text( accessoryText ?? "", - style: defaultConfig?.accessoryTextStyle?.generateTextStyle(), + style: defaultConfig.accessoryTextStyle.generateTextStyle(), ); return Container( @@ -172,28 +167,25 @@ class BrnCommonCardTitle extends StatelessWidget { ///标题widget Widget _titleWidget(BuildContext context, BrnCardTitleConfig defaultConfig) { - Widget subWidget = Container( - height: 0, - width: 0, - ); + Widget subWidget = SizedBox.shrink(); if (subTitleWidget != null) { subWidget = _subTitleWidgetFromWidget(); } var titleWidget = RichText( - textScaleFactor: MediaQuery.of(context)?.textScaleFactor ?? 1.0, + textScaleFactor: MediaQuery.of(context).textScaleFactor, text: TextSpan( - text: title ?? "", - style: defaultConfig?.titleWithHeightTextStyle?.generateTextStyle(), + text: title, + style: defaultConfig.titleWithHeightTextStyle.generateTextStyle(), children: [ WidgetSpan(child: subWidget, alignment: defaultConfig.alignment), ]), ); - List colChildren = List(); + List colChildren = []; colChildren.add(titleWidget); - if (null != detailTextString && detailTextString.isNotEmpty) { + if (null != detailTextString && detailTextString!.isNotEmpty) { Widget detailWidget = _detailTextWidget(defaultConfig); colChildren.add(detailWidget); } @@ -212,7 +204,7 @@ class BrnCommonCardTitle extends StatelessWidget { detailTextString ?? "", overflow: TextOverflow.ellipsis, maxLines: 2, - style: defaultConfig?.detailTextStyle?.generateTextStyle(), + style: defaultConfig.detailTextStyle.generateTextStyle(), ); return Container( child: tx, diff --git a/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart.dart b/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart.dart index e27cc652..30ea9fb9 100644 --- a/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart.dart +++ b/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart.dart @@ -27,25 +27,25 @@ class BrnDoughnutDataItem { double radius = 0; BrnDoughnutDataItem({ - this.value, - this.title, + required this.value, + required this.title, this.color = Colors.blueAccent, }); } /// 选中扇形区域后执行的回调 typedef BrnDoughnutSelectCallback = void Function( - BrnDoughnutDataItem selectedItem); + BrnDoughnutDataItem? selectedItem); class BrnDoughnut extends CustomPainter { ///圆心位置 - Offset circleCenter; + late Offset circleCenter; /// 选中的区域 - final BrnDoughnutDataItem selectedItem; + final BrnDoughnutDataItem? selectedItem; /// 选中区域回调 - final BrnDoughnutSelectCallback brnDoughnutSelectCallback; + final BrnDoughnutSelectCallback? brnDoughnutSelectCallback; /// 字体大小 final double fontSize; @@ -73,7 +73,7 @@ class BrnDoughnut extends CustomPainter { BrnDoughnut( {this.ringWidth = 50, - this.data, + required this.data, this.fontSize = 12, this.fontColor = Colors.white, this.selectedItem, @@ -81,10 +81,10 @@ class BrnDoughnut extends CustomPainter { this.brnDoughnutSelectCallback}) { double lastEndRadius = 0; double totalValue = 0; - this.data?.forEach((BrnDoughnutDataItem item) { + this.data.forEach((BrnDoughnutDataItem item) { totalValue += item.value; }); - this.data?.forEach((BrnDoughnutDataItem item) { + this.data.forEach((BrnDoughnutDataItem item) { item.percentage = item.value / totalValue; item.startRadius = lastEndRadius; item.radius = 2 * pi * item.percentage; @@ -108,7 +108,7 @@ class BrnDoughnut extends CustomPainter { Offset center = drawArea.center; circleCenter = center; - this.data?.forEach((BrnDoughnutDataItem item) { + this.data.forEach((BrnDoughnutDataItem item) { // 画扇形 Paint _paint = Paint() ..color = item.color @@ -124,9 +124,8 @@ class BrnDoughnut extends CustomPainter { canvas.drawArc(rect, item.startRadius, item.radius, true, _paint); // 画文本 - if (item.title != null && - (this.showTitleWhenSelected == false || - item.startRadius == selectedItem?.startRadius)) { + if (this.showTitleWhenSelected == false || + item.startRadius == selectedItem?.startRadius) { // 画引线 Offset indicarorLPoint = calcOffsetWith(item.middleRadius, indicatorLCircleRadius); @@ -228,7 +227,7 @@ class BrnDoughnut extends CustomPainter { } @override - bool hitTest(Offset position) { + bool? hitTest(Offset position) { int length = data.length; for (int i = 0; i < length; i++) { BrnDoughnutDataItem item = data[i]; @@ -236,7 +235,7 @@ class BrnDoughnut extends CustomPainter { if (item.startRadius < radain && radain < (item.startRadius + item.radius)) { if (null != brnDoughnutSelectCallback) - brnDoughnutSelectCallback( + brnDoughnutSelectCallback!( item.startRadius == selectedItem?.startRadius ? null : item); break; } @@ -268,10 +267,10 @@ class BrnDoughnutChart extends StatelessWidget { final double height; /// 选中的项目 - final BrnDoughnutDataItem selectedItem; + final BrnDoughnutDataItem? selectedItem; /// 选中项目时候的回掉 - final BrnDoughnutSelectCallback selectCallback; + final BrnDoughnutSelectCallback? selectCallback; /// 选中时展示文字大小,默认12 final double fontSize; @@ -296,7 +295,7 @@ class BrnDoughnutChart extends StatelessWidget { this.height = 0, this.padding = EdgeInsets.zero, this.ringWidth = 50, - this.data, + required this.data, this.fontSize = 12, this.fontColor = Colors.white, this.selectedItem, diff --git a/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart_legend.dart b/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart_legend.dart index a5c4c8fa..14acb767 100644 --- a/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart_legend.dart +++ b/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart_legend.dart @@ -24,21 +24,22 @@ class DoughnutChartLegend extends StatelessWidget { final List data; DoughnutChartLegend( - {this.legendStyle = BrnDoughnutChartLegendStyle.wrap, this.data}); + {this.legendStyle = BrnDoughnutChartLegendStyle.wrap, + required this.data}); @override Widget build(BuildContext context) { if (BrnDoughnutChartLegendStyle.list == this.legendStyle) { - List items = List(); - this.data?.forEach((BrnDoughnutDataItem item) { + List items = []; + this.data.forEach((BrnDoughnutDataItem item) { items.add(this.genItem(item)); }); return Column( children: items, ); } else if (BrnDoughnutChartLegendStyle.wrap == this.legendStyle) { - List items = List(); - this.data?.forEach((BrnDoughnutDataItem item) { + List items = []; + this.data.forEach((BrnDoughnutDataItem item) { items.add(this.genItem(item)); }); @@ -48,7 +49,7 @@ class DoughnutChartLegend extends StatelessWidget { children: items, ); } else { - return Container(); + return const SizedBox.shrink(); } } @@ -68,7 +69,7 @@ class DoughnutChartLegend extends StatelessWidget { width: 6, ), Text( - item.title ?? '', + item.title, style: TextStyle(color: Colors.black), ), ], diff --git a/lib/src/components/charts/brn_progress_bar_chart/brn_bar_chart_data.dart b/lib/src/components/charts/brn_progress_bar_chart/brn_bar_chart_data.dart index f8df9ff3..5cd4d015 100644 --- a/lib/src/components/charts/brn_progress_bar_chart/brn_bar_chart_data.dart +++ b/lib/src/components/charts/brn_progress_bar_chart/brn_bar_chart_data.dart @@ -7,7 +7,7 @@ class BrnBarChartScaleStyle { /// y轴获取的值,只读 double get titleValue { - if (title == null || title.isEmpty) { + if (title.isEmpty) { return 0; } else { return double.parse(title); @@ -15,23 +15,23 @@ class BrnBarChartScaleStyle { } /// 刻度标志样式 - TextStyle titleStyle; + TextStyle? titleStyle; /// 与最大数值的比率,用来计算绘制刻度的位置使用。 - double positionRetioy; + double? positionRetioy; /// 下面标注文案独属y轴使用,目前还没有x轴扩展需求,x轴设置下面参数无效,后期有需要再扩展 /// 两个刻度之间的标注文案(向前绘制即x轴在该刻度左侧绘制,y轴在该刻度下面绘制),不需要的话不设置 - String centerSubTitle; + String? centerSubTitle; /// 标注文案样式,centerSubTitle有内容时有效 - TextStyle centerSubTextStyle; + TextStyle? centerSubTextStyle; /// 标注文案位置是否是在左侧,false表示在右侧,centerSubTitle有内容时有效 bool isLeft; BrnBarChartScaleStyle( - {this.title, + {required this.title, this.titleStyle, this.centerSubTitle, this.centerSubTextStyle, @@ -58,10 +58,10 @@ class BrnBarDataBean { /// 每条线的定义 class BrnBarBean { /// 名称 - String name; + String? name; ///x轴的字体样式 - TextStyle xTitleStyle; + TextStyle? xTitleStyle; ///是否显示x轴的文字,用来处理多个线条绘制的时候,同一x轴坐标不需要绘制多次,则只需要将多条线中一个标记绘制即可 bool isDrawX; @@ -76,19 +76,19 @@ class BrnBarBean { bool isCurve; ///点集合 - List points; + List? points; ///曲线或折线的颜色 Color lineColor; ///填充色 - List colors; + List? colors; ///占位图是否需要打断线条绘制,如果打断的话这个点的y值将没有意义,只有x轴有效,如果不打断的话,y轴值有效 bool placehoderImageBreak; ///用户当前进行位置的小图标(比如一个小锁),默认没有只显示y轴的值,如果有内容则显示这个小图标, - ui.Image placehoderImage; + ui.Image? placehoderImage; BrnBarBean( {this.name, this.xTitleStyle, diff --git a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart index df33b1ee..fb12f8de 100644 --- a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart +++ b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart @@ -27,7 +27,7 @@ class BrnProgressBarChart extends StatefulWidget { /// 单个柱形宽度,默认 30 final double singleBarWidth; - /// 柱状图的最大值,柱状图的宽/高会依此值计算,默认 0 + /// 柱状图的最大值,柱状图的宽/高会依此值计算,默认 0,为0时自动计算柱状图最大值 final double barMaxValue; /// 柱状图方向,默认 BarChartStyle.vertical @@ -40,25 +40,25 @@ class BrnProgressBarChart extends StatefulWidget { final Color selectedHintTextBackgroundColor; /// 是否可点击回调 - final OnBarItemClickInterceptor onBarItemClickInterceptor; + final OnBarItemClickInterceptor? onBarItemClickInterceptor; - /// 选中柱状图时候的回调 - final BrnProgressBarChartSelectCallback barChartSelectCallback; + /// 选中柱状图时候的回调(暂仅支持垂直柱状图) + final BrnProgressBarChartSelectCallback? barChartSelectCallback; /// 图表高度,竖直柱状图有效,默认300 final double height; BrnProgressBarChart( - {Key key, + {Key? key, this.minWidth = 0, this.padding = const EdgeInsets.all(20), this.barChartStyle = BarChartStyle.vertical, - this.xAxis, - this.yAxis, - this.barBundleList, + required this.xAxis, + required this.yAxis, + required this.barBundleList, this.barGroupSpace = 30, this.singleBarWidth = 30, - this.barMaxValue, + this.barMaxValue = 0, this.selectedHintTextColor = Colors.white, this.selectedHintTextBackgroundColor = Colors.black, this.onBarItemClickInterceptor, @@ -66,21 +66,12 @@ class BrnProgressBarChart extends StatefulWidget { this.height = 300}) : super(key: key) { if (BarChartStyle.horizontal == barChartStyle) { - assert(yAxis.axisItemList != null, '水平柱形图必须要有 Y 轴'); - assert(barBundleList != null && barBundleList.length != 0, '缺少柱形图数据'); - assert( - barBundleList[0].barList != null && - barBundleList[0].barList.length == yAxis.axisItemList.length, + assert(barBundleList[0].barList.length == yAxis.axisItemList.length, '水平柱状图个数与Y轴坐标数目要相等'); } else if (BarChartStyle.vertical == barChartStyle) { - assert(xAxis.axisItemList != null, '竖直柱形图必须要有 X 轴'); - assert(barBundleList != null && barBundleList.length != 0, '缺少柱形图数据'); - assert( - barBundleList[0].barList != null && - barBundleList[0].barList.length == xAxis.axisItemList.length, + assert(barBundleList[0].barList.length == xAxis.axisItemList.length, '竖直柱状图个数与X轴坐标数目要相等'); } - assert(0 != this.barMaxValue, '柱状图最大值不能为0'); } @override @@ -90,12 +81,9 @@ class BrnProgressBarChart extends StatefulWidget { } class BrnProgressBarChartState extends State { - BrnProgressBarItem _selectedBarItem; + BrnProgressBarItem? _selectedBarItem; Size chartSize() { - if (null == widget.barBundleList) { - return Size.zero; - } int barBundleCount = widget.barBundleList.length; int numberOfBars = widget.barBundleList[0].barList.length; if (BarChartStyle.horizontal == widget.barChartStyle) { @@ -104,8 +92,7 @@ class BrnProgressBarChartState extends State { numberOfBars; ///有 x 轴 需要加上 x 轴占用的高度 - if (null != widget.xAxis?.axisItemList && - 0 < widget.xAxis.axisItemList.length) { + if (widget.xAxis.axisItemList.isNotEmpty) { height += 22; } double width = MediaQuery.of(context).size.width; @@ -116,12 +103,11 @@ class BrnProgressBarChartState extends State { numberOfBars; /// 有 y 轴需要加上 y 轴占用的宽度 - if (null != widget.yAxis?.axisItemList && - 0 < widget.yAxis.axisItemList.length) { + if (widget.yAxis.axisItemList.isNotEmpty) { width += BrnProgressBarChartPainter.maxYAxisWidth(widget.yAxis); } - return Size(widget.minWidth > width ? widget.minWidth : width, - widget.height ?? 300); + return Size( + widget.minWidth > width ? widget.minWidth : width, widget.height); } else { return Size.zero; } @@ -134,10 +120,6 @@ class BrnProgressBarChartState extends State { } void clearSelectedBarItem(BrnProgressBarChart oldWidget) { - if (null == widget.barBundleList || null == widget.barBundleList) { - _selectedBarItem = null; - return; - } if (widget.barBundleList.length == oldWidget.barBundleList.length) { int bundleCount = widget.barBundleList.length; for (int bundleIndex = 0; bundleIndex < bundleCount; bundleIndex++) { @@ -170,8 +152,8 @@ class BrnProgressBarChartState extends State { @override Widget build(BuildContext context) { Size chartSize = this.chartSize(); - if (null == widget.barBundleList || chartSize == Size.zero) { - return Container(); + if (chartSize == Size.zero) { + return const SizedBox.shrink(); } if (BarChartStyle.vertical == widget.barChartStyle) { double yAxisWidth = @@ -216,9 +198,9 @@ class BrnProgressBarChartState extends State { selectedHintTextBackgroundColor: widget.selectedHintTextBackgroundColor, brnProgressBarChartSelectCallback: - (BrnProgressBarItem item) { + (BrnProgressBarItem? item) { if (null != widget.barChartSelectCallback) - widget.barChartSelectCallback(item); + widget.barChartSelectCallback!(item); setState(() { _selectedBarItem = item; }); @@ -246,7 +228,7 @@ class BrnProgressBarChartState extends State { ), ); } else { - return Container(); + return const SizedBox.shrink(); } } } diff --git a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart index d1f52385..912efe4f 100644 --- a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart +++ b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart @@ -10,7 +10,7 @@ typedef BarItemEnumeratorCallback = void Function( /// 点击柱状数据的回调 typedef BrnProgressBarChartSelectCallback = void Function( - BrnProgressBarItem barItem); + BrnProgressBarItem? barItem); /// 点击柱状数据的拦截器 typedef bool OnBarItemClickInterceptor( @@ -31,13 +31,13 @@ enum BarChartStyle { //坐标轴样式 enum AxisStyle { ///无线条 - AxisStyleNone, + axisStyleNone, ///虚线 - AxisStyleDot, + axisStyleDot, ///实线 - AxisStyleSolid, + axisStyleSolid, } /// 坐标轴项目 @@ -46,14 +46,13 @@ class AxisItem { final String showText; /// 文本大小 - Size textSize; - AxisItem({this.showText}); + late Size textSize; + AxisItem({required this.showText}); } /// ChartAxis 图表的坐标轴样式 /// 可对坐标轴的刻度样式、线条样式、偏移量等数据进行设置 class ChartAxis { - @required final List axisItemList; /// 是否有刻度 @@ -63,7 +62,7 @@ class ChartAxis { final AxisStyle axisStyle; /// 两个刻度间距 - double space; + double? space; double maxTextHeight = 0; double maxTextWidth = 0; @@ -72,9 +71,9 @@ class ChartAxis { TextStyle textStyle = TextStyle(color: Color(0x999999), fontSize: 12); ChartAxis({ - this.axisItemList = const [], - this.hasMark, - this.axisStyle = AxisStyle.AxisStyleSolid, + required this.axisItemList, + this.hasMark = true, + this.axisStyle = AxisStyle.axisStyleSolid, }); } @@ -85,30 +84,30 @@ const _showBarValueTextStyle = /// 可对数据的数值、展示文本、选中状态的文字以及柱形的样式进行设置 class BrnProgressBarItem { /// 柱状数据的描述文本 - final String text; + final String? text; /// 柱状数据的值 final double value; /// 柱状数据的参考值,展示在当前柱状图的后面 - final double hintValue; + final double? hintValue; ///选中时气泡文字 - final String selectedHintText; + final String? selectedHintText; /// 展示柱形的值 - final String showBarValueText; + final String? showBarValueText; /// 展示柱形值文本样式 final TextStyle showBarValueTextStyle; - double percentage; - double hintPercentage; - Rect barRect; - Rect barHintRect; - Offset barGroupAxisCenter; + late double percentage; + double? hintPercentage; + Rect? barRect; + Rect? barHintRect; + late Offset barGroupAxisCenter; BrnProgressBarItem( {this.text, - @required this.value, + required this.value, this.hintValue, this.selectedHintText, this.showBarValueText, @@ -125,7 +124,7 @@ class BrnProgressBarBundle { final List colors; final List hintColors; BrnProgressBarBundle( - {this.barList, + {required this.barList, this.colors = _defaultColor, this.hintColors = _defaultHintColor}); } @@ -158,15 +157,15 @@ class BrnProgressBarChartPainter extends CustomPainter { final bool drawBar; /// 是否可点击回调 - final OnBarItemClickInterceptor onBarItemClickInterceptor; + final OnBarItemClickInterceptor? onBarItemClickInterceptor; /// 选中柱状图时条形文案颜色 final Color selectedHintTextColor; /// 选中柱状图时条形文案背景颜色 final Color selectedHintTextBackgroundColor; - final BrnProgressBarItem selectedBarItem; - final BrnProgressBarChartSelectCallback brnProgressBarChartSelectCallback; + final BrnProgressBarItem? selectedBarItem; + final BrnProgressBarChartSelectCallback? brnProgressBarChartSelectCallback; Color unselectedColor = Color(0xffDAEDFE); @@ -187,13 +186,13 @@ class BrnProgressBarChartPainter extends CustomPainter { final double _xAxisHeight = 22; BrnProgressBarChartPainter( - {this.barChartStyle, - this.xAxis, - this.yAxis, - this.barBundleList, - this.barGroupSpace, - this.singleBarWidth, - this.barMaxValue, + {required this.barChartStyle, + required this.xAxis, + required this.yAxis, + required this.barBundleList, + required this.barGroupSpace, + required this.singleBarWidth, + required this.barMaxValue, this.drawX = true, this.drawY = true, this.drawBar = true, @@ -277,7 +276,7 @@ class BrnProgressBarChartPainter extends CustomPainter { } // 找到柱状图最大值 - if (null != this.barMaxValue && 0 != this.barMaxValue) { + if (0 != this.barMaxValue) { this.maxValue = this.barMaxValue; } else { this.barBundleList.forEach((BrnProgressBarBundle barbundle) { @@ -295,7 +294,7 @@ class BrnProgressBarChartPainter extends CustomPainter { barItem.percentage = barItem.value / this.maxValue; if (null != barItem.hintValue) { - barItem.hintPercentage = barItem.hintValue / this.maxValue; + barItem.hintPercentage = barItem.hintValue! / this.maxValue; } if (BarChartStyle.horizontal == this.barChartStyle) { @@ -311,11 +310,11 @@ class BrnProgressBarChartPainter extends CustomPainter { barItem.barRect = barRect; // 条形组的坐标轴中间Offset,此处目前仅考虑有一组条形值的情况 - barItem.barGroupAxisCenter = barItem.barRect.centerLeft; + barItem.barGroupAxisCenter = barItem.barRect!.centerLeft; // BarHintRect if (null != barItem.hintPercentage) { - double hintWidth = this.contentRect.width * barItem.hintPercentage; + double hintWidth = this.contentRect.width * barItem.hintPercentage!; Rect barHintRect = Rect.fromLTWH(leftTop.dx, leftTop.dy, hintWidth, height); barItem.barHintRect = barHintRect; @@ -346,7 +345,7 @@ class BrnProgressBarChartPainter extends CustomPainter { // BarHintRect if (null != barItem.hintPercentage) { - double hintHeight = this.contentRect.height * barItem.hintPercentage; + double hintHeight = this.contentRect.height * barItem.hintPercentage!; Rect barHintRect = Rect.fromLTWH( leftBottom.dx, leftBottom.dy - hintHeight, width, hintHeight); barItem.barHintRect = barHintRect; @@ -375,13 +374,13 @@ class BrnProgressBarChartPainter extends CustomPainter { } void _drawXAxisIn(Canvas canvas, Rect xAxisRect) { - if (0 == this.xAxis?.axisItemList?.length) return; - if (AxisStyle.AxisStyleSolid == this.xAxis.axisStyle) { + if (0 == this.xAxis.axisItemList.length) return; + if (AxisStyle.axisStyleSolid == this.xAxis.axisStyle) { Offset xLineStart = xAxisRect.topLeft; Offset xLineEnd = xAxisRect.topRight; Paint xAxisPaint = Paint()..color = Color(0xff222222); canvas.drawLine(xLineStart, xLineEnd, xAxisPaint); - } else if (AxisStyle.AxisStyleDot == this.xAxis.axisStyle) { + } else if (AxisStyle.axisStyleDot == this.xAxis.axisStyle) { Offset xLineStart = xAxisRect.topLeft; Offset xLineEnd = xAxisRect.topRight; _drawDashLineOn(canvas, xLineStart, xLineEnd, Color(0xff222222)); @@ -412,7 +411,7 @@ class BrnProgressBarChartPainter extends CustomPainter { AxisItem axisItem = this.xAxis.axisItemList[xAxisItemIndex]; TextPainter textPainter = TextPainter( text: TextSpan( - text: axisItem.showText ?? '', + text: axisItem.showText, style: TextStyle(fontSize: 12, color: Color(0xff999999))), textDirection: TextDirection.ltr) ..layout(maxWidth: double.infinity, minWidth: 0); @@ -438,7 +437,7 @@ class BrnProgressBarChartPainter extends CustomPainter { AxisItem axisItem = this.xAxis.axisItemList[barGroupIndex]; TextPainter textPainter = TextPainter( text: TextSpan( - text: axisItem.showText ?? '', + text: axisItem.showText, style: TextStyle(fontSize: 12, color: Color(0xff999999))), textDirection: TextDirection.ltr) ..layout(maxWidth: double.infinity, minWidth: 0); @@ -455,13 +454,13 @@ class BrnProgressBarChartPainter extends CustomPainter { } void _drawYAxisIn(Canvas canvas, Rect yAxisRect) { - if (0 == this.yAxis?.axisItemList?.length) return; - if (AxisStyle.AxisStyleSolid == this.yAxis.axisStyle) { + if (0 == this.yAxis.axisItemList.length) return; + if (AxisStyle.axisStyleSolid == this.yAxis.axisStyle) { Offset yLineStart = yAxisRect.bottomRight; Offset yLineEnd = yAxisRect.topRight; Paint yAxisPaint = Paint()..color = Color(0xff222222); canvas.drawLine(yLineStart, yLineEnd, yAxisPaint); - } else if (AxisStyle.AxisStyleDot == this.xAxis.axisStyle) { + } else if (AxisStyle.axisStyleDot == this.xAxis.axisStyle) { Offset yLineStart = yAxisRect.bottomRight; Offset yLineEnd = yAxisRect.topRight; _drawDashLineOn(canvas, yLineStart, yLineEnd, Color(0xff222222)); @@ -486,7 +485,7 @@ class BrnProgressBarChartPainter extends CustomPainter { height: textSize.height); TextPainter( text: TextSpan( - text: axisItem.showText ?? '', + text: axisItem.showText, style: TextStyle(fontSize: 12, color: Color(0xff999999))), textDirection: TextDirection.ltr) ..layout(maxWidth: double.infinity, minWidth: 0) @@ -514,7 +513,7 @@ class BrnProgressBarChartPainter extends CustomPainter { height: textSize.height); TextPainter( text: TextSpan( - text: axisItem.showText ?? '', + text: axisItem.showText, style: TextStyle(fontSize: 12, color: Color(0xff999999))), textDirection: TextDirection.ltr) ..layout(maxWidth: double.infinity, minWidth: 0) @@ -556,7 +555,7 @@ class BrnProgressBarChartPainter extends CustomPainter { end: Alignment.topCenter, tileMode: TileMode.clamp, colors: barBundle.hintColors) - .createShader(barItem.barHintRect); + .createShader(barItem.barHintRect!); Paint hintBarPaint = Paint() ..shader = hintShader @@ -565,22 +564,22 @@ class BrnProgressBarChartPainter extends CustomPainter { ..strokeWidth = 1.5 ..style = PaintingStyle.fill; - canvas.drawRect(barItem.barHintRect, hintBarPaint); + canvas.drawRect(barItem.barHintRect!, hintBarPaint); } - RRect barRRect = RRect.fromRectAndCorners(barItem.barRect, + RRect barRRect = RRect.fromRectAndCorners(barItem.barRect!, topRight: Radius.circular(4), topLeft: Radius.circular(4)); if (this.selectedBarItem != null) { // 有选中的柱形,选中柱形保持原样,未选中的置灰 Shader shader; - if (this.selectedBarItem.barRect == barItem.barRect) { + if (this.selectedBarItem!.barRect == barItem.barRect) { // 选中的柱形 shader = LinearGradient( begin: Alignment.bottomCenter, end: Alignment.topCenter, tileMode: TileMode.clamp, colors: barBundle.colors) - .createShader(barItem.barRect); + .createShader(barItem.barRect!); } else { // 未选中需要置灰的柱形 shader = LinearGradient( @@ -588,7 +587,7 @@ class BrnProgressBarChartPainter extends CustomPainter { end: Alignment.topCenter, tileMode: TileMode.clamp, colors: [this.unselectedColor, this.unselectedColor]) - .createShader(barItem.barRect); + .createShader(barItem.barRect!); } Paint barPaint = Paint() ..shader = shader @@ -597,10 +596,10 @@ class BrnProgressBarChartPainter extends CustomPainter { ..strokeWidth = 1.5 ..style = PaintingStyle.fill; canvas.drawRRect(barRRect, barPaint); - if (this.selectedBarItem.barRect == barItem.barRect) { + if (this.selectedBarItem!.barRect == barItem.barRect) { // 选中柱形的虚线以及 HintText - this._drawDashLineOn(canvas, barItem.barRect.bottomCenter, - Offset(barItem.barRect.bottomCenter.dx, 0), Color(0xff222222)); + this._drawDashLineOn(canvas, barItem.barRect!.bottomCenter, + Offset(barItem.barRect!.bottomCenter.dx, 0), Color(0xff222222)); } } else { Shader shader = LinearGradient( @@ -608,7 +607,7 @@ class BrnProgressBarChartPainter extends CustomPainter { end: Alignment.topCenter, tileMode: TileMode.clamp, colors: barBundle.colors) - .createShader(barItem.barRect); + .createShader(barItem.barRect!); Paint barPaint = Paint() ..shader = shader ..isAntiAlias = true @@ -626,14 +625,14 @@ class BrnProgressBarChartPainter extends CustomPainter { if (null != barItem.showBarValueText) { TextPainter textPainter = TextPainter( text: TextSpan( - text: barItem.showBarValueText ?? '', + text: barItem.showBarValueText!, style: barItem.showBarValueTextStyle), textDirection: TextDirection.ltr) ..layout(maxWidth: double.infinity, minWidth: 0); double textWidth = textPainter.size.width; double textHeight = textPainter.size.height; - Offset textOffset = Offset(barItem.barRect.center.dx - textWidth / 2, - barItem.barRect.top - textHeight - 2); + Offset textOffset = Offset(barItem.barRect!.center.dx - textWidth / 2, + barItem.barRect!.top - textHeight - 2); textPainter.paint(canvas, textOffset); } }); @@ -643,8 +642,8 @@ class BrnProgressBarChartPainter extends CustomPainter { // 画选中文字 Start TextPainter selectedBarTextPainter = TextPainter( text: TextSpan( - text: selectedBarItem.selectedHintText ?? - (selectedBarItem.text ?? ''), + text: selectedBarItem!.selectedHintText ?? + (selectedBarItem!.text ?? ''), style: TextStyle(fontSize: 12, color: this.selectedHintTextColor)), textDirection: TextDirection.ltr) @@ -653,16 +652,16 @@ class BrnProgressBarChartPainter extends CustomPainter { double textHeight = selectedBarTextPainter.size.height; Offset selectedBarTextBgCenterOffset; - if (selectedBarItem.barRect.bottomCenter.dx + 10 + textWidth + 10 * 2 > + if (selectedBarItem!.barRect!.bottomCenter.dx + 10 + textWidth + 10 * 2 > this.contentRect.right) { // 需要显示在左侧 selectedBarTextBgCenterOffset = Offset( - selectedBarItem.barRect.bottomCenter.dx - 10 - 10 - textWidth / 2, + selectedBarItem!.barRect!.bottomCenter.dx - 10 - 10 - textWidth / 2, 16.0 + 16.0); } else { // 需要显示在右侧 selectedBarTextBgCenterOffset = Offset( - selectedBarItem.barRect.bottomCenter.dx + 10 + 10 + textWidth / 2, + selectedBarItem!.barRect!.bottomCenter.dx + 10 + 10 + textWidth / 2, 16.0 + 16.0); } @@ -702,7 +701,7 @@ class BrnProgressBarChartPainter extends CustomPainter { end: Alignment.centerRight, tileMode: TileMode.clamp, colors: barBundle.hintColors) - .createShader(barItem.barHintRect); + .createShader(barItem.barHintRect!); Paint hintBarPaint = Paint() ..shader = hintShader ..isAntiAlias = true @@ -710,11 +709,11 @@ class BrnProgressBarChartPainter extends CustomPainter { ..strokeWidth = 1.5 ..style = PaintingStyle.fill; - canvas.drawRect(barItem.barHintRect, hintBarPaint); + canvas.drawRect(barItem.barHintRect!, hintBarPaint); } // 绘制柱状图形 - RRect barRRect = RRect.fromRectAndCorners(barItem.barRect, + RRect barRRect = RRect.fromRectAndCorners(barItem.barRect!, topRight: Radius.circular(4), bottomRight: Radius.circular(4)); Shader shader = LinearGradient( @@ -722,7 +721,7 @@ class BrnProgressBarChartPainter extends CustomPainter { end: Alignment.centerRight, tileMode: TileMode.clamp, colors: barBundle.colors) - .createShader(barItem.barRect); + .createShader(barItem.barRect!); Paint barPaint = Paint() ..shader = shader ..isAntiAlias = true @@ -764,7 +763,7 @@ class BrnProgressBarChartPainter extends CustomPainter { } @override - bool hitTest(Offset position) { + bool? hitTest(Offset position) { if (this.brnProgressBarChartSelectCallback != null && BarChartStyle.vertical == this.barChartStyle) { this.barItemEnumerator((int barBundleIndex, @@ -772,12 +771,12 @@ class BrnProgressBarChartPainter extends CustomPainter { int barGroupIndex, BrnProgressBarItem barItem) { if (this.brnProgressBarChartSelectCallback != null && - barItem.barRect.contains(position)) { + barItem.barRect!.contains(position)) { if (this.onBarItemClickInterceptor == null || true == - this.onBarItemClickInterceptor( + this.onBarItemClickInterceptor!( barBundleIndex, barBundle, barGroupIndex, barItem)) { - this.brnProgressBarChartSelectCallback( + this.brnProgressBarChartSelectCallback!( barItem.barRect == this.selectedBarItem?.barRect ? null : barItem); diff --git a/lib/src/components/charts/brn_progress_chart/brn_progress_chart.dart b/lib/src/components/charts/brn_progress_chart/brn_progress_chart.dart index d1a9ca59..30a27266 100644 --- a/lib/src/components/charts/brn_progress_chart/brn_progress_chart.dart +++ b/lib/src/components/charts/brn_progress_chart/brn_progress_chart.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/charts/brn_progress_chart/brn_progress_chart_painter.dart'; import 'package:flutter/material.dart'; @@ -23,7 +25,7 @@ class BrnProgressChart extends StatefulWidget { final TextStyle textStyle; /// 自定义进度条上面的Widget,默认显示为文本 - final BrnProgressIndicatorBuilder brnProgressIndicatorBuilder; + final BrnProgressIndicatorBuilder? brnProgressIndicatorBuilder; /// 背景色,默认 Colors.lightBlueAccent final Color backgroundColor; @@ -35,7 +37,7 @@ class BrnProgressChart extends StatefulWidget { final bool showAnimation; const BrnProgressChart( - {Key key, + {Key? key, this.width = 0, this.height = 0, this.value = 0.2, @@ -56,8 +58,8 @@ class BrnProgressChart extends StatefulWidget { class BrnProgressChartState extends State with SingleTickerProviderStateMixin { - Animation _animation; - AnimationController _animationController; + late Animation _animation; + AnimationController? _animationController; double _value = 0; @override @@ -67,13 +69,13 @@ class BrnProgressChartState extends State _animationController = AnimationController( vsync: this, duration: Duration(milliseconds: 250)); Tween tween = Tween(begin: 0, end: widget.value); - _animation = tween.animate(_animationController); + _animation = tween.animate(_animationController!) as Animation; _animation.addListener(() { setState(() { _value = _animation.value; }); }); - _animationController.forward(); + _animationController!.forward(); } else { _value = widget.value; } @@ -106,7 +108,7 @@ class BrnProgressChartState extends State padding: EdgeInsets.only(left: widget.indicatorLeftPadding), alignment: Alignment.centerLeft, child: null != widget.brnProgressIndicatorBuilder - ? widget.brnProgressIndicatorBuilder(context, _value) + ? widget.brnProgressIndicatorBuilder!(context, _value) : _indicatorWidgetBuilder(context, _value), ) ], diff --git a/lib/src/components/charts/brn_progress_chart/brn_progress_chart_painter.dart b/lib/src/components/charts/brn_progress_chart/brn_progress_chart_painter.dart index de391f0d..396e6981 100644 --- a/lib/src/components/charts/brn_progress_chart/brn_progress_chart_painter.dart +++ b/lib/src/components/charts/brn_progress_chart/brn_progress_chart_painter.dart @@ -1,3 +1,5 @@ + + import 'package:flutter/material.dart'; class BrnProgressChartPainter extends CustomPainter { diff --git a/lib/src/components/charts/broken_line/brn_base_painter.dart b/lib/src/components/charts/broken_line/brn_base_painter.dart index c89a9832..ab648e9e 100644 --- a/lib/src/components/charts/broken_line/brn_base_painter.dart +++ b/lib/src/components/charts/broken_line/brn_base_painter.dart @@ -1,11 +1,9 @@ import 'package:flutter/material.dart'; -class BrnBasePainter extends CustomPainter { +abstract class BrnBasePainter extends CustomPainter { @override - void paint(Canvas canvas, Size size) {} + void paint(Canvas canvas, Size size); @override - bool shouldRepaint(CustomPainter oldDelegate) { - return true; - } + bool shouldRepaint(CustomPainter oldDelegate); } diff --git a/lib/src/components/charts/broken_line/brn_broken_line.dart b/lib/src/components/charts/broken_line/brn_broken_line.dart index c8ddbc0e..501f4799 100644 --- a/lib/src/components/charts/broken_line/brn_broken_line.dart +++ b/lib/src/components/charts/broken_line/brn_broken_line.dart @@ -1,11 +1,9 @@ import 'dart:math'; -import 'dart:ui'; import 'package:bruno/src/components/charts/broken_line/brn_line_data.dart'; import 'package:bruno/src/components/charts/broken_line/brn_line_painter.dart'; import 'package:bruno/src/components/charts/broken_line/brn_line_y_painter.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; /// 适用于需要折线图,曲线图的场景 /// 支持数据过多时左右滑动查看数据 @@ -21,16 +19,16 @@ class BrnBrokenLine extends StatefulWidget { final EdgeInsets contentPadding; /// 绘制的背景色 - final Color backgroundColor; + final Color? backgroundColor; /// xy轴线条的宽度,默认 2 final double xyDialLineWidth; /// xy轴的颜色 - final Color xDialColor, yDialColor; + final Color? xDialColor, yDialColor; /// x轴最小值,最大值,用来计算内部绘制点的x轴位置 - final double xDialMin, xDialMax; + final double? xDialMin, xDialMax; /// y轴最小值,最大值,用来计算内部绘制点的y轴位置 final double yDialMin, yDialMax; @@ -39,10 +37,10 @@ class BrnBrokenLine extends StatefulWidget { final double dialWidth; /// y轴左侧刻度显示,不传则没有 - final List yDialValues; + final List? yDialValues; /// x 轴刻度 - final List xDialValues; + final List? xDialValues; /// x轴的辅助线是否展示,默认 true final bool isShowXHintLine; @@ -54,7 +52,7 @@ class BrnBrokenLine extends StatefulWidget { final bool isHintLineSolid; /// 辅助线颜色 - final Color hintLineColor; + final Color? hintLineColor; /// 是否展示 x 坐标刻度,默认 false final bool isShowXDialText; @@ -72,9 +70,9 @@ class BrnBrokenLine extends StatefulWidget { final bool isTipWindowAutoDismiss; BrnBrokenLine({ - Key key, - @required this.size, - @required this.lines, + Key? key, + required this.size, + required this.lines, this.contentPadding = const EdgeInsets.only(left: 10, right: 10), this.backgroundColor, this.xyDialLineWidth = 2, @@ -86,8 +84,8 @@ class BrnBrokenLine extends StatefulWidget { this.xDialMin, this.xDialMax, this.xDialValues, - this.yDialMin, - this.yDialMax, + required this.yDialMin, + required this.yDialMax, this.yDialValues, this.isShowXHintLine = true, this.isShowYHintLine = false, @@ -96,11 +94,8 @@ class BrnBrokenLine extends StatefulWidget { this.isTipWindowAutoDismiss = true, this.isShowXDialText = false, this.isShowYDialText = false, - }) : assert(size != null), - assert(yDialMin != null), - assert(yDialMax != null), - super(key: key) { - /// 设置自定义 X 轴时,检查 x轴的最大、最小刻度范围 + }) : super(key: key) { + // 设置自定义 X 轴时,检查 x轴的最大、最小刻度范围 if (xDialValues != null) { assert(xDialMin != null); assert(xDialMax != null); @@ -156,9 +151,8 @@ class BrnBrokenLineState extends State { isShowYDialText: widget.isShowYDialText, ); //y 轴宽度 = Y 轴刻度宽度+ chartLeftPadding(SingleChildScrollView padding)+ y 轴偏移量 yAxisWidth - var yWidth = widget.size.width + - (widget.contentPadding?.left ?? 10) + - (widget.yHintLineOffset == null ? 20.0 : widget.yHintLineOffset); + var yWidth = + widget.size.width + widget.contentPadding.left + widget.yHintLineOffset; return Stack( children: [ CustomPaint( @@ -174,12 +168,12 @@ class BrnBrokenLineState extends State { : null, ), Padding( - padding: EdgeInsets.only(left: widget.yHintLineOffset ?? 20.0), + padding: EdgeInsets.only(left: widget.yHintLineOffset), child: SingleChildScrollView( padding: EdgeInsets.only( - left: widget.contentPadding?.left ?? 10, + left: widget.contentPadding.left, bottom: 25, - right: widget.contentPadding?.right ?? 10), + right: widget.contentPadding.right), scrollDirection: Axis.horizontal, child: GestureDetector( onPanDown: (DragDownDetails e) { @@ -205,14 +199,14 @@ class BrnBrokenLineState extends State { } }, onLongPressUp: () { - if (widget.isTipWindowAutoDismiss ?? true) { + if (widget.isTipWindowAutoDismiss) { pointSelectIndex = -1; lineSelectIndex = -1; setState(() {}); } }, onTapUp: (tapUpDetail) { - if (widget.isTipWindowAutoDismiss ?? true) { + if (widget.isTipWindowAutoDismiss) { pointSelectIndex = -1; lineSelectIndex = -1; setState(() {}); @@ -236,7 +230,7 @@ class BrnBrokenLineState extends State { (lineSelectIndex >= 0 && pointSelectIndex >= 0) ? _buildTouchTipWidget( widget.lines[lineSelectIndex].points[pointSelectIndex]) - : Container(), + : const SizedBox.shrink(), ]), ), ), @@ -247,19 +241,16 @@ class BrnBrokenLineState extends State { Widget _buildTouchTipWidget(BrnPointData pointData) { Widget touchTipWidget; - BrnLineTouchData selectLinePoint = pointData?.lineTouchData; - if (selectLinePoint != null && - pointData.isClickable != null && - pointData.isClickable && - selectLinePoint.onTouch != null) { - var content = selectLinePoint.onTouch(); + BrnLineTouchData? selectLinePoint = pointData.lineTouchData; + if (pointData.isClickable && selectLinePoint.onTouch != null) { + var content = selectLinePoint.onTouch!(); if (content is String) { touchTipWidget = Positioned( top: selectLinePoint.y, left: selectLinePoint.x, child: Container( - height: selectLinePoint.tipWindowSize?.height, - width: selectLinePoint.tipWindowSize?.width, + height: selectLinePoint.tipWindowSize.height, + width: selectLinePoint.tipWindowSize.width, padding: EdgeInsets.only(left: 10, right: 10, top: 8, bottom: 8), child: Center(child: Text(content)), decoration: BoxDecoration( @@ -281,20 +272,14 @@ class BrnBrokenLineState extends State { top: selectLinePoint.y, left: selectLinePoint.x, child: Container( - height: selectLinePoint.tipWindowSize?.height, - width: selectLinePoint.tipWindowSize?.width, + height: selectLinePoint.tipWindowSize.height, + width: selectLinePoint.tipWindowSize.width, child: content)); } else { - touchTipWidget = Container( - height: 0, - width: 0, - ); + touchTipWidget = const SizedBox.shrink(); } } else { - touchTipWidget = Container( - height: 0, - width: 0, - ); + touchTipWidget = const SizedBox.shrink(); } return touchTipWidget; @@ -308,8 +293,6 @@ class BrnBrokenLineState extends State { double endY, double fixedHeight, Point selectedPoint) { - if (selectedPoint == null || lineTouchData == null) return; - if (pointSelectIndex < 0 && lineSelectIndex < 0) { lineTouchData.x = -1.0; lineTouchData.y = -1.0; @@ -324,16 +307,16 @@ class BrnBrokenLineState extends State { if (selectY <= (startY - endY) / 2) { y = selectY + padding; } else { - y = selectY - (lineTouchData?.tipWindowSize?.height ?? 0.0) - padding; + y = selectY - (lineTouchData.tipWindowSize.height) - padding; } if (selectX <= (endX - startX) / 2) { x = selectX + padding; } else { - x = selectX - (lineTouchData?.tipWindowSize?.width ?? 0.0) - padding; + x = selectX - (lineTouchData.tipWindowSize.width) - padding; } - lineTouchData.x = x + lineTouchData.tipOffset?.dx ?? 0; - lineTouchData.y = y + lineTouchData.tipOffset?.dy ?? 0; + lineTouchData.x = x + lineTouchData.tipOffset.dx; + lineTouchData.y = y + lineTouchData.tipOffset.dy; } } diff --git a/lib/src/components/charts/broken_line/brn_line_data.dart b/lib/src/components/charts/broken_line/brn_line_data.dart index caa6bd33..e8ea7466 100644 --- a/lib/src/components/charts/broken_line/brn_line_data.dart +++ b/lib/src/components/charts/broken_line/brn_line_data.dart @@ -3,15 +3,15 @@ import 'package:flutter/material.dart'; class BrnDialItem { /// 刻度标志内容 - String dialText; + String? dialText; /// 刻度标志样式 - TextStyle dialTextStyle; + TextStyle? dialTextStyle; /// x,y 轴刻度值。用于刻度在坐标的真实定位 double value; - BrnDialItem({this.dialText, this.dialTextStyle, @required this.value}); + BrnDialItem({this.dialText, this.dialTextStyle, required this.value}); } class BrnPointData { @@ -25,10 +25,10 @@ class BrnPointData { Offset offset; /// 点要展示的内容 - String pointText; + String? pointText; /// 点展示内容样式 - TextStyle pointTextStyle; + TextStyle? pointTextStyle; /// 折线节点的点击击事件是否可用 bool isClickable; @@ -42,7 +42,7 @@ class BrnPointData { this.pointText, this.pointTextStyle, this.isClickable: true, - this.lineTouchData}) { + required this.lineTouchData}) { pointText ??= '$y'; pointTextStyle ??= TextStyle( fontWeight: FontWeight.w500, @@ -56,7 +56,7 @@ class BrnPointData { class BrnLineTouchData { /// 用于临时存储要展示 tip 内容在坐标的位置 - double x, y; + double? x, y; /// 要展示 tip 的相对偏移量 Offset tipOffset; @@ -65,10 +65,10 @@ class BrnLineTouchData { Size tipWindowSize; /// 点击回调,由于返回 展示内容(String 或 Widget) - Function() onTouch; + Function()? onTouch; BrnLineTouchData({ - @required this.tipWindowSize, + required this.tipWindowSize, this.tipOffset: const Offset(0, 0), this.onTouch, }); @@ -83,22 +83,22 @@ class BrnPointsLine { double lineWidth; /// Line渐变色,从曲线到x轴从上到下的闭合颜色集 - List shaderColors; + List? shaderColors; /// 曲线或折线的颜色 Color lineColor; /// 点外圈的颜色 - Color pointColor; + Color? pointColor; /// 点的外半径参数 double pointRadius; /// 点内圈的颜色 - Color pointInnerColor; + Color? pointInnerColor; /// 点内圈的半径 - double pointInnerRadius; + double? pointInnerRadius; /// 是否显示x轴的文字,用来处理多个线条绘制的时候,同一x轴坐标不需要绘制多次,则只需要将多条线中一个标记绘制即可 bool isShowXDial; @@ -120,12 +120,11 @@ class BrnPointsLine { this.pointInnerRadius, this.pointInnerColor, this.isCurve = false, - this.points, + required this.points, this.isShowPoint: true, this.isShowPointText = false, this.shaderColors, this.lineColor = Colors.purple}) { - lineColor ??= Colors.purple; pointColor ??= lineColor; pointInnerColor ??= lineColor; pointInnerRadius ??= pointRadius - 1.5; diff --git a/lib/src/components/charts/broken_line/brn_line_painter.dart b/lib/src/components/charts/broken_line/brn_line_painter.dart index 6bae7ec4..be8db97e 100644 --- a/lib/src/components/charts/broken_line/brn_line_painter.dart +++ b/lib/src/components/charts/broken_line/brn_line_painter.dart @@ -1,5 +1,4 @@ import 'dart:math'; -import 'dart:ui'; import 'package:bruno/src/components/charts/broken_line/brn_base_painter.dart'; import 'package:bruno/src/components/charts/broken_line/brn_line_data.dart'; @@ -9,32 +8,32 @@ import 'package:flutter/material.dart'; import 'package:path_drawing/path_drawing.dart'; class BrnLinePainter extends BrnBasePainter { - int lineSelectIndex = -1; - int pointSelectIndex = -1; + final int lineSelectIndex; + final int pointSelectIndex; /// xy轴线条的宽度 double xyLineWidth = 0.5; /// x轴的颜色 - Color xDialColor; + Color? xDialColor; ///y轴的颜色 - Color yDialColor; + Color? yDialColor; /// 刻度的宽度或者高度 - double rulerWidth; + final double rulerWidth; /// x轴最小值,最大值,用来计算内部绘制点的x轴位置 - double xDialMin, xDialMax; + double? xDialMin, xDialMax; /// y轴最小值,最大值,用来计算内部绘制点的y轴位置 - double yDialMin, yDialMax; + final double yDialMin, yDialMax; /// x轴 刻度 - List xDialValues; + List? xDialValues; /// y轴左侧刻度显示,不传则没有 - List yDialValues; + List? yDialValues; /// x、y轴的辅助线 bool isShowHintX, isShowHintY; @@ -43,14 +42,14 @@ class BrnLinePainter extends BrnBasePainter { bool hintLineSolid; /// 辅助线颜色 - Color hintLineColor; + Color? hintLineColor; /// 绘制线条的参数内容 List lines; bool isShowXText, isShowYText; - bool showPointDashLine; + final bool showPointDashLine; /// 默认的边距 static const double basePadding = 0; @@ -61,17 +60,13 @@ class BrnLinePainter extends BrnBasePainter { /// 图标距离 widget 顶部的 padding static const double paddingTop = 10; - double selectX; - double selectY; - double _startX = 0.0, - _endX = 0.0, - _startY = 0.0, - _endY = 0.0, - _fixedHeight, - _fixedWidth; - List _lineCanvasModels; + double? selectX; + double? selectY; + double _startX = 0.0, _endX = 0.0, _startY = 0.0, _endY = 0.0; + late double _fixedHeight, _fixedWidth; + late List _lineCanvasModels; - List> _linePointPositions = List(); + List> _linePointPositions = []; double get startX => _startX; @@ -85,23 +80,24 @@ class BrnLinePainter extends BrnBasePainter { BrnLinePainter( this.lines, { - this.lineSelectIndex = -1, - this.pointSelectIndex = -1, - this.showPointDashLine = true, - this.xDialColor, - this.yDialColor, - this.rulerWidth = 4, - this.xDialMin, - this.xDialMax, - this.xDialValues, - this.yDialMin, - this.yDialMax, - this.yDialValues, - this.isShowHintX = true, - this.isShowHintY = false, - this.hintLineSolid = true, - this.hintLineColor, + required this.lineSelectIndex, + required this.pointSelectIndex, + required this.showPointDashLine, + required this.xDialColor, + required this.yDialColor, + required this.rulerWidth, + required this.xDialMin, + required this.xDialMax, + required this.xDialValues, + required this.yDialMin, + required this.yDialMax, + required this.yDialValues, + required this.isShowHintX, + required this.isShowHintY, + required this.hintLineSolid, + required this.hintLineColor, this.isShowXText = false, + this.isShowYText = false, }) { if (xDialValues == null) { for (var i = 1; i < lines.length; i++) { @@ -164,13 +160,8 @@ class BrnLinePainter extends BrnBasePainter { .colorTextSecondary; hintLineColor ??= BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; - hintLineSolid ??= true; - xyLineWidth ??= 0.5; xDialMin ??= 0; xDialMax ??= 1; - - yDialMin ??= 0; - yDialMax ??= 1; } ///计算边界 @@ -187,22 +178,22 @@ class BrnLinePainter extends BrnBasePainter { ///计算Path void _initPath(Canvas canvas, Paint xyPaint) { _lineCanvasModels = []; - if (lines != null && lines.isNotEmpty) { + if (lines.isNotEmpty) { _linePointPositions.clear(); // 计算点和线的 数据,用于渲染。 for (var item in lines) { var paths = [], shadowPaths = []; var pointArr = []; - if (item.points != null && item.points.isNotEmpty) { - var _path = Path(); - var _shadowPath = Path(); + if (item.points.isNotEmpty) { + Path _path = Path(); + Path _shadowPath = Path(); - if (xDialValues != null && xDialValues.isNotEmpty) { + if (xDialValues != null && xDialValues!.isNotEmpty) { for (var i = 0; i < item.points.length; i++) { var xPosition = _startX + - ((item.points[i].x - xDialMin) / - (xDialMax - xDialMin) * + ((item.points[i].x - xDialMin!) / + (xDialMax! - xDialMin!) * _fixedWidth); var yPosition = _startY - ((item.points[i].y - yDialMin) / @@ -211,7 +202,7 @@ class BrnLinePainter extends BrnBasePainter { pointArr.add(Point(xPosition, yPosition)); } } else { - var xScaleCount = item.points?.length ?? 0; + var xScaleCount = item.points.length; var W = _fixedWidth / (xScaleCount > 1 ? (xScaleCount - 1) : 1); //两个点之间的x方向距离 for (var i = 0; i < item.points.length; i++) { @@ -230,20 +221,23 @@ class BrnLinePainter extends BrnBasePainter { /// 生成 Shadow path。 _shadowPath = _getSmoothLinePath(pointArr); _shadowPath - ..lineTo(pointArr[pointArr.length - 1].x, _fixedHeight) - ..lineTo(pointArr[0].x, _fixedHeight) + ..lineTo(pointArr[pointArr.length - 1].x as double, _fixedHeight) + ..lineTo(pointArr[0].x as double, _fixedHeight) ..close(); } else { - _path.moveTo(pointArr[0].x, pointArr[0].y); - _shadowPath.moveTo(pointArr[0].x, pointArr[0].y); + _path.moveTo(pointArr[0].x as double, pointArr[0].y as double); + _shadowPath.moveTo( + pointArr[0].x as double, pointArr[0].y as double); for (var i = 1; i < pointArr.length; i++) { - _path.lineTo(pointArr[i].x, pointArr[i].y); - _shadowPath.lineTo(pointArr[i].x, pointArr[i].y); + _path.lineTo(pointArr[i].x as double, pointArr[i].y as double); + _shadowPath.lineTo( + pointArr[i].x as double, pointArr[i].y as double); if (i == pointArr.length - 1) { _shadowPath - ..lineTo(pointArr[pointArr.length - 1].x, _fixedHeight) - ..lineTo(pointArr[0].x, _fixedHeight) + ..lineTo( + pointArr[pointArr.length - 1].x as double, _fixedHeight) + ..lineTo(pointArr[0].x as double, _fixedHeight) ..close(); } } @@ -259,21 +253,22 @@ class BrnLinePainter extends BrnBasePainter { shadowPaths: shadowPaths, shaderColors: item.shaderColors, points: item.isShowPoint ? pointArr : null, - pointColor: item.pointColor, - pointInnerColor: item.pointInnerColor, + pointColor: item.pointColor!, + pointInnerColor: item.pointInnerColor!, pointRadius: item.pointRadius, - pointInnerRadius: item.pointInnerRadius)); + pointInnerRadius: item.pointInnerRadius!)); } } } /// Draws smooth lines between each point. Path _getSmoothLinePath(List points) { - var targetPoints = List(); + var targetPoints = []; targetPoints.addAll(points); targetPoints.add(Point( points[points.length - 1].x * 2, points[points.length - 1].y * 2)); - var x0, y0, x1, y1, t0, path = Path(); + double? x0, y0, x1, y1, t0; + var path = Path(); for (int i = 0; i < targetPoints.length; i++) { var t1; var x = targetPoints[i].x; @@ -281,23 +276,23 @@ class BrnLinePainter extends BrnBasePainter { if (x == x1 && y == y1) break; switch (i) { case 0: - path.moveTo(x, y); + path.moveTo(x as double, y as double); break; case 1: break; case 2: - t1 = MonotoneX.slope3(x0, y0, x1, y1, x, y); + t1 = MonotoneX.slope3(x0!, y0!, x1!, y1!, x as double, y as double); MonotoneX.point( path, x0, y0, x1, y1, MonotoneX.slope2(x0, y0, x1, y1, t1), t1); break; default: - t1 = MonotoneX.slope3(x0, y0, x1, y1, x, y); - MonotoneX.point(path, x0, y0, x1, y1, t0, t1); + t1 = MonotoneX.slope3(x0!, y0!, x1!, y1!, x as double, y as double); + MonotoneX.point(path, x0, y0, x1, y1, t0!, t1); } x0 = x1; y0 = y1; - x1 = x; - y1 = y; + x1 = x as double; + y1 = y as double; t0 = t1; } return path; @@ -306,15 +301,17 @@ class BrnLinePainter extends BrnBasePainter { ///x,y轴 void _drawXy(Canvas canvas, Paint paint) { if (isShowHintY) { - canvas.drawLine(Offset(_startX, _startY), - Offset(_startX, _endY - basePadding), paint..color = yDialColor); //y轴 + canvas.drawLine( + Offset(_startX, _startY), + Offset(_startX, _endY - basePadding), + paint..color = yDialColor!); //y轴 } - if (lines != null && lines.isNotEmpty) { + if (lines.isNotEmpty) { //绘制x轴的文字部分 for (var item in lines) { - if (item.points != null && item.points.isNotEmpty && item.isShowXDial) { - _drawXRuler(canvas, paint..color = xDialColor, item.points); + if (item.points.isNotEmpty && item.isShowXDial) { + _drawXRuler(canvas, paint..color = xDialColor!, item.points); } } } @@ -322,16 +319,16 @@ class BrnLinePainter extends BrnBasePainter { ///x轴刻度 & 辅助线 void _drawXRuler(Canvas canvas, Paint paint, List points) { - if (xDialValues != null && xDialValues.isNotEmpty) { + if (xDialValues != null && xDialValues!.isNotEmpty) { // 获取刻度长度 - for (var i = 0; i < xDialValues.length; i++) { + for (var i = 0; i < xDialValues!.length; i++) { ///绘制x轴文本 var tpX = TextPainter( textAlign: TextAlign.center, ellipsis: '.', text: TextSpan( - text: xDialValues[i].dialText, - style: xDialValues[i].dialTextStyle), + text: xDialValues![i].dialText, + style: xDialValues![i].dialTextStyle), textDirection: TextDirection.ltr) ..layout(); // 开始绘制刻度 @@ -339,8 +336,8 @@ class BrnLinePainter extends BrnBasePainter { tpX, canvas, _startX + - (xDialValues[i].value - xDialMin) / - (xDialMax - xDialMin) * + (xDialValues![i].value - xDialMin!) / + (xDialMax! - xDialMin!) * _fixedWidth, paint); } @@ -357,14 +354,14 @@ class BrnLinePainter extends BrnBasePainter { ..moveTo(xPosition, _startY) ..lineTo(xPosition, _endY - basePadding); if (hintLineSolid) { - canvas.drawPath(tempPath, paint..color = hintLineColor); + canvas.drawPath(tempPath, paint..color = hintLineColor!); } else { canvas.drawPath( dashPath( tempPath, dashArray: CircularIntervalList([4.0, 2.0]), ), - paint..color = hintLineColor, + paint..color = hintLineColor!, ); } } @@ -372,7 +369,7 @@ class BrnLinePainter extends BrnBasePainter { // 绘制 x轴刻度 if (isShowHintX) { canvas.drawLine(Offset(xPosition, _startY), - Offset(xPosition, _startY + rulerWidth), paint..color = xDialColor); + Offset(xPosition, _startY + rulerWidth), paint..color = xDialColor!); } } @@ -380,13 +377,13 @@ class BrnLinePainter extends BrnBasePainter { void _drawLine(Canvas canvas) { _lineCanvasModels.forEach((element) { //阴影区域 - if (element.shadowPaths != null && element.shaderColors != null) { + if (element.shaderColors != null) { element.shadowPaths.forEach((shadowPathElement) { var shader = LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, tileMode: TileMode.clamp, - colors: element.shaderColors) + colors: element.shaderColors!) .createShader( Rect.fromLTWH(_startX, _endY, _fixedWidth, _fixedHeight)); canvas @@ -398,25 +395,23 @@ class BrnLinePainter extends BrnBasePainter { ..style = PaintingStyle.fill); }); } - if (element.paths != null) { - //路径 - element.paths.forEach((pathElement) { - var pathPaint = Paint() - ..isAntiAlias = true - ..strokeWidth = element.pathWidth - ..strokeCap = StrokeCap.round - ..color = element.pathColor - ..style = PaintingStyle.stroke; - canvas.drawPath(pathElement, pathPaint); - }); - } + //路径 + element.paths.forEach((pathElement) { + var pathPaint = Paint() + ..isAntiAlias = true + ..strokeWidth = element.pathWidth + ..strokeCap = StrokeCap.round + ..color = element.pathColor + ..style = PaintingStyle.stroke; + canvas.drawPath(pathElement, pathPaint); + }); if (element.points != null) { //点 // 画圆环的计算规则是: // 圆环宽度 strokeWidth = element.pointRadius - element.pointInnerRadius // 实际 drawCircle 半径 outerR = (element.pointRadius - element.pointInnerRadius)/2 + element.pointInnerRadius // 内部半径 innerR = element.pointInnerRadius - element.points.forEach((pointElement) { + element.points!.forEach((pointElement) { var pointPaint = Paint() ..isAntiAlias = true ..strokeCap = StrokeCap.round @@ -424,7 +419,7 @@ class BrnLinePainter extends BrnBasePainter { ..strokeWidth = element.pointRadius - element.pointInnerRadius ..style = PaintingStyle.stroke; //描边为居中描边 canvas.drawCircle( - Offset(pointElement.x, pointElement.y), + Offset(pointElement.x as double, pointElement.y as double), (element.pointRadius - element.pointInnerRadius) / 2 + element.pointInnerRadius, pointPaint); @@ -433,8 +428,8 @@ class BrnLinePainter extends BrnBasePainter { //内圆 int currentLineIndex = _lineCanvasModels.indexOf(element); - element.points.forEach((pointElement) { - int currentPointIndex = element.points.indexOf(pointElement); + element.points!.forEach((pointElement) { + int currentPointIndex = element.points!.indexOf(pointElement); Color color = Colors.white; var pointPaintBg = Paint() @@ -442,8 +437,10 @@ class BrnLinePainter extends BrnBasePainter { ..strokeCap = StrokeCap.round ..color = color ..style = PaintingStyle.fill; - canvas.drawCircle(Offset(pointElement.x, pointElement.y), - element.pointInnerRadius, pointPaintBg); + canvas.drawCircle( + Offset(pointElement.x as double, pointElement.y as double), + element.pointInnerRadius, + pointPaintBg); if (currentLineIndex == lineSelectIndex && currentPointIndex == pointSelectIndex) { @@ -454,8 +451,10 @@ class BrnLinePainter extends BrnBasePainter { ..strokeCap = StrokeCap.round ..color = color ..style = PaintingStyle.fill; - canvas.drawCircle(Offset(pointElement.x, pointElement.y), - element.pointInnerRadius, pointPaint); + canvas.drawCircle( + Offset(pointElement.x as double, pointElement.y as double), + element.pointInnerRadius, + pointPaint); }); } }); @@ -468,11 +467,11 @@ class BrnLinePainter extends BrnBasePainter { var x = _linePointPositions[lineSelectIndex][pointSelectIndex].x; var xPath = Path() - ..moveTo(x, _startY) + ..moveTo(x as double, _startY) ..lineTo(x, _endY - basePadding); var y = _linePointPositions[lineSelectIndex][pointSelectIndex].y; var yPath = Path() - ..moveTo(_startX, y) + ..moveTo(_startX, y as double) ..lineTo(_endX, y); if (showPointDashLine) { canvas.drawPath( @@ -504,18 +503,16 @@ class BrnLinePainter extends BrnBasePainter { } void _drawPointDisplayText(Canvas canvas) { - if (_linePointPositions != null && _linePointPositions.isNotEmpty) { + if (_linePointPositions.isNotEmpty) { for (int lineIndex = 0; lineIndex < _linePointPositions.length; lineIndex++) { BrnPointsLine item = lines[lineIndex]; - if (item.isShowPointText && - item.points != null && - item.points.isNotEmpty) { + if (item.isShowPointText && item.points.isNotEmpty) { var length = item.points.length; for (var i = 0; i < length; i++) { if (item.points[i].pointText == null || - item.points[i].pointText.length == 0) { + item.points[i].pointText!.length == 0) { continue; } var tpX = TextPainter( @@ -533,10 +530,10 @@ class BrnLinePainter extends BrnBasePainter { tpX.paint( canvas, Offset( - (item.points[i].offset?.dx ?? 0) + + (item.points[i].offset.dx) + _linePointPositions[lineIndex][i].x - tpX.width / 2, - (item.points[i].offset?.dy ?? 0) + + (item.points[i].offset.dy) + _linePointPositions[lineIndex][i].y + adjustOffset)); } @@ -560,19 +557,13 @@ class BrnLinePainter extends BrnBasePainter { List> getSameXValuePoints( Point currentPoint, List>> lines) { - List> sameXPoints = List(); - if (lines != null) { - for (int lineIndex = 0; lineIndex < lines.length; lineIndex++) { - List> linePoints = lines[lineIndex]; - if (linePoints != null) { - for (int pointIndex = 0; - pointIndex < linePoints.length; - pointIndex++) { - if (currentPoint.x == linePoints[pointIndex].x && - currentPoint != linePoints[pointIndex]) { - sameXPoints.add(linePoints[pointIndex]); - } - } + List> sameXPoints = []; + for (int lineIndex = 0; lineIndex < lines.length; lineIndex++) { + List> linePoints = lines[lineIndex]; + for (int pointIndex = 0; pointIndex < linePoints.length; pointIndex++) { + if (currentPoint.x == linePoints[pointIndex].x && + currentPoint != linePoints[pointIndex]) { + sameXPoints.add(linePoints[pointIndex]); } } } @@ -582,31 +573,31 @@ class BrnLinePainter extends BrnBasePainter { //绘制图表的计算之后的结果模型集 class LineCanvasModel { - List paths; - Color pathColor; - double pathWidth; - - List shadowPaths; - List shaderColors; - - List points; - Color pointColor; - double pointRadius; - double pointInnerRadius; - Color pointInnerColor; - bool showPointText; - - LineCanvasModel({ - this.paths, - this.pathColor, - this.pathWidth, - this.shadowPaths, - this.shaderColors, - this.points, - this.pointColor, - this.pointRadius, - this.pointInnerRadius, - this.pointInnerColor, + final List paths; + final Color pathColor; + final double pathWidth; + + final List shadowPaths; + final List? shaderColors; + + final List? points; + final Color pointColor; + final double pointRadius; + final double pointInnerRadius; + final Color pointInnerColor; + final bool showPointText; + + const LineCanvasModel({ + required this.paths, + required this.pathColor, + required this.pathWidth, + required this.shadowPaths, + required this.shaderColors, + required this.points, + required this.pointColor, + required this.pointRadius, + required this.pointInnerRadius, + required this.pointInnerColor, this.showPointText = false, }); } diff --git a/lib/src/components/charts/broken_line/brn_line_y_painter.dart b/lib/src/components/charts/broken_line/brn_line_y_painter.dart index 9a8e9d8f..712d2c87 100644 --- a/lib/src/components/charts/broken_line/brn_line_y_painter.dart +++ b/lib/src/components/charts/broken_line/brn_line_y_painter.dart @@ -12,29 +12,29 @@ const double _basePadding = 0; const double _contentTopPadding = 10; class BrnLineYPainter extends BrnBasePainter { - int lineSelectIndex = -1; - int pointSelectIndex = -1; + final int lineSelectIndex; + final int pointSelectIndex; /// xy轴线条的宽度 double xyLineWidth = 0.5; /// x轴的颜色 - Color xColor; + Color? xColor; /// y轴的颜色 - Color yColor; + Color? yColor; /// y轴刻度的偏移量 - double yHintLineOffset; + final double yHintLineOffset; /// 刻度的宽度或者高度 double rulerWidth; /// y轴最大值,用来计算内部绘制点的y轴位置 - double yMin, yMax; + final double yMin, yMax; /// y轴左侧刻度显示,不传则没有 - List yDialValues; + final List? yDialValues; /// x、y轴的辅助线 bool isShowXHintLine, isShowYHintLine; @@ -43,34 +43,35 @@ class BrnLineYPainter extends BrnBasePainter { bool isHintLineSolid; /// 辅助线颜色 - Color hintLineColor; + Color? hintLineColor; /// 绘制线条的参数内容 List lines; bool isShowXDialText, isShowYDialText; - double selectX; - double selectY; - double _startX = 0.0, _endX = 0.0, _startY = 0.0, _endY = 0.0, _fixedHeight; + double? selectX; + double? selectY; + double _startX = 0.0, _endX = 0.0, _startY = 0.0, _endY = 0.0; + late double _fixedHeight; BrnLineYPainter( this.lines, { - this.lineSelectIndex = -1, - this.pointSelectIndex = -1, - this.yHintLineOffset = 20, - this.xColor, - this.yColor, - this.rulerWidth = 4, - this.yMin, - this.yMax, - this.yDialValues, - this.isShowXHintLine = true, - this.isShowYHintLine = false, - this.isHintLineSolid = true, - this.hintLineColor, - this.isShowXDialText = false, - this.isShowYDialText = false, + required this.lineSelectIndex, + required this.pointSelectIndex, + required this.yHintLineOffset, + required this.xColor, + required this.yColor, + required this.rulerWidth, + required this.yMin, + required this.yMax, + required this.yDialValues, + required this.isShowXHintLine, + required this.isShowYHintLine, + required this.isHintLineSolid, + required this.hintLineColor, + required this.isShowXDialText, + required this.isShowYDialText, }); @override @@ -105,11 +106,6 @@ class BrnLineYPainter extends BrnBasePainter { .colorTextSecondary; hintLineColor ??= BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; - isHintLineSolid ??= true; - xyLineWidth ??= 0.5; - - yMin ??= 0; - yMax ??= 1; } /// 计算边界 @@ -119,7 +115,7 @@ class BrnLineYPainter extends BrnBasePainter { /// 如果展示y刻度文本,则左侧默认预留 20 像素高度展示x刻度 if (isShowYDialText) { - _startX = yHintLineOffset ?? 20.0; + _startX = yHintLineOffset; } /// 如果展示x刻度文本,则底部预留 20 像素高度展示x刻度 @@ -133,11 +129,11 @@ class BrnLineYPainter extends BrnBasePainter { void _drawXy(Canvas canvas, Paint paint) { if (isShowXHintLine) { canvas.drawLine(Offset(_startX, _startY), - Offset(_endX + _basePadding, _startY), paint..color = xColor); //x轴 + Offset(_endX + _basePadding, _startY), paint..color = xColor!); //x轴 } if (isShowYHintLine) { canvas.drawLine(Offset(_startX, _startY), - Offset(_startX, _endY - _basePadding), paint..color = yColor); //y轴 + Offset(_startX, _endY - _basePadding), paint..color = yColor!); //y轴 } _drawYRuler(canvas, paint); } @@ -147,8 +143,8 @@ class BrnLineYPainter extends BrnBasePainter { if (yDialValues == null) { return; } - for (var i = 0; i < yDialValues.length; i++) { - var ydialValue = yDialValues[i]; + for (var i = 0; i < yDialValues!.length; i++) { + var ydialValue = yDialValues![i]; // 绘制y轴文本 var yLength = (ydialValue.value - yMin) / (yMax - yMin) * _fixedHeight; @@ -177,7 +173,7 @@ class BrnLineYPainter extends BrnBasePainter { ..moveTo(_startX, _startY - yLength) ..lineTo(_startX + _endX - yHintLineOffset, _startY - yLength); if (isHintLineSolid) { - canvas.drawPath(hitXPath, paint..color = hintLineColor); + canvas.drawPath(hitXPath, paint..color = hintLineColor!); } else { canvas.drawPath( dashPath( @@ -185,7 +181,7 @@ class BrnLineYPainter extends BrnBasePainter { dashArray: CircularIntervalList([4.0, 4.0]), //虚线和间隔 ), - paint..color = hintLineColor, + paint..color = hintLineColor!, ); } } @@ -195,7 +191,7 @@ class BrnLineYPainter extends BrnBasePainter { canvas.drawLine( Offset(_startX, _startY - yLength), Offset(_startX + rulerWidth, _startY - yLength), - paint..color = yColor); + paint..color = yColor!); } } } diff --git a/lib/src/components/charts/broken_line/monotone_x.dart b/lib/src/components/charts/broken_line/monotone_x.dart index 930d7091..0494780a 100644 --- a/lib/src/components/charts/broken_line/monotone_x.dart +++ b/lib/src/components/charts/broken_line/monotone_x.dart @@ -23,7 +23,7 @@ class MonotoneX { double p = (s0 * h1 + s1 * h0) / (h0 + h1); var source = [s0.abs(), s1.abs(), 0.5 * p.abs()]; source.sort(); - return (sign(s0) + sign(s1)) * source.first ?? 0; + return (sign(s0) + sign(s1)) * source.first; } // According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations @@ -38,19 +38,16 @@ class MonotoneX { static Path addCurve(Path path, List points, {bool reversed = false, int endIndex = -1}) { - var targetPoints = List(); + var targetPoints = >[]; targetPoints.addAll(points); targetPoints.add(Point( points[points.length - 1].x * 2, points[points.length - 1].y * 2)); - double x0, y0, x1, y1, t0; - if (path == null) { - path = Path(); - } - List> arr = []; + double? x0, y0, x1, y1, t0; + List> arr = []; for (int i = 0; i < targetPoints.length; i++) { - double t1; - double x = targetPoints[i].x; - double y = targetPoints[i].y; + double? t1; + double x = targetPoints[i].x as double; + double y = targetPoints[i].y as double; if (x == x1 && y == y1) continue; switch (i) { case 0: @@ -58,11 +55,11 @@ class MonotoneX { case 1: break; case 2: - t1 = slope3(x0, y0, x1, y1, x, y); + t1 = slope3(x0!, y0!, x1!, y1!, x, y); arr.add([x0, y0, x1, y1, slope2(x0, y0, x1, y1, t1), t1]); break; default: - t1 = slope3(x0, y0, x1, y1, x, y); + t1 = slope3(x0!, y0!, x1!, y1!, x, y); arr.add([x0, y0, x1, y1, t0, t1]); } x0 = x1; @@ -75,13 +72,13 @@ class MonotoneX { if (reversed) { arr.reversed.forEach((f) { if (endIndex < 0 || index++ < endIndex) { - point(path, f[2], f[3], f[0], f[1], f[5], f[4]); + point(path, f[2]!, f[3]!, f[0]!, f[1]!, f[5]!, f[4]!); } }); } else { arr.forEach((f) { if (endIndex < 0 || index++ < endIndex) { - point(path, f[0], f[1], f[2], f[3], f[4], f[5]); + point(path, f[0]!, f[1]!, f[2]!, f[3]!, f[4]!, f[5]!); } }); } diff --git a/lib/src/components/charts/funnel_chart.dart b/lib/src/components/charts/funnel_chart.dart index da5955bd..a2ac4c7d 100644 --- a/lib/src/components/charts/funnel_chart.dart +++ b/lib/src/components/charts/funnel_chart.dart @@ -11,8 +11,8 @@ import 'package:flutter/rendering.dart'; /// \____文案____/ |____文案_____/ /// ___________ + ____________ /// \__文案___/ |____文案___/ -/// 第一种,是两边都向中间缩短的漏斗[FunnelShape.LeftAndRight]。 -/// 第二种,是只有一边向中间缩短的漏斗[FunnelShape.LeftOrRight]。 +/// 第一种,是两边都向中间缩短的漏斗[FunnelShape.leftAndRight]。 +/// 第二种,是只有一边向中间缩短的漏斗[FunnelShape.leftOrRight]。 /// 通过[inputTextStyle]来控制样式。 /// 在漏斗的两层layer之间或者左右可以插入标签markers,它们可以是一些常见的Widget,如[Text],在参数[children]中提供。 /// 通过[alignment]可以控制标签的插入位置。 @@ -60,23 +60,22 @@ class BrnFunnelChart extends MultiChildRenderObjectWidget { ]; BrnFunnelChart({ - Key key, - @required this.layerCount, - @required this.markerCount, - @required this.layerPainter, - @required MarkerBuilder builder, - this.shape = FunnelShape.LeftAndRight, + Key? key, + required this.layerCount, + required this.markerCount, + required this.layerPainter, + required MarkerBuilder builder, + this.shape = FunnelShape.leftAndRight, this.maxLayerWidth = 200, this.minLayerWidth = 0, this.layerHeight = 40, this.layerMargin = 0, this.childOffset = Offset.zero, this.alignment = MarkerAlignment.right, - }) : assert(layerCount != null), - assert(maxLayerWidth >= minLayerWidth), + }) : assert(maxLayerWidth >= minLayerWidth), assert(layerCount - markerCount == 0 || layerCount - markerCount == 1), assert(() { - if (shape == FunnelShape.LeftOrRight && + if (shape == FunnelShape.leftOrRight && alignment == MarkerAlignment.center) { debugPrint( '当shape为FunnelShape.LeftOrRight时,alignment为MarkerAlignment.center无效'); @@ -86,7 +85,7 @@ class BrnFunnelChart extends MultiChildRenderObjectWidget { super( key: key, children: () { - List children = List(); + List children = []; for (int i = 0; i < markerCount; i++) { children.add(builder(i)); } @@ -95,27 +94,25 @@ class BrnFunnelChart extends MultiChildRenderObjectWidget { ///漏斗图默认Bruno风格的命名构造函数,[layerCount]不能大于[defaultLayerColors.length]。 BrnFunnelChart.defaultStyle({ - Key key, - @required this.layerCount, - @required this.markerCount, - @required MarkerBuilder builder, + Key? key, + required this.layerCount, + required this.markerCount, + required MarkerBuilder builder, this.maxLayerWidth = 200, this.minLayerWidth = 0, this.layerHeight = 40, this.layerMargin = 0, this.childOffset = Offset.zero, }) : this.layerPainter = BrnDefaultFunnelLayerPainter(), - this.shape = FunnelShape.LeftAndRight, + this.shape = FunnelShape.leftAndRight, this.alignment = MarkerAlignment.right, - assert(layerCount != null && - layerCount <= defaultLayerColors.length && - layerCount >= 0), + assert(layerCount <= defaultLayerColors.length && layerCount >= 0), assert(maxLayerWidth >= minLayerWidth), assert(layerCount - markerCount == 0 || layerCount - markerCount == 1), super( key: key, children: () { - List children = List(); + List children = []; for (int i = 0; i < markerCount; i++) { children.add(builder(i)); } @@ -159,14 +156,14 @@ abstract class RenderFunnelChart extends RenderBox ContainerRenderObjectMixin, RenderBoxContainerDefaultsMixin { RenderFunnelChart({ - double layerMargin, - double layerHeight, - int layerCount, - double maxLayerWidth, - double minLayerWidth, - Offset childOffset, - MarkerAlignment alignment, - BrnFunnelLayerPainter layerPainter, + required double layerMargin, + required double layerHeight, + required int layerCount, + required double maxLayerWidth, + required double minLayerWidth, + required Offset childOffset, + required MarkerAlignment alignment, + required BrnFunnelLayerPainter layerPainter, }) : _layerMargin = layerMargin, _layerHeight = layerHeight, _layerCount = layerCount, @@ -275,20 +272,20 @@ abstract class RenderFunnelChart extends RenderBox } @override - bool hitTestChildren(BoxHitTestResult result, {Offset position}) { + bool hitTestChildren(BoxHitTestResult result, {required Offset position}) { return defaultHitTestChildren(result, position: position); } @override double computeMinIntrinsicWidth(double height) { return getIntrinsicDimensionHorizontal( - height, (RenderBox child) => child.getMinIntrinsicWidth(height)); + height, (RenderBox child) => child.getMinIntrinsicWidth(height))!; } @override double computeMaxIntrinsicWidth(double height) { return getIntrinsicDimensionHorizontal( - height, (RenderBox child) => child.getMinIntrinsicWidth(height)); + height, (RenderBox child) => child.getMinIntrinsicWidth(height))!; } @override @@ -304,11 +301,11 @@ abstract class RenderFunnelChart extends RenderBox } @override - double computeDistanceToActualBaseline(TextBaseline baseline) { + double? computeDistanceToActualBaseline(TextBaseline baseline) { return defaultComputeDistanceToHighestActualBaseline(baseline); } - double getIntrinsicDimensionHorizontal( + double? getIntrinsicDimensionHorizontal( double height, double mainChildSizeGetter(RenderBox child)); double getIntrinsicDimensionVertical( @@ -322,17 +319,17 @@ class BrnFunnelRender extends RenderFunnelChart { static const double HALF_PIXEL = 0.5; BrnFunnelRender({ - double layerHeight, - double layerMargin, - int layerCount, - double maxLayerWidth, - double minLayerWidth, - Offset childOffset, - bool gradient, - List layerColors, - MarkerAlignment alignment, - BrnFunnelLayerPainter layerPainter, - FunnelShape shape, + required double layerHeight, + required double layerMargin, + required int layerCount, + required double maxLayerWidth, + required double minLayerWidth, + required Offset childOffset, + bool? gradient, + List? layerColors, + required MarkerAlignment alignment, + required BrnFunnelLayerPainter layerPainter, + required FunnelShape shape, }) : _shape = shape, _paint = Paint()..isAntiAlias = true, super( @@ -350,19 +347,20 @@ class BrnFunnelRender extends RenderFunnelChart { Paint _paint; bool _hasVisualOverflow = false; - Offset _overflowOffset; - Offset _centerOffset; + late Offset _overflowOffset; + late Offset _centerOffset; @override - double getIntrinsicDimensionHorizontal( + double? getIntrinsicDimensionHorizontal( double height, double mainChildSizeGetter(RenderBox child)) { - double extent = maxLayerWidth; + double? extent = maxLayerWidth; double intrinsicHeight = getIntrinsicDimensionVertical(null, null); - RenderBox child = firstChild; + RenderBox? child = firstChild; if (_alignment == MarkerAlignment.center) { while (child != null) { - final BrnFunnelChartParentData childParentData = child.parentData; - extent = max(extent, mainChildSizeGetter(child)); + final BrnFunnelChartParentData childParentData = + child.parentData as BrnFunnelChartParentData; + extent = max(extent!, mainChildSizeGetter(child)); child = childParentData.nextSibling; } } else { @@ -378,10 +376,11 @@ class BrnFunnelRender extends RenderFunnelChart { childOffset.dx; if (child == firstChild) { - extent = max(extent, left + mainChildSizeGetter(child)); + extent = max(extent!, left + mainChildSizeGetter(child)); } num++; - BrnFunnelChartParentData childParentData = child.parentData; + BrnFunnelChartParentData childParentData = + child.parentData as BrnFunnelChartParentData; child = childParentData.nextSibling; } } @@ -390,7 +389,7 @@ class BrnFunnelRender extends RenderFunnelChart { @override double getIntrinsicDimensionVertical( - double width, double mainChildSizeGetter(RenderBox child)) { + double? width, double mainChildSizeGetter(RenderBox child)?) { return layerCount * layerHeight + (layerCount - 1) * layerMargin; } @@ -403,8 +402,8 @@ class BrnFunnelRender extends RenderFunnelChart { ? layerMargin * childCount : layerMargin * (layerCount - 1)); - RenderBox child = firstChild; - double top, bottom, left, right; + RenderBox? child = firstChild; + late double top, bottom, left, right; int num = 0; while (child != null) { if (alignment == MarkerAlignment.center) { @@ -437,8 +436,9 @@ class BrnFunnelRender extends RenderFunnelChart { childOffset.dx; } - final BrnFunnelChartParentData childParentData = child.parentData; - BoxConstraints childConstraints; + final BrnFunnelChartParentData childParentData = + child.parentData as BrnFunnelChartParentData; + late BoxConstraints childConstraints; if (alignment == MarkerAlignment.center) { childConstraints = BoxConstraints( minWidth: 0, @@ -482,7 +482,7 @@ class BrnFunnelRender extends RenderFunnelChart { _hasVisualOverflow = true; } size = constraints.constrain(intrinsicSize); - _centerOffset = centerOffset(size - intrinsicSize); + _centerOffset = centerOffset(size - intrinsicSize as ui.Offset); if (_centerOffset.dx >= 0 && _centerOffset.dy >= 0) { //当实际尺寸比必须尺寸大时,需要居中偏移一下 if (alignment == MarkerAlignment.left) { @@ -503,7 +503,8 @@ class BrnFunnelRender extends RenderFunnelChart { num = 0; child = firstChild; while (child != null) { - final BrnFunnelChartParentData childParentData = child.parentData; + final BrnFunnelChartParentData childParentData = + child.parentData as BrnFunnelChartParentData; if (alignment == MarkerAlignment.center) { childParentData.offset = Offset(0, ((num * layerMargin) + (num + 1) * layerHeight)) + @@ -536,7 +537,7 @@ class BrnFunnelRender extends RenderFunnelChart { void paintFunnel(PaintingContext context, Offset offset) { Canvas canvas = context.canvas; canvas.save(); - Rect rect = (offset + _centerOffset ?? Offset.zero) & size; + Rect rect = (offset + _centerOffset) & size; canvas.clipRect(rect); _paint.blendMode = BlendMode.srcOver; canvas.saveLayer(rect, _paint); @@ -544,7 +545,7 @@ class BrnFunnelRender extends RenderFunnelChart { //绘制漏斗layer for (int i = 0; i < layerCount; i++) { - Offset topLeft, bottomRight; + late Offset topLeft, bottomRight; if (alignment == MarkerAlignment.center) { topLeft = Offset((size.width - maxLayerWidth) / 2, i * layerHeight + i * layerMargin); @@ -564,23 +565,19 @@ class BrnFunnelRender extends RenderFunnelChart { //绘制layer背景色 if (!layerPainter.isGradient(i)) { //单色背景 - if (layerPainter.getLayerColors(i) != null) { - _paint.color = layerPainter.getLayerColors(i)[0]; - canvas.drawRect(Rect.fromPoints(topLeft, bottomRight), _paint); - } + _paint.color = layerPainter.getLayerColors(i)[0]; + canvas.drawRect(Rect.fromPoints(topLeft, bottomRight), _paint); } else { //渐变背景 - if (layerPainter.getLayerColors(i) != null) { - ui.Gradient gradient = ui.Gradient.linear( - topLeft, bottomRight, layerPainter.getLayerColors(i)); - _paint.shader = gradient; - canvas.drawRect(Rect.fromPoints(topLeft, bottomRight), _paint); - } + ui.Gradient gradient = ui.Gradient.linear( + topLeft, bottomRight, layerPainter.getLayerColors(i)); + _paint.shader = gradient; + canvas.drawRect(Rect.fromPoints(topLeft, bottomRight), _paint); } //绘制layer文案 - double safeLeft, safeTop, safeRight, safeBottom; - if (_shape == FunnelShape.LeftAndRight) { + late double safeLeft, safeTop, safeRight, safeBottom; + if (_shape == FunnelShape.leftAndRight) { safeTop = i * layerHeight + i * layerMargin; if (alignment == MarkerAlignment.right) { safeLeft = ((i + 1) * layerHeight + i * layerMargin) * @@ -640,7 +637,7 @@ class BrnFunnelRender extends RenderFunnelChart { ..blendMode = BlendMode.dstOut ..style = PaintingStyle.fill ..shader = null; - double topLeftX; + late double topLeftX; if (alignment == MarkerAlignment.center) { topLeftX = (size.width - maxLayerWidth) / 2; } else if (alignment == MarkerAlignment.right) { @@ -650,7 +647,7 @@ class BrnFunnelRender extends RenderFunnelChart { } Path path; - if (_shape == FunnelShape.LeftAndRight || + if (_shape == FunnelShape.leftAndRight || alignment == MarkerAlignment.left) { path = Path(); //这里为什么都加了HALF_PIXEL,是因为裁剪的时候边缘会留下一定像素的误差。 @@ -665,7 +662,7 @@ class BrnFunnelRender extends RenderFunnelChart { canvas.drawPath(path, _paint); } - if (_shape == FunnelShape.LeftAndRight || + if (_shape == FunnelShape.leftAndRight || alignment == MarkerAlignment.right) { path = Path(); path.moveTo(maxLayerWidth + topLeftX + HALF_PIXEL, -HALF_PIXEL); @@ -742,7 +739,7 @@ class BrnDefaultFunnelLayerPainter extends BrnFunnelLayerPainter { }) : _textPainter = TextPainter()..textDirection = TextDirection.ltr; @override - void paintLayer(Canvas canvas, double left, double top, double right, + void paintLayer(Canvas canvas, double left, double? top, double right, double bottom, int layerIndex) { if (layerIndex >= titles.length) { return; @@ -755,7 +752,7 @@ class BrnDefaultFunnelLayerPainter extends BrnFunnelLayerPainter { _textPainter.paint( canvas, Offset((left + right - _textPainter.width) / 2, - (top + bottom - _textPainter.height) / 2), + (top! + bottom - _textPainter.height) / 2), ); } @@ -777,10 +774,10 @@ class BrnDefaultFunnelLayerPainter extends BrnFunnelLayerPainter { ///漏斗图表的形状 enum FunnelShape { ///两边从上往下都缩小 - LeftAndRight, + leftAndRight, ///一边从上往下缩小 - LeftOrRight, + leftOrRight, } ///漏斗标签的摆放位置 diff --git a/lib/src/components/charts/radar_chart.dart b/lib/src/components/charts/radar_chart.dart index 1c6550bb..4e7e2804 100644 --- a/lib/src/components/charts/radar_chart.dart +++ b/lib/src/components/charts/radar_chart.dart @@ -44,7 +44,7 @@ class BrnRadarChart extends MultiChildRenderObjectWidget { final double rotateAngle; ///每个标注文案的偏移量,必须和 [sidesCount] 保持一致。 - final List offset; + final List? offset; ///The default preset chart styles ordered in priority of usage. static const List defaultRadarChartStyles = [ @@ -87,9 +87,9 @@ class BrnRadarChart extends MultiChildRenderObjectWidget { ]; BrnRadarChart({ - Key key, - @required this.provider, - @required MarkerBuilder builder, + Key? key, + required this.provider, + required MarkerBuilder builder, this.radius = 50, this.levelCount = 3, this.maxValue = 10, @@ -101,14 +101,12 @@ class BrnRadarChart extends MultiChildRenderObjectWidget { this.crossedAxisLine = false, this.animateProgress = 1.0, this.rotateAngle = 0, - }) : assert(sidesCount != null), - assert(minValue < maxValue), + }) : assert(minValue < maxValue), assert(sidesCount >= 3), - assert(provider != null && builder != null), super( key: key, children: () { - List children = List(); + List children = []; for (int i = 0; i < sidesCount; i++) { children.add(builder(i)); } @@ -119,7 +117,7 @@ class BrnRadarChart extends MultiChildRenderObjectWidget { ///The [data] length should be less than the [defaultRadarChartStyles]'s length ///or you should use the default constructor. BrnRadarChart.defaultStyle({ - Key key, + Key? key, this.radius = 50, this.levelCount = 3, this.maxValue = 10, @@ -129,11 +127,9 @@ class BrnRadarChart extends MultiChildRenderObjectWidget { this.rotateAngle = 0, this.crossedAxisLine = false, this.offset, - @required List tagNames, - @required List> data, - }) : assert(sidesCount != null && sidesCount >= 3), - assert(tagNames != null), - assert(data != null), + required List tagNames, + required List> data, + }) : assert(sidesCount >= 3), assert(tagNames.length == sidesCount), assert(minValue < maxValue), assert(data.length <= defaultRadarChartStyles.length), @@ -143,7 +139,7 @@ class BrnRadarChart extends MultiChildRenderObjectWidget { super( key: key, children: () { - List children = List(); + List children = []; for (int i = 0; i < sidesCount; i++) { children.add(Container( constraints: BoxConstraints( @@ -224,17 +220,17 @@ class RenderRadarChart extends RenderBox BrnRadarChartDataProvider _dataProvider; RenderRadarChart({ - double radius, - double markerMargin, - int sideCount, - double maxValue, - double rotateAngle, - List offset, - BrnRadarChartDataProvider provider, - int levelCount, - Color axisLineColor, - bool crossedAxisLine, - double animateProgress, + required double radius, + required double markerMargin, + required int sideCount, + required double maxValue, + required double rotateAngle, + required List offset, + required BrnRadarChartDataProvider provider, + required int levelCount, + required Color axisLineColor, + required bool crossedAxisLine, + required double animateProgress, }) : _radius = radius, _markerMargin = markerMargin, _maxValue = maxValue, @@ -351,11 +347,12 @@ class RenderRadarChart extends RenderBox double mainChildSizeGetter(RenderBox child)) { double x; double maxX = 0, minX = 0; - RenderBox child = firstChild; + RenderBox? child = firstChild; //多边形的中心为原点 int i = 0; while (child != null) { - final BrnRadarChartParentData childParentData = child.parentData; + final BrnRadarChartParentData childParentData = + child.parentData as BrnRadarChartParentData; double angle = (2 * pi * i / _sideCount + _rotateAngle) % (2 * pi); x = _radius * sin(angle); if (x >= 0) { @@ -385,11 +382,12 @@ class RenderRadarChart extends RenderBox double mainChildSizeGetter(RenderBox child)) { double y; double maxY = 0, minY = 0; - RenderBox child = firstChild; + RenderBox? child = firstChild; //多边形的中心为原点 int i = 0; while (child != null) { - final BrnRadarChartParentData childParentData = child.parentData; + final BrnRadarChartParentData childParentData = + child.parentData as BrnRadarChartParentData; double angle = (2 * pi * i / _sideCount + _rotateAngle) % (2 * pi); y = _radius * cos(angle); @@ -443,7 +441,7 @@ class RenderRadarChart extends RenderBox } @override - double computeDistanceToActualBaseline(TextBaseline baseline) { + double? computeDistanceToActualBaseline(TextBaseline baseline) { return defaultComputeDistanceToHighestActualBaseline(baseline); } @@ -453,11 +451,12 @@ class RenderRadarChart extends RenderBox double x, y; double maxX = 0, minX = 0; double maxY = 0, minY = 0; - RenderBox child = firstChild; + RenderBox? child = firstChild; //多边形的中心为原点 int i = 0; while (child != null) { - final BrnRadarChartParentData childParentData = child.parentData; + final BrnRadarChartParentData childParentData = + child.parentData as BrnRadarChartParentData; BoxConstraints childConstraints = constraints.loosen(); child.layout(childConstraints, parentUsesSize: true); final Size childSize = child.size; @@ -526,7 +525,8 @@ class RenderRadarChart extends RenderBox double angle = (2 * pi * i / _sideCount + _rotateAngle) % (2 * pi); double x = _radius * sin(angle); //在以多边形中心为原点的坐标 double y = _radius * cos(angle); //在以多边形中心为原点的坐标 - final BrnRadarChartParentData childParentData = child.parentData; + final BrnRadarChartParentData childParentData = + child.parentData as BrnRadarChartParentData; //转换到左上角为原点中的坐标 if (y >= 0) { @@ -575,7 +575,7 @@ class RenderRadarChart extends RenderBox } @override - bool hitTestChildren(BoxHitTestResult result, {Offset position}) { + bool hitTestChildren(BoxHitTestResult result, {required Offset position}) { return defaultHitTestChildren(result, position: position); } @@ -592,8 +592,8 @@ class RenderRadarChart extends RenderBox double translateX = rect.width / 2; double translateY = rect.height / 2; //translate the canvas's top left to widget'center since flutter canvas rotate pivot can only be the top left. - canvas.translate(translateX + _centerOffset?.dx ?? 0, - translateY + _centerOffset?.dy ?? 0); + canvas.translate( + translateX + _centerOffset.dx, translateY + _centerOffset.dy); canvas.rotate(_rotateAngle); _drawBackground(canvas, rect.size, translateX, translateY); _drawRadar(canvas); @@ -662,18 +662,13 @@ class RenderRadarChart extends RenderBox void _drawRadar(Canvas canvas) { int radarCount = _dataProvider.getRadarCount(); - assert(radarCount != null); for (int radarIndex = 0; radarIndex < radarCount; radarIndex++) { BrnRadarChartStyle radarStyle = _dataProvider.getRadarStyle(radarIndex); - assert(radarStyle != null); _radarPainter ..isAntiAlias = true - ..color = radarStyle?.strokeColor - ..strokeWidth = radarStyle?.strokeWidth; + ..color = radarStyle.strokeColor + ..strokeWidth = radarStyle.strokeWidth; List values = _dataProvider.getRadarValues(radarIndex); - if (values == null) { - continue; - } Path path = Path(); double percent = values[0] / _maxValue; double angle = 0; @@ -683,7 +678,7 @@ class RenderRadarChart extends RenderBox percent = 0; } double x, y; - List dotPosition = List(); + List dotPosition = []; x = _radius * percent * sin(angle) * _animateProgress; y = -_radius * percent * cos(angle) * _animateProgress; dotPosition.add(Offset(x, y)); @@ -708,10 +703,10 @@ class RenderRadarChart extends RenderBox for (int i = 0; i < dotPosition.length; i++) { _radarPainter.color = Colors.white; canvas.drawCircle( - dotPosition[i], radarStyle.dotRadius + 2 ?? 2, _radarPainter); + dotPosition[i], radarStyle.dotRadius + 2, _radarPainter); _radarPainter.color = radarStyle.dotColor ?? radarStyle.strokeColor; canvas.drawCircle( - dotPosition[i], radarStyle.dotRadius ?? 2, _radarPainter); + dotPosition[i], radarStyle.dotRadius, _radarPainter); } } } @@ -774,14 +769,14 @@ class BrnRadarChartStyle { final bool dotted; ///The color of the dotted vertexes. - final Color dotColor; + final Color? dotColor; ///The radius of the dotted circle. final double dotRadius; const BrnRadarChartStyle({ - @required this.strokeColor, - @required this.areaColor, + required this.strokeColor, + required this.areaColor, this.strokeWidth = 3, this.dotted = false, this.dotColor, @@ -796,9 +791,7 @@ class DefaultRadarProvider extends BrnRadarChartDataProvider { DefaultRadarProvider(this.dataList); @override - int getRadarCount() { - return dataList?.length ?? 0; - } + int getRadarCount() => dataList.length; @override BrnRadarChartStyle getRadarStyle(int radarIndex) { diff --git a/lib/src/components/dialog/brn_content_export_dialog.dart b/lib/src/components/dialog/brn_content_export_dialog.dart index 91d48d54..61d8b9eb 100644 --- a/lib/src/components/dialog/brn_content_export_dialog.dart +++ b/lib/src/components/dialog/brn_content_export_dialog.dart @@ -9,39 +9,39 @@ import 'package:flutter/material.dart'; // ignore: must_be_immutable class BrnContentExportWidget extends StatelessWidget { /// 标题 - final String title; + final String? title; /// 是否可关闭 final bool isClose; /// 中间内容widget - final Widget contentWidget; + final Widget? contentWidget; /// 提交按钮文字 - final String submitText; + final String? submitText; /// 内容最大高度 - final Color submitBgColor; + final Color? submitBgColor; /// 提交操作 - final VoidCallback onSubmit; + final VoidCallback? onSubmit; /// 是否展示底部操作区域 final bool isShowOperateWidget; - BrnDialogConfig themeData; + BrnDialogConfig? themeData; BrnContentExportWidget(this.contentWidget, {this.title, - this.isClose, + required this.isClose, this.submitText, this.onSubmit, this.submitBgColor, - this.isShowOperateWidget, + required this.isShowOperateWidget, this.themeData}) { this.themeData ??= BrnDialogConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) + .getConfig(configId: themeData!.configId) .dialogConfig .merge(themeData); } @@ -67,7 +67,7 @@ class BrnContentExportWidget extends StatelessWidget { color: Colors.white, borderRadius: BorderRadius.all(Radius.circular( BrnDialogUtils.getDialogRadius( - themeData))), //设置四周圆角 角度 + themeData!))), //设置四周圆角 角度 ), child: Stack( children: [ @@ -76,7 +76,7 @@ class BrnContentExportWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _generateTitleWidget(), - contentWidget, + contentWidget ?? Container(), _generateBottomWidget(context), ], ), @@ -100,7 +100,7 @@ class BrnContentExportWidget extends StatelessWidget { behavior: HitTestBehavior.opaque, child: Padding( padding: EdgeInsets.all(15), - child: BrunoTools.getAssetImage(BrnAsset.ICON_PICKER_CLOSE), + child: BrunoTools.getAssetImage(BrnAsset.iconPickerClose), ))); } return Container(); @@ -109,13 +109,13 @@ class BrnContentExportWidget extends StatelessWidget { /// 构建Dialog标题 Widget _generateTitleWidget() { return Padding( - padding: null != title && title.isNotEmpty + padding: null != title && title!.isNotEmpty ? EdgeInsets.fromLTRB(20, 28, 20, 12) : EdgeInsets.only(top: 20), - child: null != title && title.isNotEmpty + child: null != title && title!.isNotEmpty ? Text( - title, - style: BrnDialogUtils.getDialogTitleStyle(themeData), + title!, + style: BrnDialogUtils.getDialogTitleStyle(themeData!), ) : Container(), ); @@ -133,20 +133,20 @@ class BrnContentExportWidget extends StatelessWidget { decoration: BoxDecoration( //背景 color: - submitBgColor ?? themeData.commonConfig.brandPrimary, + submitBgColor ?? themeData!.commonConfig.brandPrimary, borderRadius: BorderRadius.all(Radius.circular(6.0)), //设置四周圆角 角度 ), alignment: Alignment.center, height: 48, - child: Text(submitText, + child: Text(submitText ?? "", textAlign: TextAlign.center, style: TextStyle( fontWeight: FontWeight.w600, color: Colors.white, fontSize: 18))), onTap: () { - if (onSubmit != null) onSubmit(); + if (onSubmit != null) onSubmit!(); }, ) : Container()); diff --git a/lib/src/components/dialog/brn_dialog.dart b/lib/src/components/dialog/brn_dialog.dart index cdfefe63..44e06d0e 100644 --- a/lib/src/components/dialog/brn_dialog.dart +++ b/lib/src/components/dialog/brn_dialog.dart @@ -3,7 +3,6 @@ import 'package:bruno/src/theme/base/brn_text_style.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_dialog_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; /// 底部按钮的点击监听回调 @@ -79,78 +78,78 @@ const Divider cDividerLine = const Divider( color: Color(0xF0F0F0F0), ); -enum ButtonType { +enum _ButtonType { /// 单按钮 - Single, + single, /// 多按钮 - Multi, + multi, /// 左按钮 - Left, + left, /// 右按钮 - Right, + right, } /// 对话框的样式 class BrnDialogStyle { /// title的间距 - EdgeInsetsGeometry titlePadding; + EdgeInsets? titlePadding; /// 主色调按钮样式 - TextStyle mainTextStyle; + TextStyle? mainTextStyle; /// 主色调按钮的背景 - Color mainBackgroundColor; + Color? mainBackgroundColor; /// 其他按钮的样式 - TextStyle greyActionsTextStyle; + TextStyle? greyActionsTextStyle; /// 其他按钮的背景 - Color greyActionsBackgroundColor; + Color? greyActionsBackgroundColor; /// 标题的文字样式 - TextStyle titleTextStyle; + TextStyle? titleTextStyle; /// 标题的文字对齐 - TextAlign titleTextAlign; + TextAlign? titleTextAlign; /// 内容文字的对齐 - TextAlign contentTextAlign; + TextAlign? contentTextAlign; /// 内容widget的间距 - EdgeInsetsGeometry contentPadding; + EdgeInsets? contentPadding; /// 内容文字的样式 - TextStyle contentTextStyle; + TextStyle? contentTextStyle; /// 对话框的背景 - Color backgroundColor; + Color? backgroundColor; /// 对话框的底部按钮的高度 - double bottomHeight; + double? bottomHeight; /// 对话框圆角的大小 - double radius; + double? radius; /// 边框阴影 - double elevation; + double? elevation; /// 警示文案的样式 - TextStyle warningTextStyle; + TextStyle? warningTextStyle; /// 警示文案文字的对齐 - TextAlign warningTextAlign; + TextAlign? warningTextAlign; /// 警示文案的间距 - EdgeInsetsGeometry warningPadding; + EdgeInsets? warningPadding; /// icon的间距 - EdgeInsetsGeometry iconPadding; + EdgeInsets? iconPadding; /// 标题最大行数 - int titleMaxLines; + int? titleMaxLines; BrnDialogStyle({ this.titlePadding, @@ -207,30 +206,30 @@ class BrnDialogStyle { class BrnDialog extends AlertDialog { /// 标题控件 - final Widget titleWidget; + final Widget? titleWidget; /// 内容控件 - final Widget contentWidget; + final Widget? contentWidget; /// 警示文案部分的控件 - final Widget warningWidget; + final Widget? warningWidget; /// 按钮部分控件 - final List actionsWidget; + final List? actionsWidget; ///-----如果以上属性设置了,那么对话框中的相对应的部分 以他们为基准 /// 标题文本 - final String titleText; + final String? titleText; /// 内容文本 - final String messageText; + final String? messageText; /// 警示文本 - final String warningText; + final String? warningText; /// 底部按钮文案 - final List actionsText; + final List? actionsText; /// 根据以上属性 生成对应的text控件 @@ -240,20 +239,17 @@ class BrnDialog extends AlertDialog { /// 水平分割线 final Divider divider; - /// 对话框样式 - final BrnDialogStyle brnDialogStyle; - /// 底部按钮的点击监听回调 - final DialogIndexedActionClickCallback indexedActionCallback; + final DialogIndexedActionClickCallback? indexedActionCallback; /// 是否展示头部icon final bool showIcon; /// 头部的icon - final Image iconImage; + final Image? iconImage; /// dialog配置 - final BrnDialogConfig themeData; + final BrnDialogConfig? themeData; /// 标题最大行数 final int titleMaxLines; @@ -268,7 +264,6 @@ class BrnDialog extends AlertDialog { this.warningText, this.warningWidget, this.actionsWidget, - this.brnDialogStyle, this.divider = cDividerLine, this.verticalDivider = cVerticalDivider, this.actionsText, @@ -279,8 +274,7 @@ class BrnDialog extends AlertDialog { @override Widget build(BuildContext context) { - BrnDialogConfig defaultConfig = _convertStyleToConfig(); - defaultConfig = themeData ?? BrnDialogConfig(); + BrnDialogConfig? defaultConfig = BrnDialogConfig(); defaultConfig = BrnThemeConfigurator.instance .getConfig(configId: defaultConfig.configId) @@ -312,7 +306,7 @@ class BrnDialog extends AlertDialog { } children.add(Padding( - padding: defaultConfig?.dividerPadding, + padding: defaultConfig.dividerPadding, child: SizedBox( height: 0, width: 0, @@ -332,13 +326,13 @@ class BrnDialog extends AlertDialog { return UnconstrainedBox( child: SizedBox( - width: defaultConfig?.dialogWidth, + width: defaultConfig.dialogWidth, child: Material( shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular( BrnDialogUtils.getDialogRadius(defaultConfig)))), child: dialogChild, - color: defaultConfig?.backgroundColor, + color: defaultConfig.backgroundColor, ))); } @@ -347,7 +341,7 @@ class BrnDialog extends AlertDialog { Widget _createWidget(Widget widget) { return Center( child: Padding( - padding: dialogConfig?.iconPadding, + padding: dialogConfig.iconPadding, child: SizedBox( width: 36, height: 36, @@ -358,7 +352,7 @@ class BrnDialog extends AlertDialog { } if (iconImage != null) { - return _createWidget(iconImage); + return _createWidget(iconImage!); } if (showIcon) { return _createWidget( @@ -376,20 +370,20 @@ class BrnDialog extends AlertDialog { BuildContext context, BrnDialogConfig dialogConfig) { if (titleWidget != null) { return DefaultTextStyle( - textAlign: dialogConfig?.titleTextAlign, + textAlign: dialogConfig.titleTextAlign, style: BrnDialogUtils.getDialogTitleStyle(dialogConfig), - child: titleWidget, + child: titleWidget!, ); } return Padding( padding: _configTitlePadding(dialogConfig), child: Text( - titleText, + titleText!, maxLines: titleMaxLines, overflow: TextOverflow.ellipsis, style: BrnDialogUtils.getDialogTitleStyle(dialogConfig), - textAlign: dialogConfig?.titleTextAlign, + textAlign: dialogConfig.titleTextAlign, ), ); } @@ -400,8 +394,8 @@ class BrnDialog extends AlertDialog { if (contentWidget != null) return Flexible( child: DefaultTextStyle( - style: (dialogConfig?.contentTextStyle)?.generateTextStyle(), - child: contentWidget, + style: dialogConfig.contentTextStyle.generateTextStyle(), + child: contentWidget!, ), ); @@ -409,9 +403,9 @@ class BrnDialog extends AlertDialog { padding: _configContentPadding(dialogConfig), child: Center( child: Text( - messageText, - style: (dialogConfig?.contentTextStyle)?.generateTextStyle(), - textAlign: dialogConfig?.contentTextAlign, + messageText ?? "", + style: dialogConfig.contentTextStyle.generateTextStyle(), + textAlign: dialogConfig.contentTextAlign, ), ), ); @@ -423,17 +417,17 @@ class BrnDialog extends AlertDialog { if (warningWidget != null) return Flexible( child: DefaultTextStyle( - style: (dialogConfig?.warningTextStyle)?.generateTextStyle(), - child: warningWidget, + style: dialogConfig.warningTextStyle.generateTextStyle(), + child: warningWidget!, ), ); return Padding( padding: _configWarningPadding(dialogConfig), child: Text( - warningText, - style: (dialogConfig?.warningTextStyle)?.generateTextStyle(), - textAlign: dialogConfig?.warningTextAlign, + warningText!, + style: dialogConfig.warningTextStyle.generateTextStyle(), + textAlign: dialogConfig.warningTextAlign, ), ); } @@ -442,30 +436,30 @@ class BrnDialog extends AlertDialog { /// 单个button 左右有圆角 /// 两个button 左button有左圆角&右直角 右button有右圆角&左直角 /// 多个button 最后一个左右圆角 其他均直角 - Widget _generateMainWidget(Widget widget, Color background, ButtonType type, + Widget _generateMainWidget(Widget widget, Color background, _ButtonType type, int index, BrnDialogConfig dialogConfig) { return Container( decoration: ShapeDecoration( color: background, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(type == ButtonType.Single || - type == ButtonType.Left || - (type == ButtonType.Multi && + bottomLeft: Radius.circular(type == _ButtonType.single || + type == _ButtonType.left || + (type == _ButtonType.multi && actionsText != null && - index == actionsText.length - 1) + index == actionsText!.length - 1) ? BrnDialogUtils.getDialogRadius(dialogConfig) : 0), - bottomRight: Radius.circular(type == ButtonType.Single || - type == ButtonType.Right || - (type == ButtonType.Multi && + bottomRight: Radius.circular(type == _ButtonType.single || + type == _ButtonType.right || + (type == _ButtonType.multi && actionsText != null && - index == actionsText.length - 1) + index == actionsText!.length - 1) ? BrnDialogUtils.getDialogRadius(dialogConfig) : 0)))), constraints: BoxConstraints.tightFor(height: cBottomHeight), child: DefaultTextStyle( - style: (dialogConfig?.mainActionTextStyle)?.generateTextStyle(), + style: dialogConfig.mainActionTextStyle.generateTextStyle(), child: Center( child: widget, ), @@ -477,7 +471,7 @@ class BrnDialog extends AlertDialog { /// 单个button 左右有圆角 /// 两个button 左button有左圆角&右直角 右button有右圆角&左直角 /// 多个button 最后一个左右圆角 其他均直角 - Widget _generateGreyWidget(Widget widget, Color background, ButtonType type, + Widget _generateGreyWidget(Widget widget, Color background, _ButtonType type, int index, BrnDialogConfig dialogConfig) { return Container( constraints: BoxConstraints.tightFor(height: cBottomHeight), @@ -485,22 +479,22 @@ class BrnDialog extends AlertDialog { color: background, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(type == ButtonType.Single || - type == ButtonType.Left || - (type == ButtonType.Multi && + bottomLeft: Radius.circular(type == _ButtonType.single || + type == _ButtonType.left || + (type == _ButtonType.multi && actionsText != null && - index == actionsText.length - 1) + index == actionsText!.length - 1) ? BrnDialogUtils.getDialogRadius(dialogConfig) : 0), - bottomRight: Radius.circular(type == ButtonType.Single || - type == ButtonType.Right || - (type == ButtonType.Multi && + bottomRight: Radius.circular(type == _ButtonType.single || + type == _ButtonType.right || + (type == _ButtonType.multi && actionsText != null && - index == actionsText.length - 1) + index == actionsText!.length - 1) ? BrnDialogUtils.getDialogRadius(dialogConfig) : 0)))), child: DefaultTextStyle( - style: dialogConfig?.assistActionsTextStyle?.generateTextStyle(), + style: dialogConfig.assistActionsTextStyle.generateTextStyle(), child: Center( child: widget, ), @@ -511,18 +505,18 @@ class BrnDialog extends AlertDialog { Widget _generateActionsWidget( BuildContext context, BrnDialogConfig defaultConfig) { bool showTextActions = _isEmptyActionsWidget(); - int length = showTextActions ? actionsText.length : actionsWidget.length; + int length = showTextActions ? actionsText!.length : actionsWidget!.length; if (length == 1) { return showTextActions ? _mapTextToGesWidget( context, - actionsText[0], + actionsText![0], 0, true, defaultConfig, - type: ButtonType.Single, + type: _ButtonType.single, ) - : actionsWidget[0]; + : actionsWidget![0]; } else if (length == 2) { return Row( mainAxisSize: MainAxisSize.max, @@ -531,26 +525,26 @@ class BrnDialog extends AlertDialog { Expanded( child: showTextActions ? _mapTextToGesWidget( - context, actionsText[0], 0, false, defaultConfig, - type: ButtonType.Left) - : actionsWidget[0], + context, actionsText![0], 0, false, defaultConfig, + type: _ButtonType.left) + : actionsWidget![0], ), Container( - height: defaultConfig?.bottomHeight, + height: defaultConfig.bottomHeight, child: verticalDivider, ), Expanded( child: showTextActions ? _mapTextToGesWidget( - context, actionsText[1], 1, true, defaultConfig, - type: ButtonType.Right) - : actionsWidget[1], + context, actionsText![1], 1, true, defaultConfig, + type: _ButtonType.right) + : actionsWidget![1], ) ], ); } else { return Container( - height: 3 * (defaultConfig?.bottomHeight ?? 0 + 1), + height: 3 * (defaultConfig.bottomHeight + 1), width: double.maxFinite, child: ListView.separated( shrinkWrap: true, @@ -558,9 +552,9 @@ class BrnDialog extends AlertDialog { itemBuilder: (context, i) { return showTextActions ? _mapTextToGesWidget( - context, actionsText[i], i, true, defaultConfig, - type: ButtonType.Multi) - : actionsWidget[i]; + context, actionsText![i], i, true, defaultConfig, + type: _ButtonType.multi) + : actionsWidget![i]; }, separatorBuilder: (context, i) { return divider; @@ -572,22 +566,18 @@ class BrnDialog extends AlertDialog { Widget _mapTextToGesWidget(BuildContext context, String label, int index, bool main, BrnDialogConfig dialogConfig, - {ButtonType type = ButtonType.Single}) { + {_ButtonType type = _ButtonType.single}) { Text text = Text(label); Widget ges = GestureDetector( child: main - ? _generateMainWidget(text, dialogConfig?.mainActionBackgroundColor, + ? _generateMainWidget(text, dialogConfig.mainActionBackgroundColor, type, index, dialogConfig) - : _generateGreyWidget( - text, - dialogConfig?.assistActionsBackgroundColor, - type, - index, - dialogConfig), + : _generateGreyWidget(text, dialogConfig.assistActionsBackgroundColor, + type, index, dialogConfig), onTap: () { if (indexedActionCallback != null) { //点击的监听 - indexedActionCallback(index); + indexedActionCallback!(index); } else { Navigator.pop(context); } @@ -617,66 +607,32 @@ class BrnDialog extends AlertDialog { } bool _isEmptyActionsText() { - return actionsText == null || actionsText.isEmpty; + return actionsText == null || actionsText!.isEmpty; } bool _isEmptyActionsWidget() { - return actionsWidget == null || actionsWidget.isEmpty; - } - - /// 将已有的BrnDialogStyle转换成BrnDialogConfig - /// 当用户配置了最新的themeData则ljDialogStyle失效 - /// 当用户配置仅配置ljDialogStyle,则将ljDialogStyle转换成themeData - BrnDialogConfig _convertStyleToConfig() { - if (brnDialogStyle == null) { - return themeData; - } - BrnDialogConfig defaultConfig = themeData ?? BrnDialogConfig(); - defaultConfig = defaultConfig.merge(BrnDialogConfig( - mainActionTextStyle: BrnTextStyle.withStyle(brnDialogStyle.mainTextStyle), - mainActionBackgroundColor: brnDialogStyle.mainBackgroundColor, - assistActionsTextStyle: - BrnTextStyle.withStyle(brnDialogStyle.greyActionsTextStyle), - assistActionsBackgroundColor: brnDialogStyle.greyActionsBackgroundColor, - radius: brnDialogStyle.radius, - iconPadding: brnDialogStyle.iconPadding, - titlePaddingSm: brnDialogStyle.titlePadding, - titlePaddingLg: brnDialogStyle.titlePadding, - titleTextAlign: brnDialogStyle.titleTextAlign, - titleTextStyle: BrnTextStyle.withStyle(brnDialogStyle.titleTextStyle), - contentPaddingSm: brnDialogStyle.contentPadding, - contentPaddingLg: brnDialogStyle.contentPadding, - contentTextAlign: brnDialogStyle.contentTextAlign, - contentTextStyle: BrnTextStyle.withStyle(brnDialogStyle.contentTextStyle), - warningPaddingSm: brnDialogStyle.warningPadding, - warningPaddingLg: brnDialogStyle.warningPadding, - warningTextAlign: brnDialogStyle.warningTextAlign, - warningTextStyle: BrnTextStyle.withStyle(brnDialogStyle.warningTextStyle), - bottomHeight: brnDialogStyle.bottomHeight, - backgroundColor: brnDialogStyle.backgroundColor, - )); - return defaultConfig; + return actionsWidget == null || actionsWidget!.isEmpty; } /// 主题配置的标题间距 EdgeInsetsGeometry _configTitlePadding(BrnDialogConfig dialogConfig) { return _isShowIcon() - ? dialogConfig?.titlePaddingSm - : dialogConfig?.titlePaddingLg; + ? dialogConfig.titlePaddingSm + : dialogConfig.titlePaddingLg; } /// 主题配置的内容间距 EdgeInsetsGeometry _configContentPadding(BrnDialogConfig dialogConfig) { return (_isShowIcon() || _isShowTitle()) - ? dialogConfig?.contentPaddingSm - : dialogConfig?.contentPaddingLg; + ? dialogConfig.contentPaddingSm + : dialogConfig.contentPaddingLg; } /// 主题配置的警告间距 EdgeInsetsGeometry _configWarningPadding(BrnDialogConfig dialogConfig) { return (_isShowIcon() || _isShowTitle() || _isShowContent()) - ? dialogConfig?.warningPaddingSm - : dialogConfig?.warningPaddingLg; + ? dialogConfig.warningPaddingSm + : dialogConfig.warningPaddingLg; } } @@ -710,23 +666,23 @@ class BrnDialogManager { ///labelWidget 自定义底部按钮的显示 static void showSingleButtonDialog( BuildContext context, { - @required String label, + required String label, bool showIcon = false, - Image iconWidget, - String title, - Widget titleWidget, - String message, - Widget messageWidget, - String warning, - Widget warningWidget, - Widget labelWidget, - BrnDialogStyle dialogStyle, - GestureTapCallback onTap, + Image? iconWidget, + String? title, + Widget? titleWidget, + String? message, + Widget? messageWidget, + String? warning, + Widget? warningWidget, + Widget? labelWidget, + BrnDialogStyle? dialogStyle, + GestureTapCallback? onTap, bool barrierDismissible = true, int titleMaxLines = cTitleMaxLines, - BrnDialogConfig themeData, + BrnDialogConfig? themeData, }) { - List actionsWidget = List(); + List actionsWidget = []; if (labelWidget != null) { actionsWidget.add(labelWidget); @@ -745,7 +701,6 @@ class BrnDialogManager { warningText: warning, warningWidget: warningWidget, actionsText: [label], - brnDialogStyle: dialogStyle, actionsWidget: actionsWidget, titleMaxLines: titleMaxLines, themeData: themeData, @@ -768,26 +723,26 @@ class BrnDialogManager { /// conformWidget 自定义显示的右侧 static void showConfirmDialog( BuildContext context, { - @required String cancel, - @required String confirm, + required String cancel, + required String confirm, bool showIcon = false, - Image iconWidget, - String title, - Widget titleWidget, - String message, - Widget messageWidget, - String warning, - Widget warningWidget, - Widget cancelWidget, - Widget conformWidget, - BrnDialogStyle dialogStyle, - GestureTapCallback onCancel, - GestureTapCallback onConfirm, + Image? iconWidget, + String? title, + Widget? titleWidget, + String? message, + Widget? messageWidget, + String? warning, + Widget? warningWidget, + Widget? cancelWidget, + Widget? conformWidget, + BrnDialogStyle? dialogStyle, + GestureTapCallback? onCancel, + GestureTapCallback? onConfirm, bool barrierDismissible = true, int titleMaxLines = cTitleMaxLines, - BrnDialogConfig themeData, + BrnDialogConfig? themeData, }) { - List actionsWidget = List(); + List actionsWidget = []; if (cancelWidget != null) { actionsWidget.add(cancelWidget); @@ -810,7 +765,6 @@ class BrnDialogManager { warningText: warning, themeData: themeData, titleMaxLines: titleMaxLines, - brnDialogStyle: dialogStyle, actionsText: [cancel, confirm], actionsWidget: actionsWidget, indexedActionCallback: (index) { @@ -835,21 +789,21 @@ class BrnDialogManager { ///如果数量超过了三个 会滑动展示 static void showMoreButtonDialog( BuildContext context, { - @required List actions, + required List actions, bool showIcon = false, - Image iconWidget, - String title, - Widget titleWidget, - String message, - Widget messageWidget, - String warning, - Widget warningWidget, - List actionsWidget, + Image? iconWidget, + String? title, + Widget? titleWidget, + String? message, + Widget? messageWidget, + String? warning, + Widget? warningWidget, + List? actionsWidget, bool barrierDismissible = true, - BrnDialogStyle dialogStyle, + BrnDialogStyle? dialogStyle, int titleMaxLines = cTitleMaxLines, - BrnDialogConfig themeData, - DialogIndexedActionClickCallback indexedActionClickCallback, + BrnDialogConfig? themeData, + DialogIndexedActionClickCallback? indexedActionClickCallback, }) { showDialog( context: context, @@ -864,7 +818,6 @@ class BrnDialogManager { contentWidget: messageWidget, warningWidget: warningWidget, warningText: warning, - brnDialogStyle: dialogStyle, actionsText: actions, actionsWidget: actionsWidget, themeData: themeData, diff --git a/lib/src/components/dialog/brn_dialog_utils.dart b/lib/src/components/dialog/brn_dialog_utils.dart index 4cdf2801..fcc6b430 100644 --- a/lib/src/components/dialog/brn_dialog_utils.dart +++ b/lib/src/components/dialog/brn_dialog_utils.dart @@ -4,11 +4,11 @@ import 'package:flutter/material.dart'; class BrnDialogUtils { /// dialog标题配置 static TextStyle getDialogTitleStyle(BrnDialogConfig themeData) { - return themeData?.titleTextStyle?.generateTextStyle(); + return themeData.titleTextStyle.generateTextStyle(); } /// dialog圆角配置 static double getDialogRadius(BrnDialogConfig themeData) { - return themeData?.radius; + return themeData.radius; } } diff --git a/lib/src/components/dialog/brn_enhance_operation_dialog.dart b/lib/src/components/dialog/brn_enhance_operation_dialog.dart index 2215d39a..24263dcc 100644 --- a/lib/src/components/dialog/brn_enhance_operation_dialog.dart +++ b/lib/src/components/dialog/brn_enhance_operation_dialog.dart @@ -8,16 +8,16 @@ import 'package:flutter/material.dart'; class BrnDialogConstants { /// 提示图标 - static const int ICON_ALERT = 0; + static const int iconAlert = 0; /// 警示图标 - static const int ICON_WARNING = 1; + static const int iconWarning = 1; /// 成功图标 - static const int ICON_SUCCESS = 2; + static const int iconSuccess = 2; /// 自定义图标 - static const int ICON_CUSTOM = 100; + static const int iconCustom = 100; /// icon地址列表 static const List shareItemImagePathList = [ @@ -34,40 +34,40 @@ class BrnEnhanceOperationDialog extends StatelessWidget { /// 构建环境上下文 final BuildContext context; - /// 图片类型,默认 0,[BrnDialogConstants.ICON_ALERT] + /// 图片类型,默认 0,[BrnDialogConstants.iconAlert] final int iconType; /// 自定义图标 - final Widget customIconWidget; + final Widget? customIconWidget; /// 弹框标题文案,为空则不显示标题 - final String titleText; + final String? titleText; /// 弹框辅助信息文案,为空则不显示辅助信息 - final String descText; + final String? descText; /// 主要按钮文本 final String mainButtonText; /// 次要按钮文案,为空则不显示次要按钮 - final String secondaryButtonText; + final String? secondaryButtonText; /// 主要按钮回调 - final VoidCallback onMainButtonClick; + final VoidCallback? onMainButtonClick; /// 次要按钮回调 - final VoidCallback onSecondaryButtonClick; + final VoidCallback? onSecondaryButtonClick; /// 主题配置 - BrnDialogConfig themeData; + BrnDialogConfig? themeData; BrnEnhanceOperationDialog({ - this.iconType, + this.iconType = BrnDialogConstants.iconAlert, this.customIconWidget, - this.context, + required this.context, this.titleText, this.descText, - this.mainButtonText, + this.mainButtonText = '确认', this.secondaryButtonText, this.onMainButtonClick, this.onSecondaryButtonClick, @@ -75,7 +75,7 @@ class BrnEnhanceOperationDialog extends StatelessWidget { }) { this.themeData ??= BrnDialogConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .dialogConfig .merge(this.themeData); } @@ -86,8 +86,8 @@ class BrnEnhanceOperationDialog extends StatelessWidget { type: MaterialType.transparency, child: BrnDialog( themeData: themeData, - iconImage: (iconType == BrnDialogConstants.ICON_CUSTOM) - ? customIconWidget + iconImage: (iconType == BrnDialogConstants.iconCustom) + ? customIconWidget as Image : BrunoTools.getAssetImage( BrnDialogConstants.shareItemImagePathList[iconType]), titleText: titleText, @@ -113,11 +113,11 @@ class BrnEnhanceOperationDialog extends StatelessWidget { }).then((value) { if (value == mainButtonText) { if (onMainButtonClick != null) { - onMainButtonClick(); + onMainButtonClick!(); } } else { if (onSecondaryButtonClick != null) { - onSecondaryButtonClick(); + onSecondaryButtonClick!(); } } }); @@ -125,7 +125,7 @@ class BrnEnhanceOperationDialog extends StatelessWidget { /// 构建widgets框架 List _configDialogWidgets(BuildContext context) { - List widgets = List(); + List widgets = []; //分割 widgets.add(Container( height: 16, @@ -168,9 +168,9 @@ class BrnEnhanceOperationDialog extends StatelessWidget { highlightColor: Colors.transparent, child: Center( child: Text( - secondaryButtonText, + secondaryButtonText!, style: TextStyle( - color: themeData.commonConfig.brandPrimary, + color: themeData!.commonConfig.brandPrimary, fontSize: 16, ), ), diff --git a/lib/src/components/dialog/brn_middle_input_diaolg.dart b/lib/src/components/dialog/brn_middle_input_diaolg.dart index 2416da11..ec66d2ff 100644 --- a/lib/src/components/dialog/brn_middle_input_diaolg.dart +++ b/lib/src/components/dialog/brn_middle_input_diaolg.dart @@ -6,13 +6,13 @@ import 'package:flutter/services.dart'; /// 可输入文字的弹窗。从上至下依次是 标题[title]、提示信息[message]、输入框,底部左右两个按钮,左边取消,右边确定。 class BrnMiddleInputDialog { /// 标题 - final String title; + final String? title; /// 辅助提示信息 - final String message; + final String? message; /// 输入框占位文字 - final String hintText; + final String? hintText; /// 最多可输入多少字符,默认20个 final int maxLength; @@ -24,13 +24,13 @@ class BrnMiddleInputDialog { final String confirmText; /// 点击确定时的回调,参数为输入框中的字符 - final void Function(String value) onConfirm; + final void Function(String value)? onConfirm; /// 弹窗样式。具体参见 [BrnDialogStyle] - final BrnDialogStyle dialogStyle; + final BrnDialogStyle? dialogStyle; /// 点击取消时的回调 - final VoidCallback onCancel; + final VoidCallback? onCancel; /// 点击蒙层背景,弹窗是否可关闭。默认为 true,可关闭 final bool barrierDismissible; @@ -42,16 +42,16 @@ class BrnMiddleInputDialog { final int minLines; /// 可输入的最多行数。超过 [maxLines] 指定的行数后,输入内容会变成可滑动 - final int maxLines; + final int? maxLines; /// 焦点控制 [FocusNode] - final FocusNode inputFocusNode; + final FocusNode? inputFocusNode; /// 输入控制器。如果有初始状态的填充文字,可以通过 [inputEditingController] 设置 - final TextEditingController inputEditingController; + final TextEditingController? inputEditingController; /// 输入内容格式控制器 - final List inputFormatters; + final List? inputFormatters; /// 键盘操作按钮类型,参见系统的 [TextField.textInputAction],默认为 [TextInputAction.newline] final TextInputAction textInputAction; @@ -84,11 +84,11 @@ class BrnMiddleInputDialog { } void _doShow(BuildContext context) { - String _value = inputEditingController?.text; + String _value = inputEditingController?.text ?? ""; var dialogMessageWidgets = []; - if (message != null && message.length > 0) { + if (message != null && message!.length > 0) { dialogMessageWidgets.add(Text( - message, + message!, style: cContentTextStyle, textAlign: cContentTextAlign, )); @@ -100,12 +100,13 @@ class BrnMiddleInputDialog { if (inputFormatters == null) { tmpInputFormatters = [LengthLimitingTextInputFormatter(maxLength)]; } else { - tmpInputFormatters = List() - ..addAll(inputFormatters) + tmpInputFormatters = [] + ..addAll(inputFormatters!) ..add(LengthLimitingTextInputFormatter(maxLength)); } dialogMessageWidgets.add(TextField( + maxLengthEnforcement: MaxLengthEnforcement.enforced, textInputAction: this.textInputAction, focusNode: inputFocusNode, controller: inputEditingController, @@ -114,7 +115,7 @@ class BrnMiddleInputDialog { //光标颜色 cursorColor: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, - autofocus: autoFocus ?? false, + autofocus: autoFocus, //光标圆角弧度 cursorRadius: Radius.circular(2.0), style: TextStyle( @@ -123,7 +124,6 @@ class BrnMiddleInputDialog { .getConfig() .commonConfig .colorTextBase), - maxLengthEnforced: true, onChanged: (value) { _value = value; }, @@ -161,7 +161,7 @@ class BrnMiddleInputDialog { cancel: cancelText, confirm: confirmText, title: title, - barrierDismissible: barrierDismissible ?? true, + barrierDismissible: barrierDismissible, dialogStyle: dialogStyle ?? BrnDialogStyle(), messageWidget: Padding( padding: const EdgeInsets.only(top: 12, left: 24, right: 24), @@ -170,9 +170,9 @@ class BrnMiddleInputDialog { children: dialogMessageWidgets, ), ), onConfirm: () { - if (onConfirm != null) onConfirm(_value); + if (onConfirm != null) onConfirm!(_value); }, onCancel: () { - if (onCancel != null) onCancel(); + if (onCancel != null) onCancel!(); }); } } diff --git a/lib/src/components/dialog/brn_multi_select_dialog.dart b/lib/src/components/dialog/brn_multi_select_dialog.dart index 4e00e0d6..d85ebe5c 100644 --- a/lib/src/components/dialog/brn_multi_select_dialog.dart +++ b/lib/src/components/dialog/brn_multi_select_dialog.dart @@ -36,10 +36,10 @@ class BrnMultiSelectDialog extends Dialog { final String title; /// 描述文案 - final String messageText; + final String? messageText; /// 描述widget - final Widget messageWidget; + final Widget? messageWidget; /// 选项集合 final List conditions; @@ -48,16 +48,16 @@ class BrnMultiSelectDialog extends Dialog { final String submitText; /// 点击操作按钮 - final BrnMultiSelectDialogClickSubmitCallback onSubmitClick; + final BrnMultiSelectDialogClickSubmitCallback? onSubmitClick; /// 点击选项操作 可供埋点需求用 - final BrnMultiSelectDialogOnItemClickCallback onItemClick; + final BrnMultiSelectDialogOnItemClickCallback? onItemClick; /// 操作按钮背景色 - final Color submitBgColor; + final Color? submitBgColor; /// 自定义widget - final Widget customWidget; + final Widget? customWidget; /// 是否支持滚动 默认true支持滚动 final bool isCustomFollowScroll; @@ -68,7 +68,7 @@ class BrnMultiSelectDialog extends Dialog { BrnMultiSelectDialog({ this.isClose = true, this.title = "", - this.conditions, + required this.conditions, this.messageText, this.messageWidget, this.customWidget, @@ -104,31 +104,31 @@ class MultiSelect extends StatefulWidget { final bool isClose; /// 标题 - final String title; + final String? title; /// 描述文案 - final String messageText; + final String? messageText; /// 描述widget - final Widget messageWidget; + final Widget? messageWidget; /// 选项集合 final List conditions; /// 操作按钮文案 - final String submitText; + final String? submitText; /// 点击操作按钮 - final BrnMultiSelectDialogClickSubmitCallback onSubmitClick; + final BrnMultiSelectDialogClickSubmitCallback? onSubmitClick; /// 点击选项操作 - final BrnMultiSelectDialogOnItemClickCallback onItemClick; + final BrnMultiSelectDialogOnItemClickCallback? onItemClick; /// 操作按钮背景色 - final Color submitBgColor; + final Color? submitBgColor; /// 自定义widget - final Widget customWidget; + final Widget? customWidget; /// 是否支持滚动 final bool isCustomFollowScroll; @@ -137,18 +137,18 @@ class MultiSelect extends StatefulWidget { final bool isShowOperateWidget; MultiSelect({ - this.isClose, + this.isClose = true, this.title, this.messageText, this.messageWidget, this.customWidget, - this.isCustomFollowScroll, - this.conditions, + this.isCustomFollowScroll = true, + required this.conditions, this.submitText, this.submitBgColor, this.onSubmitClick, this.onItemClick, - this.isShowOperateWidget, + this.isShowOperateWidget = true, }); @override @@ -175,7 +175,7 @@ class MultiSelectPickerWidgetState extends State { physics: NeverScrollableScrollPhysics(), itemBuilder: (context, index) => _buildItem(context, index), - itemCount: widget.conditions?.length), + itemCount: widget.conditions.length), widget.customWidget != null ? Container( child: widget.customWidget, @@ -195,7 +195,7 @@ class MultiSelectPickerWidgetState extends State { child: ListView.builder( itemBuilder: (context, index) => _buildItem(context, index), - itemCount: widget.conditions?.length), + itemCount: widget.conditions.length), ), widget.customWidget != null ? Container( @@ -218,14 +218,14 @@ class MultiSelectPickerWidgetState extends State { submitBgColor: widget.submitBgColor, isShowOperateWidget: widget.isShowOperateWidget, onSubmit: () { - List tempList = List(); + List tempList = []; if (widget.onSubmitClick != null) { - for (int i = 0; i < widget.conditions?.length; i++) { + for (int i = 0; i < widget.conditions.length; i++) { if (widget.conditions[i].isChecked) { tempList.add(widget.conditions[i]); } } - if (widget.onSubmitClick(tempList)) Navigator.of(context).pop(); + if (widget.onSubmitClick!(tempList)) Navigator.of(context).pop(); } }, ); @@ -246,7 +246,7 @@ class MultiSelectPickerWidgetState extends State { padding: EdgeInsets.only(bottom: 8, left: 20, right: 20), child: Center( child: Text( - widget.messageText, + widget.messageText!, style: cContentTextStyle, ), ), @@ -256,59 +256,55 @@ class MultiSelectPickerWidgetState extends State { } Widget _buildItem(BuildContext context, int index) { - if (widget.conditions[index] == null) { - return Container(); - } else { - return GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - setState(() { - widget.conditions[index].isChecked = - !widget.conditions[index].isChecked; - }); - if (widget.onItemClick != null) { - widget.onItemClick(context, index); - } - }, - child: Column( - children: [ - Padding( - padding: EdgeInsets.fromLTRB(20, 0, 20, 0), - child: Row( - children: [ - Expanded( - child: Text(widget.conditions[index].content, - style: TextStyle( - fontWeight: widget.conditions[index].isChecked - ? FontWeight.w600 - : FontWeight.normal, - fontSize: 16, - color: widget.conditions[index].isChecked - ? BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .brandPrimary - : BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .colorTextBase))), - Container( - alignment: Alignment.center, - height: 44, - child: widget.conditions[index].isChecked - ? BrunoTools.getAssetImageWithBandColor( - BrnAsset.iconMultiSelected) - : BrunoTools.getAssetImage(BrnAsset.iconUnSelect)), - ], - ), + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + setState(() { + widget.conditions[index].isChecked = + !widget.conditions[index].isChecked; + }); + if (widget.onItemClick != null) { + widget.onItemClick!(context, index); + } + }, + child: Column( + children: [ + Padding( + padding: EdgeInsets.fromLTRB(20, 0, 20, 0), + child: Row( + children: [ + Expanded( + child: Text(widget.conditions[index].content, + style: TextStyle( + fontWeight: widget.conditions[index].isChecked + ? FontWeight.w600 + : FontWeight.normal, + fontSize: 16, + color: widget.conditions[index].isChecked + ? BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary + : BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase))), + Container( + alignment: Alignment.center, + height: 44, + child: widget.conditions[index].isChecked + ? BrunoTools.getAssetImageWithBandColor( + BrnAsset.iconMultiSelected) + : BrunoTools.getAssetImage(BrnAsset.iconUnSelect)), + ], ), - index != widget.conditions.length - 1 - ? Padding( - padding: EdgeInsets.fromLTRB(20, 0, 20, 0), - child: BrnLine()) - : Container() - ], - )); - } + ), + index != widget.conditions.length - 1 + ? Padding( + padding: EdgeInsets.fromLTRB(20, 0, 20, 0), + child: BrnLine()) + : Container() + ], + )); } } diff --git a/lib/src/components/dialog/brn_scrollable_text_dialog.dart b/lib/src/components/dialog/brn_scrollable_text_dialog.dart index 61af7496..292e4a29 100644 --- a/lib/src/components/dialog/brn_scrollable_text_dialog.dart +++ b/lib/src/components/dialog/brn_scrollable_text_dialog.dart @@ -8,7 +8,7 @@ import 'package:flutter/material.dart'; class BrnScrollableTextDialog extends Dialog { /// 标题 - final String title; + final String? title; /// 是否可关闭 默认true支持关闭 final bool isClose; @@ -23,16 +23,16 @@ class BrnScrollableTextDialog extends Dialog { final double textFontSize; /// 提交按钮文字 - final String submitText; + final String? submitText; /// 操作按钮背景色 - final Color submitBgColor; + final Color? submitBgColor; /// 提交操作 - final VoidCallback onSubmitClick; + final VoidCallback? onSubmitClick; /// 富文本超链接点击回调 - final BrnHyperLinkCallback linksCallback; + final BrnHyperLinkCallback? linksCallback; /// 是否展示底部操作区域 默认true展示 final bool isShowOperateWidget; @@ -40,7 +40,7 @@ class BrnScrollableTextDialog extends Dialog { const BrnScrollableTextDialog( {this.title, this.isClose = true, - this.contentText, + required this.contentText, this.textColor = const Color(0xFF666666), this.textFontSize = 16, this.submitText, @@ -67,7 +67,7 @@ class BrnScrollableTextDialog extends Dialog { class BrnScrollableText extends StatelessWidget { /// 标题 - final String title; + final String? title; /// 是否可关闭 final bool isClose; @@ -76,37 +76,37 @@ class BrnScrollableText extends StatelessWidget { final String contentText; /// 文字颜色 - final Color textColor; + final Color? textColor; /// 文字字体 - final double textFontSize; + final double? textFontSize; /// 提交按钮文字 - final String submitText; + final String? submitText; /// 提交操作 - final VoidCallback onSubmitClick; + final VoidCallback? onSubmitClick; /// 操作按钮背景色 - final Color submitBgColor; + final Color? submitBgColor; /// 富文本超链接点击回调 - final BrnHyperLinkCallback linksCallback; + final BrnHyperLinkCallback? linksCallback; /// 是否展示底部操作区域 final bool isShowOperateWidget; const BrnScrollableText( {this.title, - this.isClose, - this.contentText, + this.isClose = true, + required this.contentText, this.textColor, this.textFontSize, this.submitText, this.onSubmitClick, this.submitBgColor, this.linksCallback, - this.isShowOperateWidget}); + this.isShowOperateWidget = true}); @override Widget build(BuildContext context) { @@ -131,8 +131,9 @@ class BrnScrollableText extends StatelessWidget { submitText: submitText, submitBgColor: submitBgColor, onSubmit: () { - onSubmitClick(); - Navigator.pop(context); + if (onSubmitClick != null) { + onSubmitClick!(); + } }, isShowOperateWidget: isShowOperateWidget, ); diff --git a/lib/src/components/dialog/brn_share_dialog.dart b/lib/src/components/dialog/brn_share_dialog.dart index 8e58eb68..8e282877 100644 --- a/lib/src/components/dialog/brn_share_dialog.dart +++ b/lib/src/components/dialog/brn_share_dialog.dart @@ -13,11 +13,11 @@ typedef BrnShareDialogItemClickCallBack(int shareChannel, int customIndex); /// 获取自定义分享item标题 /// index为自定义分享item索引 -typedef String BrnShareDialogGetCustomShareItemTitle(int index); +typedef String? BrnShareDialogGetCustomShareItemTitle(int index); /// 获取自定义分享item图标 /// index为自定义分享item索引 -typedef Widget BrnShareDialogGetCustomShareItemIcon(int index); +typedef Widget? BrnShareDialogGetCustomShareItemIcon(int index); // ignore: must_be_immutable class BrnShareDialog extends StatelessWidget { @@ -27,10 +27,10 @@ class BrnShareDialog extends StatelessWidget { final String titleText; /// 弹框辅助信息文案,为空则不显示辅助信息 - final String descText; + final String? descText; /// 文案与分享渠道图标间的分割线内嵌文案 - final String separatorText; + final String? separatorText; /// 分享渠道列表 final List shareChannels; @@ -48,23 +48,23 @@ class BrnShareDialog extends StatelessWidget { final Color separatorLineColor; /// 点击事件 - final BrnShareDialogItemClickCallBack clickCallBack; + final BrnShareDialogItemClickCallBack? clickCallBack; /// 回调获取名称 - final BrnShareDialogGetCustomShareItemTitle getCustomChannelTitle; + final BrnShareDialogGetCustomShareItemTitle? getCustomChannelTitle; /// 回调获取图片(Widget) - final BrnShareDialogGetCustomShareItemIcon getCustomChannelWidget; + final BrnShareDialogGetCustomShareItemIcon? getCustomChannelWidget; /// dialog配置 - BrnDialogConfig themeData; + BrnDialogConfig? themeData; BrnShareDialog({ - @required this.context, - this.titleText, + required this.context, + required this.titleText, this.descText, this.separatorText, - this.shareChannels, + required this.shareChannels, this.clickCallBack, this.getCustomChannelTitle, this.getCustomChannelWidget, @@ -76,7 +76,7 @@ class BrnShareDialog extends StatelessWidget { }) { this.themeData ??= BrnDialogConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) + .getConfig(configId: themeData!.configId) .dialogConfig .merge(themeData); } @@ -117,7 +117,9 @@ class BrnShareDialog extends StatelessWidget { if (value != null) { List info = value; if (info.length >= 2) { - clickCallBack(info[0], info[1]); + if (clickCallBack != null) { + clickCallBack!(info[0], info[1]); + } } } }); @@ -125,7 +127,7 @@ class BrnShareDialog extends StatelessWidget { /// 构建widgets框架 List _configDialogWidgets() { - List widgets = List(); + List widgets = []; widgets.add(_configDialogseparator()); //分割 widgets.add(Padding( @@ -145,7 +147,7 @@ class BrnShareDialog extends StatelessWidget { padding: EdgeInsets.only(top: 28), child: Text( titleText, - style: BrnDialogUtils.getDialogTitleStyle(themeData), + style: BrnDialogUtils.getDialogTitleStyle(themeData!), ), ), Positioned( @@ -157,7 +159,7 @@ class BrnShareDialog extends StatelessWidget { child: Container( width: 30, height: 30, - child: BrunoTools.getAssetImage(BrnAsset.ICON_PICKER_CLOSE), + child: BrunoTools.getAssetImage(BrnAsset.iconPickerClose), ), onTap: () { Navigator.of(context).pop(); @@ -184,7 +186,7 @@ class BrnShareDialog extends StatelessWidget { color: Color(0xffffffff), padding: EdgeInsets.only(left: 6, right: 6), child: Text( - (separatorText != null) ? separatorText : "你可以通过以下方式分享给客户", + separatorText ?? "你可以通过以下方式分享给客户", style: TextStyle(fontSize: 12, color: shareTextColor), ), ), @@ -195,16 +197,20 @@ class BrnShareDialog extends StatelessWidget { /// 构建分享途径部分 Widget _configDialogShareItems() { - List shareItems = List(); - String title; // 标题 - Widget image; // 图片路径 + List shareItems = []; + String? title; // 标题 + Widget? image; // 图片路径 for (int index = 0; index < shareChannels.length; index++) { title = null; image = null; - if (shareChannels[index] == BrnShareItemConstants.SHARE_CUSTOM) { + if (shareChannels[index] == BrnShareItemConstants.shareCustom) { // 获取自定义channel信息 - title = getCustomChannelTitle(index); - image = getCustomChannelWidget(index); + if (getCustomChannelTitle != null) { + title = getCustomChannelTitle!(index); + } + if (getCustomChannelTitle != null) { + image = getCustomChannelWidget!(index); + } } else { // 获取自预设channel信息 title = BrnShareItemConstants.shareItemTitleList[shareChannels[index]]; diff --git a/lib/src/components/dialog/brn_single_select.dart b/lib/src/components/dialog/brn_single_select.dart index e466f6e4..96d5726b 100644 --- a/lib/src/components/dialog/brn_single_select.dart +++ b/lib/src/components/dialog/brn_single_select.dart @@ -6,7 +6,7 @@ import 'package:bruno/src/theme/configs/brn_dialog_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -typedef BrnSingleSelectOnSubmitCallback = Function(String data); +typedef BrnSingleSelectOnSubmitCallback = Function(String? data); typedef BrnSingleSelectOnItemClickCallback = void Function( BuildContext dialogContext, int index); @@ -25,19 +25,19 @@ class BrnSingleSelectDialog extends Dialog { final String submitText; /// 提交按钮点击回调 - final BrnSingleSelectOnSubmitCallback onSubmitClick; + final BrnSingleSelectOnSubmitCallback? onSubmitClick; /// item 点击回调 - final BrnSingleSelectOnItemClickCallback onItemClick; + final BrnSingleSelectOnItemClickCallback? onItemClick; /// 提交按钮背景颜色 - final Color submitBgColor; + final Color? submitBgColor; /// 选中的选项名称 - final String checkedItem; + final String? checkedItem; /// 单选列表底部自定义 Widget - final Widget customWidget; + final Widget? customWidget; /// 内容是否可滑动。默认为 true final bool isCustomFollowScroll; @@ -48,7 +48,7 @@ class BrnSingleSelectDialog extends Dialog { const BrnSingleSelectDialog( {this.isClose: true, this.title: "", - this.conditions, + required this.conditions, this.submitText: "提交", this.submitBgColor, this.onSubmitClick, @@ -79,26 +79,26 @@ class BrnSingleSelectDialog extends Dialog { class BrnSingleSelectDialogWidget extends StatefulWidget { final bool isClose; final String title; - final List conditions; + final List? conditions; final String submitText; - final BrnSingleSelectOnSubmitCallback onSubmitClick; - final BrnSingleSelectOnItemClickCallback onItemClick; //可供埋点需求用 - final Color submitBgColor; - String checkedItem; // 选择项目 + final BrnSingleSelectOnSubmitCallback? onSubmitClick; + final BrnSingleSelectOnItemClickCallback? onItemClick; //可供埋点需求用 + final Color? submitBgColor; + String? checkedItem; // 选择项目 - final Widget customWidget; + final Widget? customWidget; final bool isCustomFollowScroll; final bool canDismissOnConfirmClick; - BrnDialogConfig themeData; + BrnDialogConfig? themeData; BrnSingleSelectDialogWidget( - {this.isClose, - this.title, + {this.isClose = true, + this.title = "", this.conditions, - this.submitText, + this.submitText = "", this.submitBgColor, this.onSubmitClick, this.onItemClick, @@ -109,7 +109,7 @@ class BrnSingleSelectDialogWidget extends StatefulWidget { this.themeData}) { this.themeData ??= BrnDialogConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) + .getConfig(configId: themeData!.configId) .dialogConfig .merge(themeData); } @@ -135,7 +135,7 @@ class BrnSingleSelectDialogWidgetState color: widget.themeData?.backgroundColor, borderRadius: BorderRadius.all(Radius.circular( BrnDialogUtils.getDialogRadius( - widget.themeData))), //设置四周圆角 角度 + widget.themeData!))), //设置四周圆角 角度 ), child: Stack( children: [ @@ -148,7 +148,7 @@ class BrnSingleSelectDialogWidgetState child: Text( widget.title, style: BrnDialogUtils.getDialogTitleStyle( - widget.themeData), + widget.themeData!), ), ), Container( @@ -226,7 +226,7 @@ class BrnSingleSelectDialogWidgetState Navigator.of(context).pop(); } if (widget.onSubmitClick != null) { - widget.onSubmitClick(widget.checkedItem); + widget.onSubmitClick!(widget.checkedItem); } }, )) @@ -242,7 +242,7 @@ class BrnSingleSelectDialogWidgetState child: Padding( padding: EdgeInsets.all(15), child: BrunoTools.getAssetImage( - BrnAsset.ICON_PICKER_CLOSE), + BrnAsset.iconPickerClose), ))) : Container() ], @@ -251,7 +251,7 @@ class BrnSingleSelectDialogWidgetState } Widget _buildItem(BuildContext context, int index) { - if (widget.conditions == null || widget.conditions[index] == null) { + if (widget.conditions == null) { return Container(); } else { return Container( @@ -265,11 +265,11 @@ class BrnSingleSelectDialogWidgetState child: InkWell( onTap: () { setState(() { - for (dynamic item in widget.conditions) { - if (widget.conditions[index] == item) { + for (dynamic item in widget.conditions!) { + if (widget.conditions![index] == item) { if (widget.onItemClick != null && widget.checkedItem != item) { - widget.onItemClick(context, index); + widget.onItemClick!(context, index); } widget.checkedItem = item; break; @@ -277,14 +277,14 @@ class BrnSingleSelectDialogWidgetState } }); }, - child: Text(widget.conditions[index], + child: Text(widget.conditions![index], style: TextStyle( fontWeight: - widget.conditions[index] == widget.checkedItem + widget.conditions![index] == widget.checkedItem ? FontWeight.w600 : FontWeight.normal, fontSize: 16, - color: widget.conditions[index] == widget.checkedItem + color: widget.conditions![index] == widget.checkedItem ? BrnThemeConfigurator.instance .getConfig() .commonConfig @@ -298,24 +298,24 @@ class BrnSingleSelectDialogWidgetState child: Container( alignment: Alignment.center, height: 44, - child: widget.checkedItem == widget.conditions[index] + child: widget.checkedItem == widget.conditions![index] ? BrunoTools.getAssetImageWithBandColor( BrnAsset.iconSingleSelected) : BrunoTools.getAssetImage(BrnAsset.iconUnSelect), ), onTap: () { if (widget.onItemClick != null) { - widget.onItemClick(context, index); + widget.onItemClick!(context, index); } setState(() { - widget.checkedItem = widget.conditions[index]; + widget.checkedItem = widget.conditions![index]; }); }, ) ], ), ), - index != widget.conditions.length - 1 + index != widget.conditions!.length - 1 ? Padding( padding: EdgeInsets.fromLTRB(20, 0, 20, 0), child: BrnLine()) : Container() diff --git a/lib/src/components/empty/brn_empty_status.dart b/lib/src/components/empty/brn_empty_status.dart index bdcfd48c..2522c917 100644 --- a/lib/src/components/empty/brn_empty_status.dart +++ b/lib/src/components/empty/brn_empty_status.dart @@ -25,8 +25,8 @@ class BrnAbnormalStateUtils { /// 通过状态获取对应空页面widget /// status: 页面状态类型为[EmptyState] static Widget getEmptyWidgetByState(BuildContext context, - AbnormalState status, BrnEmptyStatusIndexedActionClickCallback action, - {Image img}) { + AbnormalState status, + {Image? img,BrnEmptyStatusIndexedActionClickCallback? action}) { if (AbnormalState.getDataFailed == status) { return BrnAbnormalStateWidget( img: img ?? BrunoTools.getAssetImage(BrnAsset.emptyState), @@ -55,13 +55,13 @@ class BrnAbnormalStateUtils { /// 操作区域按钮类型 enum OperateAreaType { /// 单按钮 - SingleButton, + singleButton, /// 双按钮 - DoubleButton, + doubleButton, /// 文本按钮 - TextButton + textButton } /// 空页面操作区域按钮的点击回调 @@ -72,22 +72,22 @@ typedef BrnEmptyStatusIndexedActionClickCallback = void Function(int index); // ignore: must_be_immutable class BrnAbnormalStateWidget extends StatelessWidget { /// 图片 - final Image img; + final Image? img; /// 标题 - final String title; + final String? title; /// 内容 - final String content; + final String? content; /// 操作区类型 final OperateAreaType operateAreaType; /// 操作区文案 - final List operateTexts; + final List? operateTexts; /// 点击事件回调 - final BrnEmptyStatusIndexedActionClickCallback action; + final BrnEmptyStatusIndexedActionClickCallback? action; /// 是否可点击页面回调配合[action]使用 /// 当为true时调用[action]回调,当为false时不做处理 @@ -96,7 +96,7 @@ class BrnAbnormalStateWidget extends StatelessWidget { /// 顶部距离走自动计算逻辑:父视图高度的8%,可自己指定高度 /// 默认为null - final double topOffset; + final double? topOffset; /// 背景色设置 /// 默认Colors.white @@ -109,13 +109,13 @@ class BrnAbnormalStateWidget extends StatelessWidget { /// 默认 false final bool isCenterVertical; - BrnAbnormalStateConfig themeData; + BrnAbnormalStateConfig? themeData; BrnAbnormalStateWidget({ this.img, this.title, this.content, - this.operateAreaType: OperateAreaType.TextButton, + this.operateAreaType: OperateAreaType.textButton, this.operateTexts, this.action, this.enablePageTap: false, @@ -127,7 +127,7 @@ class BrnAbnormalStateWidget extends StatelessWidget { }) { this.themeData ??= BrnAbnormalStateConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .abnormalStateConfig .merge(this.themeData); } @@ -136,12 +136,12 @@ class BrnAbnormalStateWidget extends StatelessWidget { Widget build(BuildContext context) { return GestureDetector( onTap: () { - if (this.enablePageTap) { - action(0); + if (this.enablePageTap && action!=null) { + action!(0); } }, child: Container( - color: bgColor ?? Colors.white, + color: bgColor, child: Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: isCenterVertical @@ -169,7 +169,7 @@ class BrnAbnormalStateWidget extends StatelessWidget { : EdgeInsets.only(top: topOffset ?? height * topPercent), child: img, ) - : Container(); + : SizedBox.shrink(); } ///文案区域:标题 @@ -178,11 +178,11 @@ class BrnAbnormalStateWidget extends StatelessWidget { ? Container( alignment: Alignment.center, padding: EdgeInsets.fromLTRB(60, 24, 60, 0), - child: Text(title, + child: Text(title!, textAlign: TextAlign.center, - style: themeData?.titleTextStyle?.generateTextStyle()), + style: themeData!.titleTextStyle.generateTextStyle()), ) - : Container(); + : SizedBox.shrink(); } ///文案区域:内容 @@ -191,11 +191,11 @@ class BrnAbnormalStateWidget extends StatelessWidget { ? Container( alignment: Alignment.center, padding: EdgeInsets.fromLTRB(60, 12, 60, 0), - child: Text(content, + child: Text(content!, textAlign: TextAlign.center, - style: themeData?.contentTextStyle?.generateTextStyle()), + style: themeData!.contentTextStyle.generateTextStyle()), ) - : Container(); + : SizedBox.shrink(); } ///操作区域 @@ -205,42 +205,46 @@ class BrnAbnormalStateWidget extends StatelessWidget { padding: EdgeInsets.only(top: 36), child: _buildOperateContentWidget(), ) - : Container(); + : SizedBox.shrink(); } ///操作区按钮 _buildOperateContentWidget() { - if (OperateAreaType.SingleButton == operateAreaType) { + if (OperateAreaType.singleButton == operateAreaType) { return GestureDetector( - onTap: () => action(0), + onTap: () { + if (action != null) action!(0); + }, child: Container( - constraints: BoxConstraints(minWidth: themeData.singleMinWidth), + constraints: BoxConstraints(minWidth: themeData!.singleMinWidth), padding: EdgeInsets.fromLTRB(48, 16, 48, 16), decoration: BoxDecoration( - color: themeData.commonConfig.brandPrimary, + color: themeData!.commonConfig.brandPrimary, borderRadius: - BorderRadius.all(Radius.circular(themeData?.btnRadius))), - child: Text(operateTexts[0] ?? "", + BorderRadius.all(Radius.circular(themeData!.btnRadius))), + child: Text(operateTexts![0], textAlign: TextAlign.center, - style: themeData?.singleBrnTextStyle?.generateTextStyle()), + style: themeData!.singleTextStyle.generateTextStyle()), ), ); - } else if (OperateAreaType.DoubleButton == operateAreaType) { + } else if (OperateAreaType.doubleButton == operateAreaType) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ GestureDetector( - onTap: () => action(0), + onTap: () { + if (action != null) action!(0); + }, child: Container( - constraints: BoxConstraints(minWidth: themeData.doubleMinWidth), + constraints: BoxConstraints(minWidth: themeData!.doubleMinWidth), padding: EdgeInsets.fromLTRB(36, 16, 36, 16), decoration: BoxDecoration( - color: themeData.commonConfig.brandPrimary.withAlpha(0x14), + color: themeData!.commonConfig.brandPrimary.withAlpha(0x14), borderRadius: - BorderRadius.all(Radius.circular(themeData?.btnRadius))), - child: Text(operateTexts[0] ?? "", + BorderRadius.all(Radius.circular(themeData!.btnRadius))), + child: Text(operateTexts![0], textAlign: TextAlign.center, - style: themeData?.doubleBrnTextStyle?.generateTextStyle()), + style: themeData!.doubleTextStyle.generateTextStyle()), ), ), Container( @@ -248,26 +252,30 @@ class BrnAbnormalStateWidget extends StatelessWidget { color: Colors.transparent, ), GestureDetector( - onTap: () => action(1), + onTap: () { + if (action != null) action!(1); + }, child: Container( - constraints: BoxConstraints(minWidth: themeData.doubleMinWidth), + constraints: BoxConstraints(minWidth: themeData!.doubleMinWidth), padding: EdgeInsets.fromLTRB(36, 16, 36, 16), decoration: BoxDecoration( - color: themeData.commonConfig.brandPrimary.withAlpha(0x14), + color: themeData!.commonConfig.brandPrimary.withAlpha(0x14), borderRadius: - BorderRadius.all(Radius.circular(themeData?.btnRadius))), - child: Text(operateTexts[1] ?? "", + BorderRadius.all(Radius.circular(themeData!.btnRadius))), + child: Text(operateTexts![1], textAlign: TextAlign.center, - style: themeData?.doubleBrnTextStyle?.generateTextStyle()), + style: themeData!.doubleTextStyle.generateTextStyle()), ), ), ], ); - } else if (OperateAreaType.TextButton == operateAreaType) { + } else if (OperateAreaType.textButton == operateAreaType) { return GestureDetector( - onTap: () => action(0), - child: Text(operateTexts[0] ?? "", - style: themeData?.operateTextStyle?.generateTextStyle())); + onTap: () { + if (action != null) action!(0); + }, + child: Text(operateTexts![0], + style: themeData!.operateTextStyle.generateTextStyle())); } return Container(); } diff --git a/lib/src/components/form/base/brn_form_item_type.dart b/lib/src/components/form/base/brn_form_item_type.dart index 1335a8a9..08e1cf60 100644 --- a/lib/src/components/form/base/brn_form_item_type.dart +++ b/lib/src/components/form/base/brn_form_item_type.dart @@ -1,59 +1,61 @@ + + class BrnPrefixIconType { - static const String TYPE_NORMAL = "type_normal"; - static const String TYPE_ADD = "type_add"; - static const String TYPE_REMOVE = "type_remove"; + static const String normal = "type_normal"; + static const String add = "type_add"; + static const String remove = "type_remove"; } /// 用于描述表单项的类型 class BrnInputItemType { /// appbar 类型 - static const String HEADER_NORMAL_TYPE = "header_normal_type"; + static const String headerNormalType = "header_normal_type"; /// 表单项类型 - static const String TEXT_INPUT_TYPE = "text_input_type"; - static const String TEXT_FORMAT_INPUT_TYPE = "text_format_input_type"; - static const String TEXT_ARRAY_INPUT_TYPE = "text_array_input_type"; - static const String TEXT_SELECT_INPUT_TYPE = "text_select_input_type"; - static const String TEXT_BLOCK_INPUT_TYPE = "text_block_input_type"; - static const String TEXT_INPUT_TITLE_SELECT_TYPE = + static const String textInputType = "text_input_type"; + static const String textFormatInputType = "text_format_input_type"; + static const String textArrayInputType = "text_array_input_type"; + static const String textSelectInputType = "text_select_input_type"; + static const String textBlockInputType = "text_block_input_type"; + static const String textInputTitleSelectType = "text_input_title_select_type"; - static const String TEXT_RANGE_INPUT_TYPE = "text_range_input_type"; - static const String TEXT_STEP_INPUT_TYPE = "text_step_input_type"; - static const String RADIO_INPUT_TYPE = "radio_input_type"; - static const String RADIO_PORTRAIT_INPUT_TYPE = "radio_column_input_type"; - static const String MULTI_CHOICE_INPUT_TYPE = "multi_choice_input_type"; - static const String MULTI_CHOICE_PORTRAIT_INPUT_TYPE = + static const String textRangeInputType = "text_range_input_type"; + static const String textStepInputType = "text_step_input_type"; + static const String radioInputType = "radio_input_type"; + static const String radioPortraitInputType = "radio_column_input_type"; + static const String multiChoiceInputType = "multi_choice_input_type"; + static const String multiChoicePortraitInputType = "multi_choice_column_input_type"; - static const String SWITCH_TYPE = "switch_type"; + static const String switchType = "switch_type"; - static const String STAR_INPUT_TYPE = "star_input_type"; - static const String PHOTO_PICKER_TYPE = "photo_picker_type"; - static const String EXPAND_GROUP_TYPE = "expand_group_type"; - static const String NORMAL_GROUP_TYPE = "normal_group_type"; - static const String TEXT_INPUT_RATIO_TYPE = "text_input_ratio_type"; + static const String starInputType = "star_input_type"; + static const String photoPickerType = "photo_picker_type"; + static const String expandGroupType = "expand_group_type"; + static const String normalGroupType = "normal_group_type"; + static const String textInputRatioType = "text_input_ratio_type"; - static const String TEXT_QUICK_SELECT_INPUT_TYPE = + static const String textQuickSelectInputType = "text_quick_select_input_type"; /// bottom类型 - static const String BOTTOM_BTN_TYPE = "bottom_btn_type"; + static const String bottomBtnType = "bottom_btn_type"; - static const String BTN_TYPE = "btn_type"; - static const String BTN_MULTI_TYPE = "btn_multi_type"; - static const String BTN_MULTI_STATE_TYPE = "btn_multi_state_type"; + static const String btnType = "btn_type"; + static const String btnMultiType = "btn_multi_type"; + static const String btnMultiStateType = "btn_multi_state_type"; - static const String LABEL_TITLE = "label_title"; - static const String LABEL_ADD = "label_add"; + static const String labelTitle = "label_title"; + static const String labelAdd = "label_add"; } class BrnInputType { - static const String TEXT = "text"; - static const String MULTI_LINE = "multiline"; - static const String NUMBER = "number"; - static const String DECIMAL = "decimal"; - static const String PHONE = "phone"; - static const String DATE = "datetime"; - static const String EMAIL = "emailAddress"; - static const String URL = "url"; - static const String PWD = "visiblePassword"; + static const String text = "text"; + static const String multiLine = "multiline"; + static const String number = "number"; + static const String decimal = "decimal"; + static const String phone = "phone"; + static const String date = "datetime"; + static const String email = "emailAddress"; + static const String url = "url"; + static const String pwd = "visiblePassword"; } diff --git a/lib/src/components/form/base/input_item_interface.dart b/lib/src/components/form/base/input_item_interface.dart index 7bfd14e5..757f960a 100644 --- a/lib/src/components/form/base/input_item_interface.dart +++ b/lib/src/components/form/base/input_item_interface.dart @@ -1,10 +1,13 @@ /// 用于model兼容回调 /// 主要用于各种点击事件 + + + typedef OnBrnFormSelectAll = void Function(int index, bool isSelect); /// 主要用于各种输入值变化 typedef OnBrnFormRadioValueChanged = void Function( - String oldStr, String newStr); + String? oldStr, String? newStr); typedef OnBrnFormSwitchChanged = void Function(bool oldValue, bool newValue); typedef OnBrnFormValueChanged = void Function(int oldValue, int newValue); typedef OnBrnFormMultiChoiceValueChanged = void Function( diff --git a/lib/src/components/form/items/general/brn_multi_choice_input_item.dart b/lib/src/components/form/items/general/brn_multi_choice_input_item.dart index 047176ef..1c632b54 100644 --- a/lib/src/components/form/items/general/brn_multi_choice_input_item.dart +++ b/lib/src/components/form/items/general/brn_multi_choice_input_item.dart @@ -1,8 +1,7 @@ -import 'package:bruno/bruno.dart'; import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; import 'package:bruno/src/components/form/base/input_item_interface.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; -import 'package:bruno/src/components/radio/brn_radio_core.dart'; +import 'package:bruno/src/components/radio/brn_checkbox.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:flutter/material.dart'; @@ -17,23 +16,23 @@ import 'package:flutter/widgets.dart'; // ignore: must_be_immutable class BrnMultiChoiceInputFormItem extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.MULTI_CHOICE_INPUT_TYPE; + final String type = BrnInputItemType.multiChoiceInputType; /// 录入项标题 final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类 final String prefixIconType; @@ -48,51 +47,51 @@ class BrnMultiChoiceInputFormItem extends StatefulWidget { final bool isEdit; /// 点击"+"图标回调 - final VoidCallback onAddTap; + final VoidCallback? onAddTap; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 特殊字段 - List value; + final List value; /// 内容 - List options; + final List options; /// 局部禁用list - List enableList; + final List enableList; /// 选项选中状态变化回调 - final OnBrnFormMultiChoiceValueChanged onChanged; + final OnBrnFormMultiChoiceValueChanged? onChanged; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnMultiChoiceInputFormItem( - {Key key, + {Key? key, this.label, - this.title: "", + this.title = "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, - this.error: "", - this.isEdit: true, - this.isRequire: true, + this.prefixIconType = BrnPrefixIconType.normal, + this.error = "", + this.isEdit = true, + this.isRequire = true, this.onAddTap, this.onRemoveTap, this.onTip, - this.value, - this.options, - this.enableList, + this.value = const [], + this.options = const [], + this.enableList = const [], this.onChanged, this.themeData}) - : super() { + : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -106,11 +105,10 @@ class BrnMultiChoiceInputFormItem extends StatefulWidget { class BrnMultiChoiceInputFormItemState extends State { // 标记选项的选中状态,内部变量无须初始化。初始化选中状态通过设置value字段设置 - List _selectStatus; + List _selectStatus = []; @override void initState() { - _initSpecialParams(); _initSelectedStatus(); super.initState(); } @@ -119,7 +117,7 @@ class BrnMultiChoiceInputFormItemState Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.itemEdgeInsets(widget.themeData), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -132,7 +130,7 @@ class BrnMultiChoiceInputFormItemState ), child: Container( padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, - widget.isRequire, widget.themeData), + widget.isRequire, widget.themeData!), child: Row( children: [ BrnFormUtil.buildPrefixIcon( @@ -143,9 +141,9 @@ class BrnMultiChoiceInputFormItemState widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), BrnFormUtil.buildTitleWidget( - widget.title, widget.themeData), + widget.title, widget.themeData!), BrnFormUtil.buildTipLabelWidget( - widget.tipLabel, widget.onTip, widget.themeData), + widget.tipLabel, widget.onTip, widget.themeData!), ], ), ), @@ -160,16 +158,16 @@ class BrnMultiChoiceInputFormItemState ), // 副标题 - BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), + BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData!), - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData) + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!) ], ), ); } - List getCheckboxList(List options) { - List result = List(); + List getCheckboxList(List? options) { + List result = []; if (options == null || options.isEmpty) { result.add(Container()); return result; @@ -179,7 +177,7 @@ class BrnMultiChoiceInputFormItemState final int pos = index; result.add( Container( - padding: BrnFormUtil.optionsMiddlePadding(widget.themeData), + padding: BrnFormUtil.optionsMiddlePadding(widget.themeData!), child: Row( children: [ BrnCheckbox( @@ -194,12 +192,12 @@ class BrnMultiChoiceInputFormItemState radioIndex: index, disable: getRadioEnableState(index), isSelected: - (_selectStatus != null && pos < _selectStatus.length) + (pos < _selectStatus.length) ? _selectStatus[pos] : false, onValueChangedAtIndex: (position, value) { _selectStatus[position] = value; - List oldValue = List()..addAll(widget.value); + List oldValue = []..addAll(widget.value); setState(() { widget.value.clear(); @@ -225,24 +223,23 @@ class BrnMultiChoiceInputFormItemState } TextStyle getOptionTextStyle(int index) { - TextStyle result = BrnFormUtil.getOptionTextStyle(widget.themeData); + TextStyle result = BrnFormUtil.getOptionTextStyle(widget.themeData!); if (index < 0 || index >= _selectStatus.length) { return result; } if (_selectStatus[index]) { - result = BrnFormUtil.getOptionSelectedTextStyle(widget.themeData); + result = BrnFormUtil.getOptionSelectedTextStyle(widget.themeData!); } if (!widget.isEdit) { - result = BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit); + result = BrnFormUtil.getIsEditTextStyle(widget.themeData!, widget.isEdit); } - if (widget.enableList != null && - widget.enableList.isNotEmpty && + if (widget.enableList.isNotEmpty && widget.enableList.length > index && !widget.enableList[index]) { - result = BrnFormUtil.getIsEditTextStyle(widget.themeData, false); + result = BrnFormUtil.getIsEditTextStyle(widget.themeData!, false); } return result; @@ -253,41 +250,23 @@ class BrnMultiChoiceInputFormItemState return true; } - if (widget.enableList == null || - widget.enableList.isEmpty || - widget.enableList.length < index) { + if (widget.enableList.isEmpty || widget.enableList.length < index) { return false; } return !widget.enableList[index]; } - void _initSpecialParams() { - if (widget.value == null) { - widget.value = List(); - } - - if (widget.options == null) { - widget.options = List(); - } - - if (widget.enableList == null) { - widget.enableList = List(); - } - } - void _initSelectedStatus() { - if (widget.options != null && widget.options.isNotEmpty) { - _selectStatus = List(widget.options.length); - } else { - _selectStatus = List(); + if (widget.options.isNotEmpty) { + _selectStatus = List.filled(widget.options.length, false); } for (int index = 0; index < _selectStatus.length; ++index) { _selectStatus[index] = false; } - if (widget.value == null || widget.value.isEmpty) { + if (widget.value.isEmpty) { return; } diff --git a/lib/src/components/form/items/general/brn_multi_choice_portrait_input_item.dart b/lib/src/components/form/items/general/brn_multi_choice_portrait_input_item.dart index c3a535a5..8ed2e616 100644 --- a/lib/src/components/form/items/general/brn_multi_choice_portrait_input_item.dart +++ b/lib/src/components/form/items/general/brn_multi_choice_portrait_input_item.dart @@ -3,7 +3,6 @@ import 'package:bruno/src/components/form/base/input_item_interface.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/components/line/brn_line.dart'; import 'package:bruno/src/components/radio/brn_checkbox.dart'; -import 'package:bruno/src/components/radio/brn_radio_core.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:flutter/material.dart'; @@ -18,23 +17,23 @@ import 'package:flutter/widgets.dart'; // ignore: must_be_immutable class BrnMultiChoicePortraitInputFormItem extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.MULTI_CHOICE_PORTRAIT_INPUT_TYPE; + String type = BrnInputItemType.multiChoicePortraitInputType; /// 录入项标题 final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类 final String prefixIconType; @@ -49,51 +48,51 @@ class BrnMultiChoicePortraitInputFormItem extends StatefulWidget { final bool isEdit; /// 点击"+"图标回调 - final VoidCallback onAddTap; + final VoidCallback? onAddTap; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 特殊字段 - List value; + final List value; /// 内容 - List options; + final List options; /// 局部禁用list - List enableList; + final List enableList; /// 选项选中状态变化回调 - final OnBrnFormMultiChoiceValueChanged onChanged; + final OnBrnFormMultiChoiceValueChanged? onChanged; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnMultiChoicePortraitInputFormItem( - {Key key, + {Key? key, this.label, - this.title: "", - this.subTitle, + this.title = "", + this.subTitle = "", this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, - this.error: "", - this.isEdit: true, - this.isRequire: false, + this.prefixIconType = BrnPrefixIconType.normal, + this.error = "", + this.isEdit = true, + this.isRequire = false, this.onAddTap, this.onRemoveTap, this.onTip, - this.value, - this.options, - this.enableList, + this.value = const [], + this.options = const [], + this.enableList = const [], this.onChanged, this.themeData}) - : super() { + : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -107,11 +106,10 @@ class BrnMultiChoicePortraitInputFormItem extends StatefulWidget { class BrnMultiChoicePortraitInputFormItemState extends State { // 标记选项的选中状态,内部变量无须初始化。初始化选中状态通过设置value字段设置 - List _selectStatus; + List _selectStatus = []; @override void initState() { - _initSpecialParams(); _initSelectedStatus(); super.initState(); } @@ -120,7 +118,7 @@ class BrnMultiChoicePortraitInputFormItemState Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.itemEdgeInsets(widget.themeData), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -133,7 +131,7 @@ class BrnMultiChoicePortraitInputFormItemState children: [ Container( padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, - widget.isRequire, widget.themeData), + widget.isRequire, widget.themeData!), child: Row( children: [ BrnFormUtil.buildPrefixIcon( @@ -144,9 +142,9 @@ class BrnMultiChoicePortraitInputFormItemState widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), BrnFormUtil.buildTitleWidget( - widget.title, widget.themeData), + widget.title, widget.themeData!), BrnFormUtil.buildTipLabelWidget( - widget.tipLabel, widget.onTip, widget.themeData), + widget.tipLabel, widget.onTip, widget.themeData!), ], ), ), @@ -155,9 +153,9 @@ class BrnMultiChoicePortraitInputFormItemState ), // 副标题 - BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), + BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData!), - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData), + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!), Container( padding: EdgeInsets.only(left: 20, top: 14), @@ -170,8 +168,8 @@ class BrnMultiChoicePortraitInputFormItemState ); } - List getCheckboxList(List options) { - List result = List(); + List getCheckboxList(List? options) { + List result = []; if (options == null || options.isEmpty) { result.add(Container()); return result; @@ -190,12 +188,12 @@ class BrnMultiChoicePortraitInputFormItemState mainAxisSize: MainAxisSize.max, radioIndex: index, disable: getRadioEnableState(index), - isSelected: (_selectStatus != null && index < _selectStatus.length) + isSelected: (index < _selectStatus.length) ? _selectStatus[index] : false, onValueChangedAtIndex: (position, value) { _selectStatus[position] = value; - List oldValue = List()..addAll(widget.value); + List oldValue = []..addAll(widget.value); setState(() { widget.value.clear(); @@ -219,69 +217,50 @@ class BrnMultiChoicePortraitInputFormItemState } TextStyle getOptionTextStyle(int index) { - TextStyle result = BrnFormUtil.getOptionTextStyle(widget.themeData); + TextStyle result = BrnFormUtil.getOptionTextStyle(widget.themeData!); if (index < 0 || index >= _selectStatus.length) { return result; } if (_selectStatus[index]) { - result = BrnFormUtil.getOptionSelectedTextStyle(widget.themeData); + result = BrnFormUtil.getOptionSelectedTextStyle(widget.themeData!); } - if (widget.isEdit != null && !widget.isEdit) { - result = BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit); + if (!widget.isEdit) { + result = BrnFormUtil.getIsEditTextStyle(widget.themeData!, widget.isEdit); } - if (widget.enableList != null && - widget.enableList.isNotEmpty && + if (widget.enableList.isNotEmpty && widget.enableList.length > index && !widget.enableList[index]) { - result = BrnFormUtil.getIsEditTextStyle(widget.themeData, false); + result = BrnFormUtil.getIsEditTextStyle(widget.themeData!, false); } return result; } bool getRadioEnableState(int index) { - if (widget.isEdit != null && !widget.isEdit) { + if (!widget.isEdit) { return true; } - if (widget.enableList == null || - widget.enableList.isEmpty || - widget.enableList.length < index) { + if (widget.enableList.isEmpty || widget.enableList.length < index) { return false; } return !widget.enableList[index]; } - void _initSpecialParams() { - if (widget.value == null) { - widget.value = List(); - } - - if (widget.options == null) { - widget.options = List(); - } - - if (widget.enableList == null) { - widget.enableList = List(); - } - } - void _initSelectedStatus() { - if (widget.options != null && widget.options.isNotEmpty) { - _selectStatus = List(widget.options.length); - } else { - _selectStatus = List(); + if (widget.options.isNotEmpty) { + _selectStatus = List.filled(widget.options.length, false); } for (int index = 0; index < _selectStatus.length; ++index) { _selectStatus[index] = false; } - if (widget.value == null || widget.value.isEmpty) { + if (widget.value.isEmpty) { return; } diff --git a/lib/src/components/form/items/general/brn_quick_select_input_item.dart b/lib/src/components/form/items/general/brn_quick_select_input_item.dart index beb94a87..dd594699 100644 --- a/lib/src/components/form/items/general/brn_quick_select_input_item.dart +++ b/lib/src/components/form/items/general/brn_quick_select_input_item.dart @@ -1,8 +1,10 @@ + + import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; -import 'package:bruno/src/utils/font/brn_font.dart'; +import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; @@ -17,23 +19,23 @@ import 'package:flutter/widgets.dart'; // ignore: must_be_immutable class BrnTextQuickSelectFormItem extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.TEXT_QUICK_SELECT_INPUT_TYPE; + String type = BrnInputItemType.textQuickSelectInputType; /// 录入项标题 final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类 final String prefixIconType; @@ -48,49 +50,49 @@ class BrnTextQuickSelectFormItem extends StatefulWidget { final bool isEdit; /// 点击"+"图标回调 - final VoidCallback onAddTap; + final VoidCallback? onAddTap; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 点击录入区回调 - final VoidCallback onTap; + final VoidCallback? onTap; - final ValueChanged onBtnSelectChanged; + final ValueChanged? onBtnSelectChanged; /// 录入项 hint 提示 final String hint; /// 录入项 值 - String value; + String? value; /// 快捷操作按钮选项文案列表 - List btnsTxt; + List? btnsTxt; /// 快捷按钮区的初始选中状态,可不传,则内部自动生成并维护 - List selectBtnList; + List? selectBtnList; /// 快捷按钮区的是否可用状态,可不传,内部生成并维护 - List enableBtnList; + List? enableBtnList; /// 用户自定义快捷按钮视图 - Widget btns; + Widget? btns; /// 快捷按钮较多时是否可滑动,默认为 fasle,不可滑动 final bool isBtnsScroll; - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnTextQuickSelectFormItem( - {Key key, + {Key? key, this.label, this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -110,7 +112,7 @@ class BrnTextQuickSelectFormItem extends StatefulWidget { : super(key: key) { themeData ??= BrnFormItemConfig(); themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) + .getConfig(configId: themeData!.configId) .formItemConfig .merge(themeData); } @@ -127,7 +129,7 @@ class BrnTextQuickSelectFormItemState Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.itemEdgeInsets(widget.themeData), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -139,7 +141,7 @@ class BrnTextQuickSelectFormItemState children: [ Container( padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, - widget.isRequire, widget.themeData), + widget.isRequire, widget.themeData!), child: Row( children: [ BrnFormUtil.buildPrefixIcon( @@ -154,11 +156,11 @@ class BrnTextQuickSelectFormItemState // 主标题 BrnFormUtil.buildTitleWidget( - widget.title, widget.themeData), + widget.title, widget.themeData!), // 问号提示 BrnFormUtil.buildTipLabelWidget( - widget.tipLabel, widget.onTip, widget.themeData), + widget.tipLabel, widget.onTip, widget.themeData!), ], ), ), @@ -172,7 +174,7 @@ class BrnTextQuickSelectFormItemState } if (widget.onTap != null) { - widget.onTap(); + widget.onTap!(); } }, child: Row( @@ -191,7 +193,7 @@ class BrnTextQuickSelectFormItemState ), // 副标题 - BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), + BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData!), /// 快捷按钮区 Container( @@ -208,24 +210,24 @@ class BrnTextQuickSelectFormItemState )), /// 错误提示 - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData) + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!) ], ), ); } Widget buildText() { - if (widget.value != null && widget.value.isNotEmpty) { + if (widget.value != null && widget.value!.isNotEmpty) { return Text( - widget.value, + widget.value!, textAlign: TextAlign.end, - style: BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit), + style: BrnFormUtil.getIsEditTextStyle(widget.themeData!, widget.isEdit), ); } else { return Text( widget.hint, textAlign: TextAlign.end, - style: BrnFormUtil.getHintTextStyle(widget.themeData), + style: BrnFormUtil.getHintTextStyle(widget.themeData!), ); } } @@ -233,23 +235,23 @@ class BrnTextQuickSelectFormItemState // ignore: must_be_immutable class QuickButtonsWidget extends StatefulWidget { - List btnsTxt; - List selectBtnList; - List enableBtnList; - Widget btns; - bool isBtnsScroll; + List? btnsTxt; + List? selectBtnList; + List? enableBtnList; + Widget? btns; + bool? isBtnsScroll; bool isEdit; - ValueChanged onBtnSelectChanged; + ValueChanged? onBtnSelectChanged; QuickButtonsWidget({ - Key key, + Key? key, this.btnsTxt, this.selectBtnList, this.enableBtnList, this.btns, this.isBtnsScroll, - this.isEdit: true, + this.isEdit = true, this.onBtnSelectChanged, }); @@ -287,16 +289,16 @@ class QuickButtonsState extends State { } if (widget.btnsTxt == null) { - widget.btnsTxt = List(); + widget.btnsTxt = []; } if (widget.selectBtnList == null) { _useInnerStatus = true; - widget.selectBtnList = List.filled(widget.btnsTxt.length, false); + widget.selectBtnList = List.filled(widget.btnsTxt!.length, false); } if (widget.enableBtnList == null) { - widget.enableBtnList = List.filled(widget.btnsTxt.length, true); + widget.enableBtnList = List.filled(widget.btnsTxt!.length, true); } } @@ -306,9 +308,9 @@ class QuickButtonsState extends State { } if (widget.btns != null) { - return widget.btns; + return widget.btns!; } else if (widget.btnsTxt != null) { - if (widget.isBtnsScroll) { + if (widget.isBtnsScroll!) { return ListView( scrollDirection: Axis.horizontal, children: getBtnsByText(), @@ -320,20 +322,15 @@ class QuickButtonsState extends State { ); } } else { - return Container(); + return SizedBox.shrink(); } } List getBtnsByText() { - List result = List(); - - for (int index = 0; index < widget.btnsTxt.length; ++index) { - String str = widget.btnsTxt[index]; - - if (str == null) { - continue; - } + List result = []; + for (int index = 0; index < widget.btnsTxt!.length; ++index) { + String? str = widget.btnsTxt![index]; result.add(Container( padding: EdgeInsets.fromLTRB(6, 0, 6, 0), child: FlatButton( @@ -344,22 +341,22 @@ class QuickButtonsState extends State { child: Text( str, style: TextStyle( - fontSize: BrnFont.FONT_12, + fontSize: BrnFonts.f12, ), ), onPressed: () { if (!widget.isEdit || (widget.enableBtnList != null && - !widget.enableBtnList[index])) { + !widget.enableBtnList![index])) { return; } if (widget.onBtnSelectChanged != null) { - widget.onBtnSelectChanged(index); + widget.onBtnSelectChanged!(index); } if (_useInnerStatus) { // 如果是内部维护的状态,需要改变按钮的状态 - widget.selectBtnList[index] = - widget.selectBtnList[index] ? false : true; + widget.selectBtnList![index] = + widget.selectBtnList![index] ? false : true; } setState(() {}); /* @@ -384,20 +381,20 @@ class QuickButtonsState extends State { } Color getButtonColor(int index) { - if (widget.btnsTxt != null && widget.btnsTxt.isEmpty) { + if (widget.btnsTxt != null && widget.btnsTxt!.isEmpty) { return Color(0xFFF8F8F8); } /// 这个按钮不可点击 if (widget.enableBtnList != null && - index < widget.enableBtnList.length && - !widget.enableBtnList[index]) { + index < widget.enableBtnList!.length && + !widget.enableBtnList![index]) { return Color(0xFFF8F8F8); } if (widget.selectBtnList != null && - index < widget.selectBtnList.length && - widget.selectBtnList[index]) { + index < widget.selectBtnList!.length && + widget.selectBtnList![index]) { return Color(0x1F0984F9); } else { return Color(0xFFF8F8F8); @@ -405,25 +402,25 @@ class QuickButtonsState extends State { } Color getBtnTextColor(int index) { - if (widget.btnsTxt != null && widget.btnsTxt.isEmpty) { + if (widget.btnsTxt != null && widget.btnsTxt!.isEmpty) { return Color(0xFF222222); } /// 这个按钮不可点击 if (widget.enableBtnList != null && - index < widget.enableBtnList.length && - !widget.enableBtnList[index]) { + index < widget.enableBtnList!.length && + !widget.enableBtnList![index]) { return Color(0xFF999999); } if (widget.selectBtnList == null || - widget.selectBtnList.length != widget.btnsTxt.length) { + widget.selectBtnList!.length != widget.btnsTxt!.length) { return Color(0xFF222222); } if (widget.selectBtnList != null && - index < widget.selectBtnList.length && - widget.selectBtnList[index]) { + index < widget.selectBtnList!.length && + widget.selectBtnList![index]) { return Color(0xFF0984F9); } else { return Color(0xFF222222); diff --git a/lib/src/components/form/items/general/brn_radio_input_item.dart b/lib/src/components/form/items/general/brn_radio_input_item.dart index de7bdffc..b13c7eba 100644 --- a/lib/src/components/form/items/general/brn_radio_input_item.dart +++ b/lib/src/components/form/items/general/brn_radio_input_item.dart @@ -1,9 +1,11 @@ + + import 'dart:math'; -import 'package:bruno/bruno.dart'; import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; import 'package:bruno/src/components/form/base/input_item_interface.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; +import 'package:bruno/src/components/radio/brn_radio_button.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:flutter/material.dart'; @@ -15,25 +17,26 @@ import 'package:flutter/widgets.dart'; /// 包括"标题"、"副标题"、"错误信息提示"、"必填项提示"、"添加/删除按钮"、"消息提示"、 /// "单选项"等元素 /// -// ignore: must_be_immutable2 + +// ignore: must_be_immutable class BrnRadioInputFormItem extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.RADIO_INPUT_TYPE; + final String type = BrnInputItemType.radioInputType; /// 录入项标题 final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项,默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类 final String prefixIconType; @@ -48,46 +51,46 @@ class BrnRadioInputFormItem extends StatefulWidget { final bool isEdit; /// 点击"+"图标回调 - final VoidCallback onAddTap; + final VoidCallback? onAddTap; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 录入项 值 - String value; + String? value; /// 选项 - List options; + List? options; /// 局部禁用list - List enableList; + List? enableList; /// 选项选中状态变化回调 - final OnBrnFormRadioValueChanged onChanged; + final OnBrnFormRadioValueChanged? onChanged; /// 标题显示的最大行数,默认值 1 - final int titleMaxLines; + final int? titleMaxLines; /// 左边标题部分/右边选项部分的宽度比例。例如 1/2 显示就传 0.5。 /// 右边选项部分的显示宽度 = min(选项部分的实际宽度, 选项部分的比例计算宽度) - double layoutRatio; + double? layoutRatio; /// 是否自动布局 - bool _isAutoLayout; + bool? _isAutoLayout; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnRadioInputFormItem({ - Key key, + Key? key, this.label, this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -103,19 +106,19 @@ class BrnRadioInputFormItem extends StatefulWidget { }) : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); this._isAutoLayout = false; } BrnRadioInputFormItem.autoLayout({ - Key key, + Key? key, this.label, this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -133,7 +136,7 @@ class BrnRadioInputFormItem extends StatefulWidget { this._isAutoLayout = true; this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -146,13 +149,13 @@ class BrnRadioInputFormItem extends StatefulWidget { class BrnRadioInputFormItemState extends State { double _kRadioTitleLeftPadding = 6; - double _kRadionIconWidth = 16; + double _kRadioIconWidth = 16; @override Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.itemEdgeInsets(widget.themeData), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -160,10 +163,10 @@ class BrnRadioInputFormItemState extends State { ? _buildAutoLayoutTitleWidget(context) : _buildTitleWidget(context), // 副标题 - BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), + BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData!), // 错误提示 - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData) + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!) ], ), ); @@ -172,7 +175,7 @@ class BrnRadioInputFormItemState extends State { double _getTitleMaxWidth(BuildContext context, BoxConstraints constraints) { // 计算表单右边部分的宽度 double contentRatio = BrnFormUtil.getAutoLayoutContentRatio( - tipLabelHidden: widget.tipLabel == null || widget.tipLabel.isEmpty, + tipLabelHidden: widget.tipLabel == null || widget.tipLabel!.isEmpty, layoutRatio: widget.layoutRatio); double ratioWidth = constraints.maxWidth * contentRatio; double maxWidth = min(ratioWidth, _calculateTextWidth(context)); @@ -189,7 +192,7 @@ class BrnRadioInputFormItemState extends State { Flexible( child: Container( padding: BrnFormUtil.titleEdgeInsets( - widget.prefixIconType, widget.isRequire, widget.themeData), + widget.prefixIconType, widget.isRequire, widget.themeData!), child: Row( children: [ BrnFormUtil.buildPrefixIcon( @@ -224,7 +227,7 @@ class BrnRadioInputFormItemState extends State { child: GestureDetector( onTap: () { if (widget.onTip != null) { - widget.onTip(); + widget.onTip!(); } }, child: Row( @@ -241,7 +244,7 @@ class BrnRadioInputFormItemState extends State { child: Text( widget.tipLabel ?? "", overflow: TextOverflow.ellipsis, - style: BrnFormUtil.getTipsTextStyle(widget.themeData), + style: BrnFormUtil.getTipsTextStyle(widget.themeData!), ), ), ], @@ -260,22 +263,14 @@ class BrnRadioInputFormItemState extends State { /// 计算Text所占宽度 double _calculateTextWidth(BuildContext context) { - List options; - if (widget.options.isNotEmpty ?? false) { - // 模型里边的数据 - options = widget.options; - } else if (widget.options.isNotEmpty ?? false) { - // widget 里边的数据 - options = widget.options; - } - + List? options = widget.options; // 计算所有备选文案的文字长度 double totalTextWidth = 0; - if (options.isNotEmpty ?? false) { + if (options != null && options.isNotEmpty) { int idx = -1; - for (String item in options) { + for (String? item in options) { idx += 1; - TextStyle optionStyle = getOptionTextStyle(item, idx); + TextStyle? optionStyle = getOptionTextStyle(item, idx); TextPainter painter = TextPainter( locale: Localizations.localeOf(context), textAlign: TextAlign.start, @@ -286,9 +281,9 @@ class BrnRadioInputFormItemState extends State { // 6 是备选文案和单选按钮之间的间距 // 16 是 radio 按钮的宽度 double optionWidth = painter.width + - BrnFormUtil.optionsMiddlePadding(widget.themeData).left + + BrnFormUtil.optionsMiddlePadding(widget.themeData!)!.left + _kRadioTitleLeftPadding + - _kRadionIconWidth; + _kRadioIconWidth; totalTextWidth += optionWidth; } } @@ -296,12 +291,12 @@ class BrnRadioInputFormItemState extends State { } Widget _buildTitleTextWidget() { - return Text(widget.title ?? "", + return Text(widget.title , overflow: widget.titleMaxLines == null ? TextOverflow.clip : TextOverflow.ellipsis, maxLines: widget.titleMaxLines, - style: BrnFormUtil.getTitleTextStyle(widget.themeData)); + style: BrnFormUtil.getTitleTextStyle(widget.themeData!)); } Row _buildTitleWidget(BuildContext context) { @@ -314,7 +309,7 @@ class BrnRadioInputFormItemState extends State { ), child: Container( padding: BrnFormUtil.titleEdgeInsets( - widget.prefixIconType, widget.isRequire, widget.themeData), + widget.prefixIconType, widget.isRequire, widget.themeData!), child: Row( children: [ // 添加/删除图标 @@ -345,9 +340,9 @@ class BrnRadioInputFormItemState extends State { ); } - List getRadioList(List options) { - List result = List(); - String option; + List getRadioList(List? options) { + List result = []; + String? option; if (options == null || options.isEmpty) { result.add(Container()); return result; @@ -358,7 +353,7 @@ class BrnRadioInputFormItemState extends State { result.add( Container( - padding: BrnFormUtil.optionsMiddlePadding(widget.themeData), + padding: BrnFormUtil.optionsMiddlePadding(widget.themeData!), child: Row( children: [ BrnRadioButton( @@ -371,13 +366,13 @@ class BrnRadioInputFormItemState extends State { )), disable: getRadioEnableState(index), radioIndex: index, - isSelected: index == widget.options.indexOf(widget.value), + isSelected: index == widget.options!.indexOf(widget.value ?? ''), onValueChangedAtIndex: (int position, bool selected) { if (getRadioEnableState(position)) { return; } - String oldValue = widget.value; + String? oldValue = widget.value; widget.value = options[index]; BrnFormUtil.notifyRadioStatusChanged( widget.onChanged, context, oldValue, widget.value); @@ -393,25 +388,25 @@ class BrnRadioInputFormItemState extends State { return result; } - TextStyle getOptionTextStyle(String opt, int index) { - TextStyle result = BrnFormUtil.getOptionTextStyle(widget.themeData); + TextStyle getOptionTextStyle(String? opt, int index) { + TextStyle result = BrnFormUtil.getOptionTextStyle(widget.themeData!); if (opt == null) { return result; } if (opt == widget.value) { - result = BrnFormUtil.getOptionSelectedTextStyle(widget.themeData); + result = BrnFormUtil.getOptionSelectedTextStyle(widget.themeData!); } if (!widget.isEdit) { - result = BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit); + result = BrnFormUtil.getIsEditTextStyle(widget.themeData!, widget.isEdit); } if (widget.enableList != null && - widget.enableList.isNotEmpty && - widget.enableList.length > index && - !widget.enableList[index]) { - result = BrnFormUtil.getIsEditTextStyle(widget.themeData, false); + widget.enableList!.isNotEmpty && + widget.enableList!.length > index && + !widget.enableList![index]) { + result = BrnFormUtil.getIsEditTextStyle(widget.themeData!, false); } return result; @@ -423,11 +418,11 @@ class BrnRadioInputFormItemState extends State { } if (widget.enableList == null || - widget.enableList.isEmpty || - widget.enableList.length < index) { + widget.enableList!.isEmpty || + widget.enableList!.length < index) { return false; } - return !widget.enableList[index]; + return !widget.enableList![index]; } } diff --git a/lib/src/components/form/items/general/brn_radio_portrait_input_item.dart b/lib/src/components/form/items/general/brn_radio_portrait_input_item.dart index 7d9f2ecb..3a446f72 100644 --- a/lib/src/components/form/items/general/brn_radio_portrait_input_item.dart +++ b/lib/src/components/form/items/general/brn_radio_portrait_input_item.dart @@ -1,9 +1,10 @@ + + import 'package:bruno/bruno.dart'; import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; import 'package:bruno/src/components/form/base/input_item_interface.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/components/line/brn_line.dart'; -import 'package:bruno/src/components/radio/brn_radio_core.dart'; import 'package:bruno/src/theme/brn_theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; @@ -17,23 +18,23 @@ import 'package:flutter/widgets.dart'; // ignore: must_be_immutable class BrnRadioPortraitInputFormItem extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.RADIO_INPUT_TYPE; + String type = BrnInputItemType.radioInputType; /// 录入项标题 final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类 final String prefixIconType; @@ -48,36 +49,36 @@ class BrnRadioPortraitInputFormItem extends StatefulWidget { final bool isEdit; /// 点击"+"图标回调 - final VoidCallback onAddTap; + final VoidCallback? onAddTap; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 录入项 值 - String value; + String? value; /// 选项 - List options; + List? options; /// 局部禁用list - List enableList; + List? enableList; /// 选项选中状态变化回调 - final OnBrnFormRadioValueChanged onChanged; + final OnBrnFormRadioValueChanged? onChanged; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnRadioPortraitInputFormItem( - {Key key, + {Key? key, this.label, this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -92,7 +93,7 @@ class BrnRadioPortraitInputFormItem extends StatefulWidget { : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -109,7 +110,7 @@ class BrnRadioPortraitInputFormItemState Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.itemEdgeInsets(widget.themeData), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -122,7 +123,7 @@ class BrnRadioPortraitInputFormItemState children: [ Container( padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, - widget.isRequire, widget.themeData), + widget.isRequire, widget.themeData!), child: Row( children: [ BrnFormUtil.buildPrefixIcon( @@ -133,9 +134,9 @@ class BrnRadioPortraitInputFormItemState widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), BrnFormUtil.buildTitleWidget( - widget.title, widget.themeData), + widget.title, widget.themeData!), BrnFormUtil.buildTipLabelWidget( - widget.tipLabel, widget.onTip, widget.themeData), + widget.tipLabel, widget.onTip, widget.themeData!), ], ), ), @@ -144,9 +145,9 @@ class BrnRadioPortraitInputFormItemState ), // 副标题 - BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), + BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData!), - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData), + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!), Container( padding: EdgeInsets.only(left: 20, top: 14), @@ -159,9 +160,9 @@ class BrnRadioPortraitInputFormItemState ); } - List getRadioList(List options) { - List result = List(); - String option; + List getRadioList(List? options) { + List result = []; + String? option; if (options == null || options.isEmpty) { result.add(Container()); return result; @@ -176,7 +177,7 @@ class BrnRadioPortraitInputFormItemState padding: EdgeInsets.only(top: 14, bottom: 14), child: BrnRadioButton( child: Text( - option, + option!, style: getOptionTextStyle(option, index), ), childOnRight: false, @@ -184,12 +185,12 @@ class BrnRadioPortraitInputFormItemState mainAxisSize: MainAxisSize.max, disable: getRadioEnableState(index), radioIndex: index, - isSelected: index == widget.options.indexOf(widget.value), + isSelected: index == widget.options!.indexOf(widget.value ?? ''), onValueChangedAtIndex: (int position, bool isSelected) { if (getRadioEnableState(position)) { return; } - String oldValue = widget.value; + String? oldValue = widget.value; widget.value = options[position]; BrnFormUtil.notifyRadioStatusChanged( widget.onChanged, context, oldValue, widget.value); @@ -205,25 +206,25 @@ class BrnRadioPortraitInputFormItemState return result; } - TextStyle getOptionTextStyle(String opt, int index) { - TextStyle result = BrnFormUtil.getOptionTextStyle(widget.themeData); - if (opt == null /*|| widget.value == null*/) { + TextStyle getOptionTextStyle(String? opt, int index) { + TextStyle result = BrnFormUtil.getOptionTextStyle(widget.themeData!); + if (opt == null) { return result; } if (opt == widget.value) { - result = BrnFormUtil.getOptionSelectedTextStyle(widget.themeData); + result = BrnFormUtil.getOptionSelectedTextStyle(widget.themeData!); } - if (widget.isEdit != null && !widget.isEdit) { - result = BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit); + if (!widget.isEdit) { + result = BrnFormUtil.getIsEditTextStyle(widget.themeData!, widget.isEdit); } if (widget.enableList != null && - widget.enableList.isNotEmpty && - widget.enableList.length > index && - !widget.enableList[index]) { - result = BrnFormUtil.getIsEditTextStyle(widget.themeData, false); + widget.enableList!.isNotEmpty && + widget.enableList!.length > index && + !widget.enableList![index]) { + result = BrnFormUtil.getIsEditTextStyle(widget.themeData!, false); } return result; @@ -235,11 +236,11 @@ class BrnRadioPortraitInputFormItemState } if (widget.enableList == null || - widget.enableList.isEmpty || - widget.enableList.length < index) { + widget.enableList!.isEmpty || + widget.enableList!.length < index) { return false; } - return !widget.enableList[index]; + return !widget.enableList![index]; } } diff --git a/lib/src/components/form/items/general/brn_range_input_item.dart b/lib/src/components/form/items/general/brn_range_input_item.dart index 8f6eb958..00d4d1ea 100644 --- a/lib/src/components/form/items/general/brn_range_input_item.dart +++ b/lib/src/components/form/items/general/brn_range_input_item.dart @@ -1,12 +1,12 @@ + + import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; -import 'package:bruno/src/components/form/base/input_item_interface.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; -import 'package:bruno/src/utils/font/brn_font.dart'; +import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; /// /// 范围输入型录入项 @@ -14,25 +14,26 @@ import 'package:flutter/widgets.dart'; /// 包括"标题"、"副标题"、"错误信息提示"、"必填项提示"、"添加/删除按钮"、"消息提示"、 /// "输入框"等元素 /// +// ignore: must_be_immutable class BrnRangeInputFormItem extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.TEXT_RANGE_INPUT_TYPE; + String type = BrnInputItemType.textRangeInputType; /// 录入项标题 final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类 final String prefixIconType; @@ -52,13 +53,13 @@ class BrnRangeInputFormItem extends StatefulWidget { final bool isPrefixIconEnabled; /// 点击"+"图标回调 - final VoidCallback onAddTap; + final VoidCallback? onAddTap; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 最小值提示语 final String hintMin; @@ -67,41 +68,41 @@ class BrnRangeInputFormItem extends StatefulWidget { final String hintMax; /// 最小值单位 - final String minUnit; + final String? minUnit; /// 最大值单位 - final String maxUnit; + final String? maxUnit; /// 最小值输入框最大字符数 - final int leftMaxCount; + final int? leftMaxCount; /// 最大值输入框最大字符数 - final int rightMaxCount; + final int? rightMaxCount; /// 输入内容类型,参见[BrnInputType] - final String inputType; + final String? inputType; - final TextEditingController minController; - final TextEditingController maxController; - List minInputFormatters; - List maxInputFormatters; + final TextEditingController? minController; + final TextEditingController? maxController; + List? minInputFormatters; + List? maxInputFormatters; /// 最小值输入回调 - final ValueChanged onMinChanged; + final ValueChanged? onMinChanged; /// 最大值输入回调 - final ValueChanged onMaxChanged; + final ValueChanged? onMaxChanged; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnRangeInputFormItem( - {Key key, + {Key? key, this.label, this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -109,8 +110,8 @@ class BrnRangeInputFormItem extends StatefulWidget { this.onAddTap, this.onRemoveTap, this.onTip, - this.hintMin: "请输入", - this.hintMax: "请输入", + this.hintMin: '最小', + this.hintMax: '最大', this.minUnit, this.maxUnit, this.leftMaxCount, @@ -126,7 +127,7 @@ class BrnRangeInputFormItem extends StatefulWidget { : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -138,15 +139,13 @@ class BrnRangeInputFormItem extends StatefulWidget { } class BrnRangeInputFormItemState extends State { - TextEditingController _minController; - TextEditingController _maxController; - - BrnFormItemConfig config; + late TextEditingController _minController; + late TextEditingController _maxController; + late BrnFormItemConfig config; @override void initState() { config = BrnThemeConfigurator.instance.getConfig().formItemConfig; - _minController = widget.minController ?? TextEditingController(); _maxController = widget.maxController ?? TextEditingController(); @@ -157,7 +156,7 @@ class BrnRangeInputFormItemState extends State { Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.itemEdgeInsets(widget.themeData), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -170,7 +169,7 @@ class BrnRangeInputFormItemState extends State { children: [ Container( padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, - widget.isRequire, widget.themeData), + widget.isRequire, widget.themeData!), child: Row( children: [ BrnFormUtil.buildPrefixIcon( @@ -181,9 +180,9 @@ class BrnRangeInputFormItemState extends State { widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), BrnFormUtil.buildTitleWidget( - widget.title, widget.themeData), + widget.title, widget.themeData!), BrnFormUtil.buildTipLabelWidget( - widget.tipLabel, widget.onTip, widget.themeData), + widget.tipLabel, widget.onTip, widget.themeData!), ], ), ), @@ -202,12 +201,12 @@ class BrnRangeInputFormItemState extends State { maxLines: 1, maxLength: widget.leftMaxCount, style: BrnFormUtil.getIsEditTextStyle( - widget.themeData, widget.isEdit), + widget.themeData!, widget.isEdit), decoration: InputDecoration( border: InputBorder.none, hintStyle: - BrnFormUtil.getHintTextStyle(widget.themeData), - hintText: widget.hintMin ?? '最小', + BrnFormUtil.getHintTextStyle(widget.themeData!), + hintText: widget.hintMin, counterText: "", contentPadding: EdgeInsets.all(0), isDense: true, @@ -233,7 +232,7 @@ class BrnRangeInputFormItemState extends State { widget.minUnit ?? "", style: TextStyle( color: Color(0xFF101010), - fontSize: BrnFont.FONT_16, + fontSize: BrnFonts.f16, ), )), Container( @@ -242,7 +241,7 @@ class BrnRangeInputFormItemState extends State { "—", style: TextStyle( color: Color(0xFF101010), - fontSize: BrnFont.FONT_16, + fontSize: BrnFonts.f16, ), )), Container( @@ -257,12 +256,12 @@ class BrnRangeInputFormItemState extends State { maxLines: 1, maxLength: widget.rightMaxCount, style: BrnFormUtil.getIsEditTextStyle( - widget.themeData, widget.isEdit), + widget.themeData!, widget.isEdit), decoration: InputDecoration( border: InputBorder.none, hintStyle: - BrnFormUtil.getHintTextStyle(widget.themeData), - hintText: widget.hintMax ?? '最大', + BrnFormUtil.getHintTextStyle(widget.themeData!), + hintText: widget.hintMax, counterText: "", contentPadding: EdgeInsets.all(0), isDense: true, @@ -288,7 +287,7 @@ class BrnRangeInputFormItemState extends State { widget.maxUnit ?? "", style: TextStyle( color: Color(0xFF101010), - fontSize: BrnFont.FONT_16, + fontSize: BrnFonts.f16, ), )), ], @@ -298,9 +297,9 @@ class BrnRangeInputFormItemState extends State { ), // 副标题 - BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), + BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData!), - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData) + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!) ], ), ); @@ -310,11 +309,7 @@ class BrnRangeInputFormItemState extends State { void dispose() { super.dispose(); // 如果controller由外部创建不需要销毁, 若由内部创建则需要销毁 - if (widget.minController == null) { - _minController?.dispose(); - } - if (widget.maxController == null) { - _maxController?.dispose(); - } + _minController.dispose(); + _maxController.dispose(); } } diff --git a/lib/src/components/form/items/general/brn_ratio_input_item.dart b/lib/src/components/form/items/general/brn_ratio_input_item.dart index 266f70aa..2a5c1293 100644 --- a/lib/src/components/form/items/general/brn_ratio_input_item.dart +++ b/lib/src/components/form/items/general/brn_ratio_input_item.dart @@ -1,5 +1,6 @@ + + import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; -import 'package:bruno/src/components/form/base/input_item_interface.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; @@ -16,23 +17,23 @@ import 'package:flutter/widgets.dart'; // ignore: must_be_immutable class BrnRatioInputFormItem extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.TEXT_INPUT_RATIO_TYPE; + String type = BrnInputItemType.textInputRatioType; /// 录入项标题 final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类 final String prefixIconType; @@ -52,35 +53,35 @@ class BrnRatioInputFormItem extends StatefulWidget { final bool isPrefixIconEnabled; /// 点击"+"图标回调 - final VoidCallback onAddTap; + final VoidCallback? onAddTap; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; ///内容 final String hint; /// 输入内容类型 - final String inputType; - final TextEditingController controller; - List inputFormatters; + final String? inputType; + final TextEditingController? controller; + List? inputFormatters; /// 输入回调 - final ValueChanged onChanged; + final ValueChanged? onChanged; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnRatioInputFormItem( - {Key key, + {Key? key, this.label, this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -97,7 +98,7 @@ class BrnRatioInputFormItem extends StatefulWidget { : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -109,12 +110,11 @@ class BrnRatioInputFormItem extends StatefulWidget { } class BrnRatioInputFormItemState extends State { - TextEditingController _controller; + late TextEditingController _controller; @override void initState() { _controller = widget.controller ?? TextEditingController(); - super.initState(); } @@ -122,7 +122,7 @@ class BrnRatioInputFormItemState extends State { Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.itemEdgeInsets(widget.themeData), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -135,7 +135,7 @@ class BrnRatioInputFormItemState extends State { children: [ Container( padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, - widget.isRequire, widget.themeData), + widget.isRequire, widget.themeData!), child: Row( children: [ BrnFormUtil.buildPrefixIcon( @@ -146,9 +146,9 @@ class BrnRatioInputFormItemState extends State { widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), BrnFormUtil.buildTitleWidget( - widget.title, widget.themeData), + widget.title, widget.themeData!), BrnFormUtil.buildTipLabelWidget( - widget.tipLabel, widget.onTip, widget.themeData), + widget.tipLabel, widget.onTip, widget.themeData!), ], ), ), @@ -159,7 +159,7 @@ class BrnRatioInputFormItemState extends State { child: Text( "1 : ", style: - BrnFormUtil.getTitleTextStyle(widget.themeData), + BrnFormUtil.getTitleTextStyle(widget.themeData!), )), Container( width: 60, @@ -169,13 +169,13 @@ class BrnRatioInputFormItemState extends State { enabled: widget.isEdit, maxLines: 1, style: BrnFormUtil.getIsEditTextStyle( - widget.themeData, widget.isEdit), + widget.themeData!, widget.isEdit), inputFormatters: widget.inputFormatters, decoration: InputDecoration( border: InputBorder.none, hintStyle: - BrnFormUtil.getHintTextStyle(widget.themeData), - hintText: widget.hint ?? '请输入', + BrnFormUtil.getHintTextStyle(widget.themeData!), + hintText: widget.hint, counterText: "", contentPadding: EdgeInsets.all(0), isDense: true, @@ -201,9 +201,9 @@ class BrnRatioInputFormItemState extends State { ), // 副标题 - BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), + BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData!), - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData) + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!) ], ), ); @@ -213,8 +213,6 @@ class BrnRatioInputFormItemState extends State { void dispose() { super.dispose(); // 如果controller由外部创建不需要销毁, 若由内部创建则需要销毁 - if (widget.controller == null) { - _controller?.dispose(); - } + _controller.dispose(); } } diff --git a/lib/src/components/form/items/general/brn_star_input_item.dart b/lib/src/components/form/items/general/brn_star_input_item.dart index 6b15bf7d..b19cf5ab 100644 --- a/lib/src/components/form/items/general/brn_star_input_item.dart +++ b/lib/src/components/form/items/general/brn_star_input_item.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; import 'package:bruno/src/components/form/base/input_item_interface.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; @@ -17,23 +19,23 @@ import 'package:flutter/widgets.dart'; // ignore: must_be_immutable class BrnStarsFormItem extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.STAR_INPUT_TYPE; + String type = BrnInputItemType.starInputType; /// 录入项标题 final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类 final String prefixIconType; @@ -48,13 +50,13 @@ class BrnStarsFormItem extends StatefulWidget { final bool isEdit; /// 点击"+"图标回调 - final VoidCallback onAddTap; + final VoidCallback? onAddTap; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 特有字段 int value; @@ -63,18 +65,18 @@ class BrnStarsFormItem extends StatefulWidget { final int sumStar; /// 星值数量变化回调 - final OnBrnFormValueChanged onChanged; + final OnBrnFormValueChanged? onChanged; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnStarsFormItem( - {Key key, + {Key? key, this.label, this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -85,10 +87,10 @@ class BrnStarsFormItem extends StatefulWidget { this.value: 0, this.onChanged, this.themeData}) - : super() { + : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -100,13 +102,13 @@ class BrnStarsFormItem extends StatefulWidget { } class BrnStarsFormItemState extends State { - List _result = List(); + List _result = []; @override Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.itemEdgeInsets(widget.themeData), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -115,7 +117,7 @@ class BrnStarsFormItemState extends State { children: [ Container( padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, - widget.isRequire, widget.themeData), + widget.isRequire, widget.themeData!), child: ConstrainedBox( constraints: BoxConstraints( maxHeight: 25, @@ -130,9 +132,9 @@ class BrnStarsFormItemState extends State { widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), BrnFormUtil.buildTitleWidget( - widget.title, widget.themeData), + widget.title, widget.themeData!), BrnFormUtil.buildTipLabelWidget( - widget.tipLabel, widget.onTip, widget.themeData), + widget.tipLabel, widget.onTip, widget.themeData!), ], ))), Row( @@ -143,9 +145,9 @@ class BrnStarsFormItemState extends State { ), // 副标题 - BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), + BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData!), - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData) + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!) ], ), ); @@ -182,22 +184,18 @@ class BrnStarsFormItemState extends State { } bool isEnable() { - if (widget.isEdit == null) { - return true; - } - return widget.isEdit; } Image getStar(int index, int selectCount, int sum) { if (selectCount <= 0) { - return BrunoTools.getAssetImage(BrnAsset.ICON_STAR_UNSELECT); + return BrunoTools.getAssetImage(BrnAsset.iconStarUnSelect); } if (index < selectCount) { - return BrunoTools.getAssetImage(BrnAsset.ICON_STAR_SELECT); + return BrunoTools.getAssetImage(BrnAsset.iconStarSelect); } - return BrunoTools.getAssetImage(BrnAsset.ICON_STAR_UNSELECT); + return BrunoTools.getAssetImage(BrnAsset.iconStarUnSelect); } } diff --git a/lib/src/components/form/items/general/brn_step_input_item.dart b/lib/src/components/form/items/general/brn_step_input_item.dart index 8af51c31..f6c48048 100644 --- a/lib/src/components/form/items/general/brn_step_input_item.dart +++ b/lib/src/components/form/items/general/brn_step_input_item.dart @@ -5,7 +5,7 @@ import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; -import 'package:bruno/src/utils/font/brn_font.dart'; +import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; @@ -15,25 +15,26 @@ import 'package:flutter/widgets.dart'; /// 包括"标题"、"副标题"、"错误信息提示"、"必填项提示"、"添加/删除按钮"、"消息提示"、 /// "递增/递减按钮"等元素 /// +// ignore: must_be_immutable class BrnStepInputFormItem extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.TEXT_STEP_INPUT_TYPE; + final String type = BrnInputItemType.textStepInputType; /// 录入项标题 final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类 final String prefixIconType; @@ -48,16 +49,16 @@ class BrnStepInputFormItem extends StatefulWidget { final bool isEdit; /// 点击"+"图标回调 - final VoidCallback onAddTap; + final VoidCallback? onAddTap; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 特有字段 - int value; + final int? value; /// 单步上限值 final int maxLimit; @@ -66,33 +67,34 @@ class BrnStepInputFormItem extends StatefulWidget { final int minLimit; /// 当前值变化回调 - final OnBrnFormValueChanged onChanged; + final OnBrnFormValueChanged? onChanged; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnStepInputFormItem({ - Key key, + Key? key, this.label, - this.title: "", + this.title = "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, - this.error: "", - this.isEdit: true, - this.isRequire: false, + this.prefixIconType = BrnPrefixIconType.normal, + this.error = "", + this.isEdit = true, + this.isRequire = false, this.onAddTap, this.onRemoveTap, this.onTip, - this.value: 0, - this.maxLimit: 10, - this.minLimit: 0, + this.value, + this.maxLimit = 10, + this.minLimit = 0, this.onChanged, this.themeData, - }) : super(key: key) { + }) : assert(value == null || value >= minLimit && value <= maxLimit), + super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -104,11 +106,19 @@ class BrnStepInputFormItem extends StatefulWidget { } class BrnStepInputFormItemState extends State { + late int _value; + + @override + void initState() { + super.initState(); + _value = widget.value ?? widget.minLimit; + } + @override Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.itemEdgeInsets(widget.themeData), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -121,7 +131,7 @@ class BrnStepInputFormItemState extends State { children: [ Container( padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, - widget.isRequire, widget.themeData), + widget.isRequire, widget.themeData!), child: Row( children: [ BrnFormUtil.buildPrefixIcon( @@ -132,9 +142,9 @@ class BrnStepInputFormItemState extends State { widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), BrnFormUtil.buildTitleWidget( - widget.title, widget.themeData), + widget.title, widget.themeData!), BrnFormUtil.buildTipLabelWidget( - widget.tipLabel, widget.onTip, widget.themeData), + widget.tipLabel, widget.onTip, widget.themeData!), ], ), ), @@ -151,18 +161,10 @@ class BrnStepInputFormItemState extends State { return; } - if (widget.value == null) { - widget.value = 1; - BrnFormUtil.notifyValueChanged(widget.onChanged, - context, widget.value + 1, widget.value); - setState(() {}); - return; - } - if (!isReachMinLevel()) { - widget.value = widget.value - 1; - BrnFormUtil.notifyValueChanged(widget.onChanged, - context, widget.value + 1, widget.value); + _value = _value - 1; + BrnFormUtil.notifyValueChanged( + widget.onChanged, context, _value + 1, _value); setState(() {}); } }, @@ -174,10 +176,10 @@ class BrnStepInputFormItemState extends State { alignment: Alignment.center, width: 50, child: Text( - "${widget.value}", + "$_value", style: TextStyle( color: Color(0xFF222222), - fontSize: BrnFont.FONT_16, + fontSize: BrnFonts.f16, ), ), ), @@ -191,18 +193,10 @@ class BrnStepInputFormItemState extends State { return; } - if (widget.value == null) { - widget.value = 1; - BrnFormUtil.notifyValueChanged(widget.onChanged, - context, widget.value - 1, widget.value); - setState(() {}); - return; - } - if (!isReachMaxLevel()) { - widget.value = widget.value + 1; - BrnFormUtil.notifyValueChanged(widget.onChanged, - context, widget.value - 1, widget.value); + _value = _value + 1; + BrnFormUtil.notifyValueChanged( + widget.onChanged, context, _value - 1, _value); setState(() {}); } }, @@ -217,71 +211,53 @@ class BrnStepInputFormItemState extends State { ), // 副标题 - BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), + BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData!), - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData) + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!) ], ), ); } bool isEnable() { - if (widget.isEdit == null) { - return true; - } - return widget.isEdit; } Image getAddIcon() { - if (widget.isEdit != null && !widget.isEdit) { - return BrunoTools.getAssetImage(BrnAsset.ICON_ADD_DISABLE); + if (!widget.isEdit) { + return BrunoTools.getAssetImage(BrnAsset.iconAddDisable); } if (isReachMaxLevel()) { - return BrunoTools.getAssetImage(BrnAsset.ICON_ADD_DISABLE); + return BrunoTools.getAssetImage(BrnAsset.iconAddDisable); } - return BrunoTools.getAssetImage(BrnAsset.ICON_ADD_ENABLE); + return BrunoTools.getAssetImage(BrnAsset.iconAddEnable); } bool isReachMaxLevel() { - int value = widget.value; - - if (widget.value == null) { - return false; - } - - if (value >= widget.maxLimit) { + if (_value >= widget.maxLimit) { return true; } - return false; } Image getMinusIcon() { - if (widget.isEdit != null && !widget.isEdit) { - return BrunoTools.getAssetImage(BrnAsset.ICON_MINUS_DISABLE); + if (!widget.isEdit) { + return BrunoTools.getAssetImage(BrnAsset.iconMinusDisable); } if (isReachMinLevel()) { - return BrunoTools.getAssetImage(BrnAsset.ICON_MINUS_DISABLE); + return BrunoTools.getAssetImage(BrnAsset.iconMinusDisable); } - return BrunoTools.getAssetImage(BrnAsset.ICON_MINUS_ENABLE); + return BrunoTools.getAssetImage(BrnAsset.iconMinusEnable); } bool isReachMinLevel() { - int value = widget.value; - - if (widget.value == null) { - return false; - } - - if (value <= widget.minLimit) { + if (_value <= widget.minLimit) { return true; } - return false; } } diff --git a/lib/src/components/form/items/general/brn_text_block_input_item.dart b/lib/src/components/form/items/general/brn_text_block_input_item.dart index c0f85bb4..7fbc70b2 100644 --- a/lib/src/components/form/items/general/brn_text_block_input_item.dart +++ b/lib/src/components/form/items/general/brn_text_block_input_item.dart @@ -1,5 +1,4 @@ import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; -import 'package:bruno/src/components/form/base/input_item_interface.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/theme/brn_theme.dart'; import 'package:flutter/material.dart'; @@ -15,23 +14,23 @@ import 'package:flutter/widgets.dart'; // ignore: must_be_immutable class BrnTextBlockInputFormItem extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.TEXT_BLOCK_INPUT_TYPE; + final String type = BrnInputItemType.textBlockInputType; /// 录入项标题 final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类 final String prefixIconType; @@ -51,30 +50,30 @@ class BrnTextBlockInputFormItem extends StatefulWidget { final bool isPrefixIconEnabled; /// 点击"+"图标回调 - final VoidCallback onAddTap; + final VoidCallback? onAddTap; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 输入字符数上限 - final int maxCharCount; + final int? maxCharCount; /// 录入项 hint 提示 final String hint; /// 输入内容类型 - final String inputType; + final String? inputType; /// 指定对输入数据的格式化要求 - List inputFormatters; + final List? inputFormatters; /// 输入回调 - final ValueChanged onChanged; + final ValueChanged? onChanged; - final TextEditingController controller; + final TextEditingController? controller; /// 最小行数,默认值4 final int minLines; @@ -83,25 +82,24 @@ class BrnTextBlockInputFormItem extends StatefulWidget { final int maxLines; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnTextBlockInputFormItem( - {Key key, + {Key? key, this.label, - this.type: BrnInputItemType.TEXT_BLOCK_INPUT_TYPE, - this.title: "", + this.title = "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, - this.error: "", - this.isEdit: true, - this.isRequire: false, - this.isPrefixIconEnabled: false, + this.prefixIconType = BrnPrefixIconType.normal, + this.error = "", + this.isEdit = true, + this.isRequire = false, + this.isPrefixIconEnabled = false, this.onAddTap, this.onRemoveTap, this.onTip, this.onChanged, - this.hint: "请选择", + this.hint = "请输入", this.maxCharCount, this.inputType, this.inputFormatters, @@ -112,7 +110,7 @@ class BrnTextBlockInputFormItem extends StatefulWidget { : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -124,7 +122,7 @@ class BrnTextBlockInputFormItem extends StatefulWidget { } class BrnTextBlockInputFormItemState extends State { - TextEditingController _controller; + late TextEditingController _controller; @override void initState() { @@ -136,7 +134,7 @@ class BrnTextBlockInputFormItemState extends State { Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.itemEdgeInsets(widget.themeData), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -146,7 +144,7 @@ class BrnTextBlockInputFormItemState extends State { ), child: Container( padding: BrnFormUtil.titleEdgeInsets( - widget.prefixIconType, widget.isRequire, widget.themeData), + widget.prefixIconType, widget.isRequire, widget.themeData!), child: Row( children: [ // 添加/删除 按钮 @@ -160,39 +158,39 @@ class BrnTextBlockInputFormItemState extends State { BrnFormUtil.buildRequireWidget(widget.isRequire), // title - BrnFormUtil.buildTitleWidget(widget.title, widget.themeData), + BrnFormUtil.buildTitleWidget(widget.title, widget.themeData!), BrnFormUtil.buildTipLabelWidget( - widget.tipLabel, widget.onTip, widget.themeData), + widget.tipLabel, widget.onTip, widget.themeData!), ], ), ), ), // 副标题 - BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), + BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData!), // 错误提示 - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData), + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!), // 输入框 Container( - padding: BrnFormUtil.errorEdgeInsets(widget.themeData), + padding: BrnFormUtil.errorEdgeInsets(widget.themeData!), child: TextField( keyboardType: BrnFormUtil.getInputType(widget.inputType), controller: _controller, maxLength: widget.maxCharCount, - maxLengthEnforced: true, - maxLines: widget.maxLines ?? 20, - minLines: widget.minLines ?? 4, + maxLengthEnforcement: MaxLengthEnforcement.enforced, + maxLines: widget.maxLines, + minLines: widget.minLines, textAlign: TextAlign.left, enabled: widget.isEdit, style: BrnFormUtil.getIsEditTextStyle( - widget.themeData, widget.isEdit), + widget.themeData!, widget.isEdit), inputFormatters: widget.inputFormatters, decoration: InputDecoration( - hintText: widget.hint ?? "请输入", - hintStyle: BrnFormUtil.getHintTextStyle(widget.themeData), + hintText: widget.hint , + hintStyle: BrnFormUtil.getHintTextStyle(widget.themeData!), contentPadding: EdgeInsets.all(0), border: InputBorder.none, isDense: true, @@ -215,7 +213,7 @@ class BrnTextBlockInputFormItemState extends State { void dispose() { super.dispose(); if (widget.controller == null) { - _controller?.dispose(); + _controller.dispose(); } } } diff --git a/lib/src/components/form/items/general/brn_text_input_item.dart b/lib/src/components/form/items/general/brn_text_input_item.dart index 4018cb4d..02058a33 100644 --- a/lib/src/components/form/items/general/brn_text_input_item.dart +++ b/lib/src/components/form/items/general/brn_text_input_item.dart @@ -1,12 +1,10 @@ import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; -import 'package:bruno/src/components/form/base/input_item_interface.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; -import 'package:bruno/src/utils/font/brn_font.dart'; +import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; /// /// 文本输入型录入项 @@ -17,23 +15,23 @@ import 'package:flutter/widgets.dart'; // ignore: must_be_immutable class BrnTextInputFormItem extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.TEXT_INPUT_TYPE; + final String type = BrnInputItemType.textInputType; /// 录入项标题 final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项前缀图标样式 "添加项" "删除项" 详见 [BrnPrefixIconType] 类 final String prefixIconType; @@ -53,55 +51,54 @@ class BrnTextInputFormItem extends StatefulWidget { final bool isPrefixIconEnabled; /// 点击"+"图标回调 - final VoidCallback onAddTap; + final VoidCallback? onAddTap; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 固定内容 - final String prefixText; + final String? prefixText; /// 提示文案 final String hint; /// 单位 - final String unit; + final String? unit; /// 输入内容类型 - final String inputType; + final String? inputType; /// 最大可输入字符数 - final int maxCharCount; - List inputFormatters; + final int? maxCharCount; + final List? inputFormatters; /// 输入变化回调 - final ValueChanged onChanged; + final ValueChanged? onChanged; - final TextEditingController controller; + final TextEditingController? controller; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnTextInputFormItem({ - Key key, + Key? key, this.label, - this.type: BrnInputItemType.TEXT_INPUT_TYPE, - this.title: "", + this.title = "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, - this.error: "", - this.isEdit: true, - this.isRequire: false, - this.isPrefixIconEnabled: false, + this.prefixIconType = BrnPrefixIconType.normal, + this.error = "", + this.isEdit = true, + this.isRequire = false, + this.isPrefixIconEnabled = false, this.onAddTap, this.onRemoveTap, this.onTip, this.prefixText, - this.hint: "请输入", + this.hint = "请输入", this.unit, this.maxCharCount, this.inputType, @@ -112,7 +109,7 @@ class BrnTextInputFormItem extends StatefulWidget { }) : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -124,7 +121,7 @@ class BrnTextInputFormItem extends StatefulWidget { } class BrnTextInputFormItemState extends State { - TextEditingController _controller; + late TextEditingController _controller; @override void initState() { @@ -136,7 +133,7 @@ class BrnTextInputFormItemState extends State { Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.itemEdgeInsets(widget.themeData), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -148,7 +145,7 @@ class BrnTextInputFormItemState extends State { children: [ Container( padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, - widget.isRequire, widget.themeData), + widget.isRequire, widget.themeData!), child: Row( children: [ BrnFormUtil.buildPrefixIcon( @@ -159,7 +156,7 @@ class BrnTextInputFormItemState extends State { widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), BrnFormUtil.buildTitleWidget( - widget.title, widget.themeData), + widget.title, widget.themeData!), Offstage( offstage: (widget.prefixText == null), child: Container( @@ -167,11 +164,11 @@ class BrnTextInputFormItemState extends State { child: Text( widget.prefixText ?? "", style: BrnFormUtil.getTitleTextStyle( - widget.themeData), + widget.themeData!), )), ), BrnFormUtil.buildTipLabelWidget( - widget.tipLabel, widget.onTip, widget.themeData), + widget.tipLabel, widget.onTip, widget.themeData!), ], ), ), @@ -182,11 +179,11 @@ class BrnTextInputFormItemState extends State { maxLines: 1, maxLength: widget.maxCharCount, style: BrnFormUtil.getIsEditTextStyle( - widget.themeData, widget.isEdit), + widget.themeData!, widget.isEdit), decoration: InputDecoration( border: InputBorder.none, - hintStyle: BrnFormUtil.getHintTextStyle(widget.themeData), - hintText: widget.hint ?? '请输入', + hintStyle: BrnFormUtil.getHintTextStyle(widget.themeData!), + hintText: widget.hint, counterText: "", contentPadding: EdgeInsets.all(0), isDense: true, @@ -211,15 +208,15 @@ class BrnTextInputFormItemState extends State { widget.unit ?? "", style: TextStyle( color: Color(0xFF101010), - fontSize: BrnFont.FONT_16, + fontSize: BrnFonts.f16, ), )), ), ], ), ), - BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData) + BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData!), + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!) ], ), ); @@ -231,7 +228,7 @@ class BrnTextInputFormItemState extends State { // 如果controller由外部创建不需要销毁, 若由内部创建则需要销毁 if (widget.controller == null) { - _controller?.dispose(); + _controller.dispose(); } } } diff --git a/lib/src/components/form/items/general/brn_text_select_item.dart b/lib/src/components/form/items/general/brn_text_select_item.dart index 3c400269..1678b5c8 100644 --- a/lib/src/components/form/items/general/brn_text_select_item.dart +++ b/lib/src/components/form/items/general/brn_text_select_item.dart @@ -1,3 +1,5 @@ + + import 'dart:math'; import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; @@ -5,7 +7,7 @@ import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; -import 'package:bruno/src/utils/font/brn_font.dart'; +import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; @@ -19,19 +21,19 @@ import 'package:flutter/widgets.dart'; /// // ignore: must_be_immutable class BrnTextSelectFormItem extends StatefulWidget { - final String label; + final String? label; /// 录入项的唯一标识,主要用于录入类型页面框架中 - String type = BrnInputItemType.TEXT_SELECT_INPUT_TYPE; + final String type = BrnInputItemType.textSelectInputType; /// 录入项类型,主要用于录入类型页面框架中 final String title; /// 录入项标题 - final String subTitle; + final String? subTitle; /// 录入项子标题 - final String tipLabel; + final String? tipLabel; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, @@ -51,46 +53,46 @@ class BrnTextSelectFormItem extends StatefulWidget { final bool isEdit; /// 点击"+"图标回调 - final VoidCallback onAddTap; + final VoidCallback? onAddTap; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 点击录入区回调 - final VoidCallback onTap; + final VoidCallback? onTap; /// 录入项 hint 提示 final String hint; /// 录入项 值 - final String value; + final String? value; /// 选中文本最大行数 final int valueMaxLines; /// title最大行数 - final int titleMaxLines; + final int? titleMaxLines; ///是否自动布局 - bool _isAutoLayout; + bool? _isAutoLayout; /// 行布局比例值 左边「标题+问号+提示语」 右边「选项值」 /// 左:右 比例值 例如 左:右 = 6:4 则 ratio = 1.5 - double layoutRatio; + double? layoutRatio; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnTextSelectFormItem({ - Key key, + Key? key, this.label, this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -107,18 +109,18 @@ class BrnTextSelectFormItem extends StatefulWidget { this._isAutoLayout = false; this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } BrnTextSelectFormItem.autoLayout( - {Key key, + {Key? key, this.label, this.title: "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, + this.prefixIconType: BrnPrefixIconType.normal, this.error: "", this.isEdit: true, this.isRequire: false, @@ -136,7 +138,7 @@ class BrnTextSelectFormItem extends StatefulWidget { this._isAutoLayout = true; this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -147,7 +149,7 @@ class BrnTextSelectFormItem extends StatefulWidget { } } -double _fontSize = BrnFont.FONT_16; +double _fontSize = BrnFonts.f16; StrutStyle _contentStructStyle = StrutStyle( forceStrutHeight: true, height: 1, leading: 0.5, fontSize: _fontSize); @@ -166,10 +168,10 @@ class BrnTextSelectFormItemState extends State { : _buildTitleWidget(context), // 副标题 - BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), + BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData!), // 错误提示 - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData) + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!) ], ), ); @@ -177,7 +179,7 @@ class BrnTextSelectFormItemState extends State { double _getTitleMaxWidth(BuildContext context, BoxConstraints constraints) { double contentRatio = BrnFormUtil.getAutoLayoutContentRatio( - tipLabelHidden: widget.tipLabel == null || widget.tipLabel.isEmpty, + tipLabelHidden: widget.tipLabel == null || widget.tipLabel!.isEmpty, layoutRatio: widget.layoutRatio); double maxWidth = min( constraints.maxWidth * contentRatio, @@ -235,7 +237,7 @@ class BrnTextSelectFormItemState extends State { GestureDetector _buildRightWidget(BuildContext context) { return GestureDetector( onTap: () { - if (widget.isEdit != null && !widget.isEdit) { + if (!widget.isEdit) { return; } @@ -267,7 +269,7 @@ class BrnTextSelectFormItemState extends State { child: GestureDetector( onTap: () { if (widget.onTip != null) { - widget.onTip(); + widget.onTip!(); } }, child: Row( @@ -289,8 +291,8 @@ class BrnTextSelectFormItemState extends State { forceStrutHeight: true, height: 1, leading: 0.5, - fontSize: BrnFont.FONT_14), - style: BrnFormUtil.getTipsTextStyle(widget.themeData), + fontSize: BrnFonts.f14), + style: BrnFormUtil.getTipsTextStyle(widget.themeData!), ), ), ], @@ -302,13 +304,13 @@ class BrnTextSelectFormItemState extends State { // 标题widget Widget _buildTitleTextWidget() { return Text( - widget.title ?? "", + widget.title, overflow: widget.titleMaxLines == null ? TextOverflow.clip : TextOverflow.ellipsis, maxLines: widget.titleMaxLines, strutStyle: _contentStructStyle, - style: BrnFormUtil.getTitleTextStyle(widget.themeData, height: 1), + style: BrnFormUtil.getTitleTextStyle(widget.themeData!, height: 1), ); } @@ -342,7 +344,7 @@ class BrnTextSelectFormItemState extends State { // 计算Text所占宽度 double _calculateTextWidth(BuildContext context) { TextPainter painter; - if (widget.value != null && widget.value.isNotEmpty) { + if (widget.value != null && widget.value!.isNotEmpty) { painter = TextPainter( locale: Localizations.localeOf(context), textAlign: TextAlign.end, @@ -351,7 +353,7 @@ class BrnTextSelectFormItemState extends State { text: TextSpan( text: widget.value, style: BrnFormUtil.getIsEditTextStyle( - widget.themeData, widget.isEdit, + widget.themeData!, widget.isEdit, height: 1), )); } else { @@ -362,7 +364,7 @@ class BrnTextSelectFormItemState extends State { strutStyle: _contentStructStyle, text: TextSpan( text: widget.hint, - style: BrnFormUtil.getHintTextStyle(widget.themeData, height: 1), + style: BrnFormUtil.getHintTextStyle(widget.themeData!, height: 1), )); } painter.layout(); @@ -372,14 +374,14 @@ class BrnTextSelectFormItemState extends State { } Widget buildText() { - if (widget.value != null && widget.value.isNotEmpty) { + if (widget.value != null && widget.value!.isNotEmpty) { return Text( - widget.value, + widget.value!, overflow: TextOverflow.ellipsis, - maxLines: widget.valueMaxLines ?? 1, + maxLines: widget.valueMaxLines , textAlign: TextAlign.end, strutStyle: _contentStructStyle, - style: BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit, + style: BrnFormUtil.getIsEditTextStyle(widget.themeData!, widget.isEdit, height: 1), ); } else { @@ -387,7 +389,7 @@ class BrnTextSelectFormItemState extends State { widget.hint, textAlign: TextAlign.end, strutStyle: _contentStructStyle, - style: BrnFormUtil.getHintTextStyle(widget.themeData, height: 1), + style: BrnFormUtil.getHintTextStyle(widget.themeData!, height: 1), ); } } @@ -395,7 +397,7 @@ class BrnTextSelectFormItemState extends State { String getCalculateText() { String value = '请选择'; if (!BrunoTools.isEmpty(widget.value)) { - value = widget.value; + value = widget.value!; } else if (!BrunoTools.isEmpty(widget.hint)) { value = widget.hint; } @@ -406,7 +408,7 @@ class BrnTextSelectFormItemState extends State { // fontSize : 文字的大小; // maxLines:文本支持最大多少行 static double calculateTextHeight( - BuildContext context, String value, double fontSize, int maxLines) { + BuildContext context, String? value, double fontSize, int maxLines) { TextPainter painter = TextPainter( // AUTO:华为手机如果不指定locale的时候,该方法算出来的文字高度是比系统计算偏小的。 diff --git a/lib/src/components/form/items/general/brn_title_select_input_item.dart b/lib/src/components/form/items/general/brn_title_select_input_item.dart index ad23341b..4410cb96 100644 --- a/lib/src/components/form/items/general/brn_title_select_input_item.dart +++ b/lib/src/components/form/items/general/brn_title_select_input_item.dart @@ -8,7 +8,7 @@ import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; -import 'package:bruno/src/utils/font/brn_font.dart'; +import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -21,23 +21,23 @@ import 'package:flutter/services.dart'; // ignore: must_be_immutable class BrnTitleSelectInputFormItem extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.TEXT_INPUT_TITLE_SELECT_TYPE; + final String type = BrnInputItemType.textInputTitleSelectType; /// 录入项标题 - String title; + final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类 final String prefixIconType; @@ -57,19 +57,19 @@ class BrnTitleSelectInputFormItem extends StatefulWidget { final bool isPrefixIconEnabled; /// 点击"+"图标回调 - final VoidCallback onAddTap; + final VoidCallback? onAddTap; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 提示文案 final String hint; /// 最大可输入字符数 - final int maxCount; + final int? maxCount; /// 输入类型 final String inputType; @@ -78,38 +78,38 @@ class BrnTitleSelectInputFormItem extends StatefulWidget { final int selectedIndex; /// title选择列表 - List selectList; - List inputFormatters; + final List selectList; + final List? inputFormatters; /// 输入文本变化回调 - final ValueChanged onChanged; + final ValueChanged? onChanged; /// title文案选中回调 - final OnBrnFormTitleSelected onTitleSelected; - final TextEditingController controller; + final OnBrnFormTitleSelected? onTitleSelected; + final TextEditingController? controller; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnTitleSelectInputFormItem( - {Key key, + {Key? key, + required this.selectList, this.label, - this.title: "", + this.title = "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, - this.error: "", - this.isEdit: true, - this.isRequire: false, - this.isPrefixIconEnabled: false, + this.prefixIconType = BrnPrefixIconType.normal, + this.error = "", + this.isEdit = true, + this.isRequire = false, + this.isPrefixIconEnabled = false, this.onAddTap, this.onRemoveTap, this.onTip, - this.hint: "请输入", + this.hint = "请输入", this.maxCount, - this.inputType: BrnInputType.TEXT, - this.selectedIndex: -1, - this.selectList, + this.inputType = BrnInputType.text, + this.selectedIndex = -1, this.inputFormatters, this.onChanged, this.onTitleSelected, @@ -118,7 +118,7 @@ class BrnTitleSelectInputFormItem extends StatefulWidget { : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -130,10 +130,11 @@ class BrnTitleSelectInputFormItem extends StatefulWidget { class BrnTitleSelectInputFormItemState extends State { - TextEditingController _controller; - StreamController _showController; - StreamController _textController; - GlobalKey _globalKey; + late TextEditingController _controller; + late StreamController _showController; + late StreamController _textController; + late GlobalKey _globalKey; + String _title = ""; @override void initState() { @@ -145,7 +146,7 @@ class BrnTitleSelectInputFormItemState Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.itemEdgeInsets(widget.themeData), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -165,8 +166,8 @@ class BrnTitleSelectInputFormItemState ], ), ), - BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData), + BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData!), + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!), ], ), ); @@ -175,7 +176,7 @@ class BrnTitleSelectInputFormItemState Widget _buildLeftMenu() { return Container( padding: BrnFormUtil.titleEdgeInsets( - widget.prefixIconType, widget.isRequire, widget.themeData), + widget.prefixIconType, widget.isRequire, widget.themeData!), child: Row( children: [ BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, @@ -187,7 +188,7 @@ class BrnTitleSelectInputFormItemState _buildTriangle(), BrnFormUtil.buildTipLabelWidget( - widget.tipLabel, widget.onTip, widget.themeData), + widget.tipLabel, widget.onTip, widget.themeData!), ], ), ); @@ -199,15 +200,16 @@ class BrnTitleSelectInputFormItemState padding: EdgeInsets.only(right: 4), child: GestureDetector( onTap: () { - if (widget.isEdit != null && !widget.isEdit) { + if (!widget.isEdit) { return; } - RenderBox trigle = _globalKey.currentContext?.findRenderObject(); - Offset offset = trigle?.localToGlobal(Offset.zero); - final RenderBox button = context.findRenderObject(); + RenderBox? trigle = + _globalKey.currentContext?.findRenderObject() as RenderBox?; + Offset? offset = trigle?.localToGlobal(Offset.zero); + final RenderBox button = context.findRenderObject() as RenderBox; final RenderBox overlay = - Overlay.of(context).context.findRenderObject(); + Overlay.of(context)!.context.findRenderObject() as RenderBox; final RelativeRect position = RelativeRect.fromRect( Rect.fromPoints( button.localToGlobal(Offset.zero, ancestor: overlay), @@ -217,9 +219,9 @@ class BrnTitleSelectInputFormItemState ); var relativeRect = RelativeRect.fromLTRB( - position.left + offset?.dx ?? 16, + position.left + (offset?.dx ?? 0.0), position.top + 44, - position.right + offset?.dx ?? 16, + position.right + (offset?.dx ?? 0.0), position.bottom + 44); _showController.add(true); Navigator.push( @@ -234,10 +236,10 @@ class BrnTitleSelectInputFormItemState selectList: widget.selectList, selectedIndex: widget.selectedIndex, selectCallback: (item, index) { - widget.title = item; + _title = item; _textController.add(item); if (widget.onTitleSelected != null) { - widget.onTitleSelected(item, index); + widget.onTitleSelected!(item, index); } }, themeData: widget.themeData, @@ -252,11 +254,11 @@ class BrnTitleSelectInputFormItemState }, child: StreamBuilder( stream: _textController.stream, - initialData: widget.title ?? "", + initialData: _title, builder: (context, AsyncSnapshot snapshot) { return Text( - snapshot.data, - style: BrnFormUtil.getTitleTextStyle(widget.themeData), + snapshot.data!, + style: BrnFormUtil.getTitleTextStyle(widget.themeData!), ); }, ), @@ -271,10 +273,10 @@ class BrnTitleSelectInputFormItemState stream: _showController.stream, initialData: false, builder: (BuildContext context, AsyncSnapshot snapshot) { - return snapshot.data + return snapshot.data! ? BrunoTools.getAssetImageWithBandColor( - BrnAsset.ICON_SELECTED_UP_TRIANGLE) - : BrunoTools.getAssetImage(BrnAsset.ICON_UNSELECT_DOWN_TRIANGLE); + BrnAsset.iconSelectedUpTriangle) + : BrunoTools.getAssetImage(BrnAsset.iconUnSelectDownTriangle); }, ), ); @@ -287,7 +289,7 @@ class BrnTitleSelectInputFormItemState controller: _controller, enabled: widget.isEdit, maxLength: widget.maxCount, - style: BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit), + style: BrnFormUtil.getIsEditTextStyle(widget.themeData!, widget.isEdit), onChanged: (text) { BrnFormUtil.notifyInputChanged(widget.onChanged, text); }, @@ -296,9 +298,9 @@ class BrnTitleSelectInputFormItemState border: InputBorder.none, hintStyle: TextStyle( color: Color(0xFFCCCCCC), - fontSize: BrnFont.FONT_16, + fontSize: BrnFonts.f16, textBaseline: TextBaseline.alphabetic), - hintText: widget.hint ?? '请输入', + hintText: widget.hint, counterText: "", contentPadding: EdgeInsets.all(0), isDense: true, @@ -315,7 +317,7 @@ class BrnTitleSelectInputFormItemState super.dispose(); // 如果controller由外部创建不需要销毁, 若由内部创建则需要销毁 if (widget.controller == null) { - _controller?.dispose(); + _controller.dispose(); } } @@ -325,19 +327,21 @@ class BrnTitleSelectInputFormItemState _controller = widget.controller ?? TextEditingController(); _globalKey = GlobalKey(); + _title = widget.title; } } +// ignore: must_be_immutable class TitleSelectPopWidget extends StatefulWidget { List selectList; - int selectedIndex; + int? selectedIndex; final Function(String item, int index) selectCallback; - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; TitleSelectPopWidget( - {this.selectList, + {required this.selectList, this.selectedIndex, - this.selectCallback, + required this.selectCallback, this.themeData}); @override @@ -347,7 +351,7 @@ class TitleSelectPopWidget extends StatefulWidget { class _TitleSelectPopWidgetState extends State { @override Widget build(BuildContext context) { - List showList = List(); + List showList = []; for (int i = 0, n = widget.selectList.length; i < n; ++i) { showList.add(selectItem(widget.selectList[i], i, i == n - 1)); } @@ -363,7 +367,7 @@ class _TitleSelectPopWidgetState extends State { ], color: Colors.white, border: Border.all( - color: widget.themeData.commonConfig.dividerColorBase, width: 0.5), + color: widget.themeData!.commonConfig.dividerColorBase, width: 0.5), borderRadius: BorderRadius.all(Radius.circular(4)), ), child: Column( @@ -398,7 +402,7 @@ class _TitleSelectPopWidgetState extends State { bottom: BorderSide( color: isLast ? Colors.transparent - : widget.themeData.commonConfig.dividerColorBase, + : widget.themeData!.commonConfig.dividerColorBase, width: 0.5)), // 也可控件一边圆角大小 ), child: Text( @@ -406,8 +410,8 @@ class _TitleSelectPopWidgetState extends State { style: TextStyle( decoration: TextDecoration.none, color: isSelected - ? widget.themeData.commonConfig.brandPrimary - : widget.themeData.commonConfig.colorTextBase, + ? widget.themeData!.commonConfig.brandPrimary + : widget.themeData!.commonConfig.colorTextBase, fontWeight: FontWeight.w500, fontSize: 16, ), diff --git a/lib/src/components/form/undetermined/brn_expandable_group.dart b/lib/src/components/form/items/group/brn_expandable_group.dart similarity index 88% rename from lib/src/components/form/undetermined/brn_expandable_group.dart rename to lib/src/components/form/items/group/brn_expandable_group.dart index 63f05eb1..0c56bd95 100644 --- a/lib/src/components/form/undetermined/brn_expandable_group.dart +++ b/lib/src/components/form/items/group/brn_expandable_group.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. + + import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; @@ -31,19 +33,18 @@ class BrnExpandableGroup extends StatefulWidget { /// the tile to reveal or hide the [children]. The [initiallyExpanded] property must /// be non-null. BrnExpandableGroup({ - Key key, - @required this.title, + Key? key, + required this.title, this.subtitle, this.backgroundColor, this.onExpansionChanged, this.children = const [], this.initiallyExpanded = false, this.themeData, - }) : assert(initiallyExpanded != null), - super(key: key) { + }) : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -57,15 +58,14 @@ class BrnExpandableGroup extends StatefulWidget { /// /// Typically a [Text] widget. - @Deprecated('message') - final String subtitle; + final String? subtitle; /// Called when the tile expands or collapses. /// /// When the tile starts expanding, this function is called with the value /// true. When the tile starts collapsing, this function is called with /// the value false. - final ValueChanged onExpansionChanged; + final ValueChanged? onExpansionChanged; /// The widgets that are displayed when the tile expands. /// @@ -73,12 +73,12 @@ class BrnExpandableGroup extends StatefulWidget { final List children; /// The color to display behind the sublist when expanded. - final Color backgroundColor; + final Color? backgroundColor; /// Specifies if the list tile is initially expanded (true) or collapsed (false, the default). final bool initiallyExpanded; - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; @override _BrnExpansionElementState createState() => _BrnExpansionElementState(); @@ -97,13 +97,13 @@ class _BrnExpansionElementState extends State final ColorTween _iconColorTween = ColorTween(); final ColorTween _backgroundColorTween = ColorTween(); - AnimationController _controller; - Animation _iconTurns; - Animation _heightFactor; + late AnimationController _controller; + late Animation _iconTurns; + late Animation _heightFactor; bool _isExpanded = false; - Widget arrowIcon; + Widget? arrowIcon; @override void initState() { @@ -127,9 +127,9 @@ class _BrnExpansionElementState extends State if (_isExpanded) { arrowIcon = - BrunoTools.getAssetSizeImage(BrnAsset.ICON_DOWN_ARROW, 12, 12); + BrunoTools.getAssetSizeImage(BrnAsset.iconDownArrow, 12, 12); } else { - arrowIcon = BrunoTools.getAssetSizeImage(BrnAsset.ICON_UP_ARROW, 12, 12); + arrowIcon = BrunoTools.getAssetSizeImage(BrnAsset.iconUpArrow, 12, 12); } } @@ -152,10 +152,10 @@ class _BrnExpansionElementState extends State PageStorage.of(context)?.writeState(context, _isExpanded); }); if (widget.onExpansionChanged != null) - widget.onExpansionChanged(_isExpanded); + widget.onExpansionChanged!(_isExpanded); } - Widget _buildHeader(BuildContext context, Widget child) { + Widget _buildHeader(BuildContext context, Widget? child) { final Color backgroundColor = Colors.transparent; return Container( @@ -181,9 +181,9 @@ class _BrnExpansionElementState extends State Container( padding: EdgeInsets.only(right: 6), child: Text( - widget.title ?? "", + widget.title, style: BrnFormUtil.getHeadTitleTextStyle( - widget.themeData, + widget.themeData!, isBold: true), )), // 副标题 @@ -194,12 +194,12 @@ class _BrnExpansionElementState extends State child: Offstage( // ignore: deprecated_member_use_from_same_package offstage: (widget.subtitle == null || - widget.subtitle.isEmpty), + widget.subtitle!.isEmpty), child: Text( // ignore: deprecated_member_use_from_same_package widget.subtitle ?? "", style: BrnFormUtil.getSubTitleTextStyle( - widget.themeData), + widget.themeData!), ), ), ), @@ -236,8 +236,8 @@ class _BrnExpansionElementState extends State /// title 文字颜色 _headerColorTween - ..begin = theme.textTheme.subtitle1.color - ..end = theme.textTheme.subtitle1.color; + ..begin = theme.textTheme.subtitle1!.color + ..end = theme.textTheme.subtitle1!.color; /// 展开收起图标颜色 _iconColorTween diff --git a/lib/src/components/form/items/group/brn_expand_group.dart b/lib/src/components/form/items/group/brn_expandable_group_with_opreate.dart similarity index 79% rename from lib/src/components/form/items/group/brn_expand_group.dart rename to lib/src/components/form/items/group/brn_expandable_group_with_opreate.dart index 770a8191..13a06eab 100644 --- a/lib/src/components/form/items/group/brn_expand_group.dart +++ b/lib/src/components/form/items/group/brn_expandable_group_with_opreate.dart @@ -14,23 +14,23 @@ import 'package:flutter/widgets.dart'; // ignore: must_be_immutable class BrnExpandFormGroup extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.NORMAL_GROUP_TYPE; + final String type = BrnInputItemType.normalGroupType; /// 录入项标题 final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项错误提示 final String error; @@ -42,35 +42,35 @@ class BrnExpandFormGroup extends StatefulWidget { final bool isEdit; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 初始是否为展开状态 final bool isExpand; /// 右侧文案 - final String deleteLabel; + final String? deleteLabel; /// 内部子项 - List children; + final List children; BrnExpandFormGroup({ - Key key, + Key? key, this.label, - this.title: "", + this.title = "", this.subTitle, this.tipLabel, - this.error: "", - this.isEdit: true, - this.isRequire: false, + this.error = "", + this.isEdit = true, + this.isRequire = false, this.onRemoveTap, this.onTip, - this.isExpand: true, + this.isExpand = true, this.deleteLabel, - this.children, - }); + required this.children, + }) : super(key: key); @override BrnExpandFormGroupState createState() { @@ -83,7 +83,7 @@ class BrnExpandFormGroupState extends State { Widget build(BuildContext context) { return Container( child: ExpansionElementWidget( - title: widget.title ?? "", + title: widget.title, subtitle: widget.subTitle, deleteText: widget.deleteLabel, initiallyExpanded: widget.isExpand, @@ -100,17 +100,15 @@ class BrnExpandFormGroupState extends State { } List getSubItem() { - List result = List(); + List result = []; - if (widget.children == null || widget.children.isEmpty) { + if (widget.children.isEmpty) { return result; } for (Widget w in widget.children) { - if (w != null) { - result.add(BrnLine()); - result.add(w); - } + result.add(BrnLine()); + result.add(w); } return result; diff --git a/lib/src/components/form/items/group/brn_normal_group.dart b/lib/src/components/form/items/group/brn_normal_group.dart index 59bfcc76..af71d4b8 100644 --- a/lib/src/components/form/items/group/brn_normal_group.dart +++ b/lib/src/components/form/items/group/brn_normal_group.dart @@ -3,9 +3,8 @@ import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/components/line/brn_line.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; -import 'package:bruno/src/utils/font/brn_font.dart'; +import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// /// 可展开收起组类型录入项 @@ -13,25 +12,26 @@ import 'package:flutter/widgets.dart'; /// /// 包括"标题"、"副标题"、"错误信息提示"、"必填项提示"、"添加/删除按钮"、"消息提示" /// +// ignore: must_be_immutable class BrnNormalFormGroup extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - final String type = BrnInputItemType.NORMAL_GROUP_TYPE; + final String type = BrnInputItemType.normalGroupType; /// 录入项标题 final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项错误提示 final String error; @@ -43,37 +43,37 @@ class BrnNormalFormGroup extends StatefulWidget { final bool isEdit; /// 点击"-"图标回调 - final VoidCallback onRemoveTap; + final VoidCallback? onRemoveTap; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 右侧文案 - final String deleteLabel; + final String? deleteLabel; /// 内部子项 - List children; + final List children; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnNormalFormGroup({ - Key key, + Key? key, this.label, - this.title: "", + this.title = "", this.subTitle, this.tipLabel, - this.error: "", - this.isEdit: true, - this.isRequire: false, + this.error = "", + this.isEdit = true, + this.isRequire = false, this.onRemoveTap, this.onTip, this.deleteLabel, - this.children, - }) : super() { + required this.children, + }) : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -103,16 +103,16 @@ class BrnNormalFormGroupState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Offstage( - offstage: (widget.title == null || widget.title.isEmpty), + offstage: (widget.title.isEmpty), child: Container( child: Row( children: [ Container( padding: EdgeInsets.only(left: 20, right: 6), child: Text( - widget.title ?? "", + widget.title, style: BrnFormUtil.getHeadTitleTextStyle( - widget.themeData, + widget.themeData!, isBold: true), )), ], @@ -135,7 +135,7 @@ class BrnNormalFormGroupState extends State { widget.deleteLabel ?? "", style: TextStyle( color: Color(0xFFFA3F3F), - fontSize: BrnFont.FONT_16, + fontSize: BrnFonts.f16, ), ), ), @@ -148,12 +148,12 @@ class BrnNormalFormGroupState extends State { // 副标题 Container( alignment: Alignment.centerLeft, - padding: BrnFormUtil.subTitleEdgeInsets(widget.themeData), + padding: BrnFormUtil.subTitleEdgeInsets(widget.themeData!), child: Offstage( - offstage: (widget.subTitle == null || widget.subTitle.isEmpty), + offstage: (widget.subTitle == null || widget.subTitle!.isEmpty), child: Text( widget.subTitle ?? "", - style: BrnFormUtil.getSubTitleTextStyle(widget.themeData), + style: BrnFormUtil.getSubTitleTextStyle(widget.themeData!), ), ), ), @@ -169,17 +169,15 @@ class BrnNormalFormGroupState extends State { } List getSubItem() { - List result = List(); + List result = []; - if (widget.children == null || widget.children.isEmpty) { + if (widget.children.isEmpty) { return result; } for (Widget w in widget.children) { - if (w != null) { - result.add(BrnLine()); - result.add(w); - } + result.add(BrnLine()); + result.add(w); } return result; diff --git a/lib/src/components/form/undetermined/brn_portrait_radio_group.dart b/lib/src/components/form/items/group/brn_portrait_radio_group.dart similarity index 74% rename from lib/src/components/form/undetermined/brn_portrait_radio_group.dart rename to lib/src/components/form/items/group/brn_portrait_radio_group.dart index 36504d9c..88ecbf44 100644 --- a/lib/src/components/form/undetermined/brn_portrait_radio_group.dart +++ b/lib/src/components/form/items/group/brn_portrait_radio_group.dart @@ -1,7 +1,6 @@ -import 'package:bruno/bruno.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/components/line/brn_line.dart'; -import 'package:bruno/src/components/radio/brn_radio_core.dart'; +import 'package:bruno/src/components/radio/brn_radio_button.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:flutter/material.dart'; @@ -9,7 +8,7 @@ import 'package:flutter/widgets.dart'; /// 备选项点击时的回调。[oldStr] 旧的选项,如果初始没有选中项,该参数为null,[newStr] 新选中的选项。 typedef BrnPortraitRadioGroupOnChanged = void Function( - BrnPortraitRadioGroupOption oldStr, BrnPortraitRadioGroupOption newStr); + BrnPortraitRadioGroupOption? oldStr, BrnPortraitRadioGroupOption newStr); /// 纵向放置的单选 radio 视图。选项可为单行字符串,也可是标题+说明两部分。具体参见 [BrnPortraitRadioGroupOption]。 /// 选项的标题/子标题文字样式分别通过 [BrnFormItemConfig.optionTextStyle] 和 [BrnFormItemConfig.subTitleTextStyle] 控 @@ -20,16 +19,16 @@ class BrnPortraitRadioGroup extends StatefulWidget { final bool isEdit; /// 初始化时默认选中的项,匹配逻辑是 [BrnPortraitRadioGroupOption.title] 和 [BrnPortraitRadioGroupOption.subTitle] 都相等。 - BrnPortraitRadioGroupOption selectedOption; + final BrnPortraitRadioGroupOption? selectedOption; /// 备选项数组,参数类型为 [BrnPortraitRadioGroupOption] - List options; + final List? options; /// 备选项可用状态数组 - final List enableList; + final List? enableList; /// 选项变化回调 - final BrnPortraitRadioGroupOnChanged onChanged; + final BrnPortraitRadioGroupOnChanged? onChanged; /// [options] 中 title subTitle 是否换行展示。 /// false: 换行展示 @@ -38,38 +37,36 @@ class BrnPortraitRadioGroup extends StatefulWidget { final bool isCollapseContent; /// 主题配置数据 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; /// 通过传入一个字符串数组 [options],快捷构造出单行选项文案的纵向单选视图。 BrnPortraitRadioGroup.withSimpleList({ - Key key, + Key? key, this.isEdit = true, - String selectedOption, - List options, + String selectedOption = "", + required List options, this.enableList, this.onChanged, this.themeData, this.isCollapseContent = false, - }) { - this.options = options - ?.map((item) => BrnPortraitRadioGroupOption(title: item)) - ?.toList() ?? - List(); - int selectedIndex = options.indexOf(selectedOption); - if (selectedIndex > -1) { - this.selectedOption = this.options[selectedIndex]; - } - + }) : this.options = options + .map((item) => BrnPortraitRadioGroupOption(title: item)) + .toList(), + this.selectedOption = options.indexOf(selectedOption) > -1 + ? BrnPortraitRadioGroupOption( + title: options[options.indexOf(selectedOption)]) + : BrnPortraitRadioGroupOption(), + super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } /// 通过 [BrnPortraitRadioGroupOption] 类型的数组 [options],构造纵向单选视图。 BrnPortraitRadioGroup.withOptions({ - Key key, + Key? key, this.isEdit = true, this.selectedOption, this.options, @@ -77,10 +74,10 @@ class BrnPortraitRadioGroup extends StatefulWidget { this.onChanged, this.isCollapseContent = false, this.themeData, - }) { + }) :super(key: key){ this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -92,9 +89,12 @@ class BrnPortraitRadioGroup extends StatefulWidget { } class BrnPortraitRadioGroupState extends State { + late BrnPortraitRadioGroupOption? _selectedOption; + @override void initState() { super.initState(); + _selectedOption = widget.selectedOption; } @override @@ -108,8 +108,8 @@ class BrnPortraitRadioGroupState extends State { ); } - List getRadioList(List options) { - List result = List(); + List getRadioList(List? options) { + List result = []; BrnPortraitRadioGroupOption option; if (options == null || options.isEmpty) { result.add(Container()); @@ -149,16 +149,16 @@ class BrnPortraitRadioGroupState extends State { if (getRadioEnableState(position)) { return; } - BrnPortraitRadioGroupOption oldValue = widget.selectedOption; - widget.selectedOption = options[position]; + BrnPortraitRadioGroupOption? oldValue = _selectedOption; + _selectedOption = options[position]; if (widget.onChanged != null) { - widget.onChanged(oldValue, options[position]); + widget.onChanged!(oldValue, options[position]); } setState(() {}); }, ), Visibility( - visible: option.subTitle != null && option.subTitle.length > 0, + visible: option.subTitle != null && option.subTitle!.length > 0, child: Padding( padding: EdgeInsets.only(top: 4, right: 20), child: Text( @@ -166,7 +166,7 @@ class BrnPortraitRadioGroupState extends State { overflow: widget.isCollapseContent ? TextOverflow.ellipsis : null, maxLines: widget.isCollapseContent ? 1 : null, - style: BrnFormUtil.getSubTitleTextStyle(widget.themeData), + style: BrnFormUtil.getSubTitleTextStyle(widget.themeData!), ), ), ) @@ -186,8 +186,8 @@ class BrnPortraitRadioGroupState extends State { int getGroupValue() { int selectedIndex = -1; - for (int index = 0; index < widget.options.length; index++) { - if (isSameOption(widget.options[index], widget.selectedOption)) { + for (int index = 0; index < widget.options!.length; index++) { + if (isSameOption(widget.options![index], _selectedOption)) { selectedIndex = index; break; } @@ -196,57 +196,54 @@ class BrnPortraitRadioGroupState extends State { } bool isSameOption( - BrnPortraitRadioGroupOption src, BrnPortraitRadioGroupOption dst) { - if (src == null || dst == null) return false; + BrnPortraitRadioGroupOption src, BrnPortraitRadioGroupOption? dst) { + if (dst == null) return false; return src.title == dst.title && src.subTitle == dst.subTitle; } TextStyle getOptionTextStyle(BrnPortraitRadioGroupOption opt, int index) { - TextStyle result = BrnFormUtil.getOptionTextStyle(widget.themeData); - if (opt == null /*|| widget.value == null*/) { - return result; - } + TextStyle result = BrnFormUtil.getOptionTextStyle(widget.themeData!); - if (isSameOption(opt, widget.selectedOption)) { - result = BrnFormUtil.getOptionSelectedTextStyle(widget.themeData); + if (isSameOption(opt, _selectedOption)) { + result = BrnFormUtil.getOptionSelectedTextStyle(widget.themeData!); } - if (widget.isEdit != null && !widget.isEdit) { - result = BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit); + if (!widget.isEdit) { + result = BrnFormUtil.getIsEditTextStyle(widget.themeData!, widget.isEdit); } if (widget.enableList != null && - widget.enableList.isNotEmpty && - widget.enableList.length > index && - !widget.enableList[index]) { - result = BrnFormUtil.getIsEditTextStyle(widget.themeData, false); + widget.enableList!.isNotEmpty && + widget.enableList!.length > index && + !widget.enableList![index]) { + result = BrnFormUtil.getIsEditTextStyle(widget.themeData!, false); } return result; } bool getRadioEnableState(int index) { - if (widget.isEdit != null && !widget.isEdit) { + if (!widget.isEdit) { return true; } if (widget.enableList == null || - widget.enableList.isEmpty || - widget.enableList.length < index) { + widget.enableList!.isEmpty || + widget.enableList!.length < index) { return false; } - return !widget.enableList[index]; + return !widget.enableList![index]; } } /// 纵置单选视图的选项模型。文字样式见 [BrnPortraitRadioGroup] 说明。 class BrnPortraitRadioGroupOption { /// 标题 - String title; + String? title; /// 子标题说明文案 - String subTitle; + String? subTitle; BrnPortraitRadioGroupOption({this.title, this.subTitle}); } diff --git a/lib/src/components/form/items/group/element_expand_widget.dart b/lib/src/components/form/items/group/element_expand_widget.dart index dac9e2f7..72164ba6 100644 --- a/lib/src/components/form/items/group/element_expand_widget.dart +++ b/lib/src/components/form/items/group/element_expand_widget.dart @@ -2,11 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. + + import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; -import 'package:bruno/src/utils/font/brn_font.dart'; +import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; @@ -31,8 +33,8 @@ class ExpansionElementWidget extends StatefulWidget { /// the tile to reveal or hide the [children]. The [initiallyExpanded] property must /// be non-null. ExpansionElementWidget({ - Key key, - @required this.title, + Key? key, + this.title = "", this.subtitle, this.backgroundColor, this.onExpansionChanged, @@ -41,11 +43,10 @@ class ExpansionElementWidget extends StatefulWidget { this.deleteText, this.callback, this.themeData, - }) : assert(initiallyExpanded != null), - super(key: key) { + }) : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -55,19 +56,19 @@ class ExpansionElementWidget extends StatefulWidget { /// Typically a [Text] widget. final String title; - final String deleteText; + final String? deleteText; /// Additional content displayed below the title. /// /// Typically a [Text] widget. - final String subtitle; + final String? subtitle; /// Called when the tile expands or collapses. /// /// When the tile starts expanding, this function is called with the value /// true. When the tile starts collapsing, this function is called with /// the value false. - final ValueChanged onExpansionChanged; + final ValueChanged? onExpansionChanged; /// The widgets that are displayed when the tile expands. /// @@ -75,14 +76,14 @@ class ExpansionElementWidget extends StatefulWidget { final List children; /// The color to display behind the sublist when expanded. - final Color backgroundColor; + final Color? backgroundColor; /// Specifies if the list tile is initially expanded (true) or collapsed (false, the default). final bool initiallyExpanded; - final VoidCallback callback; + final VoidCallback? callback; - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; @override _ExpansionElementState createState() => _ExpansionElementState(); @@ -103,13 +104,13 @@ class _ExpansionElementState extends State final ColorTween _iconColorTween = ColorTween(); final ColorTween _backgroundColorTween = ColorTween(); - AnimationController _controller; - Animation _iconTurns; - Animation _heightFactor; + late AnimationController _controller; + late Animation _iconTurns; + late Animation _heightFactor; bool _isExpanded = false; - Widget arrowIcon; + late Widget arrowIcon; @override void initState() { @@ -163,10 +164,10 @@ class _ExpansionElementState extends State PageStorage.of(context)?.writeState(context, _isExpanded); }); if (widget.onExpansionChanged != null) - widget.onExpansionChanged(_isExpanded); + widget.onExpansionChanged!(_isExpanded); } - Widget _buildHeader(BuildContext context, Widget child) { + Widget _buildHeader(BuildContext context, Widget? child) { final Color borderSideColor = /*_borderColor.value ??*/ Colors.transparent; final Color backgroundColor = /*_backgroundColor.value ??*/ Colors .transparent; @@ -198,9 +199,9 @@ class _ExpansionElementState extends State Container( padding: EdgeInsets.only(right: 6), child: Text( - widget.title ?? "", + widget.title, style: BrnFormUtil.getHeadTitleTextStyle( - widget.themeData, + widget.themeData!, isBold: true), )), RotationTransition( @@ -216,7 +217,7 @@ class _ExpansionElementState extends State child: GestureDetector( onTap: () { if (widget.callback != null) { - widget.callback(); + widget.callback!(); } }, child: Container( @@ -225,7 +226,7 @@ class _ExpansionElementState extends State widget.deleteText ?? "", style: TextStyle( color: Color(0xFFFA3F3F), - fontSize: BrnFont.FONT_16, + fontSize: BrnFonts.f16, ), ), ), @@ -241,10 +242,10 @@ class _ExpansionElementState extends State alignment: Alignment.centerLeft, padding: EdgeInsets.only(left: 20, top: 4, bottom: 14), child: Offstage( - offstage: (widget.subtitle == null || widget.subtitle.isEmpty), + offstage: (widget.subtitle == null || widget.subtitle!.isEmpty), child: Text( widget.subtitle ?? "", - style: BrnFormUtil.getSubTitleTextStyle(widget.themeData), + style: BrnFormUtil.getSubTitleTextStyle(widget.themeData!), ), ), ), @@ -271,8 +272,8 @@ class _ExpansionElementState extends State /// title 文字颜色 _headerColorTween - ..begin = theme.textTheme.subtitle1.color - ..end = theme.textTheme.subtitle1.color; + ..begin = theme.textTheme.subtitle1!.color + ..end = theme.textTheme.subtitle1!.color; /// 展开收起图标颜色 _iconColorTween diff --git a/lib/src/components/form/items/misc/brn_add_label_item.dart b/lib/src/components/form/items/misc/brn_add_label_item.dart index 87981746..731c179d 100644 --- a/lib/src/components/form/items/misc/brn_add_label_item.dart +++ b/lib/src/components/form/items/misc/brn_add_label_item.dart @@ -1,19 +1,19 @@ + + import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; -import 'package:bruno/src/components/form/base/input_item_interface.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; -import 'package:bruno/src/utils/font/brn_font.dart'; +import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// 添加组类型录入项所使用的Widget // ignore: must_be_immutable class BrnAddLabel extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.LABEL_ADD; + final String type = BrnInputItemType.labelAdd; /// 标题文案 final String title; @@ -22,15 +22,15 @@ class BrnAddLabel extends StatefulWidget { final bool isEdit; /// 点击录入区回调 - final VoidCallback onTap; + final VoidCallback? onTap; BrnAddLabel({ - Key key, + Key? key, this.label, - this.title: "", - this.isEdit: true, + this.title = "", + this.isEdit = true, this.onTap, - }); + }) : super(key: key); @override BrnAddLabelState createState() { @@ -53,13 +53,13 @@ class BrnAddLabelState extends State { color: Colors.white, padding: EdgeInsets.fromLTRB(20, 15, 0, 15), child: Text( - widget.title ?? "", + widget.title, style: TextStyle( color: BrnThemeConfigurator.instance .getConfig() .commonConfig .brandPrimary, - fontSize: BrnFont.FONT_18, + fontSize: BrnFonts.f18, ), ), ), diff --git a/lib/src/components/form/items/misc/brn_title_item.dart b/lib/src/components/form/items/misc/brn_title_item.dart index fe024075..a3d77a21 100644 --- a/lib/src/components/form/items/misc/brn_title_item.dart +++ b/lib/src/components/form/items/misc/brn_title_item.dart @@ -2,7 +2,7 @@ import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; -import 'package:bruno/src/utils/font/brn_font.dart'; +import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; @@ -10,23 +10,23 @@ import 'package:flutter/widgets.dart'; // ignore: must_be_immutable class BrnTitleFormItem extends StatefulWidget { /// 录入项的唯一标识,主要用于录入类型页面框架中 - final String label; + final String? label; /// 录入项类型,主要用于录入类型页面框架中 - String type = BrnInputItemType.LABEL_TITLE; + final String type = BrnInputItemType.labelTitle; /// 录入项标题 final String title; /// 录入项子标题 - final String subTitle; + final String? subTitle; /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类 final String prefixIconType; @@ -41,27 +41,27 @@ class BrnTitleFormItem extends StatefulWidget { final bool isRequire; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 点击操作区标识 - final String operationLabel; + final String? operationLabel; /// 点击回调 - final VoidCallback onTap; + final VoidCallback? onTap; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnTitleFormItem( - {Key key, + {Key? key, this.label, - this.title: "", + this.title = "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, - this.error: "", - this.isEdit: true, - this.isRequire: false, + this.prefixIconType = BrnPrefixIconType.normal, + this.error = "", + this.isEdit = true, + this.isRequire = false, this.onTip, this.operationLabel, this.onTap, @@ -69,7 +69,7 @@ class BrnTitleFormItem extends StatefulWidget { : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -85,7 +85,7 @@ class BrnTitleFormItemState extends State { Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.itemEdgeInsets(widget.themeData), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -98,20 +98,20 @@ class BrnTitleFormItemState extends State { children: [ Container( padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, - widget.isRequire, widget.themeData), + widget.isRequire, widget.themeData!), child: Row( children: [ // 主标题 Container( child: Text( - widget.title ?? "", + widget.title, style: - BrnFormUtil.getHeadTitleTextStyle(widget.themeData), + BrnFormUtil.getHeadTitleTextStyle(widget.themeData!), )), // 问号提示 BrnFormUtil.buildTipLabelWidget( - widget.tipLabel, widget.onTip, widget.themeData), + widget.tipLabel, widget.onTip, widget.themeData!), ], ), ), @@ -132,8 +132,8 @@ class BrnTitleFormItemState extends State { child: Text( widget.operationLabel ?? "", style: TextStyle( - color: widget.themeData.commonConfig.brandPrimary, - fontSize: BrnFont.FONT_16, + color: widget.themeData!.commonConfig.brandPrimary, + fontSize: BrnFonts.f16, ), )), ), @@ -143,10 +143,10 @@ class BrnTitleFormItemState extends State { ), // 副标题 - BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData), + BrnFormUtil.buildSubTitleWidget(widget.subTitle, widget.themeData!), // 错误提示 - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData) + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!) ], ), ); diff --git a/lib/src/components/form/items/title/brn_base_title_item.dart b/lib/src/components/form/items/title/brn_base_title_item.dart index b03187ac..90a1ba0a 100644 --- a/lib/src/components/form/items/title/brn_base_title_item.dart +++ b/lib/src/components/form/items/title/brn_base_title_item.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; @@ -16,7 +18,7 @@ class BrnBaseTitle extends StatefulWidget { final String title; /// 子标题 - final String subTitle; + final String? subTitle; /// 是否必填项 final bool isRequire; @@ -32,40 +34,40 @@ class BrnBaseTitle extends StatefulWidget { /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 标题Widget - final Widget titleWidget; + final Widget? titleWidget; /// 子标题Widget - final Widget subTitleWidget; + final Widget? subTitleWidget; /// 右侧自定义操作区 - final Widget customActionWidget; + final Widget? customActionWidget; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnBaseTitle({ - Key key, - this.title: "", + Key? key, + this.title= "", this.subTitle, - this.isRequire: false, - this.isEdit: true, - this.error: "", + this.isRequire= false, + this.isEdit= true, + this.error= "", this.tipLabel, this.titleWidget, this.subTitleWidget, this.customActionWidget, this.onTip, this.themeData, - }) { + }) : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -86,7 +88,7 @@ class BrnTitleState extends State { Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.itemEdgeInsets(widget.themeData), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -99,7 +101,7 @@ class BrnTitleState extends State { children: [ Container( padding: BrnFormUtil.titleEdgeInsetsForHead( - widget.isRequire, widget.themeData), + widget.isRequire, widget.themeData!), child: Row( children: [ // 必填项符号 @@ -110,7 +112,7 @@ class BrnTitleState extends State { // 问号提示 BrnFormUtil.buildTipLabelWidget( - widget.tipLabel, widget.onTip, widget.themeData), + widget.tipLabel, widget.onTip, widget.themeData!), ], ), ), @@ -126,12 +128,12 @@ class BrnTitleState extends State { // 副标题 Offstage( - offstage: (widget.subTitle == null || widget.subTitle.isEmpty), + offstage: (widget.subTitle == null || widget.subTitle!.isEmpty), child: getSubTitleWidget(), ), // 错误提示 - BrnFormUtil.buildErrorWidget(widget.error, widget.themeData) + BrnFormUtil.buildErrorWidget(widget.error, widget.themeData!) ], ), ); @@ -139,24 +141,24 @@ class BrnTitleState extends State { Widget getTitleWidget() { if (widget.titleWidget != null) { - return widget.titleWidget; + return widget.titleWidget!; } else { - return BrnFormUtil.buildTitleWidget(widget.title, widget.themeData); + return BrnFormUtil.buildTitleWidget(widget.title, widget.themeData!); } } Widget getSubTitleWidget() { if (widget.subTitleWidget != null) { return Container( - padding: BrnFormUtil.subTitleEdgeInsets(widget.themeData), + padding: BrnFormUtil.subTitleEdgeInsets(widget.themeData!), child: widget.subTitleWidget, ); } else { return Container( - padding: BrnFormUtil.subTitleEdgeInsets(widget.themeData), + padding: BrnFormUtil.subTitleEdgeInsets(widget.themeData!), child: Text( widget.subTitle ?? "", - style: BrnFormUtil.getSubTitleTextStyle(widget.themeData), + style: BrnFormUtil.getSubTitleTextStyle(widget.themeData!), )); } } diff --git a/lib/src/components/form/items/title/brn_select_all_title_item.dart b/lib/src/components/form/items/title/brn_select_all_title_item.dart index 36a45110..9f1c804b 100644 --- a/lib/src/components/form/items/title/brn_select_all_title_item.dart +++ b/lib/src/components/form/items/title/brn_select_all_title_item.dart @@ -2,7 +2,6 @@ import 'package:bruno/src/components/form/base/input_item_interface.dart'; import 'package:bruno/src/components/form/items/title/brn_base_title_item.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/components/radio/brn_checkbox.dart'; -import 'package:bruno/src/components/radio/brn_radio_core.dart'; import 'package:bruno/src/theme/brn_theme.dart'; import 'package:flutter/widgets.dart'; @@ -17,7 +16,7 @@ class BrnSelectAllTitle extends StatefulWidget { final String title; /// 子标题 - final String subTitle; + final String? subTitle; /// 是否必填项 final bool isRequire; @@ -33,42 +32,42 @@ class BrnSelectAllTitle extends StatefulWidget { /// 2. 若赋值为非空字符串时 展示"问号图标&文案", /// 3. 若不赋值或赋值为null时 不显示提示项 /// 默认值为 3 - final String tipLabel; + final String? tipLabel; /// 标题Widget - final Widget titleWidget; + final Widget? titleWidget; /// 子标题Widget - final Widget subTitleWidget; + final Widget? subTitleWidget; /// 右侧自定义操作区 - final Widget customActionWidget; + final Widget? customActionWidget; /// 点击"?"图标回调 - final VoidCallback onTip; + final VoidCallback? onTip; /// 全选状态回调 - final OnBrnFormSelectAll onSelectAll; + final OnBrnFormSelectAll? onSelectAll; /// 选中项文案 - final String selectText; + final String? selectText; /// 选中项Widget - final Widget selectTextWidget; + final Widget? selectTextWidget; /// 选中项状态 - bool selectState; + final bool selectState; /// form配置 - BrnFormItemConfig themeData; + BrnFormItemConfig? themeData; BrnSelectAllTitle({ - Key key, - this.title: "", + Key? key, + this.title = "", this.subTitle, - this.isRequire: false, - this.isEdit: true, - this.error: "", + this.isRequire = false, + this.isEdit = true, + this.error = "", this.tipLabel, this.titleWidget, this.subTitleWidget, @@ -76,13 +75,13 @@ class BrnSelectAllTitle extends StatefulWidget { this.onSelectAll, this.selectText, this.selectTextWidget, - this.selectState: true, + this.selectState = true, this.themeData, this.customActionWidget, - }) { + }):super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -94,16 +93,18 @@ class BrnSelectAllTitle extends StatefulWidget { } class BrnSelectAllTitleState extends State { + late bool _selectState; + @override void initState() { super.initState(); + _selectState = widget.selectState; } @override void didUpdateWidget(BrnSelectAllTitle oldWidget) { super.didUpdateWidget(oldWidget); - - widget.selectState = oldWidget.selectState; + _selectState = oldWidget.selectState; } @override @@ -121,16 +122,16 @@ class BrnSelectAllTitleState extends State { child: getSelectTextWidget(), radioIndex: 0, disable: !widget.isEdit, - isSelected: widget.selectState, + isSelected: _selectState, onValueChangedAtIndex: (position, value) { - if (widget.isEdit != null && !widget.isEdit) { + if (!widget.isEdit) { return; } - widget.selectState = value; + _selectState = value; if (widget.onSelectAll != null) { - widget.onSelectAll(position, value); + widget.onSelectAll!(position, value); } }, ), @@ -138,7 +139,7 @@ class BrnSelectAllTitleState extends State { ); } - Widget getSelectTextWidget() { + Widget? getSelectTextWidget() { if (widget.selectTextWidget != null) { return widget.selectTextWidget; } else { @@ -151,13 +152,13 @@ class BrnSelectAllTitleState extends State { } } - TextStyle getOptionTextStyle(BrnFormItemConfig themeData) { - if (widget.selectState) { - return BrnFormUtil.getOptionSelectedTextStyle(widget.themeData); + TextStyle getOptionTextStyle(BrnFormItemConfig? themeData) { + if (_selectState) { + return BrnFormUtil.getOptionSelectedTextStyle(widget.themeData!); } - if (widget.isEdit != null && !widget.isEdit) { - return BrnFormUtil.getIsEditTextStyle(widget.themeData, widget.isEdit); + if (!widget.isEdit) { + return BrnFormUtil.getIsEditTextStyle(widget.themeData!, widget.isEdit); } - return BrnFormUtil.getOptionTextStyle(widget.themeData); + return BrnFormUtil.getOptionTextStyle(widget.themeData!); } } diff --git a/lib/src/components/form/utils/brn_form_util.dart b/lib/src/components/form/utils/brn_form_util.dart index b15c7c33..5ae9d8c7 100644 --- a/lib/src/components/form/utils/brn_form_util.dart +++ b/lib/src/components/form/utils/brn_form_util.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; import 'package:bruno/src/components/form/base/input_item_interface.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; @@ -12,9 +14,9 @@ class BrnFormUtil { /// 获取添加、删除图标 static Widget buildPrefixIcon(String prefixIconType, bool isEdit, - BuildContext context, VoidCallback onAddTap, VoidCallback onRemoveTap) { + BuildContext context, VoidCallback? onAddTap, VoidCallback? onRemoveTap) { return Offstage( - offstage: prefixIconType == BrnPrefixIconType.TYPE_NORMAL, + offstage: prefixIconType == BrnPrefixIconType.normal, child: Container( padding: EdgeInsets.only(right: 6), child: GestureDetector( @@ -37,9 +39,9 @@ class BrnFormUtil { return Container( padding: errorEdgeInsets(themeData), child: Offstage( - offstage: (error == null || error.isEmpty), + offstage: (error.isEmpty), child: Text( - error ?? "", + error, style: getErrorTextStyle(themeData), )), ); @@ -47,7 +49,7 @@ class BrnFormUtil { /// 获取子标题Widget static Widget buildSubTitleWidget( - String subTitle, BrnFormItemConfig themeData) { + String? subTitle, BrnFormItemConfig themeData) { return Offstage( offstage: (subTitle == null || subTitle.isEmpty), child: Container( @@ -62,14 +64,14 @@ class BrnFormUtil { /// 获取必填项 static Widget buildRequireWidget(bool isRequire) { return Offstage( - offstage: (isRequire == null || !isRequire), + offstage: (!isRequire), child: BrnFormUtil.getRequireIcon(isRequire), ); } /// 获取问号 static Widget buildTipLabelWidget( - String tipLabel, VoidCallback onTip, BrnFormItemConfig themeData) { + String? tipLabel, VoidCallback? onTip, BrnFormItemConfig themeData) { return Offstage( offstage: (tipLabel == null), child: GestureDetector( @@ -100,31 +102,28 @@ class BrnFormUtil { static Widget buildTitleWidget(String title, BrnFormItemConfig themeData) { return Container( child: Text( - title ?? "", + title, style: BrnFormUtil.getTitleTextStyle(themeData), )); } /// 录入项是否可编辑 static bool isEdit(bool isEdit) { - if (isEdit == null) { - return true; - } return isEdit; } static Widget getPrefixIcon(String type) { - if (type == BrnPrefixIconType.TYPE_ADD) { - return BrunoTools.getAssetImageWithBandColor(BrnAsset.ICON_ADD_FORM_ITEM); - } else if (type == BrnPrefixIconType.TYPE_REMOVE) { - return BrunoTools.getAssetImage(BrnAsset.ICON_REMOVE_FORM_ITEM); + if (type == BrnPrefixIconType.add) { + return BrunoTools.getAssetImageWithBandColor(BrnAsset.iconAddFormItem); + } else if (type == BrnPrefixIconType.remove) { + return BrunoTools.getAssetImage(BrnAsset.iconRemoveFormItem); } else { return Container(); } } static Widget getPrefixIconWithDisable(String type, bool isEnabled) { - return (isEnabled ?? true) + return (isEnabled) ? BrnFormUtil.getPrefixIcon(type) : ColorFiltered( colorFilter: ColorFilter.mode( @@ -138,13 +137,12 @@ class BrnFormUtil { } static Widget getRequireIcon(bool isRequire) { - isRequire ??= false; return Container( padding: isRequire ? EdgeInsets.only(right: 2) : EdgeInsets.only(right: 0), child: isRequire - ? BrunoTools.getAssetSizeImage(BrnAsset.ICON_REQUIRE_RED, 8, 8, + ? BrunoTools.getAssetSizeImage(BrnAsset.iconRequireRed, 8, 8, color: Color(0xFFFA3F3F)) : null, ); @@ -153,23 +151,21 @@ class BrnFormUtil { /// 视觉同学要求修改右箭头图标 static Image getRightArrowIcon() { return BrunoTools.getAssetSizeImage( - BrnAsset.ICON_RIGHT_ARROW, rightArrowSize, rightArrowSize); + BrnAsset.iconRightArrow, rightArrowSize, rightArrowSize); } static Image getQuestionMarkIcon() { - return BrunoTools.getAssetImage(BrnAsset.ICON_QUESTION); + return BrunoTools.getAssetImage(BrnAsset.iconQuestion); } /// 设置录入项总的padding, 不包括顶部和底部padding static EdgeInsets computeItemEdgeInsets2(String type, bool isRequire) { - isRequire ??= false; return EdgeInsets.fromLTRB(0, 0, 20, 14); } /// 设置内容行padding, 包括顶部和底部padding static EdgeInsets computeEdgeInsets2(String type, bool isRequire) { - isRequire ??= false; - if (isRequire && type == BrnPrefixIconType.TYPE_NORMAL) { + if (isRequire && type == BrnPrefixIconType.normal) { return EdgeInsets.only(left: 10, top: 14); } @@ -177,14 +173,13 @@ class BrnFormUtil { } static EdgeInsets computeErrorEdgeInsets(String type, bool isRequire) { - isRequire ??= false; return EdgeInsets.only( left: 20, top: 4, ); } - static TextInputType getInputType(String type) { + static TextInputType getInputType(String? type) { TextInputType inputType = TextInputType.text; if (type == null || type.isEmpty) { @@ -192,31 +187,31 @@ class BrnFormUtil { } switch (type) { - case BrnInputType.TEXT: + case BrnInputType.text: inputType = TextInputType.text; break; - case BrnInputType.MULTI_LINE: + case BrnInputType.multiLine: inputType = TextInputType.multiline; break; - case BrnInputType.NUMBER: + case BrnInputType.number: inputType = TextInputType.number; break; - case BrnInputType.DECIMAL: + case BrnInputType.decimal: inputType = TextInputType.numberWithOptions(decimal: true); break; - case BrnInputType.PHONE: + case BrnInputType.phone: inputType = TextInputType.phone; break; - case BrnInputType.DATE: + case BrnInputType.date: inputType = TextInputType.datetime; break; - case BrnInputType.EMAIL: + case BrnInputType.email: inputType = TextInputType.emailAddress; break; - case BrnInputType.URL: + case BrnInputType.url: inputType = TextInputType.url; break; - case BrnInputType.PWD: + case BrnInputType.pwd: inputType = TextInputType.visiblePassword; break; default: @@ -232,12 +227,12 @@ class BrnFormUtil { /// 处理点击"添加/删除"按钮动作 static void notifyAddRemoveTap(BuildContext context, String prefixIconType, - VoidCallback onAddTap, VoidCallback onRemoveTap) { - if (BrnPrefixIconType.TYPE_ADD == prefixIconType) { + VoidCallback? onAddTap, VoidCallback? onRemoveTap) { + if (BrnPrefixIconType.add == prefixIconType) { if (onAddTap != null) { onAddTap(); } - } else if (BrnPrefixIconType.TYPE_REMOVE == prefixIconType) { + } else if (BrnPrefixIconType.remove == prefixIconType) { if (onRemoveTap != null) { onRemoveTap(); } @@ -245,21 +240,21 @@ class BrnFormUtil { } /// 处理点击"添加/删除"按钮动作 - static void notifyAddTap(BuildContext context, VoidCallback onAddTap) { + static void notifyAddTap(BuildContext context, VoidCallback? onAddTap) { if (onAddTap != null) { onAddTap(); } } /// 处理点击"添加/删除"按钮动作 - static void notifyRemoveTap(BuildContext context, VoidCallback onRemoveTap) { + static void notifyRemoveTap(BuildContext context, VoidCallback? onRemoveTap) { if (onRemoveTap != null) { onRemoveTap(); } } /// 处理点击"按钮"动作 - static void notifyTap(BuildContext context, VoidCallback onWidgetTap) { + static void notifyTap(BuildContext context, VoidCallback? onWidgetTap) { if (onWidgetTap != null) { onWidgetTap(); } @@ -267,14 +262,14 @@ class BrnFormUtil { /// 处理 输入状态 变化 static void notifyInputChanged( - ValueChanged onTextChanged, String newStr) { + ValueChanged? onTextChanged, String newStr) { if (onTextChanged != null) { onTextChanged(/*oldStr, */ newStr); } } /// 处理 开关 变化 - static void notifySwitchChanged(OnBrnFormSwitchChanged onSwitchChanged, + static void notifySwitchChanged(OnBrnFormSwitchChanged? onSwitchChanged, BuildContext context, bool oldValue, bool newValue) { if (onSwitchChanged != null) { onSwitchChanged(oldValue, newValue); @@ -282,7 +277,7 @@ class BrnFormUtil { } /// 处理 数字值 变化 - static void notifyValueChanged(OnBrnFormValueChanged onValueChanged, + static void notifyValueChanged(OnBrnFormValueChanged? onValueChanged, BuildContext context, int oldVal, int newVal) { if (onValueChanged != null) { onValueChanged(oldVal, newVal); @@ -290,19 +285,19 @@ class BrnFormUtil { } /// 处理 单选选中状态变化 - static void notifyRadioStatusChanged(OnBrnFormRadioValueChanged onTextChanged, - BuildContext context, Object oldVal, Object newVal) { + static void notifyRadioStatusChanged(OnBrnFormRadioValueChanged? onTextChanged, + BuildContext context, Object? oldVal, Object? newVal) { if (onTextChanged != null) { - onTextChanged(oldVal, newVal); + onTextChanged(oldVal as String?, newVal as String?); } } /// 处理 多选选中状态变化 static void notifyMultiChoiceStatusChanged( - OnBrnFormMultiChoiceValueChanged onChoiceChanged, + OnBrnFormMultiChoiceValueChanged? onChoiceChanged, BuildContext context, - Object oldVal, - Object newVal, + List oldVal, + List newVal, ) { if (onChoiceChanged != null) { onChoiceChanged(oldVal, newVal); @@ -314,45 +309,43 @@ class BrnFormUtil { /// /// 选项之间的间距 - static EdgeInsets optionsMiddlePadding(BrnFormItemConfig themeData) { - return themeData?.optionsMiddlePadding; + static EdgeInsets? optionsMiddlePadding(BrnFormItemConfig themeData) { + return themeData.optionsMiddlePadding; } /// 走主题配置 上下右间距 static EdgeInsets itemEdgeInsets(BrnFormItemConfig themeData) { - return themeData?.formPadding; + return themeData.formPadding; } /// 标题行的左间距 static EdgeInsets titleEdgeInsets( String type, bool isRequire, BrnFormItemConfig themeData) { - isRequire ??= false; - if (isRequire && type == BrnPrefixIconType.TYPE_NORMAL) { - return themeData?.titlePaddingSm; + if (isRequire && type == BrnPrefixIconType.normal) { + return themeData.titlePaddingSm; } - return themeData?.titlePaddingLg; + return themeData.titlePaddingLg; } /// 标题行的左间距 static EdgeInsets titleEdgeInsetsForHead( bool isRequire, BrnFormItemConfig themeData) { - isRequire ??= false; - return isRequire ? themeData?.titlePaddingSm : themeData?.titlePaddingLg; + return isRequire ? themeData.titlePaddingSm : themeData.titlePaddingLg; } /// 子标题的右上间距 static EdgeInsets subTitleEdgeInsets(BrnFormItemConfig themeData) { - return themeData?.subTitlePadding; + return themeData.subTitlePadding; } /// error的右上间距 static EdgeInsets errorEdgeInsets(BrnFormItemConfig themeData) { - return themeData?.errorPadding; + return themeData.errorPadding; } /// 提示文本样式 static TextStyle getTipsTextStyle(BrnFormItemConfig themeData) { - return themeData?.tipsTextStyle?.generateTextStyle(); + return themeData.tipsTextStyle.generateTextStyle(); } /// 获取 右侧 输入、选择默认文本样式 @@ -360,28 +353,27 @@ class BrnFormUtil { {double height = 0}) { if (height > 0) { return BrnTextStyle(height: height) - .merge(themeData?.hintTextStyle) - ?.generateTextStyle(); + .merge(themeData.hintTextStyle) + .generateTextStyle(); } - return themeData?.hintTextStyle?.generateTextStyle(); + return themeData.hintTextStyle.generateTextStyle(); } /// 获取是否可编辑的字体 static TextStyle getIsEditTextStyle(BrnFormItemConfig themeData, bool isEdit, {double height = 0}) { - isEdit ??= true; if (height > 0) { return isEdit ? BrnTextStyle(height: height) - .merge(themeData?.contentTextStyle) - ?.generateTextStyle() + .merge(themeData.contentTextStyle) + .generateTextStyle() : BrnTextStyle(height: height) - .merge(themeData?.disableTextStyle) - ?.generateTextStyle(); + .merge(themeData.disableTextStyle) + .generateTextStyle(); } return isEdit - ? themeData?.contentTextStyle?.generateTextStyle() - : themeData?.disableTextStyle?.generateTextStyle(); + ? themeData.contentTextStyle.generateTextStyle() + : themeData.disableTextStyle.generateTextStyle(); } /// 获取标题文本样式 @@ -389,41 +381,41 @@ class BrnFormUtil { {double height = 0}) { if (height > 0) { return BrnTextStyle(height: height) - .merge(themeData?.titleTextStyle) - ?.generateTextStyle(); + .merge(themeData.titleTextStyle) + .generateTextStyle(); } - return themeData?.titleTextStyle?.generateTextStyle(); + return themeData.titleTextStyle.generateTextStyle(); } /// 获取标题文本样式 static TextStyle getHeadTitleTextStyle(BrnFormItemConfig themeData, {bool isBold = false}) { if (isBold) { - return themeData?.headTitleTextStyle - ?.merge(BrnTextStyle(fontWeight: FontWeight.w600)) - ?.generateTextStyle(); + return themeData.headTitleTextStyle + .merge(BrnTextStyle(fontWeight: FontWeight.w600)) + .generateTextStyle(); } - return themeData?.headTitleTextStyle?.generateTextStyle(); + return themeData.headTitleTextStyle.generateTextStyle(); } /// 获取左侧辅助样式 static TextStyle getSubTitleTextStyle(BrnFormItemConfig themeData) { - return themeData?.subTitleTextStyle?.generateTextStyle(); + return themeData.subTitleTextStyle.generateTextStyle(); } /// 获取error 文本样式 static TextStyle getErrorTextStyle(BrnFormItemConfig themeData) { - return themeData?.errorTextStyle?.generateTextStyle(); + return themeData.errorTextStyle.generateTextStyle(); } /// 获取选项文本样式 static TextStyle getOptionTextStyle(BrnFormItemConfig themeData) { - return themeData?.optionTextStyle?.generateTextStyle(); + return themeData.optionTextStyle.generateTextStyle(); } /// 获取选中选项文本样式 static TextStyle getOptionSelectedTextStyle(BrnFormItemConfig themeData) { - return themeData?.optionSelectedTextStyle?.generateTextStyle(); + return themeData.optionSelectedTextStyle.generateTextStyle(); } /// @@ -443,7 +435,7 @@ class BrnFormUtil { /// 当左右内容超出默认比例且「无」提示语,则按比例 4:6 布局 /// 有用户自定义比例时用用户自定义比例 static double getAutoLayoutContentRatio( - {bool tipLabelHidden, double layoutRatio}) { + {required bool tipLabelHidden, double? layoutRatio}) { double defaultRatio = tipLabelHidden ? BrnFormUtil.contentRatio : 1 - BrnFormUtil.contentRatio; diff --git a/lib/src/components/gallery/config/brn_basic_gallery_config.dart b/lib/src/components/gallery/config/brn_basic_gallery_config.dart index 73e00487..f7eb3871 100644 --- a/lib/src/components/gallery/config/brn_basic_gallery_config.dart +++ b/lib/src/components/gallery/config/brn_basic_gallery_config.dart @@ -1,27 +1,27 @@ import 'package:flutter/material.dart'; abstract class BrnBasicGroupConfig { - //每一个组的标题 - String title; + /// 每一个组的标题 + String? title; - List configList; + List? configList; - BrnBasicGroupConfig({this.title, @required this.configList}); + BrnBasicGroupConfig({this.title, required this.configList}); } -//每一个item的配置接口,定制化的需求可以自己实现相关接口 +/// 每一个 item 的配置接口,定制化的需求可以自己实现相关接口 abstract class BrnBasicItemConfig { - //该配置的groupIndex - int groupIndex; + /// 该配置的 groupIndex + int? groupIndex; - //改配置的type信息 - String type; + /// 该配置的 type 信息 + String? type; - //构建查看详情页的widget + /// 构建查看详情页的 widget Widget buildDetailWidget(BuildContext context, List allConfig, int groupId, int index); - //构建简略页的widget + /// 构建简略页的 widget Widget buildSummaryWidget(BuildContext context, List allConfig, int groupId, int index); } diff --git a/lib/src/components/gallery/config/brn_bottom_card.dart b/lib/src/components/gallery/config/brn_bottom_card.dart index ca8ff2ea..e811c5bb 100644 --- a/lib/src/components/gallery/config/brn_bottom_card.dart +++ b/lib/src/components/gallery/config/brn_bottom_card.dart @@ -5,21 +5,21 @@ import 'package:bruno/src/theme/configs/brn_gallery_detail_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -/// fold 收起状态 -/// unfold 展开状态 -/// cantFold 不可折叠的状态,描述信息直接展开 +/// [fold] 收起状态 +/// [unfold] 展开状态 +/// [cantFold] 不可折叠的状态,描述信息直接展开 enum PhotoBottomCardState { fold, unFold, cantFold } // ignore: must_be_immutable class BrnPhotoBottomCard extends StatefulWidget { - final String name; - final String des; + final String? name; + final String? des; final PhotoBottomCardState model; final double contentHeight; - BrnGalleryDetailConfig themeData; + BrnGalleryDetailConfig? themeData; BrnPhotoBottomCard( - {Key key, + {Key? key, this.name, this.des, this.model = PhotoBottomCardState.cantFold, @@ -33,7 +33,7 @@ class BrnPhotoBottomCard extends StatefulWidget { class _BrnPhotoBottomCardState extends State with TickerProviderStateMixin { - PhotoBottomCardState state; + PhotoBottomCardState? state; @override void initState() { @@ -45,14 +45,14 @@ class _BrnPhotoBottomCardState extends State Widget build(BuildContext context) { return Container( width: double.infinity, - color: widget.themeData.bottomBackgroundColor, + color: widget.themeData!.bottomBackgroundColor, child: state == PhotoBottomCardState.cantFold ? buildCantFoldWidget() : buildFoldableWidget(), ); } - //构建可折叠的card + /// 构建可折叠的card Widget buildFoldableWidget() { if (state == PhotoBottomCardState.fold) { return Container( @@ -62,7 +62,7 @@ class _BrnPhotoBottomCardState extends State mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(widget.name ?? "", - style: widget.themeData.titleStyle?.generateTextStyle()), + style: widget.themeData!.titleStyle.generateTextStyle()), GestureDetector( onTap: () { setState(() { @@ -76,12 +76,12 @@ class _BrnPhotoBottomCardState extends State padding: EdgeInsets.only(right: 4), child: Text('展开', style: - widget.themeData.actionStyle?.generateTextStyle()), + widget.themeData!.actionStyle.generateTextStyle()), ), Transform.rotate( angle: pi, child: BrunoTools.getAssetImageWithColor( - BrnAsset.ICON_UPARROW, widget.themeData.iconColor), + BrnAsset.iconUpArrow, widget.themeData!.iconColor), ) ], ), @@ -100,7 +100,7 @@ class _BrnPhotoBottomCardState extends State mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(widget.name ?? "", - style: widget.themeData.titleStyle?.generateTextStyle()), + style: widget.themeData!.titleStyle.generateTextStyle()), GestureDetector( onTap: () { setState(() { @@ -113,11 +113,11 @@ class _BrnPhotoBottomCardState extends State Padding( padding: EdgeInsets.only(right: 4), child: Text('收起', - style: widget.themeData.actionStyle - ?.generateTextStyle()), + style: widget.themeData!.actionStyle + .generateTextStyle()), ), BrunoTools.getAssetImageWithColor( - BrnAsset.ICON_UPARROW, widget.themeData.iconColor) + BrnAsset.iconUpArrow, widget.themeData!.iconColor) ], ), ) @@ -126,7 +126,7 @@ class _BrnPhotoBottomCardState extends State ), Text( widget.des ?? "", - style: widget.themeData.contentStyle?.generateTextStyle(), + style: widget.themeData!.contentStyle.generateTextStyle(), ) ], ), @@ -134,7 +134,7 @@ class _BrnPhotoBottomCardState extends State } } - //构建不可折叠的card,content是一个ScrollView + /// 构建不可折叠的 card, content 是一个 ScrollView Widget buildCantFoldWidget() { return Column( mainAxisAlignment: MainAxisAlignment.start, @@ -146,18 +146,18 @@ class _BrnPhotoBottomCardState extends State padding: EdgeInsets.only(top: 16, bottom: 12, left: 20, right: 20), child: Text( widget.name ?? "", - style: widget.themeData.titleStyle?.generateTextStyle(), + style: widget.themeData!.titleStyle.generateTextStyle(), ), ), ), Container( - height: widget.contentHeight ?? 150, + height: widget.contentHeight, child: SingleChildScrollView( physics: BouncingScrollPhysics(), child: Padding( child: Text( widget.des ?? "", - style: widget.themeData.contentStyle?.generateTextStyle(), + style: widget.themeData!.contentStyle.generateTextStyle(), ), padding: EdgeInsets.only(left: 20, right: 20)), )) diff --git a/lib/src/components/gallery/config/brn_controller.dart b/lib/src/components/gallery/config/brn_controller.dart index 685de414..fffb4c9f 100644 --- a/lib/src/components/gallery/config/brn_controller.dart +++ b/lib/src/components/gallery/config/brn_controller.dart @@ -1,3 +1,5 @@ + + import 'package:flutter/material.dart'; /// 控制页面刷新,并跳转到指定的 index @@ -9,7 +11,6 @@ class BrnGalleryController extends ChangeNotifier { /// [groupId] 第几组图片 /// [indexId] 组内的第几张 void refresh(int groupId, int indexId) { - assert(groupId != null && indexId != null); this.groupId = groupId; this.indexId = indexId; notifyListeners(); diff --git a/lib/src/components/gallery/config/brn_photo_gallery_config.dart b/lib/src/components/gallery/config/brn_photo_gallery_config.dart index e7c1542f..0a7f8e9a 100644 --- a/lib/src/components/gallery/config/brn_photo_gallery_config.dart +++ b/lib/src/components/gallery/config/brn_photo_gallery_config.dart @@ -8,61 +8,71 @@ import 'package:flutter/material.dart'; import 'package:photo_view/photo_view.dart'; class BrnPhotoGroupConfig extends BrnBasicGroupConfig { - final List urls; - final String title; - List configList; - final BrnGalleryDetailConfig themeData; - - //通过url列表生成配置 - BrnPhotoGroupConfig.url({this.title, @required this.urls, this.themeData}) { - configList = List(); - urls.forEach((item) => - configList.add(BrnPhotoItemConfig(url: item, themeData: themeData))); - } - - //自定义配置列表 - BrnPhotoGroupConfig({this.urls, this.title, this.configList, this.themeData}); + final List? urls; + final String? title; + final BrnGalleryDetailConfig? themeData; + + /// 通过 [urls] 列表生成配置 + BrnPhotoGroupConfig.url( + {this.title, + required this.urls, + this.themeData, + List? configList}) + : super( + title: title, + configList: urls + ?.map((item) => + BrnPhotoItemConfig(url: item, themeData: themeData)) + .toList()); + + /// 自定义配置列表 + BrnPhotoGroupConfig( + {this.urls, + this.title, + List? configList, + this.themeData}) + : super(title: title, configList: configList); } -//图片类的配置 +/// 图片类的配置 class BrnPhotoItemConfig extends BrnBasicItemConfig { - //图片url + /// 图片url final String url; - //图片的展示模式 + /// 图片的展示模式 final BoxFit fit; - //展位图 + /// 占位图 final String placeHolder; - //图片名称 用于详情页展示 - final String name; + /// 图片名称 用于详情页展示 + final String? name; - //图片描述公 用于详情页展示 - final String des; + /// 图片描述公 用于详情页展示 + final String? des; - //详情页图片点击回调 - final VoidCallback onTap; + /// 详情页图片点击回调 + final VoidCallback? onTap; - //详情页双击回调 - final VoidCallback onDoubleTap; + /// 详情页双击回调 + final VoidCallback? onDoubleTap; - //详情页长按回调 - final VoidCallback onLongPress; + /// 详情页长按回调 + final VoidCallback? onLongPress; - //详情页是否展示底部卡片,需要提供name和des信息 + /// 详情页是否展示底部卡片,需要提供name和des信息 final bool showBottom; - //底部展示卡片的模式// 0 表示 展开不可收起 1 收起可展开 2、 展开可收起 + /// [PhotoBottomCardState] 底部展示卡片的模式 final PhotoBottomCardState bottomCardModel; - //指定展开不可收起下 content的高度 + /// 指定展开不可收起下 content的高度 final double bottomContentHeight; - BrnGalleryDetailConfig themeData; + BrnGalleryDetailConfig? themeData; BrnPhotoItemConfig({ - @required this.url, + required this.url, this.fit = BoxFit.cover, this.placeHolder = "packages/${BrnStrings.flutterPackageName}/assets/icons/grey_place_holder.png", @@ -78,7 +88,7 @@ class BrnPhotoItemConfig extends BrnBasicItemConfig { }) { this.themeData ??= BrnGalleryDetailConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .galleryDetailConfig .merge(this.themeData); } @@ -115,23 +125,23 @@ class BrnPhotoItemConfig extends BrnBasicItemConfig { bottom: 0, child: GestureDetector( onTap: () { - if (onTap != null) onTap(); + onTap?.call(); }, onDoubleTap: () { - if (onDoubleTap != null) onDoubleTap(); + onDoubleTap?.call(); }, onLongPress: () { - if (onLongPress != null) onLongPress(); + onLongPress?.call(); }, child: Container( color: Colors.white, child: PhotoView( backgroundDecoration: - BoxDecoration(color: themeData.pageBackgroundColor), + BoxDecoration(color: themeData!.pageBackgroundColor), loadingBuilder: (context, event) { return Container( child: BrnLoadingDialog(), - color: themeData.pageBackgroundColor, + color: themeData!.pageBackgroundColor, ); }, imageProvider: NetworkImage(url), diff --git a/lib/src/components/gallery/page/brn_gallery_detail_page.dart b/lib/src/components/gallery/page/brn_gallery_detail_page.dart index 78701edf..829bb00f 100644 --- a/lib/src/components/gallery/page/brn_gallery_detail_page.dart +++ b/lib/src/components/gallery/page/brn_gallery_detail_page.dart @@ -31,17 +31,17 @@ class BrnGalleryDetailPage extends StatefulWidget { final bool fromSummary; /// 右上角自定义设置按钮,若为空,则展示 "全部图片" - final Widget Function(int groupId, int indexId) detailRightAction; + final Widget Function(int? groupId, int? indexId)? detailRightAction; /// 控制图片查看刷新 - final BrnGalleryController controller; + final BrnGalleryController? controller; /// 主题配置 - BrnGalleryDetailConfig themeData; + BrnGalleryDetailConfig? themeData; BrnGalleryDetailPage( - {Key key, - @required this.allConfig, + {Key? key, + required this.allConfig, this.initGroupId = 0, this.initIndexId = 0, this.fromSummary = false, @@ -51,7 +51,7 @@ class BrnGalleryDetailPage extends StatefulWidget { : super(key: key) { this.themeData ??= BrnGalleryDetailConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .galleryDetailConfig .merge(this.themeData); } @@ -63,24 +63,24 @@ class BrnGalleryDetailPage extends StatefulWidget { class _BrnGalleryDetailPageState extends State with TickerProviderStateMixin { /// title 关联的通知,因为 title 与图片所处的位置关联 - ValueNotifier _titleNotifier; - TabController _tabController; - List _allConfig = List(); - int _curTab; - int _curIndex; + ValueNotifier? _titleNotifier; + TabController? _tabController; + List _allConfig = []; + int? _curTab; + int? _curIndex; bool _assorted = false; - List _columnViews = List(); - List _tabs = List(); + List _columnViews = []; + List _tabs = []; String _groupTitle = ""; String _indexTitle = ""; - PageController _pageController; - List _pageViews = List(); + PageController? _pageController; + List _pageViews = []; Map _groupStartPosition = Map(); Map _groupCount = Map(); int _allCount = 0; - BrnAppBarConfig _appBarConfig; + BrnAppBarConfig? _appBarConfig; - BrnTabBarConfig _tabBarConfig; + late BrnTabBarConfig _tabBarConfig; @override void initState() { @@ -88,27 +88,27 @@ class _BrnGalleryDetailPageState extends State // 打平 appbar _appBarConfig = BrnThemeConfigurator.instance - .getConfig(configId: widget.themeData.configId) + .getConfig(configId: widget.themeData!.configId) .appBarConfig .merge(BrnAppBarConfig( - titleStyle: widget.themeData.appbarTitleStyle, - backgroundColor: widget.themeData.appbarBackgroundColor, - actionsStyle: widget.themeData.appbarActionStyle)); + titleStyle: widget.themeData!.appbarTitleStyle, + backgroundColor: widget.themeData!.appbarBackgroundColor, + actionsStyle: widget.themeData!.appbarActionStyle)); // 打平 tabBar _tabBarConfig = BrnThemeConfigurator.instance - .getConfig(configId: widget.themeData.configId) + .getConfig(configId: widget.themeData!.configId) .tabBarConfig .merge(BrnTabBarConfig( - unselectedLabelStyle: widget.themeData.tabBarUnSelectedLabelStyle, - labelStyle: widget.themeData.tabBarLabelStyle, - backgroundColor: widget.themeData.tabBarBackgroundColor, + unselectedLabelStyle: widget.themeData!.tabBarUnSelectedLabelStyle, + labelStyle: widget.themeData!.tabBarLabelStyle, + backgroundColor: widget.themeData!.tabBarBackgroundColor, )); _curIndex = widget.initIndexId; _curTab = widget.initGroupId; if (widget.controller != null) { - widget.controller.addListener(_refreshByController); + widget.controller!.addListener(_refreshByController); } } @@ -118,31 +118,31 @@ class _BrnGalleryDetailPageState extends State if (widget.controller != null && oldWidget.controller != widget.controller) { oldWidget.controller?.removeListener(_refreshByController); - widget.controller.addListener(_refreshByController); + widget.controller!.addListener(_refreshByController); } } void _refreshByController() { if (mounted) { - _curIndex = widget.controller.indexId; - _curTab = widget.controller.groupId; + _curIndex = widget.controller!.indexId; + _curTab = widget.controller!.groupId; setState(() {}); } } /// 根据groupIndex和index查page的位置 - int _getPagePosition(int groupIndex, int index) { + int? _getPagePosition(int? groupIndex, int? index) { return _groupStartPosition[groupIndex] + index; } /// 根据page的位置反查groupIndex和index List _getGroupIndexAndIndex(int pagePosition) { - List result = List(); + List result = []; MapEntry entry = _groupStartPosition.entries.toList().firstWhere((entry) { return (entry.value > pagePosition); }); result.add(entry.key - 1); - result.add(pagePosition - (_groupStartPosition[entry.key - 1])); + result.add(pagePosition - (_groupStartPosition[entry.key - 1]) as int); return result; } @@ -152,13 +152,12 @@ class _BrnGalleryDetailPageState extends State _columnViews.clear(); _allConfig.clear(); // 过滤 config 中内容为空的选项 - if (widget.allConfig != null) { - widget.allConfig.forEach((e) { - if (e.configList != null && e.configList.isNotEmpty) { - _allConfig.add(e); - } - }); - } + widget.allConfig.forEach((e) { + if (e.configList != null && e.configList!.isNotEmpty) { + _allConfig.add(e); + } + }); + _allCount = 0; _groupCount.clear(); _groupStartPosition.clear(); @@ -168,57 +167,55 @@ class _BrnGalleryDetailPageState extends State void _buildViews() { _reset(); - _titleNotifier = ValueNotifier(null); + _titleNotifier = ValueNotifier(''); _tabController = TabController( - length: _allConfig.length, vsync: this, initialIndex: _curTab) + length: _allConfig.length, vsync: this, initialIndex: _curTab!) ..addListener(() { - _curTab = _tabController.index; + _curTab = _tabController!.index; }); - if (_allConfig != null) { - int i = 0; - for (; i < _allConfig.length; i++) { - _groupStartPosition[i] = _allCount; - _allCount += _allConfig[i].configList.length; - _groupCount[i] = _allConfig[i].configList.length; - } + int i = 0; + for (; i < _allConfig.length; i++) { _groupStartPosition[i] = _allCount; + _allCount += _allConfig[i].configList!.length; + _groupCount[i] = _allConfig[i].configList!.length; } + _groupStartPosition[i] = _allCount; + _pageController = - PageController(initialPage: _getPagePosition(_curTab, _curIndex)); - if (_allConfig != null) { - _assorted = _allConfig.length > 1; + PageController(initialPage: _getPagePosition(_curTab, _curIndex)!); + _assorted = _allConfig.length > 1; - _allConfig.forEach((item) => _tabs.add( - BadgeTab(text: '${item.title ?? ""}(${item.configList.length})'))); - if (_allConfig.length > 1) - _columnViews.add(BrnTabBar( - backgroundcolor: _tabBarConfig.backgroundColor, - unselectedLabelStyle: - _tabBarConfig.unselectedLabelStyle?.generateTextStyle(), - unselectedLabelColor: _tabBarConfig.unselectedLabelStyle?.color, - labelColor: _tabBarConfig.labelStyle?.color, - indicatorColor: _tabBarConfig.labelStyle?.color, - labelStyle: _tabBarConfig.labelStyle?.generateTextStyle(), - tabs: _tabs, - controller: _tabController, - onTap: (state, index) { - _pageController.animateToPage(_getPagePosition(index, 0), - duration: Duration(microseconds: 100), curve: Curves.linear); - }, - )); + _allConfig.forEach((item) => _tabs.add( + BadgeTab(text: '${item.title ?? ""}(${item.configList!.length})'))); + if (_allConfig.length > 1) + _columnViews.add(BrnTabBar( + backgroundcolor: _tabBarConfig.backgroundColor, + unselectedLabelStyle: + _tabBarConfig.unselectedLabelStyle.generateTextStyle(), + unselectedLabelColor: _tabBarConfig.unselectedLabelStyle.color, + labelColor: _tabBarConfig.labelStyle.color, + indicatorColor: _tabBarConfig.labelStyle.color, + labelStyle: _tabBarConfig.labelStyle.generateTextStyle(), + tabs: _tabs, + controller: _tabController, + onTap: (state, index) { + _pageController!.animateToPage(_getPagePosition(index, 0)!, + duration: Duration(microseconds: 100), curve: Curves.linear); + }, + )); - for (int i = 0; i < _allConfig.length; i++) { - for (int j = 0; j < _allConfig[i].configList.length; j++) { - _pageViews.add(_allConfig[i] - .configList[j] - .buildDetailWidget(context, _allConfig, i, j)); - } + for (int i = 0; i < _allConfig.length; i++) { + for (int j = 0; j < _allConfig[i].configList!.length; j++) { + _pageViews.add(_allConfig[i] + .configList![j] + .buildDetailWidget(context, _allConfig, i, j)); } } - _groupTitle = _allConfig[_curTab].title ?? ""; - _indexTitle = "${_curIndex + 1}/${_allConfig[_curTab].configList.length}"; - _titleNotifier.value = + _groupTitle = _allConfig[_curTab!].title ?? ""; + _indexTitle = + "${_curIndex! + 1}/${_allConfig[_curTab!].configList!.length}"; + _titleNotifier?.value = _assorted ? "$_groupTitle($_indexTitle)" : "$_indexTitle"; _columnViews.add(Expanded( @@ -233,7 +230,7 @@ class _BrnGalleryDetailPageState extends State )); } - Future _moveToIndex(index) { + Future? _moveToIndex(index) { // 改变 title List pos = _getGroupIndexAndIndex(index); _indexTitle = "${pos[1] + 1}/${_groupCount[pos[0]]}"; @@ -242,9 +239,9 @@ class _BrnGalleryDetailPageState extends State // 处理是是否需要切换 tab if (_curTab != pos[0]) { _curTab = pos[0]; - _tabController.animateTo(pos[0]); + _tabController!.animateTo(pos[0]); } - _titleNotifier.value = + _titleNotifier?.value = _assorted ? "$_groupTitle($_indexTitle)" : "$_indexTitle"; return null; } @@ -255,24 +252,24 @@ class _BrnGalleryDetailPageState extends State return Scaffold( key: GlobalKey(), appBar: BrnAppBar( - brightness: widget.themeData.appbarBrightness, - backgroundColor: _appBarConfig.backgroundColor, + brightness: widget.themeData!.appbarBrightness, + backgroundColor: _appBarConfig!.backgroundColor, showDefaultBottom: false, themeData: _appBarConfig, title: ValueListenableBuilder( - valueListenable: _titleNotifier, - builder: (c, v, _) { + valueListenable: _titleNotifier!, + builder: (c, String v, _) { return Text( - v ?? "", - style: _appBarConfig.titleStyle?.generateTextStyle(), + v, + style: _appBarConfig!.titleStyle.generateTextStyle(), ); }, ), actions: widget.detailRightAction != null ? ValueListenableBuilder( builder: (c, v, _) => - widget.detailRightAction(_curTab, _curIndex), - valueListenable: _titleNotifier, + widget.detailRightAction!(_curTab, _curIndex), + valueListenable: _titleNotifier!, ) : BrnTextAction( '全部图片', @@ -289,10 +286,10 @@ class _BrnGalleryDetailPageState extends State fromDetail: true, ); })).then((result) { - if (result is List && result != null) { - _tabController.animateTo(result[0]); - _pageController - .jumpToPage(_getPagePosition(result[0], result[1])); + if (result is List) { + _tabController!.animateTo(result[0]); + _pageController!.jumpToPage( + _getPagePosition(result[0], result[1])!); } }); } @@ -304,10 +301,10 @@ class _BrnGalleryDetailPageState extends State } Widget _body() { - if (_allConfig == null || _allConfig.isEmpty) return Row(); + if (_allConfig.isEmpty) return Row(); return NotificationListener( child: Container( - color: widget.themeData.pageBackgroundColor, + color: widget.themeData!.pageBackgroundColor, child: Column( children: _columnViews, ), diff --git a/lib/src/components/gallery/page/brn_gallery_summary_page.dart b/lib/src/components/gallery/page/brn_gallery_summary_page.dart index bc81ebe0..2e7d7c93 100644 --- a/lib/src/components/gallery/page/brn_gallery_summary_page.dart +++ b/lib/src/components/gallery/page/brn_gallery_summary_page.dart @@ -22,13 +22,13 @@ class BrnGallerySummaryPage extends StatefulWidget { final bool fromDetail; /// 图片详情页右上角自定义设置按钮,若为空,则展示 "全部图片" - final Widget Function(int groupId, int indexId) detailRightAction; + final Widget Function(int? groupId, int? indexId)? detailRightAction; /// 控制图片查看刷新 - final BrnGalleryController controller; + final BrnGalleryController? controller; BrnGallerySummaryPage( - {@required this.allConfig, + {required this.allConfig, this.rowCount = 4, this.fromDetail = false, this.detailRightAction, @@ -43,7 +43,7 @@ class _BrnGallerySummaryPageState extends State { void initState() { super.initState(); if (widget.controller != null) { - widget.controller.addListener(() { + widget.controller!.addListener(() { if (mounted) { setState(() {}); } @@ -56,7 +56,7 @@ class _BrnGallerySummaryPageState extends State { super.didUpdateWidget(oldWidget); if (widget.controller != null && oldWidget.controller != widget.controller) { - widget.controller.addListener(() { + widget.controller!.addListener(() { if (mounted) { setState(() {}); } @@ -76,40 +76,36 @@ class _BrnGallerySummaryPageState extends State { } Widget _body() { - if (widget?.allConfig != null) { - List allConfig = widget.allConfig; - if (allConfig.length == 1) { - return SingleChildScrollView(child: _buildItem(allConfig[0], 0)); - } else { - return Padding( - padding: EdgeInsets.only(bottom: 20), - child: BrnAnchorTab( - widgetIndexedBuilder: (c, i) { - return _buildItem(allConfig[i], i); - }, - tabIndexedBuilder: (c, i) { - return BadgeTab( - text: - '${allConfig[i].title}(${allConfig[i].configList.length})'); - }, - itemCount: allConfig.length), - ); - } + List allConfig = widget.allConfig; + if (allConfig.length == 1) { + return SingleChildScrollView(child: _buildItem(allConfig[0], 0)); } else { - return Row(); + return Padding( + padding: EdgeInsets.only(bottom: 20), + child: BrnAnchorTab( + widgetIndexedBuilder: (c, i) { + return _buildItem(allConfig[i], i); + }, + tabIndexedBuilder: (c, i) { + return BadgeTab( + text: + '${allConfig[i].title ?? ""}(${allConfig[i].configList?.length ?? 0})'); + }, + itemCount: allConfig.length), + ); } } - Widget _buildItem(BrnBasicGroupConfig groupConfig, int groupId) { + Widget _buildItem(BrnBasicGroupConfig? groupConfig, int groupId) { if (groupConfig == null) return Row(); - List columnViews = List(); + List columnViews = []; if (groupConfig.title != null) columnViews.add(Container( height: 53, child: Padding( padding: EdgeInsets.only(top: 16, bottom: 12, left: 20, right: 20), child: Text( - '${groupConfig.title}(${groupConfig.configList.length})', + '${groupConfig.title}(${groupConfig.configList?.length ?? 0})', style: TextStyle( color: Color(0xFF222222), fontSize: 18, @@ -118,8 +114,8 @@ class _BrnGallerySummaryPageState extends State { ), )); if (groupConfig.configList != null) { - List gridViews = List(); - for (int i = 0; i < groupConfig.configList.length; i++) + List gridViews = []; + for (int i = 0; i < groupConfig.configList!.length; i++) gridViews.add(GestureDetector( onTap: () { //页面的跳转不应该交个子Widget处理 @@ -137,7 +133,7 @@ class _BrnGallerySummaryPageState extends State { ); })); }, - child: groupConfig.configList[i] + child: groupConfig.configList![i] .buildSummaryWidget(context, widget.allConfig, groupId, i), )); columnViews.add(GridView.count( diff --git a/lib/src/components/guide/brn_delay_rendered_widget.dart b/lib/src/components/guide/brn_delay_rendered_widget.dart index 364b8cae..0c8bc91b 100644 --- a/lib/src/components/guide/brn_delay_rendered_widget.dart +++ b/lib/src/components/guide/brn_delay_rendered_widget.dart @@ -15,10 +15,10 @@ class _DelayRenderedWidget extends StatefulWidget { final bool removed; const _DelayRenderedWidget({ - Key key, + Key? key, this.removed = false, this.duration = const Duration(milliseconds: 200), - this.child, + required this.child, this.childPersist = false, }) : super(key: key); @@ -28,8 +28,8 @@ class _DelayRenderedWidget extends StatefulWidget { class _DelayRenderedWidgetState extends State<_DelayRenderedWidget> { double opacity = 0; - Widget child; - Timer timer; + late Widget child; + late Timer timer; /// Time interval between animations final Duration durationInterval = Duration(milliseconds: 100); @@ -49,8 +49,8 @@ class _DelayRenderedWidgetState extends State<_DelayRenderedWidget> { @override void dispose() { - super.dispose(); timer.cancel(); + super.dispose(); } @override diff --git a/lib/src/components/guide/brn_flutter_guide.dart b/lib/src/components/guide/brn_flutter_guide.dart index 672cd925..5eac9e50 100644 --- a/lib/src/components/guide/brn_flutter_guide.dart +++ b/lib/src/components/guide/brn_flutter_guide.dart @@ -32,18 +32,18 @@ class BrnTipInfoBean { /// 支持 强引导:界面变灰,引导框高亮| 弱引导:直接在界面浮现提示框两种 class BrnGuide { bool _removed = false; - double _widgetWidth; - double _widgetHeight; - Offset _widgetOffset; - OverlayEntry _overlayEntry; + late double _widgetWidth; + late double _widgetHeight; + late Offset _widgetOffset; + OverlayEntry? _overlayEntry; int _currentStepIndex = 0; - Widget _stepWidget; + late Widget _stepWidget; List _configMap = []; List _globalKeys = []; final Color _maskColor = Colors.black.withOpacity(.6); final Duration _animationDuration = Duration(milliseconds: 300); final _th = _Throttling(duration: Duration(milliseconds: 500)); - Size _lastScreenSize; + late Size _lastScreenSize; /// 当前处于第几步 int get currentStepIndex => _currentStepIndex; @@ -61,15 +61,15 @@ class BrnGuide { final int stepCount; /// 每次点击的下一步的时候的回调 - final void Function(int nextIndex) onNextClick; + final void Function(int nextIndex)? onNextClick; /// 引导交互的模式 GuideMode introMode; BrnGuide( - {@required this.introMode, - @required this.widgetBuilder, - @required this.stepCount, + {required this.introMode, + required this.widgetBuilder, + required this.stepCount, this.borderRadius = const BorderRadius.all(Radius.circular(4)), this.padding = const EdgeInsets.all(10), this.onNextClick}) @@ -89,8 +89,8 @@ class BrnGuide { /// [borderRadius] BorderRadius setting void setStepConfig( int stepIndex, { - EdgeInsets padding, - BorderRadiusGeometry borderRadius, + EdgeInsets? padding, + BorderRadiusGeometry? borderRadius, }) { assert(stepIndex >= 0 && stepIndex < stepCount); _configMap[stepIndex] = { @@ -106,8 +106,8 @@ class BrnGuide { /// [borderRadius] BorderRadius setting void setStepsConfig( List stepsIndex, { - EdgeInsets padding, - BorderRadiusGeometry borderRadius, + EdgeInsets? padding, + BorderRadiusGeometry? borderRadius, }) { assert(stepsIndex .every((stepIndex) => stepIndex >= 0 && stepIndex < stepCount)); @@ -122,9 +122,9 @@ class BrnGuide { void _getWidgetInfo(GlobalKey globalKey) { try { - EdgeInsets currentConfig = _configMap[_currentStepIndex]['padding']; - RenderBox renderBox; - renderBox = globalKey.currentContext.findRenderObject(); + EdgeInsets? currentConfig = _configMap[_currentStepIndex]['padding']; + RenderBox renderBox = + globalKey.currentContext?.findRenderObject() as RenderBox; _widgetWidth = renderBox.size.width + (currentConfig?.horizontal ?? padding.horizontal); _widgetHeight = @@ -139,20 +139,20 @@ class BrnGuide { _widgetWidth = 0; _widgetHeight = 0; _widgetOffset = Offset.zero; - debugPrint('获取组件尺寸信息异常'); + debugPrint('获取组件尺寸信息异常${e.toString()}'); } } Widget _maskBuilder({ - double width, - double height, - BlendMode backgroundBlendMode, - @required double left, - @required double top, - double bottom, - double right, - BorderRadiusGeometry borderRadiusGeometry, - Widget child, + double? width, + double? height, + BlendMode? backgroundBlendMode, + required double left, + required double top, + double? bottom, + double? right, + BorderRadiusGeometry? borderRadiusGeometry, + Widget? child, }) { final decoration = BoxDecoration( color: Colors.white, @@ -189,7 +189,7 @@ class BrnGuide { _lastScreenSize = screenSize; _th.throttle(() { _createStepWidget(context); - _overlayEntry.markNeedsBuild(); + _overlayEntry?.markNeedsBuild(); }); } @@ -239,14 +239,14 @@ class BrnGuide { ); }, ); - Overlay.of(context).insert(_overlayEntry); + Overlay.of(context)?.insert(_overlayEntry!); } void _onNext(BuildContext context) { _currentStepIndex++; if (_currentStepIndex < stepCount) { if (onNextClick != null) { - onNextClick(currentStepIndex); + onNextClick!(currentStepIndex); } _renderStep(context); } @@ -255,9 +255,9 @@ class BrnGuide { void _onFinish() { if (_overlayEntry == null) return; _removed = true; - _overlayEntry.markNeedsBuild(); + _overlayEntry!.markNeedsBuild(); Timer(_animationDuration, () { - _overlayEntry.remove(); + _overlayEntry?.remove(); _overlayEntry = null; }); } @@ -272,12 +272,8 @@ class BrnGuide { screenSize: screenSize, size: widgetSize, onNext: _currentStepIndex == stepCount - 1 - ? () { - _onFinish(); - } - : () { - _onNext(context); - }, + ? () => _onFinish() + : () => _onNext(context), offset: _widgetOffset, currentStepIndex: _currentStepIndex, stepCount: stepCount, @@ -287,7 +283,7 @@ class BrnGuide { void _renderStep(BuildContext context) { _createStepWidget(context); - if (_overlayEntry != null) _overlayEntry.markNeedsBuild(); + _overlayEntry?.markNeedsBuild(); } /// 触发引导操作 [context]当前环境[BuildContext]的启动方法 diff --git a/lib/src/components/guide/brn_pulse_widget.dart b/lib/src/components/guide/brn_pulse_widget.dart index b03d9581..86181202 100644 --- a/lib/src/components/guide/brn_pulse_widget.dart +++ b/lib/src/components/guide/brn_pulse_widget.dart @@ -6,7 +6,8 @@ class PulseWidget extends StatefulWidget { final double width; final double height; - const PulseWidget({Key key, this.width, this.height}) : super(key: key); + const PulseWidget({Key? key, required this.width, required this.height}) + : super(key: key); @override _PulseWidgetState createState() => _PulseWidgetState(); @@ -14,9 +15,9 @@ class PulseWidget extends StatefulWidget { class _PulseWidgetState extends State with TickerProviderStateMixin { - AnimationController _scaleController; - AnimationController _fadeController; - Animation _alphaAnimation; + late AnimationController _scaleController; + late AnimationController _fadeController; + late Animation _alphaAnimation; @override void initState() { diff --git a/lib/src/components/guide/brn_step_widget_builder.dart b/lib/src/components/guide/brn_step_widget_builder.dart index a6a25747..32b95f36 100644 --- a/lib/src/components/guide/brn_step_widget_builder.dart +++ b/lib/src/components/guide/brn_step_widget_builder.dart @@ -6,7 +6,10 @@ enum GuideDirection { left, right, topLeft, bottomLeft, topRight, bottomRight } /// 单步引导组件 class StepWidgetBuilder { static Map _smartGetPosition( - {Size size, Size screenSize, Offset offset, GuideMode introMode}) { + {required Size size, + required Size screenSize, + required Offset offset, + required GuideMode introMode}) { double height = size.height; double width = size.width; double screenWidth = screenSize.width; @@ -164,8 +167,8 @@ class StepWidgetBuilder { //showSkipLabel表示是否展示跳过按钮 //showClose表示是否展示关闭按钮 static Widget Function(StepWidgetParams params) useDefaultTheme( - {@required List tipInfo, - String Function(int currentStepIndex, int stepCount) buttonTextBuilder, + {required List tipInfo, + String Function(int currentStepIndex, int stepCount)? buttonTextBuilder, bool showStepLabel = true, bool showSkipLabel = true, bool showClose = true}) { diff --git a/lib/src/components/guide/brn_step_widget_params.dart b/lib/src/components/guide/brn_step_widget_params.dart index f8120379..d5c56cd7 100644 --- a/lib/src/components/guide/brn_step_widget_params.dart +++ b/lib/src/components/guide/brn_step_widget_params.dart @@ -3,20 +3,20 @@ part of brn_intro; /// Highlight component parameters class WidgetParams { /// Padding of highlighted area - EdgeInsets padding; + EdgeInsets? padding; /// Border radius of the highlighted area - BorderRadiusGeometry borderRadius; + BorderRadiusGeometry? borderRadius; } /// The data passed in when the system calls [GuideStep.widgetBuilder] when the guide page is generated /// class StepWidgetParams { /// Enter the next guide page method, or null if there is no - final VoidCallback onNext; + final VoidCallback? onNext; /// End all guide page methods - final VoidCallback onFinish; + final VoidCallback? onFinish; /// Which guide page is currently displayed, starting from 0 final int currentStepIndex; @@ -35,14 +35,14 @@ class StepWidgetParams { final GuideMode introMode; StepWidgetParams({ - this.introMode, + required this.introMode, this.onNext, this.onFinish, - @required this.screenSize, - @required this.size, - @required this.currentStepIndex, - @required this.stepCount, - @required this.offset, + required this.screenSize, + required this.size, + required this.currentStepIndex, + required this.stepCount, + required this.offset, }); @override diff --git a/lib/src/components/guide/brn_throttling.dart b/lib/src/components/guide/brn_throttling.dart index 9ebfcb7c..f4055c84 100644 --- a/lib/src/components/guide/brn_throttling.dart +++ b/lib/src/components/guide/brn_throttling.dart @@ -3,11 +3,11 @@ part of brn_intro; /// Throttling /// Have method [throttle] class _Throttling { - Duration _duration; - Timer _timer; + late Duration _duration; + Timer? _timer; _Throttling({Duration duration = const Duration(seconds: 1)}) - : assert(duration is Duration && !duration.isNegative) { + : assert(!duration.isNegative) { _duration = duration; } diff --git a/lib/src/components/guide/brn_tip_widget.dart b/lib/src/components/guide/brn_tip_widget.dart index 6fa23b68..d8e1f094 100644 --- a/lib/src/components/guide/brn_tip_widget.dart +++ b/lib/src/components/guide/brn_tip_widget.dart @@ -10,12 +10,12 @@ enum GuideMode { force, soft } /// 默认的引导组件包含,强和弱两种交互模式 class BrnTipInfoWidget extends StatelessWidget { final GuideDirection direction; - final void Function() onClose; - final void Function() onNext; - final void Function() onSkip; + final void Function()? onClose; + final void Function()? onNext; + final void Function()? onSkip; final double width; - final double height; + final double? height; final BrnTipInfoBean info; final GuideMode mode; @@ -24,21 +24,21 @@ class BrnTipInfoWidget extends StatelessWidget { /// Total number of guide pages final int stepCount; - final num arrowPadding; - final String nextTip; + final double? arrowPadding; + final String? nextTip; const BrnTipInfoWidget( - {Key key, + {Key? key, this.onClose, this.onNext, this.onSkip, - @required this.width, - @required this.height, - this.currentStepIndex, - this.stepCount, - this.info, + required this.width, + this.height, + this.currentStepIndex = 0, + required this.stepCount, + required this.info, this.mode = GuideMode.force, - this.direction, + required this.direction, this.arrowPadding, this.nextTip}) : super(key: key); @@ -160,7 +160,7 @@ class BrnTipInfoWidget extends StatelessWidget { } Widget buildImage() { - if (info.imgUrl == null || info.imgUrl.isEmpty) return Row(); + if (info.imgUrl.isEmpty) return Row(); double imageSize = width - 16; return Padding( padding: EdgeInsets.only(top: 14), @@ -195,10 +195,10 @@ class BrnTipInfoWidget extends StatelessWidget { ? Row() : GestureDetector( onTap: () { - onClose(); + onClose!(); }, child: BrunoTools.getAssetImageWithColor( - BrnAsset.ICON_CLOSE, Colors.black), + BrnAsset.iconClose, Colors.black), ), ), ], @@ -207,7 +207,7 @@ class BrnTipInfoWidget extends StatelessWidget { } Widget buildMessage() { - if (info.message == null) return Row(); + if (info.message.isEmpty) return Row(); return Padding( padding: EdgeInsets.only(top: 6), child: Text('${info.message}', @@ -234,7 +234,7 @@ class BrnTipInfoWidget extends StatelessWidget { alignment: Alignment.centerLeft, child: GestureDetector( onTap: () { - onSkip(); + onSkip!(); }, child: Text( '跳过 (${currentStepIndex + 1}/$stepCount)', @@ -264,12 +264,13 @@ class BrnTipInfoWidget extends StatelessWidget { ), child: GestureDetector( onTap: () { - onNext(); + onNext!(); }, child: Text( - nextTip ?? stepCount == currentStepIndex + 1 - ? '我知道了' - : '下一步', + nextTip ?? + (stepCount == currentStepIndex + 1 + ? '我知道了' + : '下一步'), style: TextStyle(color: Colors.white, fontSize: 14), ), ), @@ -300,7 +301,7 @@ class BrnTipInfoWidget extends StatelessWidget { alignment: Alignment.centerLeft, child: GestureDetector( onTap: () { - onSkip(); + onSkip!(); }, child: Text( '跳过 (${currentStepIndex + 1}/$stepCount)', @@ -322,12 +323,13 @@ class BrnTipInfoWidget extends StatelessWidget { alignment: Alignment.centerLeft, child: GestureDetector( onTap: () { - onNext(); + onNext!(); }, child: Text( - nextTip ?? stepCount == currentStepIndex + 1 - ? '我知道了' - : '下一步', + nextTip ?? + (stepCount == currentStepIndex + 1 + ? '我知道了' + : '下一步'), style: TextStyle( color: BrnThemeConfigurator.instance .getConfig() @@ -357,7 +359,7 @@ class CustomTrianglePainter extends CustomPainter { CustomTrianglePainter( {this.color = Colors.white, this.borderColor = const Color(0XFFCCCCCC), - @required this.direction}); + required this.direction}); @override void paint(Canvas canvas, Size size) { diff --git a/lib/src/components/input/brn_input_text.dart b/lib/src/components/input/brn_input_text.dart index f1e2b352..8642af4b 100644 --- a/lib/src/components/input/brn_input_text.dart +++ b/lib/src/components/input/brn_input_text.dart @@ -19,10 +19,10 @@ typedef BrnInputTextEditingCompleteCallback = Function(String input); class BrnInputText extends StatelessWidget { /// 搜索框输入内容改变时候的回调函数 - final BrnInputTextChangeCallback onTextChange; + final BrnInputTextChangeCallback? onTextChange; /// 点击确定后的回调 - final BrnInputTextSubmitCallback onSubmit; + final BrnInputTextSubmitCallback? onSubmit; /// 容器的最大高度,默认 200 final double maxHeight; @@ -37,10 +37,11 @@ class BrnInputText extends StatelessWidget { final String hint; /// 输入框的初始值,默认为"" + /// 不能定义为String,兼容example调用的传值 final String textString; /// 用于对 TextField 更精细的控制,若传入该字段,[textString] 参数将失效,可使用 TextEditingController.text 进行赋值。 - final TextEditingController textEditingController; + final TextEditingController? textEditingController; /// 最大字数,默认200 final int maxLength; @@ -52,22 +53,22 @@ class BrnInputText extends StatelessWidget { final EdgeInsetsGeometry padding; /// 最大hint行数 - final int maxHintLines; + final int? maxHintLines; /// 搜索框的焦点控制器 - final FocusNode focusNode; + final FocusNode? focusNode; /// 键盘输入行为, 默认为 TextInputAction.done final TextInputAction textInputAction; /// 光标展示 - final bool autoFocus; + final bool? autoFocus; /// 背景圆角 - final double borderRadius; + final double? borderRadius; /// 边框颜色 - final Color borderColor; + final Color? borderColor; BrnInputText({ this.onTextChange, @@ -96,13 +97,13 @@ class BrnInputText extends StatelessWidget { Widget _inputText(BuildContext context) { String textData = textString; - if (textData != null && textString.runes.length > maxLength) { + if (textString.runes.length > maxLength) { var sRunes = textData.runes; textData = String.fromCharCodes(sRunes, 0, maxLength); } var _controller = textEditingController; if (_controller == null) { - if (textData != null && textData.length > 0) { + if (textData.isNotEmpty) { _controller = TextEditingController.fromValue(TextEditingValue( text: textData, selection: TextSelection.fromPosition(TextPosition( @@ -128,7 +129,7 @@ class BrnInputText extends StatelessWidget { controller: _controller, keyboardType: TextInputType.multiline, maxLength: maxLength, - maxLengthEnforced: true, + maxLengthEnforcement: MaxLengthEnforcement.enforced, maxLines: null, autofocus: autoFocus ?? true, focusNode: focusNode, @@ -141,8 +142,12 @@ class BrnInputText extends StatelessWidget { .getConfig() .commonConfig .colorTextBase), - buildCounter: (BuildContext context, - {int currentLength, int maxLength, bool isFocused}) { + buildCounter: ( + BuildContext context, { + required int currentLength, + required int? maxLength, + required bool isFocused, + }) { return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ @@ -182,12 +187,13 @@ class BrnInputText extends StatelessWidget { ), onSubmitted: (text) { if (onSubmit != null) { - onSubmit(text); + onSubmit!(text); } }, + onChanged: (text) { if (onTextChange != null) { - onTextChange(text); + onTextChange!(text); } }, ), diff --git a/lib/src/components/line/brn_dashed_line.dart b/lib/src/components/line/brn_dashed_line.dart index c952f449..c7a2abe4 100644 --- a/lib/src/components/line/brn_dashed_line.dart +++ b/lib/src/components/line/brn_dashed_line.dart @@ -11,33 +11,29 @@ import 'package:flutter/material.dart'; /// 分割线所在位置 enum BrnDashedLinePosition { /// 头部 - DashedLineTrailing, + trailing, /// 尾部 - DashedLineLeading, + leading, } -/// 虚线分割线 -class BrnDashedLine extends StatelessWidget { - /// 默认虚线方向 - static const Axis _normalAxis = Axis.horizontal; +/// 默认虚线方向 +const Axis _normalAxis = Axis.horizontal; - /// 默认虚线长度 - static const double _normalDashedLength = 8; +/// 默认虚线长度 +const double _normalDashedLength = 8; - /// 默认虚线厚度 - static const double _normalDashedThickness = 1; +/// 默认虚线厚度 +const double _normalDashedThickness = 1; - /// 默认间距 - static const double _normalDashedSpacing = 4; +/// 默认间距 +const double _normalDashedSpacing = 4; - /// 默认颜色 - static Color _normalColor = - BrnThemeConfigurator.instance.getConfig().commonConfig.dividerColorBase; +/// 默认位置,头部 +const BrnDashedLinePosition _normalPosition = BrnDashedLinePosition.leading; - /// 默认位置,头部 - static const BrnDashedLinePosition _normalPosition = - BrnDashedLinePosition.DashedLineLeading; +/// 虚线分割线 +class BrnDashedLine extends StatelessWidget { /// 虚线方向,默认值[_normalAxis] final Axis axis; @@ -52,7 +48,7 @@ class BrnDashedLine extends StatelessWidget { final double dashedSpacing; /// 颜色,默认值[_normalColor] - final Color color; + final Color? color; /// 虚线的Widget final Widget contentWidget; @@ -64,28 +60,28 @@ class BrnDashedLine extends StatelessWidget { final BrnDashedLinePosition position; BrnDashedLine({ - Key key, - @required this.contentWidget, - this.axis, - this.dashedLength, - this.dashedThickness, - this.dashedSpacing, + Key? key, + required this.contentWidget, + this.axis = _normalAxis, + this.dashedLength = _normalDashedLength, + this.dashedThickness = _normalDashedThickness, + this.dashedSpacing = _normalDashedSpacing, this.color, - this.dashedOffset, - this.position, + this.dashedOffset = 0.0, + this.position = _normalPosition, }); @override Widget build(BuildContext context) { return CustomPaint( painter: BrnDashedPainter( - axis: this.axis ?? _normalAxis, - dashedLength: this.dashedLength ?? _normalDashedLength, - dashedThickness: this.dashedThickness ?? _normalDashedThickness, - dashedSpacing: this.dashedSpacing ?? _normalDashedSpacing, - color: this.color ?? _normalColor, - dashedOffset: this.dashedOffset ?? 0, - position: this.position ?? _normalPosition), + axis: this.axis, + dashedLength: this.dashedLength , + dashedThickness: this.dashedThickness, + dashedSpacing: this.dashedSpacing , + color: this.color , + dashedOffset: this.dashedOffset, + position: this.position), child: this.contentWidget, ); } @@ -105,22 +101,22 @@ class BrnDashedPainter extends CustomPainter { final double dashedSpacing; /// 颜色 - final Color color; + final Color? color; /// 距离边缘的位置 - final double dashedOffset; + final double? dashedOffset; /// 分割线所在位置 - final BrnDashedLinePosition position; + final BrnDashedLinePosition? position; BrnDashedPainter({ - this.axis, - this.dashedLength, - this.dashedThickness, - this.dashedSpacing, + this.axis = _normalAxis, + this.dashedLength = _normalDashedLength, + this.dashedThickness = _normalDashedThickness, + this.dashedSpacing = _normalDashedSpacing, this.color, - this.dashedOffset, - this.position, + this.dashedOffset = 0.0, + this.position = _normalPosition, }); @override @@ -128,7 +124,7 @@ class BrnDashedPainter extends CustomPainter { var paint = Paint() // 创建一个画笔并配置其属性 ..strokeWidth = this.dashedThickness // 画笔的宽度 ..isAntiAlias = true // 是否抗锯齿 - ..color = this.color; // 画笔颜色 + ..color = this.color?? BrnThemeConfigurator.instance.getConfig().commonConfig.dividerColorBase; // 画笔颜色 var maxWidth = size.width; // size获取到宽度 var maxHeight = size.height; // size获取到宽度 @@ -137,12 +133,12 @@ class BrnDashedPainter extends CustomPainter { double startX = 0; final space = (this.dashedSpacing + this.dashedLength); double height = 0; - if (this.position == BrnDashedLinePosition.DashedLineLeading) { + if (this.position == BrnDashedLinePosition.leading) { // 头部 - height = dashedOffset + this.dashedThickness / 2; + height = dashedOffset! + this.dashedThickness / 2; } else { // 尾部 - height = size.height - dashedOffset - this.dashedThickness / 2; + height = size.height - dashedOffset! - this.dashedThickness / 2; } while (startX < maxWidth) { if ((maxWidth - startX) < this.dashedLength) { @@ -159,12 +155,12 @@ class BrnDashedPainter extends CustomPainter { double startY = 0; final space = (this.dashedSpacing + this.dashedLength); double width = 0; - if (this.position == BrnDashedLinePosition.DashedLineLeading) { + if (this.position == BrnDashedLinePosition.leading) { // 头部 - width = dashedOffset + this.dashedThickness / 2; + width = dashedOffset! + this.dashedThickness / 2; } else { // 尾部 - width = size.width - dashedOffset - this.dashedThickness / 2; + width = size.width - dashedOffset! - this.dashedThickness / 2; } while (startY < maxHeight) { if ((maxHeight - startY) < this.dashedLength) { diff --git a/lib/src/components/line/brn_line.dart b/lib/src/components/line/brn_line.dart index b1573a41..ef7a14d4 100644 --- a/lib/src/components/line/brn_line.dart +++ b/lib/src/components/line/brn_line.dart @@ -19,7 +19,7 @@ import 'package:flutter/material.dart'; /// class BrnLine extends StatelessWidget { /// 分割线的或者分割条的颜色 可以通过[BrnThemeConfigurator]配置默认颜色 - final Color color; + final Color? color; /// 分割线的或者分割条的高度 默认0.5 final double height; @@ -31,7 +31,7 @@ class BrnLine extends StatelessWidget { final double rightInset; BrnLine({ - Key key, + Key? key, this.color, this.height = 0.5, this.leftInset = 0, @@ -45,11 +45,8 @@ class BrnLine extends StatelessWidget { child: Divider( thickness: this.height, height: this.height, - color: this.color ?? - BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .dividerColorBase, + color: + this.color ?? BrnThemeConfigurator.instance.getConfig().commonConfig.dividerColorBase, ), ); } diff --git a/lib/src/components/loading/brn_loading.dart b/lib/src/components/loading/brn_loading.dart index 5bfca09e..9e83fdd7 100644 --- a/lib/src/components/loading/brn_loading.dart +++ b/lib/src/components/loading/brn_loading.dart @@ -1,3 +1,4 @@ +import 'package:bruno/src/constants/brn_strings_constants.dart'; import 'package:flutter/material.dart'; /// 页面或者弹窗中间的圆形加载框,左侧是可定制的加载文案[content],比如:加载中、提交中等等 @@ -29,7 +30,7 @@ import 'package:flutter/material.dart'; class BrnPageLoading extends StatelessWidget { final String content; - BrnPageLoading({this.content}); + const BrnPageLoading({this.content = BrnStrings.loadingContent}); @override Widget build(BuildContext context) { @@ -38,9 +39,7 @@ class BrnPageLoading extends StatelessWidget { height: 50, width: 130, decoration: BoxDecoration( - color: Color(0xff222222), - border: null, - borderRadius: BorderRadius.circular(5)), + color: Color(0xff222222), borderRadius: BorderRadius.circular(5)), child: Center( child: Row( mainAxisSize: MainAxisSize.min, @@ -56,7 +55,7 @@ class BrnPageLoading extends StatelessWidget { Container( margin: EdgeInsets.only(left: 8), child: Text( - content ?? "加载中...", + content, style: TextStyle( fontSize: 15, fontWeight: FontWeight.w600, @@ -78,7 +77,8 @@ class BrnLoadingDialog extends Dialog { /// 加载时的提示文案,默认为 `加载中...` final String content; - BrnLoadingDialog({Key key, this.content = "加载中..."}) : super(key: key); + const BrnLoadingDialog({Key? key, this.content = BrnStrings.loadingContent}) + : super(key: key); @override Widget build(BuildContext context) { @@ -92,13 +92,13 @@ class BrnLoadingDialog extends Dialog { /// * [barrierDismissible] 点击蒙层背景是否关闭弹窗,默认为 true,可关闭,详见 [showDialog] 中的 [barrierDismissible] /// * [useRootNavigator] 把弹窗添加到 [context] 中的 rootNavigator 还是最近的 [Navigator],默认为 true,添加到 /// rootNavigator,详见 [showDialog] 中的 [useRootNavigator]。 - static void show( + static Future show( BuildContext context, { - String content, + String content = BrnStrings.loadingContent, bool barrierDismissible = true, bool useRootNavigator = true, }) { - showDialog( + return showDialog( context: context, barrierDismissible: barrierDismissible, useRootNavigator: useRootNavigator, @@ -110,7 +110,7 @@ class BrnLoadingDialog extends Dialog { /// 关闭弹窗。 /// /// * [context] 上下文。 - static void dismiss(BuildContext context) { - Navigator.pop(context); + static void dismiss(BuildContext context, [T? result]) { + Navigator.pop(context, result); } } diff --git a/lib/src/components/navbar/brn_appbar.dart b/lib/src/components/navbar/brn_appbar.dart index 7630350b..93ee65b5 100644 --- a/lib/src/components/navbar/brn_appbar.dart +++ b/lib/src/components/navbar/brn_appbar.dart @@ -5,7 +5,6 @@ import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_appbar_config.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; /// AppBar组件,基于[AppBar]封装。为了解决原生的AppBar对Leading宽度的限制 /// 在1.21版本之后,Flutter放开了宽度的限制[https://github.com/flutter/flutter/blob/flutter-1.21-candidate.0/packages/flutter/lib/src/material/app_bar.dart] @@ -97,7 +96,7 @@ import 'package:flutter/widgets.dart'; class BrnAppBar extends PreferredSize { /// 导航栏左侧活动区域,在为null且 /// [automaticallyImplyLeading]为true时默认赋值为[BrnBackLeading] - final Widget leading; + final Widget? leading; /// AppBar标题,必须是String或者Widget类型 /// 为String时,会使用[BrnAppBarTitle]来加载title @@ -113,43 +112,43 @@ class BrnAppBar extends PreferredSize { /// 以下属性都对应于[AppBar]中的属性 /// 详细介绍可以查阅[AppBar]的文档 - final Color backgroundColor; - final PreferredSizeWidget bottom; + final Color? backgroundColor; + final PreferredSizeWidget? bottom; final double elevation; - final Brightness brightness; + final Brightness? brightness; final double toolbarOpacity; final double bottomOpacity; final Alignment titleAlignment; - final Widget flexibleSpace; - final double leadingWidth; - final Color shadowColor; - final ShapeBorder shape; - final IconThemeData iconTheme; - final IconThemeData actionsIconTheme; - final TextTheme textTheme; + final Widget? flexibleSpace; + final double? leadingWidth; + final Color? shadowColor; + final ShapeBorder? shape; + final IconThemeData? iconTheme; + final IconThemeData? actionsIconTheme; + final TextTheme? textTheme; final bool primary; final bool excludeHeaderSemantics; - final double titleSpacing; + final double? titleSpacing; /// 默认处理了返回按钮,flutter的pop,如果是native打开的话,可能需要单独处理,否则会出现白屏 /// backLeadCallback是默认的处理回调 /// DefaultLeadingCallBack 也可以通过改方法参数 设置统一的返回处理,该参数是静态的 - final VoidCallback backLeadCallback; + final VoidCallback? backLeadCallback; /// 是否显示默认的eeeeee分割线,默认显示,可以设置为不显示 final bool showDefaultBottom; final bool showLeadingDivider; - final BrnAppBarConfig themeData; + final BrnAppBarConfig? themeData; BrnAppBar( - {Key key, + {Key? key, this.leading, this.showLeadingDivider = false, this.title, this.actions, this.backgroundColor, this.bottom, - this.elevation, + this.elevation = 0, this.automaticallyImplyLeading = true, this.brightness, this.toolbarOpacity = 1.0, @@ -164,18 +163,18 @@ class BrnAppBar extends PreferredSize { this.shape, this.iconTheme, this.actionsIconTheme, - this.excludeHeaderSemantics, - this.primary, + this.excludeHeaderSemantics = false, + this.primary = true, this.textTheme, this.titleSpacing}) : assert( actions == null || actions is Widget || (actions is List)), assert(title == null || title is String || title is Widget), - super(key: key, child: null, preferredSize: null); + super(key: key, child: Container(), preferredSize: Size(0, 0)); BrnAppBar.buildSearchResultStyle( - {Key key, - String title, + {Key? key, + String? title, this.backgroundColor, this.bottom, this.brightness, @@ -189,8 +188,8 @@ class BrnAppBar extends PreferredSize { this.shape, this.iconTheme, this.actionsIconTheme, - this.excludeHeaderSemantics, - this.primary, + this.excludeHeaderSemantics = false, + this.primary = true, this.textTheme, this.titleSpacing}) : this.actions = null, @@ -211,7 +210,7 @@ class BrnAppBar extends PreferredSize { backLeadCallback: backLeadCallback, showDefaultBottom: showDefaultBottom, ), - super(key: key, child: null, preferredSize: null); + super(key: key, child: Container(), preferredSize: const Size(0, 0)); @override Size get preferredSize { @@ -221,7 +220,7 @@ class BrnAppBar extends PreferredSize { .appBarConfig .merge(_defaultConfig); return Size.fromHeight( - _defaultConfig.appBarHeight + (bottom?.preferredSize?.height ?? 0.0)); + _defaultConfig.appBarHeight + (bottom?.preferredSize.height ?? 0.0)); } @override @@ -241,13 +240,13 @@ class BrnAppBar extends PreferredSize { .appBarConfig .merge(_defaultConfig); - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance?.addPostFrameCallback((_) { SystemChrome.setSystemUIOverlayStyle(_defaultConfig.systemUiOverlayStyle); }); return super.build(context); } - Widget _buildBarBottom() { + PreferredSizeWidget? _buildBarBottom() { if (brightness == null || brightness == Brightness.light) { if (bottom == null && showDefaultBottom) { return BrnBarBottomDivider(); @@ -273,13 +272,12 @@ class BrnAppBar extends PreferredSize { .appBarConfig .merge(_defaultConfig); - Widget flexibleSpace; - if (_defaultConfig.flexibleSpace != null) { + Widget? flexibleSpace; + if (this.flexibleSpace != null) { flexibleSpace = Container( height: _defaultConfig.appBarHeight + - MediaQueryData.fromWindow(window)?.padding?.top ?? - 0, - child: _defaultConfig.flexibleSpace, + MediaQueryData.fromWindow(window).padding.top, + child: this.flexibleSpace, ); } @@ -291,28 +289,28 @@ class BrnAppBar extends PreferredSize { automaticallyImplyLeading: false, title: _buildAppBarTitle(_defaultConfig), centerTitle: true, - elevation: elevation ?? 0, + elevation: elevation, backgroundColor: _defaultConfig.backgroundColor, actions: _wrapActions(_defaultConfig), bottom: _buildBarBottom(), brightness: brightness ?? Brightness.light, - toolbarOpacity: toolbarOpacity ?? 1.0, - bottomOpacity: bottomOpacity ?? 1.0, + toolbarOpacity: toolbarOpacity, + bottomOpacity: bottomOpacity, flexibleSpace: flexibleSpace, shadowColor: shadowColor, shape: shape, iconTheme: iconTheme, actionsIconTheme: actionsIconTheme, textTheme: textTheme, - primary: primary ?? true, - excludeHeaderSemantics: excludeHeaderSemantics ?? false, + primary: primary, + excludeHeaderSemantics: excludeHeaderSemantics, ); } // 根据输入的leading 设置默认的leadingWidth double _culLeadingSize(BrnAppBarConfig themeData) { if (leadingWidth != null) { - return leadingWidth; + return leadingWidth!; } if (leading is BrnDoubleLeading) { return themeData.leftAndRightPadding + @@ -328,7 +326,7 @@ class BrnAppBar extends PreferredSize { // 对[actions]进行包装: 单一的Widget会添加右边距 // List在添加右边距的 并 添加action中的间距 - List _wrapActions(BrnAppBarConfig themeData) { + List? _wrapActions(BrnAppBarConfig themeData) { if (actions == null || !(actions is List || actions is Widget)) { return null; } @@ -338,9 +336,9 @@ class BrnAppBar extends PreferredSize { if (actions.isEmpty) { return actionList; } - List tmp = (actions as List)?.map((_) { + List tmp = (actions as List).map((_) { return (_ is BrnTextAction) ? _warpRealAction(_) : _; - })?.toList(); + }).toList(); for (int i = 0, n = tmp.length; i < n; i++) { actionList.add(tmp[i]); @@ -364,10 +362,10 @@ class BrnAppBar extends PreferredSize { } // 详情请参考_ToolbarLayout的布局方法 - Widget _buildAppBarTitle( + Widget? _buildAppBarTitle( BrnAppBarConfig themeData, ) { - Widget realTitle; + Widget? realTitle; if (title is Widget) { return title; } @@ -382,8 +380,8 @@ class BrnAppBar extends PreferredSize { } // 如果leading是BrnBackLeading 需要添加左边距 - Widget _wrapLeading(BrnAppBarConfig barConfig) { - Widget realLeading = leading; + Widget? _wrapLeading(BrnAppBarConfig barConfig) { + Widget? realLeading = leading; if (leading == null && automaticallyImplyLeading) { realLeading = BrnBackLeading( iconPressed: backLeadCallback, @@ -403,12 +401,12 @@ class BrnAppBar extends PreferredSize { /// [BrnAppBar]中leading的默认实现 /// 宽度范围是40 class BrnBackLeading extends StatelessWidget { - final Widget child; - final VoidCallback iconPressed; - final BrnAppBarConfig themeData; + final Widget? child; + final VoidCallback? iconPressed; + final BrnAppBarConfig? themeData; BrnBackLeading({ - Key key, + Key? key, this.iconPressed, this.child, this.themeData, @@ -453,9 +451,10 @@ class BrnBackLeading extends StatelessWidget { class BrnDoubleLeading extends StatelessWidget { final Widget first; final Widget second; - final BrnAppBarConfig themeData; + final BrnAppBarConfig? themeData; - BrnDoubleLeading({Key key, this.first, this.second, this.themeData}) + BrnDoubleLeading( + {Key? key, required this.first, required this.second, this.themeData}) : super(key: key); @override @@ -485,15 +484,15 @@ class BrnDoubleLeading extends StatelessWidget { /// 标题文字个数限制在8个以内,并且单行展示 class BrnAppBarTitle extends StatelessWidget { final String title; - final BrnAppBarConfig themeData; + final BrnAppBarConfig? themeData; - BrnAppBarTitle(this.title, {Key key, this.themeData}) : super(key: key); + BrnAppBarTitle(this.title, {Key? key, this.themeData}) : super(key: key); @override Widget build(BuildContext context) { BrnAppBarConfig _defaultThemeData = themeData ?? BrnAppBarConfig(); _defaultThemeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) + .getConfig(configId: _defaultThemeData.configId) .appBarConfig .merge(this.themeData); @@ -504,7 +503,7 @@ class BrnAppBarTitle extends StatelessWidget { overflow: TextOverflow.ellipsis, ), constraints: BoxConstraints.loose(Size.fromWidth( - _defaultThemeData.titleStyle.generateTextStyle().fontSize * + (_defaultThemeData.titleStyle.generateTextStyle().fontSize ?? 18) * (_defaultThemeData.titleMaxLength + 1))), ); } @@ -515,17 +514,16 @@ class BrnAppBarTitle extends StatelessWidget { class BrnIconAction extends StatelessWidget { final Widget child; final VoidCallback iconPressed; - final double size; - final BrnAppBarConfig themeData; + final double? size; + final BrnAppBarConfig? themeData; BrnIconAction({ - Key key, - this.iconPressed, - this.child, + Key? key, + required this.iconPressed, + required this.child, this.size, this.themeData, - }) : assert(child != null && iconPressed != null), - super(key: key); + }) : super(key: key); @override Widget build(BuildContext context) { @@ -552,10 +550,10 @@ class BrnIconAction extends StatelessWidget { /// 此Widget中实现了大小约束,和点击实现,添加文本action时必须使用此类包裹 class BrnTextAction extends StatelessWidget { final String text; - final VoidCallback iconPressed; - final BrnAppBarConfig themeData; + final VoidCallback? iconPressed; + final BrnAppBarConfig? themeData; - BrnTextAction(this.text, {Key key, this.iconPressed, this.themeData}) + BrnTextAction(this.text, {Key? key, this.iconPressed, this.themeData}) : super(key: key); @override @@ -581,6 +579,9 @@ class BrnTextAction extends StatelessWidget { /// AppBar底部分割线,将实例传入[BrnAppBar.bottom]属性即可 class BrnBarBottomDivider extends PreferredSize { + BrnBarBottomDivider() + : super(child: Container(), preferredSize: const Size(0, 0)); + @override Size get preferredSize => Size.fromHeight(0.5); @@ -589,8 +590,8 @@ class BrnBarBottomDivider extends PreferredSize { } class _BrnSearchResultAppBar extends StatelessWidget { - final BrnAppBarConfig appBarConfig; - final String title; + final BrnAppBarConfig? appBarConfig; + final String? title; final backgroundColor; final bottom; final brightness; diff --git a/lib/src/components/navbar/brn_appbar_theme.dart b/lib/src/components/navbar/brn_appbar_theme.dart index 50cea13d..204e81a7 100644 --- a/lib/src/components/navbar/brn_appbar_theme.dart +++ b/lib/src/components/navbar/brn_appbar_theme.dart @@ -1,8 +1,8 @@ -import 'dart:ui'; - import 'package:flutter/material.dart'; class BrnAppBarTheme { + const BrnAppBarTheme._(); + /// [BrnAppBar] 高度固定值 static const double appBarHeight = 44; diff --git a/lib/src/components/navbar/brn_empty_appbar.dart b/lib/src/components/navbar/brn_empty_appbar.dart deleted file mode 100644 index 141e27c1..00000000 --- a/lib/src/components/navbar/brn_empty_appbar.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; - -class BrnEmptyAppBar extends PreferredSize { - final double height; - final Color color; - - BrnEmptyAppBar(this.height, {this.color}); - - @override - Size get preferredSize => Size.fromHeight(height); - - @override - Widget build(BuildContext context) { - return Container( - color: color ?? Colors.white, - ); - } -} diff --git a/lib/src/components/navbar/brn_search_bar.dart b/lib/src/components/navbar/brn_search_bar.dart index 06cec3f3..802ab87e 100644 --- a/lib/src/components/navbar/brn_search_bar.dart +++ b/lib/src/components/navbar/brn_search_bar.dart @@ -1,5 +1,3 @@ -import 'dart:ui'; - import 'package:bruno/src/components/navbar/brn_appbar.dart'; import 'package:bruno/src/components/navbar/brn_appbar_theme.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; @@ -35,37 +33,37 @@ typedef BrnSearchBarInputSubmitCallback = Function(String input); /// 更多信息 请查看[BrnAppBar] class BrnSearchAppbar extends PreferredSize { /// 搜索框的文本输入控制器 - final TextEditingController controller; + final TextEditingController? controller; /// 搜索框的焦点控制器 - final FocusNode focusNode; + final FocusNode? focusNode; /// 搜索框的左侧leading - final BrnSearchBarLeadClickCallback leadClickCallback; + final BrnSearchBarLeadClickCallback? leadClickCallback; /// 可以是字符串也可以是widget final dynamic leading; /// 取消点击的回调 - final BrnSearchBarDismissClickCallback dismissClickCallback; + final BrnSearchBarDismissClickCallback? dismissClickCallback; /// 输入变化的监听 - final BrnSearchBarInputChangeCallback searchBarInputChangeCallback; + final BrnSearchBarInputChangeCallback? searchBarInputChangeCallback; /// 输入框提交的监听 - final BrnSearchBarInputSubmitCallback searchBarInputSubmitCallback; + final BrnSearchBarInputSubmitCallback? searchBarInputSubmitCallback; /// 输入框的hint文字 - final String hint; + final String? hint; /// 输入框的hint的Style - final TextStyle hintStyle; + final TextStyle? hintStyle; /// 输入框的文本Style - final TextStyle inputTextStyle; + final TextStyle? inputTextStyle; /// 右侧取消的文本Style - final TextStyle dismissStyle; + final TextStyle? dismissStyle; /// 左侧的leading和搜索的分割线 final bool showDivider; @@ -77,7 +75,7 @@ class BrnSearchAppbar extends PreferredSize { final Brightness brightness; /// 清空回调 - final VoidCallback onClearTap; + final VoidCallback? onClearTap; const BrnSearchAppbar( {this.controller, @@ -94,7 +92,8 @@ class BrnSearchAppbar extends PreferredSize { this.autoFocus = true, this.brightness = Brightness.dark, this.onClearTap, - this.inputTextStyle}); + this.inputTextStyle}) + : super(child: const Center(), preferredSize: const Size(0, 0)); @override Widget get child => BrnAppBar( @@ -107,7 +106,7 @@ class BrnSearchAppbar extends PreferredSize { Size get preferredSize => Size.fromHeight(BrnAppBarTheme.appBarHeight); Widget build(BuildContext context) { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance?.addPostFrameCallback((_) { SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light); }); return super.build(context); @@ -144,21 +143,21 @@ class BrnSearchAppbar extends PreferredSize { } class _SearchInputWidget extends StatefulWidget { - final FocusNode focusNode; - final TextEditingController textEditingController; - final BrnSearchBarLeadClickCallback leadClickCallback; - final BrnSearchBarDismissClickCallback dismissClickCallback; + final FocusNode? focusNode; + final TextEditingController? textEditingController; + final BrnSearchBarLeadClickCallback? leadClickCallback; + final BrnSearchBarDismissClickCallback? dismissClickCallback; final dynamic leading; - final BrnSearchBarInputChangeCallback searchBarInputChangeCallback; - final BrnSearchBarInputSubmitCallback searchBarInputSubmitCallback; - final String hint; - final TextStyle hintStyle; - final TextStyle inputTextStyle; - final TextStyle dismissStyle; + final BrnSearchBarInputChangeCallback? searchBarInputChangeCallback; + final BrnSearchBarInputSubmitCallback? searchBarInputSubmitCallback; + final String? hint; + final TextStyle? hintStyle; + final TextStyle? inputTextStyle; + final TextStyle? dismissStyle; final bool showDivider; final bool autoFocus; - final VoidCallback clearTapCallback; - final Brightness brightness; + final VoidCallback? clearTapCallback; + final Brightness? brightness; _SearchInputWidget( {this.focusNode, @@ -168,7 +167,7 @@ class _SearchInputWidget extends StatefulWidget { this.textEditingController, this.searchBarInputChangeCallback, this.searchBarInputSubmitCallback, - this.hint, + this.hint= '请输入搜索内容', this.hintStyle, this.inputTextStyle, this.showDivider = true, @@ -182,14 +181,14 @@ class _SearchInputWidget extends StatefulWidget { } class __SearchInputWidgetState extends State<_SearchInputWidget> { - FocusNode _focusNode; - ValueNotifier valueNotifier; - TextEditingController _controller; - Color _defaultInputTextColor; - Color _defaultCancelTextColor; - Color _defaultDividerColor; - Color _defaultHintTextColor; - Color _defaultClearIconColor; + late FocusNode _focusNode; + late ValueNotifier valueNotifier; + late TextEditingController _controller; + late Color _defaultInputTextColor; + late Color _defaultCancelTextColor; + late Color _defaultDividerColor; + late Color _defaultHintTextColor; + late Color _defaultClearIconColor; @override void initState() { @@ -226,7 +225,7 @@ class __SearchInputWidgetState extends State<_SearchInputWidget> { @override void dispose() { super.dispose(); - _focusNode?.removeListener(_handleFocusChangeListenerTick); + _focusNode.removeListener(_handleFocusChangeListenerTick); } void _handleFocusChangeListenerTick() { @@ -243,7 +242,7 @@ class __SearchInputWidgetState extends State<_SearchInputWidget> { GestureDetector( onTap: () { if (widget.leadClickCallback != null) { - widget.leadClickCallback(_controller, () { + widget.leadClickCallback!(_controller, () { setState(() {}); }); } @@ -268,7 +267,7 @@ class __SearchInputWidgetState extends State<_SearchInputWidget> { Padding( padding: EdgeInsets.only(right: 8.0), child: - BrunoTools.getAssetSizeImage(BrnAsset.ICON_SEARCH, 16, 16), + BrunoTools.getAssetSizeImage(BrnAsset.iconSearch, 16, 16), ), Expanded( child: TextField( @@ -309,20 +308,20 @@ class __SearchInputWidgetState extends State<_SearchInputWidget> { color: _defaultHintTextColor, ), // 提示文本属性,提示字段接受哪种输入的文本。 - hintText: widget.hint ?? "请输入搜索内容", + hintText: widget.hint, ), // 在改变属性,当正在编辑的文本发生更改时调用。 onChanged: (content) { valueNotifier.value = true; if (widget.searchBarInputChangeCallback != null) { - widget.searchBarInputChangeCallback(content); + widget.searchBarInputChangeCallback!(content); } setState(() {}); }, onSubmitted: (content) { valueNotifier.value = false; if (widget.searchBarInputSubmitCallback != null) { - widget.searchBarInputSubmitCallback(content); + widget.searchBarInputSubmitCallback!(content); } }), ), @@ -330,7 +329,7 @@ class __SearchInputWidgetState extends State<_SearchInputWidget> { onTap: () { _controller.clear(); if (widget.clearTapCallback != null) { - widget.clearTapCallback(); + widget.clearTapCallback!(); } setState(() {}); }, @@ -341,7 +340,7 @@ class __SearchInputWidgetState extends State<_SearchInputWidget> { right: valueNotifier.value ? 24 : 20, left: valueNotifier.value ? 24 : 20), child: Image.asset( - 'assets/${BrnAsset.ICON_DELETE_TEXT}', + 'assets/${BrnAsset.iconDeleteText}', color: _defaultClearIconColor, scale: 3.0, height: 16, @@ -356,12 +355,12 @@ class __SearchInputWidgetState extends State<_SearchInputWidget> { ), ValueListenableBuilder( valueListenable: valueNotifier, - builder: (context, value, child) { + builder: (context, bool value, child) { return value ? GestureDetector( onTap: () { if (widget.dismissClickCallback != null) { - widget.dismissClickCallback(_controller, () { + widget.dismissClickCallback!(_controller, () { setState(() {}); }); } diff --git a/lib/src/components/noticebar/brn_marquee_text.dart b/lib/src/components/noticebar/brn_marquee_text.dart index 0dc6a9f6..4b6b3435 100644 --- a/lib/src/components/noticebar/brn_marquee_text.dart +++ b/lib/src/components/noticebar/brn_marquee_text.dart @@ -8,7 +8,7 @@ class BrnMarqueeText extends StatefulWidget { final String text; /// 文字样式 - final TextStyle textStyle; + final TextStyle? textStyle; ///滚动方向,水平或者垂直 final Axis scrollAxis; @@ -25,16 +25,14 @@ class BrnMarqueeText extends StatefulWidget { double height; BrnMarqueeText({ - @required this.text, + required this.text, this.width: 0, this.height: 0, this.timerRest: 100, this.textStyle, this.scrollAxis: Axis.horizontal, this.ratioOfBlankToScreen: 0.25, - }) : assert( - text != null, - ); + }); @override State createState() { @@ -44,26 +42,26 @@ class BrnMarqueeText extends StatefulWidget { class BrnMarqueeTextState extends State with SingleTickerProviderStateMixin { - ScrollController scroController; + late ScrollController scroController; double blankWidth = 1; double blankHeight = 1; double position = 0.0; - Timer timer; + Timer? timer; final double _moveDistance = 3.0; - GlobalKey _key = null; + GlobalKey? _key; @override void initState() { super.initState(); scroController = new ScrollController(); - WidgetsBinding.instance.addPostFrameCallback((callback) { - var size = context?.findRenderObject()?.paintBounds?.size; + WidgetsBinding.instance?.addPostFrameCallback((callback) { + var size = context.findRenderObject()!.paintBounds.size; widget.width = (widget.width) > 0 ? widget.width : size.width; widget.height = (widget.height) > 0 ? widget.height : size.height; _key = GlobalKey(); - if (calculateTextWith(widget.text, widget.textStyle.fontSize, - widget.textStyle.fontWeight, double.infinity, 1, context) > + if (calculateTextWith(widget.text, widget.textStyle?.fontSize, + widget.textStyle?.fontWeight, double.infinity, 1, context) > widget.width) { blankWidth = widget.width * widget.ratioOfBlankToScreen; blankHeight = widget.height * widget.ratioOfBlankToScreen; @@ -136,10 +134,8 @@ class BrnMarqueeTextState extends State @override void dispose() { - if (timer != null) { - timer.cancel(); - } - scroController = null; + timer?.cancel(); + scroController.dispose(); super.dispose(); } @@ -162,8 +158,13 @@ class BrnMarqueeTextState extends State ); } - double calculateTextWith(String value, double fontSize, FontWeight fontWeight, - double maxWidth, int maxLines, BuildContext context) { + double calculateTextWith( + String value, + double? fontSize, + FontWeight? fontWeight, + double maxWidth, + int maxLines, + BuildContext context) { TextPainter painter = TextPainter( ///AUTO:华为手机如果不指定locale的时候,该方法算出来的文字高度是比系统计算偏小的。 diff --git a/lib/src/components/noticebar/brn_notice_bar.dart b/lib/src/components/noticebar/brn_notice_bar.dart index 78e0e1fe..637a20d6 100644 --- a/lib/src/components/noticebar/brn_notice_bar.dart +++ b/lib/src/components/noticebar/brn_notice_bar.dart @@ -10,7 +10,7 @@ import 'package:flutter/material.dart'; class BrnNoticeBar extends StatelessWidget { /// 自定义左边的图标 - final Widget leftWidget; + final Widget? leftWidget; /// 是否显示左边的图标 final bool showLeftIcon; @@ -19,30 +19,30 @@ class BrnNoticeBar extends StatelessWidget { final String content; /// 通知的文字颜色 - final Color textColor; + final Color? textColor; /// 背景颜色 - final Color backgroundColor; + final Color? backgroundColor; /// 右边的图标 - final Widget rightWidget; + final Widget? rightWidget; /// 是否显示右边的图标 /// 默认值true final bool showRightIcon; /// 默认样式,取[NoticeStyles]里面的值 - final NoticeStyle noticeStyle; + final NoticeStyle? noticeStyle; /// 是否跑马灯 /// 默认值false final bool marquee; /// 通知钮点击的回调 - final VoidCallback onNoticeTap; + final VoidCallback? onNoticeTap; /// 右侧图标点击的回调 - final VoidCallback onRightIconTap; + final VoidCallback? onRightIconTap; /// 最小高度。leftWidget、rightWidget 都为空时,限制的最小高度。 /// 可以通过该属性控制组件高度,内容会自动垂直居中。 @@ -50,13 +50,13 @@ class BrnNoticeBar extends StatelessWidget { final double minHeight; /// 内容的内边距 - final EdgeInsets padding; + final EdgeInsets? padding; const BrnNoticeBar( - {Key key, + {Key? key, this.leftWidget, this.showLeftIcon = true, - @required this.content, + required this.content, this.textColor, this.backgroundColor, this.rightWidget, @@ -67,8 +67,7 @@ class BrnNoticeBar extends StatelessWidget { this.marquee = false, this.padding, this.minHeight = 36}) - : assert(content != null), - super(key: key); + : super(key: key); @override Widget build(BuildContext context) { @@ -80,7 +79,7 @@ class BrnNoticeBar extends StatelessWidget { tempRightWidget = GestureDetector( child: tempRightWidget, onTap: () { - onRightIconTap(); + onRightIconTap!(); }, ); } @@ -89,7 +88,7 @@ class BrnNoticeBar extends StatelessWidget { if (marquee) { contentWidget = BrnMarqueeText( height: 36, - text: content ?? '', + text: content, textStyle: TextStyle( color: textColor ?? (noticeStyle?.textColor ?? defaultStyle.textColor), @@ -98,7 +97,7 @@ class BrnNoticeBar extends StatelessWidget { ); } else { contentWidget = Text( - content ?? '', + content, overflow: TextOverflow.ellipsis, style: TextStyle( color: @@ -111,14 +110,14 @@ class BrnNoticeBar extends StatelessWidget { return Container( color: backgroundColor ?? (noticeStyle != null - ? noticeStyle.backgroundColor + ? noticeStyle!.backgroundColor : defaultStyle.backgroundColor), padding: this.padding ?? EdgeInsets.symmetric(horizontal: 20), constraints: BoxConstraints(minHeight: this.minHeight), child: GestureDetector( onTap: () { if (onNoticeTap != null) { - onNoticeTap(); + onNoticeTap!(); } }, child: Row( @@ -152,73 +151,73 @@ class BrnNoticeBar extends StatelessWidget { class NoticeStyles { ///红色+失败+箭头 static NoticeStyle failWithArrow = NoticeStyle( - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_FAIL), + BrunoTools.getAssetImage(BrnAsset.iconNoticeFail), Color(0xFFFA3F3F), Color(0xFFFEEDED), - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_ARROW_RED)); + BrunoTools.getAssetImage(BrnAsset.iconNoticeArrowRed)); ///红色+失败+关闭 static NoticeStyle failWithClose = NoticeStyle( - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_FAIL), + BrunoTools.getAssetImage(BrnAsset.iconNoticeFail), Color(0xFFFA3F3F), Color(0xFFFEEDED), - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_CLOSE_RED)); + BrunoTools.getAssetImage(BrnAsset.iconNoticeCloseRed)); ///蓝色+进行中+箭头 static NoticeStyle runningWithArrow = NoticeStyle( - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_RUNNING), + BrunoTools.getAssetImage(BrnAsset.iconNoticeRunning), Color(0xFF0984F9), Color(0xFFE0EDFF), - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_ARROW_BLUE)); + BrunoTools.getAssetImage(BrnAsset.iconNoticeArrowBlue)); ///蓝色+进行中+关闭 static NoticeStyle runningWithClose = NoticeStyle( - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_RUNNING), + BrunoTools.getAssetImage(BrnAsset.iconNoticeRunning), Color(0xFF0984F9), Color(0xFFE0EDFF), - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_CLOSE_BLUE)); + BrunoTools.getAssetImage(BrnAsset.iconNoticeCloseBlue)); ///绿色+完成+箭头 static NoticeStyle succeedWithArrow = NoticeStyle( - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_SUCCEED), + BrunoTools.getAssetImage(BrnAsset.iconNoticeSucceed), Color(0xFF00AE66), Color(0xFFEBFFF7), - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_ARROW_GREEN)); + BrunoTools.getAssetImage(BrnAsset.iconNoticeArrowGreen)); ///绿色+完成+关闭 static NoticeStyle succeedWithClose = NoticeStyle( - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_SUCCEED), + BrunoTools.getAssetImage(BrnAsset.iconNoticeSucceed), Color(0xFF00AE66), Color(0xFFEBFFF7), - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_CLOSE_GREEN)); + BrunoTools.getAssetImage(BrnAsset.iconNoticeCloseGreen)); ///橘色+警告+箭头 static NoticeStyle warningWithArrow = NoticeStyle( - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_WARNING), + BrunoTools.getAssetImage(BrnAsset.iconNoticeWarning), Color(0xFFFAAD14), Color(0xFFFDFCEC), - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_ARROW_ORANGE)); + BrunoTools.getAssetImage(BrnAsset.iconNoticeArrowOrange)); ///橘色+警告+关闭 static NoticeStyle warningWithClose = NoticeStyle( - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_WARNING), + BrunoTools.getAssetImage(BrnAsset.iconNoticeWarning), Color(0xFFFAAD14), Color(0xFFFDFCEC), - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_CLOSE_ORANGE)); + BrunoTools.getAssetImage(BrnAsset.iconNoticeCloseOrange)); ///橘色+通知+箭头 static NoticeStyle normalNoticeWithArrow = NoticeStyle( - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE), + BrunoTools.getAssetImage(BrnAsset.iconNotice), Color(0xFFFAAD14), Color(0xFFFDFCEC), - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_ARROW_ORANGE)); + BrunoTools.getAssetImage(BrnAsset.iconNoticeArrowOrange)); ///橘色+通知+关闭 static NoticeStyle normalNoticeWithClose = NoticeStyle( - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE), + BrunoTools.getAssetImage(BrnAsset.iconNotice), Color(0xFFFAAD14), Color(0xFFFDFCEC), - BrunoTools.getAssetImage(BrnAsset.ICON_NOTICE_CLOSE_ORANGE)); + BrunoTools.getAssetImage(BrnAsset.iconNoticeCloseOrange)); } /// 通知样式 diff --git a/lib/src/components/noticebar/brn_notice_bar_with_button.dart b/lib/src/components/noticebar/brn_notice_bar_with_button.dart index c21b7055..7e1e59fd 100644 --- a/lib/src/components/noticebar/brn_notice_bar_with_button.dart +++ b/lib/src/components/noticebar/brn_notice_bar_with_button.dart @@ -11,52 +11,52 @@ class BrnNoticeBarWithButton extends StatelessWidget { final String content; /// 通知的背景色 - final Color backgroundColor; + final Color? backgroundColor; /// 通知的文字颜色 - final Color contentTextColor; + final Color? contentTextColor; /// 左边标签的文字 - final String leftTagText; + final String? leftTagText; /// 左边标签的文字颜色 - final Color leftTagTextColor; + final Color? leftTagTextColor; /// 左边标签的背景颜色 - final Color leftTagBackgroundColor; + final Color? leftTagBackgroundColor; /// 自定义左边的控件 - final Widget leftWidget; + final Widget? leftWidget; ///右边按钮的文字 - final String rightButtonText; + final String? rightButtonText; ///右边按钮的文字颜色 - final Color rightButtonTextColor; + final Color? rightButtonTextColor; ///右边按钮的边框颜色 - final Color rightButtonBorderColor; + final Color? rightButtonBorderColor; /// 自定义右边的控件 - final Widget rightWidget; + final Widget? rightWidget; /// 是否跑马灯 /// 默认值false final bool marquee; /// 右边按钮点击回调 - final VoidCallback onRightButtonTap; + final VoidCallback? onRightButtonTap; /// 最小高度。leftWidget、rightWidget 都为空时,限制的最小高度。 /// 可以通过该属性控制组件高度,内容会自动垂直居中。默认值 54。 final double minHeight; /// 内容的内边距 - final EdgeInsets padding; + final EdgeInsets? padding; const BrnNoticeBarWithButton( - {Key key, - @required this.content, + {Key? key, + required this.content, this.backgroundColor, this.contentTextColor, this.leftTagText, @@ -71,8 +71,7 @@ class BrnNoticeBarWithButton extends StatelessWidget { this.rightWidget, this.padding, this.minHeight = 54}) - : assert(content != null), - super(key: key); + : super(key: key); @override Widget build(BuildContext context) { @@ -97,7 +96,7 @@ class BrnNoticeBarWithButton extends StatelessWidget { /// 左边的标签 Widget _buildLeftTag() { if (leftWidget != null) { - return leftWidget; + return leftWidget!; } if (leftTagText?.isEmpty ?? true) { @@ -113,7 +112,7 @@ class BrnNoticeBarWithButton extends StatelessWidget { borderRadius: BorderRadius.circular(2), ), child: Text( - leftTagText, + leftTagText!, style: TextStyle( color: leftTagTextColor ?? Colors.white, fontSize: 11, @@ -125,14 +124,14 @@ class BrnNoticeBarWithButton extends StatelessWidget { } Widget _buildContent() { - if (content?.isEmpty ?? true) { + if (content.isEmpty) { return Container(); } if (marquee) { return BrnMarqueeText( height: 20, - text: content ?? '', + text: content, textStyle: TextStyle( color: contentTextColor ?? Color(0xFF333333), fontSize: 14, @@ -140,7 +139,7 @@ class BrnNoticeBarWithButton extends StatelessWidget { ); } else { return Text( - content ?? '', + content, overflow: TextOverflow.ellipsis, style: TextStyle( color: contentTextColor ?? Color(0xFF333333), @@ -153,7 +152,7 @@ class BrnNoticeBarWithButton extends StatelessWidget { /// 右边的按钮 Widget _buildRightBtn() { if (rightWidget != null) { - return rightWidget; + return rightWidget!; } if (rightButtonText?.isEmpty ?? true) { @@ -162,7 +161,7 @@ class BrnNoticeBarWithButton extends StatelessWidget { return GestureDetector( onTap: () { if (onRightButtonTap != null) { - onRightButtonTap(); + onRightButtonTap!(); } }, child: Padding( @@ -181,7 +180,7 @@ class BrnNoticeBarWithButton extends StatelessWidget { borderRadius: BorderRadius.circular(4), ), child: Text( - rightButtonText, + rightButtonText!, style: TextStyle( color: rightButtonTextColor ?? Color(0xFFFA5741), fontSize: 12, diff --git a/lib/src/components/picker/base/brn_picker.dart b/lib/src/components/picker/base/brn_picker.dart index d23a3d10..2f4a01e9 100644 --- a/lib/src/components/picker/base/brn_picker.dart +++ b/lib/src/components/picker/base/brn_picker.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. + + import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; @@ -10,7 +12,7 @@ import 'package:flutter/widgets.dart'; /// Color of the 'magnifier' lens border. const Color _kHighlighterBorder = Color(0xFFF0F0F0); -const Color _kDefaultBackground = Color(0xFFD2D4DB); +const Color _kDefaultBackground = Color(0xFFFFFFFF); // Eyeballed values comparing with a native picker to produce the right // curvatures and densities. const double _kDefaultDiameterRatio = 3; @@ -59,7 +61,7 @@ class BrnPicker extends StatefulWidget { /// will loop the list back to the beginning. If set to false, the list will /// stop scrolling when you reach the end or the beginning. BrnPicker({ - Key key, + Key? key, this.diameterRatio = _kDefaultDiameterRatio, this.backgroundColor = _kDefaultBackground, this.lineColor = _kHighlighterBorder, @@ -68,9 +70,9 @@ class BrnPicker extends StatefulWidget { this.magnification = 1.0, this.scrollController, this.squeeze = _kSqueeze, - @required this.itemExtent, - @required this.onSelectedItemChanged, - @required List children, + required this.itemExtent, + required this.onSelectedItemChanged, + required List children, bool looping = false, }) : assert(children != null), assert(diameterRatio != null), @@ -104,7 +106,7 @@ class BrnPicker extends StatefulWidget { /// disable the background painting entirely; this is mildly more efficient /// than using [Colors.transparent]. BrnPicker.builder({ - Key key, + Key? key, this.diameterRatio = _kDefaultDiameterRatio, this.backgroundColor = _kDefaultBackground, this.lineColor = _kHighlighterBorder, @@ -113,10 +115,10 @@ class BrnPicker extends StatefulWidget { this.magnification = 1.0, this.scrollController, this.squeeze = _kSqueeze, - @required this.itemExtent, - @required this.onSelectedItemChanged, - @required IndexedWidgetBuilder itemBuilder, - int childCount, + required this.itemExtent, + required this.onSelectedItemChanged, + required IndexedWidgetBuilder itemBuilder, + int? childCount, }) : assert(itemBuilder != null), assert(diameterRatio != null), assert(diameterRatio > 0.0, @@ -151,7 +153,7 @@ class BrnPicker extends StatefulWidget { final Color backgroundColor; ///分割线颜色 - final Color lineColor; + final Color? lineColor; /// {@macro flutter.rendering.wheelList.offAxisFraction} final double offAxisFraction; @@ -165,7 +167,7 @@ class BrnPicker extends StatefulWidget { /// A [FixedExtentScrollController] to read and control the current item. /// /// If null, an implicit one will be created internally. - final FixedExtentScrollController scrollController; + final FixedExtentScrollController? scrollController; /// The uniform height of all children. /// @@ -195,8 +197,8 @@ class BrnPicker extends StatefulWidget { } class _CupertinoPickerState extends State { - int _lastHapticIndex; - FixedExtentScrollController _controller; + int? _lastHapticIndex; + FixedExtentScrollController? _controller; @override void initState() { @@ -247,8 +249,7 @@ class _CupertinoPickerState extends State { if (widget.backgroundColor != null && widget.backgroundColor.alpha < 255) return Container(); - final Color widgetBackgroundColor = - widget.backgroundColor ?? const Color(0xFFFFFFFF); + final Color widgetBackgroundColor = widget.backgroundColor; return Positioned.fill( child: IgnorePointer( child: Container( @@ -286,7 +287,7 @@ class _CupertinoPickerState extends State { /// Makes the magnifier lens look so that the colors are normal through /// the lens and partially grayed out around it. Widget _buildMagnifierScreen() { - final Color foreground = widget.backgroundColor?.withAlpha( + final Color foreground = widget.backgroundColor.withAlpha( (widget.backgroundColor.alpha * _kForegroundScreenOpacityFraction) .toInt()); @@ -324,7 +325,7 @@ class _CupertinoPickerState extends State { } Widget _buildUnderMagnifierScreen() { - final Color foreground = widget.backgroundColor?.withAlpha( + final Color foreground = widget.backgroundColor.withAlpha( (widget.backgroundColor.alpha * _kForegroundScreenOpacityFraction) .toInt()); @@ -359,7 +360,7 @@ class _CupertinoPickerState extends State { children: [ Positioned.fill( child: _CupertinoPickerSemantics( - scrollController: widget.scrollController ?? _controller, + scrollController: widget.scrollController ?? _controller!, child: ListWheelScrollView.useDelegate( controller: widget.scrollController ?? _controller, physics: const FixedExtentScrollPhysics(), @@ -404,9 +405,9 @@ class _CupertinoPickerState extends State { // scroll controller. class _CupertinoPickerSemantics extends SingleChildRenderObjectWidget { const _CupertinoPickerSemantics({ - Key key, - Widget child, - @required this.scrollController, + Key? key, + Widget? child, + required this.scrollController, }) : super(key: key, child: child); final FixedExtentScrollController scrollController; @@ -431,16 +432,16 @@ class _RenderCupertinoPickerSemantics extends RenderProxyBox { this.controller = controller; } - FixedExtentScrollController get controller => _controller; - FixedExtentScrollController _controller; + FixedExtentScrollController? get controller => _controller; + FixedExtentScrollController? _controller; - set controller(FixedExtentScrollController value) { + set controller(FixedExtentScrollController? value) { if (value == _controller) return; if (_controller != null) - _controller.removeListener(_handleScrollUpdate); + _controller!.removeListener(_handleScrollUpdate); else - _currentIndex = value.initialItem ?? 0; - value.addListener(_handleScrollUpdate); + _currentIndex = value!.initialItem; + value?.addListener(_handleScrollUpdate); _controller = value; } @@ -456,17 +457,17 @@ class _RenderCupertinoPickerSemantics extends RenderProxyBox { int _currentIndex = 0; void _handleIncrease() { - controller.jumpToItem(_currentIndex + 1); + controller!.jumpToItem(_currentIndex + 1); } void _handleDecrease() { if (_currentIndex == 0) return; - controller.jumpToItem(_currentIndex - 1); + controller!.jumpToItem(_currentIndex - 1); } void _handleScrollUpdate() { - if (controller.selectedItem == _currentIndex) return; - _currentIndex = controller.selectedItem; + if (controller!.selectedItem == _currentIndex) return; + _currentIndex = controller!.selectedItem; markNeedsSemanticsUpdate(); } @@ -483,7 +484,7 @@ class _RenderCupertinoPickerSemantics extends RenderProxyBox { if (children.isEmpty) return super.assembleSemanticsNode(node, config, children); final SemanticsNode scrollable = children.first; - final Map indexedChildren = {}; + final Map indexedChildren = {}; scrollable.visitChildren((SemanticsNode child) { assert(child.indexInParent != null); indexedChildren[child.indexInParent] = child; @@ -492,9 +493,9 @@ class _RenderCupertinoPickerSemantics extends RenderProxyBox { if (indexedChildren[_currentIndex] == null) { return node.updateWith(config: config); } - config.value = indexedChildren[_currentIndex].label; - final SemanticsNode previousChild = indexedChildren[_currentIndex - 1]; - final SemanticsNode nextChild = indexedChildren[_currentIndex + 1]; + config.value = indexedChildren[_currentIndex]!.label; + final SemanticsNode? previousChild = indexedChildren[_currentIndex - 1]; + final SemanticsNode? nextChild = indexedChildren[_currentIndex + 1]; if (nextChild != null) { config.increasedValue = nextChild.label; config.onIncrease = _handleIncrease; diff --git a/lib/src/components/picker/base/brn_picker_constants.dart b/lib/src/components/picker/base/brn_picker_constants.dart index bbc22b4d..9ed44cc5 100755 --- a/lib/src/components/picker/base/brn_picker_constants.dart +++ b/lib/src/components/picker/base/brn_picker_constants.dart @@ -1,26 +1,28 @@ -import 'dart:ui'; - import 'package:flutter/material.dart'; /// Default value of DatePicker's item [TextStyle]. -const TextStyle DATETIME_PICKER_ITEM_TEXT_STYLE = - const TextStyle(color: Color(0xFF222222), fontSize: 18.0); +const TextStyle datetimePickerItemTextStyle = TextStyle( + color: Color(0xFF222222), + fontSize: 18.0, +); /// Default value of DatePicker's background color. -const PICKER_BACKGROUND_COLOR = Colors.white; +const pickerBackgroundColor = Colors.white; /// Default value of whether show title widget or not. -const PICKER_SHOW_TITLE_DEFAULT = true; +const pickerShowTitleDefault = true; /// Default value of DatePicker's height. -const double PICKER_HEIGHT = 240.0; +const double pickerHeight = 240.0; /// Default value of DatePicker's title height. -const double PICKER_TITLE_HEIGHT = 48.0; +const double pickerTitleHeight = 48.0; /// Default value of DatePicker's column height. -const double PICKER_ITEM_HEIGHT = 48.0; +const double pickerItemHeight = 48.0; /// Default value of DatePicker's item [TextStyle]. -const TextStyle PICKER_ITEM_TEXT_STYLE = - const TextStyle(color: Color(0xFF222222), fontSize: 18.0); +const TextStyle pickerItemTextStyle = TextStyle( + color: Color(0xFF222222), + fontSize: 18.0, +); diff --git a/lib/src/components/picker/base/brn_picker_title.dart b/lib/src/components/picker/base/brn_picker_title.dart index 33cf3427..7079cbbf 100755 --- a/lib/src/components/picker/base/brn_picker_title.dart +++ b/lib/src/components/picker/base/brn_picker_title.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/picker/time_picker/brn_date_picker_constants.dart'; import 'package:bruno/src/components/picker/base/brn_picker_title_config.dart'; import 'package:bruno/src/theme/brn_theme.dart'; @@ -9,21 +11,21 @@ import 'package:flutter/material.dart'; // ignore: must_be_immutable class BrnPickerTitle extends StatelessWidget { final BrnPickerTitleConfig pickerTitleConfig; - final DateTimePickerLocale locale; + final DateTimePickerLocale? locale; final DateVoidCallback onCancel, onConfirm; - BrnPickerConfig themeData; + BrnPickerConfig? themeData; BrnPickerTitle({ - Key key, + Key? key, this.locale, - @required this.onCancel, - @required this.onConfirm, - this.pickerTitleConfig, + required this.onCancel, + required this.onConfirm, + this.pickerTitleConfig = BrnPickerTitleConfig.Default, this.themeData, }) : super(key: key) { this.themeData ??= BrnPickerConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .pickerConfig .merge(this.themeData); } @@ -31,16 +33,16 @@ class BrnPickerTitle extends StatelessWidget { @override Widget build(BuildContext context) { if (pickerTitleConfig.title != null) { - return pickerTitleConfig.title; + return pickerTitleConfig.title!; } return Container( - height: themeData.titleHeight, + height: themeData!.titleHeight, decoration: ShapeDecoration( - color: themeData.backgroundColor, + color: themeData!.backgroundColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( - topLeft: Radius.circular(themeData.cornerRadius), - topRight: Radius.circular(themeData.cornerRadius), + topLeft: Radius.circular(themeData!.cornerRadius), + topRight: Radius.circular(themeData!.cornerRadius), ), ), ), @@ -49,7 +51,7 @@ class BrnPickerTitle extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Container( - height: themeData.titleHeight - 0.5, + height: themeData!.titleHeight - 0.5, padding: EdgeInsets.symmetric(horizontal: 20), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -62,7 +64,7 @@ class BrnPickerTitle extends StatelessWidget { ), Text( pickerTitleConfig.titleContent, - style: themeData.titleTextStyle.generateTextStyle(), + style: themeData!.titleTextStyle.generateTextStyle(), ), GestureDetector( child: _renderConfirmWidget(context), @@ -74,7 +76,7 @@ class BrnPickerTitle extends StatelessWidget { ), ), Divider( - color: themeData.dividerColor, + color: themeData!.dividerColor, indent: 0.0, height: 0.5, ), @@ -85,9 +87,9 @@ class BrnPickerTitle extends StatelessWidget { /// render cancel button widget Widget _renderCancelWidget(BuildContext context) { - Widget cancelWidget = pickerTitleConfig.cancel; + Widget? cancelWidget = pickerTitleConfig.cancel; if (cancelWidget == null) { - TextStyle textStyle = themeData.cancelTextStyle.generateTextStyle(); + TextStyle textStyle = themeData!.cancelTextStyle.generateTextStyle(); cancelWidget = Text( '取消', style: textStyle, @@ -99,9 +101,9 @@ class BrnPickerTitle extends StatelessWidget { /// render confirm button widget Widget _renderConfirmWidget(BuildContext context) { - Widget confirmWidget = pickerTitleConfig.confirm; + Widget? confirmWidget = pickerTitleConfig.confirm; if (confirmWidget == null) { - TextStyle textStyle = themeData.confirmTextStyle.generateTextStyle(); + TextStyle textStyle = themeData!.confirmTextStyle.generateTextStyle(); confirmWidget = Text( '完成', style: textStyle, diff --git a/lib/src/components/picker/base/brn_picker_title_config.dart b/lib/src/components/picker/base/brn_picker_title_config.dart index 0c57d664..84d0cafc 100755 --- a/lib/src/components/picker/base/brn_picker_title_config.dart +++ b/lib/src/components/picker/base/brn_picker_title_config.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/picker/base/brn_picker_constants.dart'; import 'package:flutter/material.dart'; @@ -15,20 +17,20 @@ class BrnPickerTitleConfig { this.cancel, this.confirm, this.title, - this.showTitle: PICKER_SHOW_TITLE_DEFAULT, + this.showTitle: pickerShowTitleDefault, this.titleContent: "请选择", }); static const BrnPickerTitleConfig Default = const BrnPickerTitleConfig(); /// Custom cancel [Widget]. - final Widget cancel; + final Widget? cancel; /// Custom confirm [Widget]. - final Widget confirm; + final Widget? confirm; /// Custom title [Widget]. If specify a title widget, the cancel and confirm widgets will not display. - final Widget title; + final Widget? title; /// Whether display title widget or not. If set false, the default cancel and confirm widgets will not display, but the custom title widget will display if had specified one custom title widget. final bool showTitle; diff --git a/lib/src/components/picker/brn_bottom_picker.dart b/lib/src/components/picker/brn_bottom_picker.dart index 05fd0d8e..91a531c9 100644 --- a/lib/src/components/picker/brn_bottom_picker.dart +++ b/lib/src/components/picker/brn_bottom_picker.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/picker/base/brn_picker_title.dart'; import 'package:bruno/src/components/picker/base/brn_picker_title_config.dart'; import 'package:bruno/src/components/picker/brn_picker_cliprrect.dart'; @@ -24,12 +26,12 @@ import 'package:flutter/rendering.dart'; class BrnBottomPicker { static void show( BuildContext context, { - @required contentWidget, + required contentWidget, String title = '请选择', dynamic confirm, dynamic cancel, - VoidCallback onConfirm, - VoidCallback onCancel, + VoidCallback? onConfirm, + VoidCallback? onCancel, bool barrierDismissible = true, bool showTitle = true, }) { @@ -48,7 +50,7 @@ class BrnBottomPicker { pickerTitleConfig: BrnPickerTitleConfig(titleContent: title, showTitle: showTitle), ); - return theme != null ? Theme(data: theme, child: pageChild) : pageChild; + return Theme(data: theme, child: pageChild); }, barrierDismissible: barrierDismissible, barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, @@ -73,14 +75,14 @@ class BrnBottomPickerWidget extends StatefulWidget { final Widget contentWidget; final dynamic confirm; final dynamic cancel; - final Function() onConfirmPressed; - final Function() onCancelPressed; + final Function()? onConfirmPressed; + final Function()? onCancelPressed; final barrierDismissible; final BrnPickerTitleConfig pickerTitleConfig; const BrnBottomPickerWidget({ - Key key, - this.contentWidget, + Key? key, + required this.contentWidget, this.confirm, this.cancel, this.onConfirmPressed, @@ -97,8 +99,8 @@ class BrnBottomPickerWidget extends StatefulWidget { class BrnBottomPickerWidgetState extends State with TickerProviderStateMixin { - AnimationController _controller; - Animation _animation; + late AnimationController _controller; + late Animation _animation; @override void initState() { @@ -115,7 +117,7 @@ class BrnBottomPickerWidgetState extends State Widget build(BuildContext context) { return WillPopScope( onWillPop: () async { - _controller?.reverse(); + _controller.reverse(); return true; }, child: Scaffold( @@ -134,12 +136,12 @@ class BrnBottomPickerWidgetState extends State @override void dispose() { super.dispose(); - _controller?.dispose(); + _controller.dispose(); } Widget _buildBottomWidget() { return SlideTransition( - position: _animation, + position: _animation as Animation, child: BrnPickerClipRRect( borderRadius: BorderRadius.only( topLeft: Radius.circular(BrnThemeConfigurator.instance @@ -175,14 +177,14 @@ class BrnBottomPickerWidgetState extends State if (widget.onCancelPressed == null) { _closeDialog(); } else { - widget.onCancelPressed(); + widget.onCancelPressed!(); } }, onConfirm: () { if (widget.onConfirmPressed == null) { _closeDialog(); } else { - widget.onConfirmPressed(); + widget.onConfirmPressed!(); } }, pickerTitleConfig: BrnPickerTitleConfig( @@ -192,8 +194,8 @@ class BrnBottomPickerWidgetState extends State ); } - Widget _buildConfirmWidget() { - Widget confirmWidget; + Widget? _buildConfirmWidget() { + Widget? confirmWidget; if (widget.confirm is Widget) { confirmWidget = widget.confirm; } else if (widget.confirm is String) { @@ -204,8 +206,8 @@ class BrnBottomPickerWidgetState extends State return confirmWidget; } - Widget _buildCancelWidget() { - Widget cancelWidget; + Widget? _buildCancelWidget() { + Widget? cancelWidget; if (widget.cancel is Widget) { cancelWidget = widget.cancel; } else if (widget.cancel is String) { @@ -229,7 +231,7 @@ class BrnBottomPickerWidgetState extends State ); } - Widget _buildDefaultCancel(String string) { + Widget _buildDefaultCancel(String? string) { return Text( string ?? '取消', style: TextStyle( diff --git a/lib/src/components/picker/brn_bottom_write_picker.dart b/lib/src/components/picker/brn_bottom_write_picker.dart index cbd9bbd3..c5a5cbaf 100644 --- a/lib/src/components/picker/brn_bottom_write_picker.dart +++ b/lib/src/components/picker/brn_bottom_write_picker.dart @@ -1,15 +1,17 @@ + + import 'package:bruno/src/components/picker/base/brn_picker_title_config.dart'; import 'package:bruno/src/components/picker/brn_bottom_picker.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:flutter/material.dart'; ///取消输入事件回调 -typedef BrnBottomWritePickerClickCallback = Future Function( - String content); +typedef BrnBottomWritePickerClickCallback = Future? Function( + String? content); ///确认输入事件回调 -typedef BrnBottomWritePickerConfirmClickCallback = Future Function( - BuildContext dialogContext, String content); +typedef BrnBottomWritePickerConfirmClickCallback = Future? Function( + BuildContext dialogContext, String? content); class BrnBottomWritePicker extends StatefulWidget { /// 弹窗左边自定义文案,默认 '取消' @@ -28,22 +30,22 @@ class BrnBottomWritePicker extends StatefulWidget { final int maxLength; /// 取消输入事件回调 - final BrnBottomWritePickerClickCallback onCancel; + final BrnBottomWritePickerClickCallback? onCancel; /// 确认输入内容事件回调 - final BrnBottomWritePickerConfirmClickCallback onConfirm; + final BrnBottomWritePickerConfirmClickCallback? onConfirm; /// 弹窗右边文案颜色 - final Color rightTextColor; + final Color? rightTextColor; /// 光标颜色 - final Color cursorColor; + final Color? cursorColor; /// 默认文本 - final String defaultText; + final String? defaultText; /// 用于对 TextField 更精细的控制,若传入该字段,[defaultText] 参数将失效,可使用 TextEditingController.text 进行赋值。 - final TextEditingController textEditingController; + final TextEditingController? textEditingController; const BrnBottomWritePicker( {this.maxLength = 200, @@ -69,14 +71,14 @@ class BrnBottomWritePicker extends StatefulWidget { String leftTag = "取消", String title = "", String rightTag = "确认", - BrnBottomWritePickerClickCallback onCancel, - BrnBottomWritePickerConfirmClickCallback onConfirm, + BrnBottomWritePickerClickCallback? onCancel, + BrnBottomWritePickerConfirmClickCallback? onConfirm, bool confirmDismiss = false, bool cancelDismiss = true, - Color rightTextColor, - Color cursorColor, - String defaultText, - TextEditingController textEditingController}) { + Color? rightTextColor, + Color? cursorColor, + String? defaultText, + TextEditingController? textEditingController}) { final ThemeData theme = Theme.of(context); showGeneralDialog( context: context, @@ -103,26 +105,24 @@ class BrnBottomWritePicker extends StatefulWidget { defaultText: defaultText, textEditingController: textEditingController, ); - return theme != null - ? Theme(data: theme, child: pageChild) - : pageChild; + return Theme(data: theme, child: pageChild); }); } } class _BottomWritePickerState extends State { - TextEditingController _controller; + TextEditingController? _controller; @override void initState() { super.initState(); if (_controller == null) { - if (widget.defaultText != null && widget.defaultText.length > 0) { + if (widget.defaultText != null && widget.defaultText!.length > 0) { _controller = TextEditingController.fromValue(TextEditingValue( - text: widget.defaultText, + text: widget.defaultText!, selection: TextSelection.fromPosition(TextPosition( affinity: TextAffinity.downstream, - offset: widget.defaultText.length)))); + offset: widget.defaultText!.length)))); } else { _controller = TextEditingController(); } @@ -171,12 +171,12 @@ class _BottomWritePickerState extends State { cancel: widget.leftTag, onConfirmPressed: () { if (widget.onConfirm != null) { - widget.onConfirm(context, _controller?.text); + widget.onConfirm!(context, _controller?.text); } }, onCancelPressed: () { if (widget.onCancel != null) { - widget.onCancel(_controller?.text); + widget.onCancel!(_controller?.text); } }, barrierDismissible: true, diff --git a/lib/src/components/picker/brn_mulit_select_tags_picker.dart b/lib/src/components/picker/brn_mulit_select_tags_picker.dart index 7326c839..d222640d 100644 --- a/lib/src/components/picker/brn_mulit_select_tags_picker.dart +++ b/lib/src/components/picker/brn_mulit_select_tags_picker.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/picker/base/brn_picker_title_config.dart'; import 'package:bruno/src/components/picker/brn_tags_common_picker.dart'; import 'package:bruno/src/components/picker/brn_tags_picker_config.dart'; @@ -23,14 +25,15 @@ typedef BrnMultiSelectTagOnItemClick = void Function( /// 多选标签弹框,适用于底部弹出 Picker,且选择样式为 Tag 的场景。 /// 功能:多选标签弹框,适用于从底部弹出的情况,属于 Picker; /// 可自定义标题、默认选中、字体大小等。 +// ignore: must_be_immutable class BrnMultiSelectTagsPicker extends CommonTagsPicker { BrnMultiSelectTagsPicker({ - Key key, - @required this.context, - @required this.onConfirm, + Key? key, + required this.context, + required this.onConfirm, this.onCancel, - @required this.tagPickerConfig, - @required this.onTagValueGetter, + required this.tagPickerConfig, + required this.onTagValueGetter, this.onMaxSelectClick, this.onItemClick, this.maxSelectItemCount = 0, @@ -38,7 +41,7 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { this.itemHeight = 34.0, this.layoutStyle = BrnMultiSelectTagsLayoutStyle.average, BrnPickerTitleConfig pickerTitleConfig = BrnPickerTitleConfig.Default, - BrnPickerConfig themeData, + BrnPickerConfig? themeData, }) : super( key: key, context: context, @@ -54,16 +57,16 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { final ValueChanged onConfirm; /// 点击取消按钮 - final VoidCallback onCancel; + final VoidCallback? onCancel; /// 当点击到最大数目时的点击事件 - final VoidCallback onMaxSelectClick; + final VoidCallback? onMaxSelectClick; /// 点击某个按钮的回调 - final BrnMultiSelectTagOnItemClick onItemClick; + final BrnMultiSelectTagOnItemClick? onItemClick; /// 一行多少个数据,默认4个 - final int crossAxisCount; + final int? crossAxisCount; /// 最多选择多少个item,默认可以无限选 final int maxSelectItemCount; @@ -82,8 +85,8 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { final double itemHeight; /// 操作类型属性 - List _selectedTags; - List _sourceTags; + late List _selectedTags; + late List _sourceTags; @override void show() { @@ -97,8 +100,8 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { } @override - Widget createBuilder(BuildContext context, VoidCallback onUpdate) { - if (this.tagPickerConfig?.tagItemSource?.isNotEmpty ?? false) { + Widget createBuilder(BuildContext context, VoidCallback? onUpdate) { + if (this.tagPickerConfig.tagItemSource.isNotEmpty) { return _buildContent(context, onUpdate); } else { return Container( @@ -110,12 +113,12 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { } } - Widget _buildContent(BuildContext context, VoidCallback onUpdate) { + Widget _buildContent(BuildContext context, VoidCallback? onUpdate) { if (this.layoutStyle == BrnMultiSelectTagsLayoutStyle.average) { return LayoutBuilder( builder: (_, constraints) { - double maxwidth = constraints.maxWidth; - return _buildGridViewWidget(context, onUpdate, maxwidth); + double maxWidth = constraints.maxWidth; + return _buildGridViewWidget(context, onUpdate, maxWidth); }, ); } else { @@ -125,11 +128,11 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { ///等宽度的布局 Widget _buildGridViewWidget( - BuildContext context, VoidCallback onUpdate, double maxWidth) { + BuildContext context, VoidCallback? onUpdate, double maxWidth) { int brnCrossAxisCount = - (this.crossAxisCount == 0 || this.crossAxisCount == null) + (this.crossAxisCount == null || this.crossAxisCount == 0) ? 4 - : this.crossAxisCount; + : this.crossAxisCount!; double width = (maxWidth - (brnCrossAxisCount - 1) * 12 - 40) / brnCrossAxisCount; //计算宽高比 @@ -141,9 +144,9 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { .getConfig() .commonConfig .colorTextImportant; - Color tagBackgroudColor = + Color tagBackgroundColor = this.tagPickerConfig.tagBackgroudColor ?? Color(0xffF8F8F8); - Color selectedTagBackgroudColor = + Color selectedTagBackgroundColor = this.tagPickerConfig.selectedTagBackgroudColor ?? BrnThemeConfigurator.instance .getConfig() @@ -175,8 +178,8 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { selected: selected, padding: edgeInsets, pressElevation: 0, - backgroundColor: tagBackgroudColor, - selectedColor: selectedTagBackgroudColor, + backgroundColor: tagBackgroundColor, + selectedColor: selectedTagBackgroundColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(2.0)), label: Container( @@ -199,12 +202,12 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { value == true) { if (this.onMaxSelectClick != null) { // ignore: unnecessary_statements - this.onMaxSelectClick(); + this.onMaxSelectClick!(); } return; } _clickTag(value, choice); - onUpdate(); + onUpdate!(); }, ); }).toList(), @@ -213,7 +216,7 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { } ///流式布局 - Widget _buildWrapViewWidget(BuildContext context, VoidCallback onUpdate) { + Widget _buildWrapViewWidget(BuildContext context, VoidCallback? onUpdate) { Color selectedTagTitleColor = this.tagPickerConfig.selectedTagTitleColor ?? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary; Color tagTitleColor = this.tagPickerConfig.tagTitleColor ?? @@ -221,9 +224,9 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { .getConfig() .commonConfig .colorTextImportant; - Color tagBackgroudColor = + Color tagBackgroundColor = this.tagPickerConfig.tagBackgroudColor ?? Color(0xffF8F8F8); - Color selectedTagBackgroudColor = + Color selectedTagBackgroundColor = this.tagPickerConfig.selectedTagBackgroudColor ?? BrnThemeConfigurator.instance .getConfig() @@ -245,8 +248,8 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { selected: selected, padding: edgeInsets, pressElevation: 0, - backgroundColor: tagBackgroudColor, - selectedColor: selectedTagBackgroudColor, + backgroundColor: tagBackgroundColor, + selectedColor: selectedTagBackgroundColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(2.0)), label: Text( @@ -266,12 +269,12 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { value == true) { if (this.onMaxSelectClick != null) { // ignore: unnecessary_statements - this.onMaxSelectClick(); + this.onMaxSelectClick!(); } return; } _clickTag(value, choice); - onUpdate(); + onUpdate!(); }, ); }).toList(), @@ -279,12 +282,12 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { } void _dataSetup() { - List tagItems = List(); - List tagSelectItems = List(); + List tagItems = []; + List tagSelectItems = []; for (BrnTagItemBean item in this.tagPickerConfig.tagItemSource) { tagItems.add(item); //选中的按钮 - if (item.isSelect == true && item.name != null) { + if (item.isSelect == true) { tagSelectItems.add(item); } } @@ -306,7 +309,7 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { ///点击tag if (this.onItemClick != null) { - this.onItemClick(tagName, selected); + this.onItemClick!(tagName, selected); } } } diff --git a/lib/src/components/picker/brn_multi_picker.dart b/lib/src/components/picker/brn_multi_picker.dart index 06ff4bec..e6ad7cc4 100644 --- a/lib/src/components/picker/brn_multi_picker.dart +++ b/lib/src/components/picker/brn_multi_picker.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/picker/base/brn_picker.dart'; import 'package:bruno/src/components/picker/base/brn_picker_title.dart'; import 'package:bruno/src/components/picker/base/brn_picker_title_config.dart'; @@ -5,8 +7,7 @@ import 'package:bruno/src/components/picker/brn_picker_cliprrect.dart'; import 'package:bruno/src/theme/brn_theme.dart'; import 'package:flutter/material.dart'; -///数据选择控件高度 -const pickerHeight = 240.0; +import 'base/brn_picker_constants.dart'; /// 可以自定义实现 item Widget样式,更灵活 /// [isSelect] 是否被选中 @@ -34,7 +35,7 @@ abstract class BrnMultiDataPickerDelegate { String titleForRowInComponent(int component, int index); /// 定义每列内容的高度 - double rowHeightForComponent(int component); + double? rowHeightForComponent(int component); /// 定义选择更改后的操作 void selectRowInComponent(int component, int row); @@ -50,7 +51,7 @@ class BrnMultiDataPicker extends StatefulWidget { final String title; ///多级数据选择标题文案样式 - final TextStyle titleTextStyle; + final TextStyle? titleTextStyle; /// 多级数据选择弹窗所要覆盖页面的context final BuildContext context; @@ -59,50 +60,50 @@ class BrnMultiDataPicker extends StatefulWidget { final BrnMultiDataPickerDelegate delegate; ///多级数据选择确认文案样式 - final TextStyle confirmTextStyle; + final TextStyle? confirmTextStyle; ///多级数据选择取消文案样式 - final TextStyle cancelTextStyle; + final TextStyle? cancelTextStyle; /// 多级数据选择每一级的默认标题 - final List pickerTitles; + final List? pickerTitles; /// 多级数据选择每一级默认标题的字体大小 - final double pickerTitleFontSize; + final double? pickerTitleFontSize; /// 多级数据选择每一级默认标题的文案颜色 - final Color pickerTitleColor; + final Color? pickerTitleColor; /// 多级数据选择数据字体大小 - final double textFontSize; + final double? textFontSize; /// 多级数据选择数据文案颜色 - final Color textColor; + final Color? textColor; /// 多级数据选择数据选中文案颜色 - final Color textSelectedColor; + final Color? textSelectedColor; /// 多级数据选择数据widget容器 - final List controllers = List(); + final List controllers = []; /// 多级数据选择确认点击回调 - final ConfirmButtonClick confirmClick; + final ConfirmButtonClick? confirmClick; /// 选择轮盘的滚动行为 - final ScrollBehavior behavior; + final ScrollBehavior? behavior; /// 返回自定义 itemWidget 的回调 - final BrnMultiDataPickerCreateWidgetCallback createItemWidget; + final BrnMultiDataPickerCreateWidgetCallback? createItemWidget; /// 是否复位数据位置。默认 true final bool sync; - BrnPickerConfig themeData; + BrnPickerConfig? themeData; BrnMultiDataPicker( - {Key key, - @required this.context, - @required this.delegate, + {Key? key, + required this.context, + required this.delegate, this.title = "", this.titleTextStyle, this.confirmTextStyle, @@ -117,10 +118,9 @@ class BrnMultiDataPicker extends StatefulWidget { this.confirmClick, this.createItemWidget, this.themeData, - this.sync = true}) - : assert(delegate != null) { + this.sync = true}) { this.themeData ??= BrnPickerConfig(); - this.themeData = this.themeData.merge(BrnPickerConfig( + this.themeData = this.themeData!.merge(BrnPickerConfig( cancelTextStyle: BrnTextStyle.withStyle(cancelTextStyle), confirmTextStyle: BrnTextStyle.withStyle(confirmTextStyle), titleTextStyle: BrnTextStyle.withStyle(titleTextStyle), @@ -130,7 +130,7 @@ class BrnMultiDataPicker extends StatefulWidget { )); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .pickerConfig .merge(this.themeData); } @@ -153,7 +153,7 @@ class BrnMultiDataPicker extends StatefulWidget { } class _BrnMultiDataPickerState extends State { - List _selectedIndexList = List(); + List _selectedIndexList = []; @override void initState() { @@ -166,7 +166,7 @@ class _BrnMultiDataPickerState extends State { @override Widget build(BuildContext context) { return Container( - height: widget.themeData.pickerHeight + widget.themeData.titleHeight, + height: widget.themeData!.pickerHeight + widget.themeData!.titleHeight, child: Material( type: MaterialType.transparency, child: new Column( @@ -174,8 +174,8 @@ class _BrnMultiDataPickerState extends State { children: [ BrnPickerClipRRect( borderRadius: BorderRadius.only( - topLeft: Radius.circular(widget.themeData.cornerRadius), - topRight: Radius.circular(widget.themeData.cornerRadius), + topLeft: Radius.circular(widget.themeData!.cornerRadius), + topRight: Radius.circular(widget.themeData!.cornerRadius), ), child: _configHeaderWidget(), ), @@ -198,7 +198,8 @@ class _BrnMultiDataPickerState extends State { }, onConfirm: () { Navigator.of(context).pop(_selectedIndexList); - widget?.confirmClick(_selectedIndexList); + if (widget.confirmClick != null) + widget.confirmClick!(_selectedIndexList); }, ); } @@ -216,7 +217,7 @@ class _BrnMultiDataPickerState extends State { } List _pickersWithTitle() { - List pickersWithTitle = List(); + List pickersWithTitle = []; for (int i = 0; i < widget.delegate.numberOfComponent(); i++) { int initRow = widget.delegate.initSelectedRowForComponent(i); FixedExtentScrollController controller = @@ -234,7 +235,7 @@ class _BrnMultiDataPickerState extends State { child: Padding( padding: EdgeInsets.only(top: 25), child: Text( - widget.pickerTitles[i], + widget.pickerTitles == null ? '' : widget.pickerTitles![i], style: TextStyle( fontSize: widget.pickerTitleFontSize, color: widget.pickerTitleColor), @@ -250,7 +251,7 @@ class _BrnMultiDataPickerState extends State { //picker数据 List _pickers() { - List pickers = List(); + List pickers = []; for (int i = 0; i < widget.delegate.numberOfComponent(); i++) { int initRow = widget.delegate.initSelectedRowForComponent(i); FixedExtentScrollController controller = @@ -266,25 +267,25 @@ class _BrnMultiDataPickerState extends State { //构建单列数据 Widget _configSinglePicker(int component) { return MyPicker( - backgroundColor: widget.themeData.backgroundColor, - lineColor: widget.themeData.dividerColor, + backgroundColor: widget.themeData!.backgroundColor, + lineColor: widget.themeData!.dividerColor, controller: widget.controllers[component], key: Key(component.toString()), createWidgetList: () { if (widget.createItemWidget != null) { - List widgetList = List(); + List widgetList = []; for (int i = 0; i < widget.delegate.numberOfRowsInComponent(component); i++) { bool isSelect = _selectedIndexList[component] == i; widgetList.add(widget.createItemWidget != null - ? widget.createItemWidget( + ? widget.createItemWidget!( isSelect, component, i, _selectedIndexList) : Container()); } return widgetList; } else { - List list = List(); + List list = []; for (int i = 0; i < widget.delegate.numberOfRowsInComponent(component); i++) { @@ -292,8 +293,8 @@ class _BrnMultiDataPickerState extends State { child: Text( widget.delegate.titleForRowInComponent(component, i), style: _selectedIndexList[component] == i - ? widget.themeData.itemTextSelectedStyle.generateTextStyle() - : widget.themeData.itemTextStyle.generateTextStyle(), + ? widget.themeData!.itemTextSelectedStyle.generateTextStyle() + : widget.themeData!.itemTextStyle.generateTextStyle(), ), )); } @@ -301,7 +302,7 @@ class _BrnMultiDataPickerState extends State { } }, itemExtent: widget.delegate.rowHeightForComponent(component) ?? - widget.themeData.itemHeight, + widget.themeData!.itemHeight, changed: (int index) { widget.delegate.selectRowInComponent(component, index); _selectedIndexList[component] = index; @@ -309,7 +310,7 @@ class _BrnMultiDataPickerState extends State { for (int i = component + 1; i < widget.delegate.numberOfComponent(); i++) { - List list = List(); + List list = []; for (int j = 0; j < widget.delegate.numberOfRowsInComponent(component); j++) { @@ -332,33 +333,31 @@ class _BrnMultiDataPickerState extends State { /// 一级数据选择widget class MyPicker extends StatefulWidget { ///创建数据widget列表 - final CreateWidgetList createWidgetList; + final CreateWidgetList? createWidgetList; ///数据选择改变回调 - final ValueChanged changed; - - final Key key; + final ValueChanged? changed; /// 数据显示高度 final double itemExtent; /// 滚动行为 - final ScrollBehavior scrollBehavior; + final ScrollBehavior? scrollBehavior; - final FixedExtentScrollController controller; + final FixedExtentScrollController? controller; final Color backgroundColor; - final Color lineColor; + final Color? lineColor; MyPicker({ + Key? key, this.createWidgetList, this.changed, - this.key, this.scrollBehavior, this.itemExtent = 45, this.controller, this.backgroundColor = Colors.white, this.lineColor, - }); + }) : super(key: key); @override State createState() { @@ -369,7 +368,7 @@ class MyPicker extends StatefulWidget { class _MyPickerState extends State { @override Widget build(BuildContext context) { - var children = widget.createWidgetList(); + var children = widget.createWidgetList!(); return Container( child: ScrollConfiguration( behavior: widget.scrollBehavior ?? _DefaultScrollBehavior(), @@ -381,7 +380,7 @@ class _MyPickerState extends State { lineColor: widget.lineColor, onSelectedItemChanged: (index) { if (widget.changed != null) { - widget.changed(index); + widget.changed!(index); } }, children: children.length > 0 diff --git a/lib/src/components/picker/brn_picker_cliprrect.dart b/lib/src/components/picker/brn_picker_cliprrect.dart index eed8707b..ca5ac7e3 100644 --- a/lib/src/components/picker/brn_picker_cliprrect.dart +++ b/lib/src/components/picker/brn_picker_cliprrect.dart @@ -6,12 +6,11 @@ import 'package:flutter/widgets.dart'; /// [borderRadius] 默认值为 BorderRadius.only(topLeft: Radius.circular(8.0), topRight: Radius.circular(8.0)), class BrnPickerClipRRect extends ClipRRect { const BrnPickerClipRRect({ - Key key, + Key? key, BorderRadius borderRadius = const BorderRadius.only( topLeft: Radius.circular(8.0), topRight: Radius.circular(8.0), ), - Widget child, - }) : assert(borderRadius != null), - super(key: key, borderRadius: borderRadius, child: child); + Widget? child, + }) : super(key: key, borderRadius: borderRadius, child: child); } diff --git a/lib/src/components/picker/brn_select_tags_with_input_picker.dart b/lib/src/components/picker/brn_select_tags_with_input_picker.dart index a3f9474e..bb39f13f 100644 --- a/lib/src/components/picker/brn_select_tags_with_input_picker.dart +++ b/lib/src/components/picker/brn_select_tags_with_input_picker.dart @@ -9,9 +9,9 @@ import 'package:flutter/rendering.dart'; typedef SelectTagWithInputValueGetter = String Function(V data); ///提交按钮事件回调 -typedef BrnTagInputConfirmClickCallback = Future Function( +typedef BrnTagInputConfirmClickCallback = Future? Function( BuildContext dialogContext, - List selectedTags, + List? selectedTags, String content); ///关闭 picker回调 @@ -29,19 +29,19 @@ class BrnSelectTagsWithInputPicker extends Dialog { final int maxLength; ///输入内容事件回调 - final BrnTagInputConfirmClickCallback confirm; + final BrnTagInputConfirmClickCallback? confirm; ///关闭 picker 回调 - final BrnTagInputCancelClickCallBack cancelCallBack; + final BrnTagInputCancelClickCallBack? cancelCallBack; ///光标颜色 - final Color cursorColor; + final Color? cursorColor; /// 默认文本 - final String defaultText; + final String? defaultText; /// 用于对 TextField 更精细的控制,若传入该字段,[defaultText] 参数将失效,可使用 TextEditingController.text 进行赋值。 - final TextEditingController textEditingController; + final TextEditingController? textEditingController; /// 强制显示文本框 final bool forceShowTextInput; @@ -66,8 +66,8 @@ class BrnSelectTagsWithInputPicker extends Dialog { this.multiSelect = false, this.defaultText, this.textEditingController, - @required this.tagPickerConfig, - @required this.onTagValueGetter}); + required this.tagPickerConfig, + required this.onTagValueGetter}); @override Widget build(BuildContext context) { @@ -89,29 +89,29 @@ class BrnSelectTagsWithInputPicker extends Dialog { } class BrnSelectTagsWithInputPickerWidget extends StatefulWidget { - final String title; - final BrnTagInputConfirmClickCallback confirm; - final BrnTagInputCancelClickCallBack cancelCallBack; - final int maxLength; - final String hintText; - final Color cursorColor; + final String? title; + final BrnTagInputConfirmClickCallback? confirm; + final BrnTagInputCancelClickCallBack? cancelCallBack; + final int? maxLength; + final String? hintText; + final Color? cursorColor; final bool forceShowTextInput; final bool multiSelect; - final String defaultText; - final TextEditingController textEditingController; - final BrnTagsInputPickerConfig tagPickerBean; - final SelectTagWithInputValueGetter onTagValueGetter; + final String? defaultText; + final TextEditingController? textEditingController; + final BrnTagsInputPickerConfig? tagPickerBean; + final SelectTagWithInputValueGetter? onTagValueGetter; const BrnSelectTagsWithInputPickerWidget( - {Key key, + {Key? key, this.title, this.confirm, this.cancelCallBack, this.maxLength, this.hintText, this.cursorColor, - this.forceShowTextInput, - this.multiSelect, + this.forceShowTextInput = false, + this.multiSelect = false, this.defaultText, this.textEditingController, this.tagPickerBean, @@ -126,13 +126,13 @@ class BrnSelectTagsWithInputPickerWidget extends StatefulWidget { class _BrnSelectTagsWithInputPickerWidgetState extends State with AutomaticKeepAliveClientMixin { - TextEditingController _textEditingController; + TextEditingController? _textEditingController; /// 暂定只支持两列标签 int brnCrossAxisCount = 2; - List _selectedTags; - List _sourceTags; + late List _selectedTags; + late List _sourceTags; @override void initState() { @@ -140,11 +140,11 @@ class _BrnSelectTagsWithInputPickerWidgetState _dataSetup(); _textEditingController = widget.textEditingController ?? TextEditingController.fromValue(TextEditingValue( - text: widget.defaultText == null ? "" : widget.defaultText, + text: widget.defaultText == null ? "" : widget.defaultText!, selection: TextSelection.fromPosition(TextPosition( affinity: TextAffinity.downstream, offset: widget.defaultText != null - ? widget.defaultText.length + ? widget.defaultText!.length : 0)))); } @@ -169,7 +169,7 @@ class _BrnSelectTagsWithInputPickerWidgetState ), child: Column( mainAxisSize: MainAxisSize.min, - children: (widget.tagPickerBean?.tagItemSource?.isNotEmpty ?? false) + children: (widget.tagPickerBean?.tagItemSource.isNotEmpty ?? false) ? _buildBody(context) : _buildNoTagsBody(context), ), @@ -216,16 +216,19 @@ class _BrnSelectTagsWithInputPickerWidgetState } void _dataSetup() { - List tagItems = List(); - List tagSelectedItems = List(); - for (BrnTagInputItemBean item in widget.tagPickerBean.tagItemSource) { - tagItems.add(item); - //选中的按钮 - if (item.isSelect == true && item.name != null) { - tagSelectedItems.add(item); + List tagItems = []; + List tagSelectedItems = []; + if (widget.tagPickerBean != null) { + for (BrnTagInputItemBean item in widget.tagPickerBean!.tagItemSource) { + tagItems.add(item); + //选中的按钮 + if (item.isSelect == true ) { + tagSelectedItems.add(item); + } } } + this._sourceTags = tagItems; // 重新排序,name 越长,越靠后 this._sourceTags.sort((left, right) { @@ -244,7 +247,7 @@ class _BrnSelectTagsWithInputPickerWidgetState mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - widget.title, + widget.title ?? '', style: TextStyle( color: BrnThemeConfigurator.instance .getConfig() @@ -257,13 +260,13 @@ class _BrnSelectTagsWithInputPickerWidgetState InkWell( onTap: () { if (widget.cancelCallBack != null) { - widget.cancelCallBack(context); + widget.cancelCallBack!(context); } Navigator.of(context).pop(); }, child: Padding( padding: EdgeInsets.all(4), - child: BrunoTools.getAssetImage(BrnAsset.ICON_PICKER_CLOSE), + child: BrunoTools.getAssetImage(BrnAsset.iconPickerClose), )) ], ), @@ -281,7 +284,7 @@ class _BrnSelectTagsWithInputPickerWidgetState double preferredWidthWithText(String content) { double originalTextWidth = paintWidthWithTextStyle( - content, TextStyle(fontSize: widget.tagPickerBean.tagTitleFontSize)); + content, TextStyle(fontSize: widget.tagPickerBean!.tagTitleFontSize)); double maxTextWidthInHalf = (MediaQuery.of(context).size.width - (brnCrossAxisCount - 1) * 12 - 20 * 2) / @@ -293,17 +296,17 @@ class _BrnSelectTagsWithInputPickerWidgetState } Widget _tagsArea(BuildContext context) { - Color selectedTagTitleColor = widget.tagPickerBean.selectedTagTitleColor ?? + Color selectedTagTitleColor = widget.tagPickerBean?.selectedTagTitleColor ?? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary; - Color tagTitleColor = widget.tagPickerBean.tagTitleColor ?? + Color tagTitleColor = widget.tagPickerBean?.tagTitleColor ?? BrnThemeConfigurator.instance .getConfig() .commonConfig .colorTextImportant; - Color tagBackgroudColor = - widget.tagPickerBean.tagBackgroudColor ?? Color(0xffF8F8F8); - Color selectedTagBackgroudColor = - widget.tagPickerBean.selectedTagBackgroudColor ?? + Color tagBackgroundColor = + widget.tagPickerBean?.tagBackgroundColor ?? Color(0xffF8F8F8); + Color selectedTagBackgroundColor = + widget.tagPickerBean?.selectedTagBackgroundColor ?? BrnThemeConfigurator.instance .getConfig() .commonConfig @@ -318,11 +321,11 @@ class _BrnSelectTagsWithInputPickerWidgetState children: this._sourceTags.map((choice) { bool selected = choice.isSelect; Color titleColor = selected ? selectedTagTitleColor : tagTitleColor; - String textToDisplay = widget.onTagValueGetter(choice); + String textToDisplay = widget.onTagValueGetter!(choice); return ChoiceChip( selected: selected, - backgroundColor: tagBackgroudColor, - selectedColor: selectedTagBackgroudColor, + backgroundColor: tagBackgroundColor, + selectedColor: selectedTagBackgroundColor, pressElevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(4.0)), @@ -331,7 +334,7 @@ class _BrnSelectTagsWithInputPickerWidgetState labelStyle: TextStyle( color: titleColor, fontWeight: selected ? FontWeight.w600 : FontWeight.w400, - fontSize: widget.tagPickerBean.tagTitleFontSize), + fontSize: widget.tagPickerBean!.tagTitleFontSize), label: Container( width: preferredWidthWithText(textToDisplay), child: Text( @@ -421,8 +424,8 @@ class _BrnSelectTagsWithInputPickerWidgetState onTap: () { if (!isCommitBtnEnable()) return; if (widget.confirm != null) { - widget.confirm( - context, this._selectedTags, _textEditingController.text); + widget.confirm!( + context, this._selectedTags, _textEditingController!.text); } }, child: Container( @@ -451,8 +454,16 @@ class _BrnSelectTagsWithInputPickerWidgetState } bool isCommitBtnEnable() { + bool needExpend = false; + for (int i = 0; i < this._selectedTags.length; i++) { + BrnTagInputItemBean brnTagInputItemBean = this._selectedTags[i]; + if (true == brnTagInputItemBean.needExpend) { + needExpend = true; + break; + } + } return this._selectedTags.length > 0 && - (isShowTextInput() ? _textEditingController.text.length > 0 : true); + (needExpend ? _textEditingController!.text.length > 0 : true); } bool isShowTextInput() { @@ -461,11 +472,11 @@ class _BrnSelectTagsWithInputPickerWidgetState } for (int i = 0; i < this._selectedTags.length; i++) { BrnTagInputItemBean brnTagInputItemBean = this._selectedTags[i]; - if (true == brnTagInputItemBean.needExplane) { + if (true == brnTagInputItemBean.needExpend) { return true; } } - _textEditingController.clear(); + _textEditingController!.clear(); return false; } @@ -482,19 +493,19 @@ class BrnTagInputItemBean { bool isSelect; ///选中tag的index - int index; + int? index; /// 选中后是否展示文本输入框 - bool needExplane; + bool needExpend; /// 附带的更多数据,方便在点击回调中取用。 - Map ext; + Map? ext; BrnTagInputItemBean({ - this.name, + this.name = '', this.isSelect = false, this.index, - this.needExplane = false, + this.needExpend = false, this.ext, }); } @@ -504,18 +515,18 @@ class BrnTagsInputPickerConfig { {this.tagTitleFontSize = 16.0, this.tagTitleColor, this.selectedTagTitleColor, - this.tagBackgroudColor, - this.selectedTagBackgroudColor, + this.tagBackgroundColor, + this.selectedTagBackgroundColor, this.tagItemSource = const []}) { this.tagTitleColor = BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; } double tagTitleFontSize; - Color tagTitleColor; - Color selectedTagTitleColor; - Color tagBackgroudColor; - Color selectedTagBackgroudColor; + Color? tagTitleColor; + Color? selectedTagTitleColor; + Color? tagBackgroundColor; + Color? selectedTagBackgroundColor; List tagItemSource; } diff --git a/lib/src/components/picker/brn_tags_common_picker.dart b/lib/src/components/picker/brn_tags_common_picker.dart index 7a1fef20..d6cb4a5e 100644 --- a/lib/src/components/picker/brn_tags_common_picker.dart +++ b/lib/src/components/picker/brn_tags_common_picker.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/picker/base/brn_picker_title.dart'; import 'package:bruno/src/components/picker/base/brn_picker_title_config.dart'; import 'package:bruno/src/components/picker/brn_picker_cliprrect.dart'; @@ -11,21 +13,22 @@ enum BrnCommonPickBackType { } typedef TagsPickerContentBuilder = Widget Function( - BuildContext context, VoidCallback onUpdate); + BuildContext context, VoidCallback? onUpdate); /// 创建时传入Builder 或者 子类实现 createBuilder 函数 +// ignore: must_be_immutable class CommonTagsPicker extends StatefulWidget { final BuildContext context; - final ValueChanged onConfirm; - final VoidCallback onCancel; - final TagsPickerContentBuilder contentBuilder; + final ValueChanged? onConfirm; + final VoidCallback? onCancel; + final TagsPickerContentBuilder? contentBuilder; final BrnPickerTitleConfig pickerTitleConfig; - BrnPickerConfig themeData; + BrnPickerConfig? themeData; CommonTagsPicker( - {Key key, - @required this.context, + {Key? key, + required this.context, this.onConfirm, this.onCancel, this.contentBuilder, @@ -34,7 +37,7 @@ class CommonTagsPicker extends StatefulWidget { : super(key: key) { this.themeData ??= BrnPickerConfig(); this.themeData = this - .themeData + .themeData! .merge(BrnThemeConfigurator.instance.getConfig().pickerConfig); } @@ -47,11 +50,11 @@ class CommonTagsPicker extends StatefulWidget { }).then((type) { if (type == BrnCommonPickBackType.confirm) { if (onConfirm != null) { - onConfirm(getConfirmData()); + onConfirm!(getConfirmData()); } } else { if (onCancel != null) { - onCancel(); + onCancel!(); } } }); @@ -59,7 +62,7 @@ class CommonTagsPicker extends StatefulWidget { /// 子类重写实现builder @protected - Widget createBuilder(BuildContext context, VoidCallback onUpdate) { + Widget? createBuilder(BuildContext context, VoidCallback? onUpdate) { return null; } @@ -78,7 +81,7 @@ class CommonTagsPicker extends StatefulWidget { } class _CommonPickerState extends State { - VoidCallback _onUpdate; + VoidCallback? _onUpdate; @override void initState() { @@ -133,9 +136,9 @@ class _CommonPickerState extends State { /// 创建内容视图 Widget _createContentWidget() { - Widget contentWidget; + Widget? contentWidget; if (widget.contentBuilder != null) { - contentWidget = widget.contentBuilder(context, _onUpdate); + contentWidget = widget.contentBuilder!(context, _onUpdate); } else { contentWidget = widget.createBuilder(context, _onUpdate); } @@ -148,7 +151,7 @@ class _CommonPickerState extends State { ); } return Container( - padding: EdgeInsets.only(top: widget.themeData.titleHeight), // 流出头部视图 + padding: EdgeInsets.only(top: widget.themeData!.titleHeight), // 流出头部视图 child: ListView( shrinkWrap: true, // 列表高度自适应 controller: ScrollController(keepScrollOffset: false), // 若视图小于弹窗则不滑动 diff --git a/lib/src/components/picker/brn_tags_picker_config.dart b/lib/src/components/picker/brn_tags_picker_config.dart index 76f82a7d..1303df3c 100644 --- a/lib/src/components/picker/brn_tags_picker_config.dart +++ b/lib/src/components/picker/brn_tags_picker_config.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:flutter/material.dart'; @@ -24,19 +26,19 @@ class BrnTagsPickerHeaderConfig { final double headerHeight; final String title; - Color titleColor; + Color? titleColor; final double titleFontSize; final String confirmTitle; - final Color confirmColor; + final Color? confirmColor; final double confirmFontSize; final String cancelTitle; - Color cancelColor; + Color? cancelColor; final double cancelFontSize; //分割线颜色 - final Color dividingLineColor; + final Color? dividingLineColor; } class BrnTagsPickerConfig { @@ -56,19 +58,19 @@ class BrnTagsPickerConfig { double tagTitleFontSize; ///tag 文字颜色 - Color tagTitleColor; + Color? tagTitleColor; ///选中的tag颜色 - Color selectedTagTitleColor; + Color? selectedTagTitleColor; ///tag 背景颜色 - Color tagBackgroudColor; + Color? tagBackgroudColor; ///选中的颜色 - Color selectedTagBackgroudColor; + Color? selectedTagBackgroudColor; ///内部item的边距 - EdgeInsets chipPadding; + EdgeInsets? chipPadding; ///数据源 List tagItemSource; @@ -82,13 +84,13 @@ class BrnTagItemBean { String code; ///code唯一标识 - int index; + int? index; ///是被选中 bool isSelect; ///自己添加的扩展 - Map ext; + Map? ext; BrnTagItemBean( {this.name = '', diff --git a/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart b/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart index c6368103..b64f03df 100644 --- a/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart +++ b/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart @@ -2,54 +2,50 @@ import 'package:bruno/src/constants/brn_constants.dart'; import 'package:bruno/src/utils/brn_tools.dart'; enum PickerFilterType { - None, //未设置 - UnLimit, // 不限类型,与其他所有类型互斥。 - Radio, //单选列表、单选项 type为radio - Checkbox, //多选列表、多选项 type为checkbox + none, //未设置 + unLimit, // 不限类型,与其他所有类型互斥。 + radio, //单选列表、单选项 type为radio + checkbox, //多选列表、多选项 type为checkbox } /// 筛选弹窗展示风格 enum PickerWindowType { - List, //列表类型,使用列表 Item 展示。 - Range, //值范围类型,使用 Tag + Range 的 Item 展示 + list, //列表类型,使用列表 Item 展示。 + range, //值范围类型,使用 Tag + Range 的 Item 展示 } class BrnPickerEntity { - String uniqueId; //唯一的id - String + String? uniqueId; //唯一的id + String? type; //类型 目前支持的类型有不限(unlimit)、单选(radio)、复选(checkbox), 最终被解析成 PickerFilterType 类型 - String key; //回传给服务器 - String value; //回传给服务器 + String? key; //回传给服务器 + String? value; //回传给服务器 String name; //显示的文案 - String defaultValue; + String? defaultValue; List children; //下级筛选项 - Map extMap; //扩展字段,目前只有min和max + Map? extMap; //扩展字段,目前只有min和max bool isSelected; //是否选中 int maxSelectedCount; - BrnPickerEntity parent; //上级筛选项 - PickerFilterType filterType; //筛选类型 + BrnPickerEntity? parent; //上级筛选项 + PickerFilterType? filterType; //筛选类型 BrnPickerEntity( {this.uniqueId, this.key, this.value, this.defaultValue, - this.name, - this.children, + this.name = '', + this.children = const [], this.isSelected = false, this.extMap, this.type, - this.maxSelectedCount}) { + this.maxSelectedCount = BrnSelectionConstant.maxSelectCount}) { this.filterType = this.parserFilterTypeWithType(this.type); - - /// 默认支持最大选中个数为 65535 - this.maxSelectedCount = - maxSelectedCount ?? BrnSelectionConstant.MAX_SELECT_COUNT; } - static BrnPickerEntity fromMap(Map map) { - if (map == null) return null; + static BrnPickerEntity fromMap(Map? map) { + if (map == null) return BrnPickerEntity(); BrnPickerEntity entity = BrnPickerEntity(); entity.uniqueId = map['id'] ?? ""; entity.name = map['name'] ?? ""; @@ -61,14 +57,15 @@ class BrnPickerEntity { entity.value = map['value'] ?? ""; if (map['maxSelectedCount'] != null && int.tryParse(map['maxSelectedCount']) != null) { - entity.maxSelectedCount = int.tryParse(map['maxSelectedCount']); + entity.maxSelectedCount = int.tryParse(map['maxSelectedCount']) ?? + BrnSelectionConstant.maxSelectCount; } else { - entity.maxSelectedCount = BrnSelectionConstant.MAX_SELECT_COUNT; + entity.maxSelectedCount = BrnSelectionConstant.maxSelectCount; } entity.extMap = map['ext'] ?? {}; // entity.children = map['children'] ?? []; - entity.children = List() - ..addAll((map['children'] as List ?? []) + entity.children = [] + ..addAll((map['children'] as List? ?? []) .map((o) => BrnPickerEntity.fromMap(o))); return entity; } @@ -79,11 +76,11 @@ class BrnPickerEntity { } void configDefaultValue() { - if (this.children != null && this.children.length > 0) { + if (this.children.length > 0) { for (BrnPickerEntity entity in this.children) { if (!BrunoTools.isEmpty(defaultValue)) { - List values = defaultValue.split(','); - entity.isSelected = values != null && values.contains(entity.value); + List values = defaultValue!.split(','); + entity.isSelected = values.contains(entity.value); } entity.configDefaultValue(); } @@ -93,7 +90,7 @@ class BrnPickerEntity { } void configRelationship() { - if (this.children != null && this.children.length > 0) { + if (this.children.length > 0) { for (BrnPickerEntity entity in this.children) { entity.parent = this; entity.configRelationship(); @@ -103,26 +100,26 @@ class BrnPickerEntity { PickerWindowType parserShowType(String showType) { if (showType == "list") { - return PickerWindowType.List; + return PickerWindowType.list; } else if (showType == "range") { - return PickerWindowType.Range; + return PickerWindowType.range; } - return PickerWindowType.List; + return PickerWindowType.list; } - PickerFilterType parserFilterTypeWithType(String type) { + PickerFilterType parserFilterTypeWithType(String? type) { if (type == "unlimit") { - return PickerFilterType.UnLimit; + return PickerFilterType.unLimit; } else if (type == "radio") { - return PickerFilterType.Radio; + return PickerFilterType.radio; } else if (type == "checkbox") { - return PickerFilterType.Checkbox; + return PickerFilterType.checkbox; } - return PickerFilterType.None; + return PickerFilterType.none; } void clearChildSelection() { - if (this.children != null && this.children.length > 0) { + if (this.children.length > 0) { for (BrnPickerEntity entity in this.children) { entity.isSelected = false; entity.clearChildSelection(); @@ -131,18 +128,14 @@ class BrnPickerEntity { } List selectedLastColumnList() { - List list = List(); - if (this.children != null && this.children.length > 0) { - List firstList = List(); + List list = []; + if (this.children.length > 0) { + List firstList = []; for (BrnPickerEntity firstEntity in this.children) { - if (firstEntity != null && - firstEntity.children != null && - firstEntity.children.length > 0) { - List secondList = List(); + if (firstEntity.children.length > 0) { + List secondList = []; for (BrnPickerEntity secondEntity in firstEntity.children) { - if (secondEntity != null && - secondEntity.children != null && - secondEntity.children.length > 0) { + if (secondEntity.children.length > 0) { List thirds = this.currentSelectListForEntity(secondEntity); if (thirds.length > 0) { @@ -150,12 +143,12 @@ class BrnPickerEntity { } else if (secondEntity.isSelected) { secondList.add(secondEntity); } - } else if (secondEntity != null && secondEntity.isSelected) { + } else if (secondEntity.isSelected) { secondList.add(secondEntity); } } list.addAll(secondList); - } else if (firstEntity != null && firstEntity.isSelected) { + } else if (firstEntity.isSelected) { firstList.add(firstEntity); } } @@ -166,27 +159,25 @@ class BrnPickerEntity { List selectedListWithoutUnlimit() { List selected = selectedList(); - return selected?.where((_) => !_.isUnLimit())?.toList() ?? List(); + return selected.where((_) => !_.isUnLimit()).toList() ; } List selectedList() { - List results = List(); + List results = []; List firstColumn = this.currentSelectListForEntity(this); results.addAll(firstColumn); - if (firstColumn != null && firstColumn.length > 0) { + if (firstColumn.length > 0) { for (BrnPickerEntity firstEntity in firstColumn) { - if (firstEntity != null) { List secondColumn = this.currentSelectListForEntity(firstEntity); results.addAll(secondColumn); - if (secondColumn != null && secondColumn.length > 0) { + if (secondColumn.length > 0) { for (BrnPickerEntity secondEntity in secondColumn) { List thirdColumn = this.currentSelectListForEntity(secondEntity); results.addAll(thirdColumn); } } - } } } return results; @@ -194,8 +185,8 @@ class BrnPickerEntity { /// 返回状态为选中的子节点 List currentSelectListForEntity(BrnPickerEntity entity) { - List list = List(); - if (entity.children != null && entity.children.length > 0) { + List list = []; + if (entity.children.length > 0) { for (BrnPickerEntity entity in entity.children) { if (entity.isSelected) { list.add(entity); @@ -221,13 +212,11 @@ class BrnPickerEntity { /// 判断当前的筛选 Item 是否为当前层次中第一个被选中的 Item。 /// 用于展开筛选弹窗时显示选中效果。 int getIndexInCurrentLevel() { - if (parent == null || - parent.children == null || - parent.children.length == 0) return -1; + if (parent == null || parent!.children.length == 0) return -1; - for (BrnPickerEntity entity in parent.children) { + for (BrnPickerEntity entity in parent!.children) { if (entity == this) { - return parent.children.indexOf(entity); + return parent!.children.indexOf(entity); } } return -1; @@ -235,11 +224,10 @@ class BrnPickerEntity { bool isInLastLevel() { if (parent == null || - parent.children == null || - parent.children.length == 0) return true; + parent!.children.length == 0) return true; - for (BrnPickerEntity entity in parent.children) { - if (entity.children != null && entity.children.length > 0) { + for (BrnPickerEntity entity in parent!.children) { + if (entity.children.length > 0) { return false; } } @@ -248,18 +236,18 @@ class BrnPickerEntity { /// 在这里简单认为 value 为空【null 或 ''】时为 unLimit. bool isUnLimit() { - return filterType == PickerFilterType.UnLimit || - (BrunoTools.isEmpty(value) && filterType == PickerFilterType.Radio); + return filterType == PickerFilterType.unLimit || + (BrunoTools.isEmpty(value) && filterType == PickerFilterType.radio); } void clearSelectedEntity() { - List tmp = List(); + List tmp = []; BrnPickerEntity node = this; tmp.add(node); while (tmp.isNotEmpty) { node = tmp.removeLast(); node.isSelected = false; - node.children?.forEach((data) { + node.children.forEach((data) { tmp.add(data); }); } diff --git a/lib/src/components/picker/multi_range_picker/brn_multi_column_converter.dart b/lib/src/components/picker/multi_range_picker/brn_multi_column_converter.dart index b29bcbaa..c4c60f41 100644 --- a/lib/src/components/picker/multi_range_picker/brn_multi_column_converter.dart +++ b/lib/src/components/picker/multi_range_picker/brn_multi_column_converter.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart'; import 'package:bruno/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart'; import 'package:bruno/src/utils/brn_tools.dart'; @@ -13,7 +15,7 @@ class BrnMultiRangeSelConverter { } Map> getSelectionParams( - List selectedResults, + List? selectedResults, {bool includeUnlimitSelection = false}) { Map> params = Map(); if (selectedResults == null) return params; @@ -26,19 +28,19 @@ class BrnMultiRangeSelConverter { } else if (levelCount == 2) { params.addAll(getCurrentSelectionEntityParams(menuItemEntity, includeUnlimitSelection: includeUnlimitSelection)); - menuItemEntity.children?.forEach((firstLevelItem) => mergeParams( + menuItemEntity.children.forEach((firstLevelItem) => mergeParams( params, getCurrentSelectionEntityParams(firstLevelItem, includeUnlimitSelection: includeUnlimitSelection))); } else if (levelCount == 3) { params.addAll(getCurrentSelectionEntityParams(menuItemEntity, includeUnlimitSelection: includeUnlimitSelection)); - menuItemEntity.children?.forEach((firstLevelItem) { + menuItemEntity.children.forEach((firstLevelItem) { mergeParams( params, getCurrentSelectionEntityParams(firstLevelItem, includeUnlimitSelection: includeUnlimitSelection)); - firstLevelItem.children?.forEach((secondLevelItem) { + firstLevelItem.children.forEach((secondLevelItem) { mergeParams( params, getCurrentSelectionEntityParams(secondLevelItem, @@ -50,14 +52,14 @@ class BrnMultiRangeSelConverter { return params; } - Map> mergeParams( - Map> params, - Map> selectedParams) { - selectedParams?.forEach((String key, List value) { - if (params != null && params.containsKey(key)) { + Map> mergeParams( + Map> params, + Map> selectedParams) { + selectedParams.forEach((String? key, List value) { + if ( params.containsKey(key)) { params[key]?.addAll(value); } else { - params?.addAll(selectedParams); + params.addAll(selectedParams); } }); return params; @@ -67,20 +69,19 @@ class BrnMultiRangeSelConverter { BrnPickerEntity selectionEntity, {bool includeUnlimitSelection = false}) { Map> params = Map(); - String parentKey = selectionEntity.key; + String parentKey = selectionEntity.key ?? ''; var selectedEntity = selectionEntity.children - ?.where((BrnPickerEntity f) => f.isSelected) - ?.where((BrnPickerEntity f) { + .where((BrnPickerEntity f) => f.isSelected) + .where((BrnPickerEntity f) { if (includeUnlimitSelection) { return true; } else { return !BrunoTools.isEmpty(f.value); } }) - ?.map((BrnPickerEntity f) => f) - ?.toList(); - List selectedParams = - selectedEntity == null ? [] : selectedEntity; + .map((BrnPickerEntity f) => f) + .toList(); + List selectedParams = selectedEntity; if (!BrunoTools.isEmpty(selectedParams) && !BrunoTools.isEmpty(parentKey)) { params[parentKey] = selectedParams; } diff --git a/lib/src/components/picker/multi_range_picker/brn_multi_column_list.dart b/lib/src/components/picker/multi_range_picker/brn_multi_column_list.dart index 1a4c6b83..1d6b7a55 100644 --- a/lib/src/components/picker/multi_range_picker/brn_multi_column_list.dart +++ b/lib/src/components/picker/multi_range_picker/brn_multi_column_list.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart'; import 'package:bruno/src/components/picker/multi_range_picker/brn_multi_column_picker.dart'; import 'package:bruno/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart'; @@ -10,48 +12,48 @@ import 'package:flutter/material.dart'; /// [index] 点击位置处于当前列的位置 /// [entity] 被点击位置的数据 typedef bool BrnOnSelectEntityInterceptor( - int listIndex, int index, BrnPickerEntity entity); + int? listIndex, int index, BrnPickerEntity entity); // ignore: must_be_immutable class BrnMultiColumnListWidget extends StatefulWidget { - List _selectedItems; - int focusedIndex = -1; - List items; + List? _selectedItems; + int? focusedIndex = -1; + List? items; Color normalColor; Color selectedColor; - Color backgroundColor; - Color selectedBackgroundColor; + Color? backgroundColor; + Color? selectedBackgroundColor; int flex; - BrnOnEntityTap singleListItemPick; - int currentListIndex; + BrnOnEntityTap? singleListItemPick; + int? currentListIndex; double maxHeight; - BrnOnSelectEntityInterceptor onSelectEntityInterceptor; + BrnOnSelectEntityInterceptor? onSelectEntityInterceptor; BrnMultiColumnListWidget({ - @required this.items, + required this.items, this.normalColor = const Color(0Xff4a4e59), this.selectedColor = const Color(0xff41bc6a), this.maxHeight = 0, this.backgroundColor, this.selectedBackgroundColor, - this.flex, + required this.flex, this.focusedIndex, this.singleListItemPick, this.onSelectEntityInterceptor, }) { if (items == null) { - items = List(); + items = []; } - items.forEach((element) { + items!.forEach((element) { element.configRelationship(); }); currentListIndex = BrnMultiColumnPickerUtil.getCurrentColumnIndex( - items.length > 0 ? items[0] : null); + items!.length > 0 ? items![0] : null); - _selectedItems = items?.where((f) => f.isSelected)?.toList(); + _selectedItems = items?.where((f) => f.isSelected).toList(); if (_selectedItems == null) { - _selectedItems = List(); + _selectedItems = []; } } @@ -59,7 +61,7 @@ class BrnMultiColumnListWidget extends StatefulWidget { _BrnMultiColumnListWidgetState createState() => _BrnMultiColumnListWidgetState(); - List getSelectedItems() { + List? getSelectedItems() { return _selectedItems; } } @@ -70,7 +72,7 @@ class _BrnMultiColumnListWidgetState extends State { return Expanded( flex: widget.flex, child: Container( - constraints: (widget.maxHeight == null || widget.maxHeight == 0) + constraints: (widget.maxHeight == 0) ? BoxConstraints.expand() : BoxConstraints(maxHeight: widget.maxHeight), color: widget.backgroundColor, @@ -78,10 +80,10 @@ class _BrnMultiColumnListWidgetState extends State { shrinkWrap: true, padding: EdgeInsets.only(top: 0), scrollDirection: Axis.vertical, - itemCount: widget.items.length, + itemCount: widget.items!.length, separatorBuilder: (BuildContext context, int index) => Container(), itemBuilder: (BuildContext context, int index) { - BrnPickerEntity item = widget.items[index]; + BrnPickerEntity item = widget.items![index]; /// 点击筛选,展开弹窗时,默认展示上次选中的筛选项。 bool isCurrentFocused = _isItemFocused(index, item); @@ -97,14 +99,16 @@ class _BrnMultiColumnListWidgetState extends State { isFirstLevel: (1 == widget.currentListIndex) ? true : false, itemSelectFunction: (BrnPickerEntity entity) { if (widget.onSelectEntityInterceptor != null && - widget.onSelectEntityInterceptor( + widget.onSelectEntityInterceptor!( widget.currentListIndex, index, entity) == false) { return; } _processFilterData(entity); - widget.singleListItemPick( - widget.currentListIndex, index, entity); + if(widget.singleListItemPick!=null){ + widget.singleListItemPick!( + widget.currentListIndex ?? 0, index, entity); + } }, ); }, @@ -122,12 +126,12 @@ class _BrnMultiColumnListWidgetState extends State { } /// Item 点击之后的数据处理 - void _processFilterData(BrnPickerEntity selectedEntity) { + void _processFilterData(BrnPickerEntity? selectedEntity) { if (null == selectedEntity) { return; } - if (selectedEntity.filterType == PickerFilterType.Checkbox && + if (selectedEntity.filterType == PickerFilterType.checkbox && !selectedEntity.isSelected) { if (!BrnMultiColumnPickerUtil.isSelectedCountExceed(selectedEntity)) { BrnToast.show("您选择的数量已达上限", context); @@ -137,8 +141,8 @@ class _BrnMultiColumnListWidgetState extends State { int totalLevel = BrnMultiColumnPickerUtil.getTotalColumnCount(selectedEntity); - if (selectedEntity.isUnLimit()) { - selectedEntity.parent.clearChildSelection(); + if (selectedEntity.isUnLimit() && selectedEntity.parent !=null) { + selectedEntity.parent!.clearChildSelection(); } /// 设置选中数据。 @@ -155,35 +159,37 @@ class _BrnMultiColumnListWidgetState extends State { /// Warning !!! /// (两列、三列时)第一列节点是否被选中取决于它的子节点是否被选中, /// 只有当它子节点被选中时才会认为第一列的节点相应被选中。 - if (widget.items != null && widget.items.length > 0) { - widget.items[0].parent?.isSelected = widget.items[0].parent.children + if (widget.items != null && + widget.items!.length > 0 && + widget.items![0].parent != null ) { + widget.items![0].parent?.isSelected = widget.items![0].parent!.children .where((BrnPickerEntity f) => f.isSelected) .length > 0; } - for (BrnPickerEntity item in widget.items) { + for (BrnPickerEntity item in widget.items!) { if (item.isSelected) { - if (!widget._selectedItems.contains(item)) { - widget._selectedItems.add(item); + if (!widget._selectedItems!.contains(item)) { + widget._selectedItems!.add(item); } } else { - if (widget._selectedItems.contains(item)) { - widget._selectedItems.remove(item); + if (widget._selectedItems!.contains(item)) { + widget._selectedItems!.remove(item); } } } } void _configFirstList(BrnPickerEntity selectedEntity) { - if (PickerFilterType.Radio == selectedEntity.filterType) { + if (PickerFilterType.radio == selectedEntity.filterType) { /// 单选,清除同一级别选中的状态,则其他的设置为未选中。 - selectedEntity.parent.clearChildSelection(); + selectedEntity.parent!.clearChildSelection(); selectedEntity.isSelected = true; - } else if (PickerFilterType.Checkbox == selectedEntity.filterType) { + } else if (PickerFilterType.checkbox == selectedEntity.filterType) { /// 选中【不限】清除同一级别其他的状态 if (selectedEntity.isUnLimit()) { - selectedEntity.parent.clearChildSelection(); + selectedEntity.parent!.clearChildSelection(); selectedEntity.isSelected = true; } else { ///清除【不限】类型。 @@ -191,7 +197,7 @@ class _BrnMultiColumnListWidgetState extends State { if (selectedEntity.parent == null) { brotherItems = widget.items; } else { - brotherItems = selectedEntity.parent.children; + brotherItems = selectedEntity.parent!.children; } for (BrnPickerEntity entity in brotherItems) { if (entity.isUnLimit()) { @@ -203,20 +209,20 @@ class _BrnMultiColumnListWidgetState extends State { } } - void _configSecondList(BrnPickerEntity selectedEntity, int currentListIndex) { + void _configSecondList(BrnPickerEntity selectedEntity, int? currentListIndex) { if (currentListIndex == 1) { - if (PickerFilterType.Checkbox != selectedEntity.filterType) { - selectedEntity.parent.clearChildSelection(); + if (PickerFilterType.checkbox != selectedEntity.filterType) { + selectedEntity.parent!.clearChildSelection(); } } else { /// 单选,清除同一级别选中的状态,则其他的设置为未选中。 - if (PickerFilterType.Radio == selectedEntity.filterType) { - selectedEntity.parent.clearChildSelection(); + if (PickerFilterType.radio == selectedEntity.filterType) { + selectedEntity.parent!.clearChildSelection(); selectedEntity.isSelected = true; - } else if (PickerFilterType.Checkbox == selectedEntity.filterType) { + } else if (PickerFilterType.checkbox == selectedEntity.filterType) { /// 选中【不限】清除同一级别其他的状态 if (selectedEntity.isUnLimit()) { - selectedEntity.parent.clearChildSelection(); + selectedEntity.parent!.clearChildSelection(); selectedEntity.isSelected = true; } else { ///清除【不限】类型。 @@ -224,7 +230,7 @@ class _BrnMultiColumnListWidgetState extends State { if (selectedEntity.parent == null) { brotherItems = widget.items; } else { - brotherItems = selectedEntity.parent.children; + brotherItems = selectedEntity.parent!.children; } for (BrnPickerEntity entity in brotherItems) { if (entity.isUnLimit()) { @@ -237,20 +243,20 @@ class _BrnMultiColumnListWidgetState extends State { } } - void _configThirdList(BrnPickerEntity selectedEntity, int currentListIndex) { + void _configThirdList(BrnPickerEntity selectedEntity, int? currentListIndex) { if (currentListIndex == 1) { - if (PickerFilterType.Checkbox != selectedEntity.filterType) { - selectedEntity.parent.clearChildSelection(); + if (PickerFilterType.checkbox != selectedEntity.filterType) { + selectedEntity.parent!.clearChildSelection(); } } else { /// 单选,清除同一级别选中的状态,则其他的设置为未选中。 - if (PickerFilterType.Radio == selectedEntity.filterType) { - selectedEntity.parent.clearChildSelection(); + if (PickerFilterType.radio == selectedEntity.filterType) { + selectedEntity.parent!.clearChildSelection(); selectedEntity.isSelected = true; - } else if (PickerFilterType.Checkbox == selectedEntity.filterType) { + } else if (PickerFilterType.checkbox == selectedEntity.filterType) { /// 选中【不限】清除同一级别其他的状态 if (selectedEntity.isUnLimit()) { - selectedEntity.parent.clearChildSelection(); + selectedEntity.parent!.clearChildSelection(); selectedEntity.isSelected = true; } else { ///清除【不限】类型。 @@ -258,7 +264,7 @@ class _BrnMultiColumnListWidgetState extends State { if (selectedEntity.parent == null) { brotherItems = widget.items; } else { - brotherItems = selectedEntity.parent.children; + brotherItems = selectedEntity.parent!.children; } for (BrnPickerEntity entity in brotherItems) { if (entity.isUnLimit()) { diff --git a/lib/src/components/picker/multi_range_picker/brn_multi_column_picker.dart b/lib/src/components/picker/multi_range_picker/brn_multi_column_picker.dart index 22bfd61e..e070c441 100644 --- a/lib/src/components/picker/multi_range_picker/brn_multi_column_picker.dart +++ b/lib/src/components/picker/multi_range_picker/brn_multi_column_picker.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/picker/base/brn_picker_title.dart'; import 'package:bruno/src/components/picker/base/brn_picker_title_config.dart'; import 'package:bruno/src/components/picker/brn_picker_cliprrect.dart'; @@ -23,7 +25,7 @@ typedef void BrnOnEntityTap( /// [secondIndex] 第二列被选中数据的位置 /// [thirdIndex] 第三列被选中数据的位置 typedef void BrnOnPickerConfirm(Map> results, - int firstIndex, int secondIndex, int thirdIndex); + int? firstIndex, int? secondIndex, int? thirdIndex); /// 从屏幕下方弹起的多级筛选选择器 /// 可设置筛项的层级、多选、单选等筛选相关功能 @@ -33,7 +35,7 @@ class BrnMultiColumnPicker extends StatefulWidget { final BrnPickerEntity entity; /// 初始化时的选中选项 - final List defaultFocusedIndexes; + final List? defaultFocusedIndexes; /// Picker展示最大高度,默认 280 final double maxHeight; @@ -46,23 +48,23 @@ class BrnMultiColumnPicker extends StatefulWidget { final bool isIncludeUnLimit; /// 选择数据后回调函数 - final BrnOnPickerConfirm onConfirm; + final BrnOnPickerConfirm? onConfirm; /// 选择项目后回调函数 - final BrnOnEntityTap onEntityTap; + final BrnOnEntityTap? onEntityTap; /// 当前选项是否可以被选中:返回 true 可以被选中 false 不可以被选中 - final BrnOnSelectEntityInterceptor canSelectEntryInterceptor; + final BrnOnSelectEntityInterceptor? canSelectEntryInterceptor; /// 主题定制,只有 Picker Title 部分样式生效 - BrnPickerConfig themeData; + BrnPickerConfig? themeData; /// Picker Title 数据配置 final BrnPickerTitleConfig pickerTitleConfig; BrnMultiColumnPicker( - {Key key, - @required this.entity, + {Key? key, + required this.entity, this.maxHeight = 280.0, this.showSelectedCount = false, this.isIncludeUnLimit = false, @@ -75,7 +77,7 @@ class BrnMultiColumnPicker extends StatefulWidget { : super(key: key) { this.themeData ??= BrnPickerConfig(); this.themeData = this - .themeData + .themeData! .merge(BrnThemeConfigurator.instance.getConfig().pickerConfig); } @@ -86,23 +88,23 @@ class BrnMultiColumnPicker extends StatefulWidget { class _BrnSelectionGroupViewState extends State { static const BrnMultiRangeSelConverter defaultConverter = const BrnMultiRangeSelConverter(); - List _firstList = List(); - List _secondList = List(); - List _thirdList = List(); - List _originalSelectedItemsList = List(); - int _firstIndex; - int _secondIndex; - int _thirdIndex; + List _firstList = []; + List? _secondList = []; + List? _thirdList = []; + List _originalSelectedItemsList = []; + int? _firstIndex; + int? _secondIndex; + int? _thirdIndex; int get _columnCount { return BrnMultiColumnPickerUtil.getTotalColumnCount(widget.entity); } /// 未选中状态颜色,默认 Color(0Xff4a4e59) - Color _normalColor; + late Color _normalColor; /// 选中状态颜色,默认 Color(0xff41bc6a) - Color _selectedColor; + late Color _selectedColor; @override void initState() { @@ -121,8 +123,8 @@ class _BrnSelectionGroupViewState extends State { height: widget.maxHeight + 48, child: BrnPickerClipRRect( borderRadius: BorderRadius.only( - topLeft: Radius.circular(widget.themeData.cornerRadius), - topRight: Radius.circular(widget.themeData.cornerRadius), + topLeft: Radius.circular(widget.themeData!.cornerRadius), + topRight: Radius.circular(widget.themeData!.cornerRadius), ), child: Column( children: _configWidgets(), @@ -133,7 +135,7 @@ class _BrnSelectionGroupViewState extends State { //pragma mark -- config widgets List _configWidgets() { - List widgetList = List(); + List widgetList = []; widgetList.add( Offstage( offstage: !widget.pickerTitleConfig.showTitle, @@ -157,7 +159,7 @@ class _BrnSelectionGroupViewState extends State { } Widget _listWidget() { - List widgets = List(); + List widgets = []; if (!BrunoTools.isEmpty(_firstList) && BrunoTools.isEmpty(_secondList) && @@ -178,11 +180,11 @@ class _BrnSelectionGroupViewState extends State { (int listIndex, int index, BrnPickerEntity entity) { _setFirstIndex(index); if (_columnCount == 1 && - widget.entity.filterType == PickerFilterType.Radio) { + widget.entity.filterType == PickerFilterType.radio) { _confirmButtonClickEvent(); } if (widget.onEntityTap != null) { - widget.onEntityTap(0, index, entity); + widget.onEntityTap!(0, index, entity); } })); } else if (!BrunoTools.isEmpty(_firstList) && @@ -202,7 +204,7 @@ class _BrnSelectionGroupViewState extends State { (int listIndex, int index, BrnPickerEntity entity) { _setFirstIndex(index); if (widget.onEntityTap != null) { - widget.onEntityTap(0, index, entity); + widget.onEntityTap!(0, index, entity); } })); @@ -219,7 +221,7 @@ class _BrnSelectionGroupViewState extends State { (int listIndex, int index, BrnPickerEntity entity) { _setSecondIndex(index); if (widget.onEntityTap != null) { - widget.onEntityTap(1, index, entity); + widget.onEntityTap!(1, index, entity); } })); } else if (!BrunoTools.isEmpty(_firstList) && @@ -239,7 +241,7 @@ class _BrnSelectionGroupViewState extends State { (int listIndex, int index, BrnPickerEntity entity) { _setFirstIndex(index); if (widget.onEntityTap != null) { - widget.onEntityTap(0, index, entity); + widget.onEntityTap!(0, index, entity); } })); @@ -256,7 +258,7 @@ class _BrnSelectionGroupViewState extends State { (int listIndex, int index, BrnPickerEntity entity) { _setSecondIndex(index); if (widget.onEntityTap != null) { - widget.onEntityTap(1, index, entity); + widget.onEntityTap!(1, index, entity); } })); widgets.add(BrnMultiColumnListWidget( @@ -277,7 +279,7 @@ class _BrnSelectionGroupViewState extends State { } setState(() {}); if (widget.onEntityTap != null) { - widget.onEntityTap(2, index, entity); + widget.onEntityTap!(2, index, entity); } })); } @@ -302,7 +304,7 @@ class _BrnSelectionGroupViewState extends State { Map> result = defaultConverter .convertPickedData([widget.entity], includeUnlimitSelection: widget.isIncludeUnLimit); - widget.onConfirm(result, _firstIndex, _secondIndex, _thirdIndex); + widget.onConfirm!(result, _firstIndex, _secondIndex, _thirdIndex); } } @@ -341,10 +343,10 @@ class _BrnSelectionGroupViewState extends State { // 刷新3个ListView的数据源 void _refreshDataSource() { _firstList = widget.entity.children; - if (_firstIndex >= 0 && _firstList.length > _firstIndex) { - _secondList = _firstList[_firstIndex].children; - if (_secondIndex >= 0 && _secondList.length > _secondIndex) { - _thirdList = _secondList[_secondIndex].children; + if (_firstIndex! >= 0 && _firstList.length > _firstIndex!) { + _secondList = _firstList[_firstIndex!].children; + if (_secondIndex! >= 0 && _secondList!.length > _secondIndex!) { + _thirdList = _secondList![_secondIndex!].children; } else { _thirdList = null; } @@ -356,51 +358,41 @@ class _BrnSelectionGroupViewState extends State { void _configDefaultSelectedData() { _firstList = widget.entity.children; - //是否已选择的item里面有第一列的 - if (_firstList == null) { - _secondIndex = -1; - _secondList = null; - - _thirdIndex = -1; - _thirdList = null; - - return; - } _firstIndex = _getInitialSelectIndex(_firstList); if (_firstIndex == -1) { if (widget.defaultFocusedIndexes != null) { for (int index = 0; - index < widget.defaultFocusedIndexes.length; + index < widget.defaultFocusedIndexes!.length; index++) { - if (index == 0 && widget.defaultFocusedIndexes[index] >= 0) { - _firstIndex = widget.defaultFocusedIndexes[index]; + if (index == 0 && widget.defaultFocusedIndexes![index] >= 0) { + _firstIndex = widget.defaultFocusedIndexes![index]; } - if (index == 1 && _firstIndex >= 0) { - _secondIndex = widget.defaultFocusedIndexes[index]; + if (index == 1 && _firstIndex! >= 0) { + _secondIndex = widget.defaultFocusedIndexes![index]; } - if (index == 2 && _secondIndex >= 0) { - _thirdIndex = widget.defaultFocusedIndexes[index]; + if (index == 2 && _secondIndex! >= 0) { + _thirdIndex = widget.defaultFocusedIndexes![index]; } } } - if (_firstIndex >= 0 && _firstIndex < _firstList.length) { - _secondList = _firstList[_firstIndex].children; + if (_firstIndex! >= 0 && _firstIndex! < _firstList.length) { + _secondList = _firstList[_firstIndex!].children; } if (_secondList == null) { _thirdIndex = -1; _thirdList = null; return; } - if (_secondIndex >= 0 && _secondIndex < _secondList.length) { - _thirdList = _secondList[_secondIndex].children; + if (_secondIndex! >= 0 && _secondIndex! < _secondList!.length) { + _thirdList = _secondList![_secondIndex!].children; } } else { - if (_firstIndex >= 0 && _firstIndex < _firstList.length) { - _secondList = _firstList[_firstIndex].children; + if (_firstIndex! >= 0 && _firstIndex! < _firstList.length) { + _secondList = _firstList[_firstIndex!].children; if (_secondList != null) { _secondIndex = _getInitialSelectIndex(_secondList); } @@ -411,8 +403,8 @@ class _BrnSelectionGroupViewState extends State { _thirdList = null; return; } - if (_secondIndex >= 0 && _secondIndex < _secondList.length) { - _thirdList = _secondList[_secondIndex].children; + if (_secondIndex! >= 0 && _secondIndex! < _secondList!.length) { + _thirdList = _secondList![_secondIndex!].children; if (_thirdList != null) { _thirdIndex = _getInitialSelectIndex(_thirdList); } @@ -423,10 +415,8 @@ class _BrnSelectionGroupViewState extends State { //设置数据为未选中状态 void _resetSelectionDatas(BrnPickerEntity entity) { entity.isSelected = false; - if (entity.children != null) { - for (BrnPickerEntity subEntity in entity.children) { - _resetSelectionDatas(subEntity); - } + for (BrnPickerEntity subEntity in entity.children) { + _resetSelectionDatas(subEntity); } } @@ -435,15 +425,13 @@ class _BrnSelectionGroupViewState extends State { void _setFirstIndex(int firstIndex) { _firstIndex = firstIndex; _secondIndex = -1; - if (widget.entity.children.length > _firstIndex) { + if (widget.entity.children.length > _firstIndex!) { List seconds = - widget.entity.children[_firstIndex].children; - if (seconds != null) { - _secondIndex = _getInitialSelectIndex(seconds); + widget.entity.children[_firstIndex!].children; + _secondIndex = _getInitialSelectIndex(seconds); - if (_secondIndex >= 0) { - _setSecondIndex(_secondIndex); - } + if (_secondIndex! >= 0) { + _setSecondIndex(_secondIndex); } } setState(() { @@ -451,23 +439,21 @@ class _BrnSelectionGroupViewState extends State { }); } - void _setSecondIndex(int secondIndex) { + void _setSecondIndex(int? secondIndex) { _secondIndex = secondIndex; _thirdIndex = -1; List seconds = - widget.entity.children[_firstIndex].children; - if (seconds.length > _secondIndex) { - List thirds = seconds[_secondIndex].children; - if (thirds != null) { - _thirdIndex = _getInitialSelectIndex(thirds); - } + widget.entity.children[_firstIndex!].children; + if (seconds.length > _secondIndex!) { + List thirds = seconds[_secondIndex!].children; + _thirdIndex = _getInitialSelectIndex(thirds); } setState(() { _refreshDataSource(); }); } - int _getInitialSelectIndex(List levelList) { + int _getInitialSelectIndex(List? levelList) { int index = -1; if (levelList == null || levelList.length == 0) { return index; @@ -486,7 +472,7 @@ class _BrnSelectionGroupViewState extends State { // 例如1级为多选,不应该默认选中2级的不限 // 否则每选中任意一个1级选项,就默认有了一个2级的不限 if (entity.isUnLimit() && - entity.parent.filterType != PickerFilterType.Checkbox) { + entity.parent!.filterType != PickerFilterType.checkbox) { index = levelList.indexOf(entity); break; } diff --git a/lib/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart b/lib/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart index a719ca04..03a0d5d7 100644 --- a/lib/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart +++ b/lib/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart @@ -1,27 +1,25 @@ + + import 'package:bruno/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart'; -import 'package:bruno/src/utils/brn_tools.dart'; /// BrnMultiColumnPicker相关工具类 class BrnMultiColumnPickerUtil { /// 筛选项最多不超过三层,故直接写代码判断,本质为深度优先搜索。 - static int getTotalColumnCount(BrnPickerEntity entity) { + static int getTotalColumnCount(BrnPickerEntity? entity) { int count = 0; - BrnPickerEntity rootEntity = entity; - while (rootEntity.parent != null) { - rootEntity = rootEntity.parent; + BrnPickerEntity? rootEntity = entity; + while (rootEntity?.parent != null) { + rootEntity = rootEntity?.parent!; } - if (rootEntity != null && - rootEntity.children != null && + if (rootEntity != null && rootEntity.children.length > 0) { count = count > 1 ? count : 1; for (BrnPickerEntity firstLevelEntity in rootEntity.children) { - if (firstLevelEntity.children != null && - firstLevelEntity.children.length > 0) { + if (firstLevelEntity.children.length > 0) { count = count > 2 ? count : 2; for (BrnPickerEntity secondLevelEntity in firstLevelEntity.children) { - if (secondLevelEntity.children != null && - secondLevelEntity.children.length > 0) { + if (secondLevelEntity.children.length > 0) { count = 3; break; } @@ -33,7 +31,7 @@ class BrnMultiColumnPickerUtil { } /// 确定当前 Item 在第几层级 - static int getCurrentColumnIndex(BrnPickerEntity currentItem) { + static int getCurrentColumnIndex(BrnPickerEntity? currentItem) { int listIndex = -1; if (currentItem != null) { listIndex = 0; @@ -50,9 +48,9 @@ class BrnMultiColumnPickerUtil { /// [entity] 传入当前点击的 Item /// !!! 在设置 isSelected = true之前进行 check。 /// 返回 true 符合条件,false 不符合条件 - static bool isSelectedCountExceed(BrnPickerEntity entity) { - if (entity == null && entity.parent == null) return false; - return entity.parent.getSelectedChildCount() < - entity.parent.maxSelectedCount; + static bool isSelectedCountExceed(BrnPickerEntity? entity) { + if (entity == null || entity.parent == null) return false; + return entity.parent!.getSelectedChildCount() < + entity.parent!.maxSelectedCount; } } diff --git a/lib/src/components/picker/multi_range_picker/btn_multi_column_picker_item.dart b/lib/src/components/picker/multi_range_picker/btn_multi_column_picker_item.dart index 3310c1d0..55dbb9be 100644 --- a/lib/src/components/picker/multi_range_picker/btn_multi_column_picker_item.dart +++ b/lib/src/components/picker/multi_range_picker/btn_multi_column_picker_item.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart'; import 'package:bruno/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; @@ -10,17 +12,17 @@ class BrnMultiRangePickerCommonItem extends StatelessWidget { final BrnPickerEntity item; final Color normalColor; final Color selectColor; - final Color backgroundColor; - final Color selectedBackgroundColor; - final bool isCurrentFocused; + final Color? backgroundColor; + final Color? selectedBackgroundColor; + final bool? isCurrentFocused; final bool isFirstLevel; final bool isMoreSelectionListType; - final ItemSelectFunction itemSelectFunction; + final ItemSelectFunction? itemSelectFunction; BrnMultiRangePickerCommonItem({ - @required this.item, + required this.item, this.normalColor = const Color(0Xff4a4e59), this.selectColor = const Color(0xff41bc6a), this.backgroundColor, @@ -35,7 +37,7 @@ class BrnMultiRangePickerCommonItem extends StatelessWidget { Widget build(BuildContext context) { var checkbox; if (!item.isUnLimit() && - (item.children == null || item.children.length == 0)) { + (item.children.length == 0)) { if (item.isInLastLevel() && _hasCheckBoxBrother(item)) { checkbox = Container( padding: EdgeInsets.only(left: 6), @@ -55,7 +57,7 @@ class BrnMultiRangePickerCommonItem extends StatelessWidget { return GestureDetector( onTap: () { if (itemSelectFunction != null) { - itemSelectFunction(item); + itemSelectFunction!(item); } }, child: Container( @@ -88,8 +90,8 @@ class BrnMultiRangePickerCommonItem extends StatelessWidget { ); } - Color _getItemBGColor() { - if (isCurrentFocused) { + Color? _getItemBGColor() { + if (isCurrentFocused!) { return this.selectedBackgroundColor; } else { return this.backgroundColor; @@ -97,23 +99,23 @@ class BrnMultiRangePickerCommonItem extends StatelessWidget { } Color _getItemTextColor() { - Color itemColor = (item.isUnLimit() ? isCurrentFocused : item.isSelected) + Color itemColor = (item.isUnLimit() ? isCurrentFocused : item.isSelected)! ? selectColor : normalColor; if (!item.isInLastLevel()) { - itemColor = isCurrentFocused ? selectColor : normalColor; + itemColor = isCurrentFocused! ? selectColor : normalColor; } return itemColor; } FontWeight _getItemFontWeight() { FontWeight fontWeight = - (item.isUnLimit() ? isCurrentFocused : item.isSelected) + (item.isUnLimit() ? isCurrentFocused : item.isSelected)! ? FontWeight.w600 : FontWeight.normal; if (!item.isInLastLevel()) { - fontWeight = isCurrentFocused ? FontWeight.w600 : FontWeight.normal; + fontWeight = isCurrentFocused! ? FontWeight.w600 : FontWeight.normal; } return fontWeight; } @@ -121,8 +123,7 @@ class BrnMultiRangePickerCommonItem extends StatelessWidget { String _getSelectedItemCount(BrnPickerEntity item) { String itemCount = ""; if ((BrnMultiColumnPickerUtil.getTotalColumnCount(item) < 3 || - !isFirstLevel) && - item.children != null) { + !isFirstLevel)) { int count = item.children.where((f) => f.isSelected && !f.isUnLimit()).length; if (count > 1) { @@ -133,9 +134,12 @@ class BrnMultiRangePickerCommonItem extends StatelessWidget { } bool _hasCheckBoxBrother(BrnPickerEntity item) { - int count = item.parent.children - ?.where((f) => f.filterType == PickerFilterType.Checkbox) - ?.length; + int? count; + if (item.parent != null) { + count = item.parent!.children + .where((f) => f.filterType == PickerFilterType.checkbox) + .length; + } return count == null ? false : count > 0; } } diff --git a/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_data.dart b/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_data.dart index 9d9eebab..a48143db 100644 --- a/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_data.dart +++ b/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_data.dart @@ -1,3 +1,5 @@ + + class BrnMultiSelectBottomPickerItem { String code; //选项编号 diff --git a/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_list_picker.dart b/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_list_picker.dart index 6aee590e..c1427243 100644 --- a/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_list_picker.dart +++ b/lib/src/components/picker/multi_select_bottom_picker/brn_multi_select_list_picker.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/line/brn_line.dart'; import 'package:bruno/src/components/picker/base/brn_picker_constants.dart'; import 'package:bruno/src/components/picker/base/brn_picker_title.dart'; @@ -22,19 +24,19 @@ typedef BrnMultiSelectListPickerItemClick = void Function( /// 多选列表 Picker class BrnMultiSelectListPicker extends StatefulWidget { - final String title; + final String? title; final List items; - final BrnMultiSelectListPickerSubmit onSubmit; - final VoidCallback onCancel; - final BrnMultiSelectListPickerItemClick onItemClick; + final BrnMultiSelectListPickerSubmit? onSubmit; + final VoidCallback? onCancel; + final BrnMultiSelectListPickerItemClick? onItemClick; final BrnPickerTitleConfig pickerTitleConfig; static void show( BuildContext context, { - @required List items, - BrnMultiSelectListPickerSubmit onSubmit, - VoidCallback onCancel, - BrnMultiSelectListPickerItemClick onItemClick, + required List items, + BrnMultiSelectListPickerSubmit? onSubmit, + VoidCallback? onCancel, + BrnMultiSelectListPickerItemClick? onItemClick, BrnPickerTitleConfig pickerTitleConfig = BrnPickerTitleConfig.Default, bool isDismissible = true, }) { @@ -55,9 +57,9 @@ class BrnMultiSelectListPicker extends StatefulWidget { } BrnMultiSelectListPicker({ - Key key, + Key? key, this.title, - this.items, + required this.items, this.pickerTitleConfig = BrnPickerTitleConfig.Default, this.onSubmit, this.onCancel, @@ -98,15 +100,15 @@ class MultiSelectDialogWidgetState extends State { pickerTitleConfig: widget.pickerTitleConfig, onConfirm: () { List selectedItems = - List(); + []; if (widget.onSubmit != null) { - for (int i = 0; i < widget.items?.length; i++) { + for (int i = 0; i < widget.items.length; i++) { if (widget.items[i].isChecked) { selectedItems.add(widget.items[i]); } } if (widget.onSubmit != null) { - widget.onSubmit(selectedItems); + widget.onSubmit!(selectedItems); } } }, @@ -118,12 +120,12 @@ class MultiSelectDialogWidgetState extends State { ), LimitedBox( maxWidth: double.infinity, - maxHeight: PICKER_HEIGHT, + maxHeight: pickerHeight, child: ListView.builder( shrinkWrap: true, itemBuilder: (context, index) => _buildItem(context, index), - itemCount: widget.items?.length)), + itemCount: widget.items.length)), ], ), ], @@ -133,9 +135,7 @@ class MultiSelectDialogWidgetState extends State { } Widget _buildItem(BuildContext context, int index) { - if (widget.items[index] == null) { - return Container(); - } else { + return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { @@ -143,7 +143,7 @@ class MultiSelectDialogWidgetState extends State { widget.items[index].isChecked = !widget.items[index].isChecked; }); if (widget.onItemClick != null) { - widget.onItemClick(context, index); + widget.onItemClick!(context, index); } }, child: Column( @@ -178,13 +178,13 @@ class MultiSelectDialogWidgetState extends State { ], ), ), - index != widget.items.length - 1 + index != widget.items.length - 1 ? Padding( padding: EdgeInsets.fromLTRB(20, 0, 20, 0), child: BrnLine()) : Container() ], )); - } + } } diff --git a/lib/src/components/picker/time_picker/brn_date_picker_constants.dart b/lib/src/components/picker/time_picker/brn_date_picker_constants.dart index 04f36245..8c8dffe6 100755 --- a/lib/src/components/picker/time_picker/brn_date_picker_constants.dart +++ b/lib/src/components/picker/time_picker/brn_date_picker_constants.dart @@ -1,4 +1,7 @@ /// Selected value of DatePicker. + + + typedef DateValueCallback(DateTime dateTime, List selectedIndex); typedef DateRangeValueCallback(DateTime startDateTime, DateTime endDateTime, @@ -11,25 +14,25 @@ typedef DateRangeSideValueCallback( typedef DateVoidCallback(); /// Default value of minimum datetime. -const String DATE_PICKER_MIN_DATETIME = "1900-01-01 00:00:00"; +const String datePickerMinDatetime = "1900-01-01 00:00:00"; /// Default value of maximum datetime. -const String DATE_PICKER_MAX_DATETIME = "2100-12-31 23:59:59"; +const String datePickerMaxDatetime = "2100-12-31 23:59:59"; /// Default value of date format -const String DATETIME_PICKER_DATE_FORMAT = 'yyyy-MM-dd'; +const String datetimePickerDateFormat = 'yyyy-MM-dd'; /// Default value of time format -const String DATETIME_PICKER_TIME_FORMAT = 'HH:mm:ss'; +const String datetimePickerTimeFormat = 'HH:mm:ss'; /// Default value of datetime format -const String DATETIME_PICKER_DATETIME_FORMAT = 'yyyyMMdd HH:mm:ss'; +const String datetimePickerDatetimeFormat = 'yyyyMMdd HH:mm:ss'; /// Default value of date format -const String DATETIME_RANGE_PICKER_DATE_FORMAT = 'MM-dd'; +const String datetimeRangePickerDateFormat = 'MM-dd'; /// Default value of time format -const String DATETIME_RANGE_PICKER_TIME_FORMAT = 'HH:mm'; +const String datetimeRangePickerTimeFormat = 'HH:mm'; /// Default value of datetime format -const String DATETIME_RANGE_PICKER_DATETIME_FORMAT = 'MMdd HH:mm'; +const String datetimeRangePickerDatetimeFormat = 'MMdd HH:mm'; diff --git a/lib/src/components/picker/time_picker/brn_date_time_formatter.dart b/lib/src/components/picker/time_picker/brn_date_time_formatter.dart index ca584c9e..18bb9d78 100755 --- a/lib/src/components/picker/time_picker/brn_date_time_formatter.dart +++ b/lib/src/components/picker/time_picker/brn_date_time_formatter.dart @@ -10,49 +10,49 @@ import 'package:intl/intl.dart'; const String DATE_FORMAT_SEPARATOR = r'[|,-\._: ]+'; class DateTimeFormatter { - static DateTime convertStringToDate(String format, String date) { + static DateTime? convertStringToDate(String? format, String? date) { if (BrunoTools.isEmpty(format) || BrunoTools.isEmpty(date)) return null; - return DateFormat(format).parse(date); + return DateFormat(format).parse(date!); } - static DateTime convertIntValueToDateTime(String value) { + static DateTime? convertIntValueToDateTime(String? value) { if (value == null) { return null; } else { return int.tryParse(value) != null - ? DateTime.fromMillisecondsSinceEpoch(int.tryParse(value)) + ? DateTime.fromMillisecondsSinceEpoch(int.tryParse(value)!) : null; } } /// Get default value of date format. static String generateDateFormat( - String dateFormat, BrnDateTimePickerMode pickerMode) { + String? dateFormat, BrnDateTimePickerMode pickerMode) { if (dateFormat != null && dateFormat.length > 0) { return dateFormat; } switch (pickerMode) { case BrnDateTimePickerMode.date: - return DATETIME_PICKER_DATE_FORMAT; + return datetimePickerDateFormat; case BrnDateTimePickerMode.time: - return DATETIME_PICKER_TIME_FORMAT; + return datetimePickerTimeFormat; case BrnDateTimePickerMode.datetime: - return DATETIME_PICKER_DATETIME_FORMAT; + return datetimePickerDatetimeFormat; } return ''; } static String generateDateRangePickerFormat( - String dateFormat, BrnDateTimeRangePickerMode pickerMode) { + String? dateFormat, BrnDateTimeRangePickerMode pickerMode) { if (dateFormat != null && dateFormat.length > 0) { return dateFormat; } switch (pickerMode) { case BrnDateTimeRangePickerMode.date: - return DATETIME_RANGE_PICKER_DATE_FORMAT; + return datetimeRangePickerDateFormat; case BrnDateTimeRangePickerMode.time: - return DATETIME_RANGE_PICKER_TIME_FORMAT; + return datetimeRangePickerTimeFormat; } return ''; } @@ -68,15 +68,15 @@ class DateTimeFormatter { } /// Split date format to array. - static List splitDateFormat(String dateFormat, - {BrnDateTimePickerMode mode}) { + static List splitDateFormat(String? dateFormat, + {BrnDateTimePickerMode? mode}) { if (dateFormat == null || dateFormat.length == 0) { return []; } List result = dateFormat.split(RegExp(DATE_FORMAT_SEPARATOR)); if (mode == BrnDateTimePickerMode.datetime) { // datetime mode need join day format - List temp = List(); + List temp = []; StringBuffer dayFormat = StringBuffer(); for (int i = 0; i < result.length; i++) { String format = result[i]; @@ -99,7 +99,7 @@ class DateTimeFormatter { temp.insert(0, dayFormat.toString()); } else { // add default date format - temp.insert(0, DATETIME_PICKER_DATE_FORMAT); + temp.insert(0, datetimePickerDateFormat); } result = temp; } diff --git a/lib/src/components/picker/time_picker/date_picker/brn_date_picker.dart b/lib/src/components/picker/time_picker/date_picker/brn_date_picker.dart index 009af06f..a9680532 100755 --- a/lib/src/components/picker/time_picker/date_picker/brn_date_picker.dart +++ b/lib/src/components/picker/time_picker/date_picker/brn_date_picker.dart @@ -44,49 +44,49 @@ class BrnDatePicker { bool rootNavigator = false, /// 点击弹框外部区域能否消失 - bool canBarrierDismissible, + bool? canBarrierDismissible, /// 能滚动到的最小日期 - DateTime minDateTime, + DateTime? minDateTime, /// 能滚动到的最大日期 - DateTime maxDateTime, + DateTime? maxDateTime, /// 初始选择的时间。默认当前时间 - DateTime initialDateTime, + DateTime? initialDateTime, /// 时间格式化的格式 - String dateFormat, + String? dateFormat, /// 分钟间切换的差值 int minuteDivider: 1, - DateTimePickerLocale locale: DATETIME_PICKER_LOCALE_DEFAULT, + DateTimePickerLocale locale = datetimePickerLocaleDefault, /// 时间选择组件显示的时间类型 - BrnDateTimePickerMode pickerMode: BrnDateTimePickerMode.date, + BrnDateTimePickerMode pickerMode = BrnDateTimePickerMode.date, /// 时间选择组件的主题样式 - BrnPickerTitleConfig pickerTitleConfig, + BrnPickerTitleConfig pickerTitleConfig = BrnPickerTitleConfig.Default, /// 点击【取消】回调给调用方的回调事件 - DateVoidCallback onCancel, + DateVoidCallback? onCancel, /// 点击【完成】回调给调用方的数据 - DateVoidCallback onClose, + DateVoidCallback? onClose, /// 时间滚动选择时候的回调事件 - DateValueCallback onChange, + DateValueCallback? onChange, /// 弹框点击外围消失的回调事件 - DateValueCallback onConfirm, - BrnPickerConfig themeData, + DateValueCallback? onConfirm, + BrnPickerConfig? themeData, }) { // handle the range of datetime if (minDateTime == null) { - minDateTime = DateTime.parse(DATE_PICKER_MIN_DATETIME); + minDateTime = DateTime.parse(datePickerMinDatetime); } if (maxDateTime == null) { - maxDateTime = DateTime.parse(DATE_PICKER_MAX_DATETIME); + maxDateTime = DateTime.parse(datePickerMaxDatetime); } // handle initial DateTime @@ -129,37 +129,37 @@ class _DatePickerRoute extends PopupRoute { this.initialDateTime, this.minuteDivider, this.dateFormat, - this.locale, - this.pickerMode, - this.pickerTitleConfig, + this.locale = datetimePickerLocaleDefault, + this.pickerMode = BrnDateTimePickerMode.date, + this.pickerTitleConfig = BrnPickerTitleConfig.Default, this.onCancel, this.onChange, this.onConfirm, this.theme, this.barrierLabel, this.canBarrierDismissible, - RouteSettings settings, + RouteSettings? settings, this.themeData, }) : super(settings: settings) { this.themeData ??= BrnPickerConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .pickerConfig .merge(this.themeData); } - final DateTime minDateTime, maxDateTime, initialDateTime; - final String dateFormat; + final DateTime? minDateTime, maxDateTime, initialDateTime; + final String? dateFormat; final DateTimePickerLocale locale; final BrnDateTimePickerMode pickerMode; final BrnPickerTitleConfig pickerTitleConfig; - final VoidCallback onCancel; - final DateValueCallback onChange; - final DateValueCallback onConfirm; - bool canBarrierDismissible; - final int minuteDivider; - final ThemeData theme; - BrnPickerConfig themeData; + final VoidCallback? onCancel; + final DateValueCallback? onChange; + final DateValueCallback? onConfirm; + bool? canBarrierDismissible; + final int? minuteDivider; + final ThemeData? theme; + BrnPickerConfig? themeData; @override Duration get transitionDuration => const Duration(milliseconds: 200); @@ -168,27 +168,27 @@ class _DatePickerRoute extends PopupRoute { bool get barrierDismissible => canBarrierDismissible ?? true; @override - final String barrierLabel; + final String? barrierLabel; @override Color get barrierColor => Colors.black54; - AnimationController _animationController; + AnimationController? _animationController; @override AnimationController createAnimationController() { assert(_animationController == null); _animationController = - BottomSheet.createAnimationController(navigator.overlay); - return _animationController; + BottomSheet.createAnimationController(navigator!.overlay!); + return _animationController!; } @override Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { - double height = themeData.pickerHeight; + double height = themeData!.pickerHeight; if (pickerTitleConfig.title != null || pickerTitleConfig.showTitle) { - height += themeData.titleHeight; + height += themeData!.titleHeight; } Widget bottomSheet = MediaQuery.removePadding( @@ -198,7 +198,7 @@ class _DatePickerRoute extends PopupRoute { ); if (theme != null) { - bottomSheet = Theme(data: theme, child: bottomSheet); + bottomSheet = Theme(data: theme!, child: bottomSheet); } return bottomSheet; } @@ -209,12 +209,12 @@ class _DatePickerComponent extends StatelessWidget { final _DatePickerRoute route; final double _pickerHeight; - _DatePickerComponent({@required this.route, @required pickerHeight}) + _DatePickerComponent({required this.route, required pickerHeight}) : this._pickerHeight = pickerHeight; @override Widget build(BuildContext context) { - Widget pickerWidget; + Widget? pickerWidget; switch (route.pickerMode) { case BrnDateTimePickerMode.date: pickerWidget = BrnDateWidget( @@ -263,16 +263,15 @@ class _DatePickerComponent extends StatelessWidget { } return GestureDetector( child: AnimatedBuilder( - animation: route.animation, - builder: (BuildContext context, Widget child) { + animation: route.animation!, + builder: (BuildContext context, Widget? child) { return ClipRect( child: CustomSingleChildLayout( - delegate: _BottomPickerLayout(route.animation.value, - contentHeight: _pickerHeight), + delegate: _BottomPickerLayout(route.animation!.value, _pickerHeight), child: BrnPickerClipRRect( borderRadius: BorderRadius.only( - topLeft: Radius.circular(route.themeData.cornerRadius), - topRight: Radius.circular(route.themeData.cornerRadius), + topLeft: Radius.circular(route.themeData!.cornerRadius), + topRight: Radius.circular(route.themeData!.cornerRadius), ), child: pickerWidget, ), @@ -285,7 +284,7 @@ class _DatePickerComponent extends StatelessWidget { } class _BottomPickerLayout extends SingleChildLayoutDelegate { - _BottomPickerLayout(this.progress, {this.contentHeight}); + _BottomPickerLayout(this.progress, this.contentHeight); final double progress; final double contentHeight; diff --git a/lib/src/components/picker/time_picker/date_picker/brn_date_widget.dart b/lib/src/components/picker/time_picker/date_picker/brn_date_widget.dart index 3c08e2dd..1d0b2a9f 100755 --- a/lib/src/components/picker/time_picker/date_picker/brn_date_widget.dart +++ b/lib/src/components/picker/time_picker/date_picker/brn_date_widget.dart @@ -1,3 +1,5 @@ + + import 'dart:math'; import 'package:bruno/src/components/picker/base/brn_picker.dart'; @@ -9,7 +11,7 @@ import 'package:bruno/src/theme/brn_theme.dart'; import 'package:bruno/src/utils/i18n/brn_date_picker_i18n.dart'; import 'package:flutter/material.dart'; -enum ColumnType { Year, Month, Day } +enum ColumnType { year, month, day } /// Solar months of 31 days. const List _solarMonthsOf31Days = const [1, 3, 5, 7, 8, 10, 12]; @@ -19,38 +21,38 @@ const List _solarMonthsOf31Days = const [1, 3, 5, 7, 8, 10, 12]; // ignore: must_be_immutable class BrnDateWidget extends StatefulWidget { BrnDateWidget({ - Key key, + Key? key, this.minDateTime, this.maxDateTime, this.initialDateTime, - this.dateFormat: DATETIME_PICKER_DATE_FORMAT, - this.locale: DATETIME_PICKER_LOCALE_DEFAULT, - this.pickerTitleConfig: BrnPickerTitleConfig.Default, + this.dateFormat = datetimePickerDateFormat, + this.locale = datetimePickerLocaleDefault, + this.pickerTitleConfig= BrnPickerTitleConfig.Default, this.onCancel, this.onChange, this.onConfirm, this.canPop = true, this.themeData, }) : super(key: key) { - DateTime minTime = minDateTime ?? DateTime.parse(DATE_PICKER_MIN_DATETIME); - DateTime maxTime = maxDateTime ?? DateTime.parse(DATE_PICKER_MAX_DATETIME); + DateTime minTime = minDateTime ?? DateTime.parse(datePickerMinDatetime); + DateTime maxTime = maxDateTime ?? DateTime.parse(datePickerMaxDatetime); assert(minTime.compareTo(maxTime) < 0); this.themeData ??= BrnPickerConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .pickerConfig .merge(this.themeData); } - final DateTime minDateTime, maxDateTime, initialDateTime; - final String dateFormat; + final DateTime? minDateTime, maxDateTime, initialDateTime; + final String? dateFormat; final DateTimePickerLocale locale; final BrnPickerTitleConfig pickerTitleConfig; - final DateVoidCallback onCancel; - final DateValueCallback onChange, onConfirm; + final DateVoidCallback? onCancel; + final DateValueCallback? onChange, onConfirm; final bool canPop; - BrnPickerConfig themeData; + BrnPickerConfig? themeData; @override State createState() => _BrnDateWidgetState( @@ -58,18 +60,18 @@ class BrnDateWidget extends StatefulWidget { } class _BrnDateWidgetState extends State { - DateTime _minDateTime, _maxDateTime; - int _currYear, _currMonth, _currDay; - List _yearRange, _monthRange, _dayRange; - FixedExtentScrollController _yearScrollCtrl, _monthScrollCtrl, _dayScrollCtrl; + late DateTime _minDateTime, _maxDateTime; + late int _currYear, _currMonth, _currDay; + late List _yearRange, _monthRange, _dayRange; + late FixedExtentScrollController? _yearScrollCtrl, _monthScrollCtrl, _dayScrollCtrl; - Map _scrollCtrlMap; - Map> _valueRangeMap; + late Map _scrollCtrlMap; + late Map?> _valueRangeMap; bool _isChangeDateRange = false; _BrnDateWidgetState( - DateTime minDateTime, DateTime maxDateTime, DateTime initialDateTime) { + DateTime? minDateTime, DateTime? maxDateTime, DateTime? initialDateTime) { // handle current selected year、month、day DateTime initDateTime = initialDateTime ?? DateTime.now(); this._currYear = initDateTime.year; @@ -77,8 +79,8 @@ class _BrnDateWidgetState extends State { this._currDay = initDateTime.day; // handle DateTime range - this._minDateTime = minDateTime ?? DateTime.parse(DATE_PICKER_MIN_DATETIME); - this._maxDateTime = maxDateTime ?? DateTime.parse(DATE_PICKER_MAX_DATETIME); + this._minDateTime = minDateTime ?? DateTime.parse(datePickerMinDatetime); + this._maxDateTime = maxDateTime ?? DateTime.parse(datePickerMaxDatetime); // limit the range of year this._yearRange = _calcYearRange(); @@ -139,7 +141,7 @@ class _BrnDateWidgetState extends State { /// pressed cancel widget void _onPressedCancel() { if (widget.onCancel != null) { - widget.onCancel(); + widget.onCancel!(); } if (widget.canPop) Navigator.pop(context); } @@ -148,7 +150,7 @@ class _BrnDateWidgetState extends State { void _onPressedConfirm() { if (widget.onConfirm != null) { DateTime dateTime = DateTime(_currYear, _currMonth, _currDay); - widget.onConfirm(dateTime, _calcSelectIndexList()); + widget.onConfirm!(dateTime, _calcSelectIndexList()); } if (widget.canPop) Navigator.pop(context); } @@ -157,13 +159,13 @@ class _BrnDateWidgetState extends State { void _onSelectedChange() { if (widget.onChange != null) { DateTime dateTime = DateTime(_currYear, _currMonth, _currDay); - widget.onChange(dateTime, _calcSelectIndexList()); + widget.onChange!(dateTime, _calcSelectIndexList()); } } /// find scroll controller by specified format - FixedExtentScrollController _findScrollCtrl(String format) { - FixedExtentScrollController scrollCtrl; + FixedExtentScrollController? _findScrollCtrl(String format) { + FixedExtentScrollController? scrollCtrl; _scrollCtrlMap.forEach((key, value) { if (format.contains(key)) { scrollCtrl = value; @@ -173,8 +175,8 @@ class _BrnDateWidgetState extends State { } /// find item value range by specified format - List _findPickerItemRange(String format) { - List valueRange; + List? _findPickerItemRange(String format) { + List? valueRange; _valueRangeMap.forEach((key, value) { if (format.contains(key)) { valueRange = value; @@ -185,11 +187,11 @@ class _BrnDateWidgetState extends State { /// render the picker widget of year、month and day Widget _renderDatePickerWidget() { - List pickers = List(); + List pickers = []; List formatArr = DateTimeFormatter.splitDateFormat(widget.dateFormat); formatArr.forEach((format) { - List valueRange = _findPickerItemRange(format); + List valueRange = _findPickerItemRange(format)!; Widget pickerColumn = _renderDatePickerColumnComponent( scrollCtrl: _findScrollCtrl(format), @@ -212,27 +214,27 @@ class _BrnDateWidgetState extends State { } Widget _renderDatePickerColumnComponent({ - @required FixedExtentScrollController scrollCtrl, - @required List valueRange, - @required String format, - @required ValueChanged valueChanged, + required FixedExtentScrollController? scrollCtrl, + required List valueRange, + required String format, + required ValueChanged valueChanged, }) { return Expanded( flex: 1, child: Container( - height: widget.themeData.pickerHeight, - decoration: BoxDecoration(color: widget.themeData.backgroundColor), + height: widget.themeData!.pickerHeight, + decoration: BoxDecoration(color: widget.themeData!.backgroundColor), child: BrnPicker.builder( - backgroundColor: widget.themeData.backgroundColor, - lineColor: widget.themeData.dividerColor, + backgroundColor: widget.themeData!.backgroundColor, + lineColor: widget.themeData!.dividerColor, scrollController: scrollCtrl, - itemExtent: widget.themeData.itemHeight, + itemExtent: widget.themeData!.itemHeight, onSelectedItemChanged: valueChanged, childCount: valueRange.last - valueRange.first + 1, itemBuilder: (context, index) => _renderDatePickerItemComponent( format.contains("y") - ? ColumnType.Year - : (format.contains("M") ? ColumnType.Month : ColumnType.Day), + ? ColumnType.year + : (format.contains("M") ? ColumnType.month : ColumnType.day), index, valueRange.first + index, format), @@ -243,15 +245,15 @@ class _BrnDateWidgetState extends State { Widget _renderDatePickerItemComponent( ColumnType columnType, int index, int value, String format) { - TextStyle textStyle = widget.themeData.itemTextStyle.generateTextStyle(); - if ((ColumnType.Year == columnType && index == _calcSelectIndexList()[0]) || - (ColumnType.Month == columnType && + TextStyle textStyle = widget.themeData!.itemTextStyle.generateTextStyle(); + if ((ColumnType.year == columnType && index == _calcSelectIndexList()[0]) || + (ColumnType.month == columnType && index == _calcSelectIndexList()[1]) || - (ColumnType.Day == columnType && index == _calcSelectIndexList()[2])) { - textStyle = widget.themeData.itemTextSelectedStyle.generateTextStyle(); + (ColumnType.day == columnType && index == _calcSelectIndexList()[2])) { + textStyle = widget.themeData!.itemTextSelectedStyle.generateTextStyle(); } return Container( - height: widget.themeData.itemHeight, + height: widget.themeData!.itemHeight, alignment: Alignment.center, child: Text( DateTimeFormatter.formatDateTime(value, format, widget.locale), @@ -323,18 +325,18 @@ class _BrnDateWidgetState extends State { if (monthRangeChanged) { // CupertinoPicker refresh data not working (https://github.com/flutter/flutter/issues/22999) int currMonth = _currMonth; - _monthScrollCtrl.jumpToItem(monthRange.last - monthRange.first); + _monthScrollCtrl!.jumpToItem(monthRange.last - monthRange.first); if (currMonth < monthRange.last) { - _monthScrollCtrl.jumpToItem(currMonth - monthRange.first); + _monthScrollCtrl!.jumpToItem(currMonth - monthRange.first); } } if (dayRangeChanged) { // CupertinoPicker refresh data not working (https://github.com/flutter/flutter/issues/22999) int currDay = _currDay; - _dayScrollCtrl.jumpToItem(dayRange.last - dayRange.first); + _dayScrollCtrl!.jumpToItem(dayRange.last - dayRange.first); if (currDay < dayRange.last) { - _dayScrollCtrl.jumpToItem(currDay - dayRange.first); + _dayScrollCtrl!.jumpToItem(currDay - dayRange.first); } } diff --git a/lib/src/components/picker/time_picker/date_picker/brn_datetime_widget.dart b/lib/src/components/picker/time_picker/date_picker/brn_datetime_widget.dart index 34023ba7..b0f33a65 100755 --- a/lib/src/components/picker/time_picker/date_picker/brn_datetime_widget.dart +++ b/lib/src/components/picker/time_picker/date_picker/brn_datetime_widget.dart @@ -1,3 +1,5 @@ + + import 'dart:math'; import 'package:bruno/src/components/picker/base/brn_picker.dart'; @@ -9,18 +11,18 @@ import 'package:bruno/src/theme/brn_theme.dart'; import 'package:bruno/src/utils/i18n/brn_date_picker_i18n.dart'; import 'package:flutter/material.dart'; -enum ColumnType { Year, Month, Day, Hour, Minute, Second } +enum ColumnType { year, month, day, hour, minute, second } /// DateTimePicker widget. Can display date and time picker // ignore: must_be_immutable class BrnDateTimeWidget extends StatefulWidget { BrnDateTimeWidget({ - Key key, + Key? key, this.minDateTime, this.maxDateTime, this.initDateTime, - this.dateFormat: DATETIME_PICKER_TIME_FORMAT, - this.locale: DATETIME_PICKER_LOCALE_DEFAULT, + this.dateFormat: datetimePickerTimeFormat, + this.locale: datetimePickerLocaleDefault, this.pickerTitleConfig: BrnPickerTitleConfig.Default, this.onCancel, this.onChange, @@ -28,25 +30,25 @@ class BrnDateTimeWidget extends StatefulWidget { this.minuteDivider, this.themeData, }) : super(key: key) { - DateTime minTime = minDateTime ?? DateTime.parse(DATE_PICKER_MIN_DATETIME); - DateTime maxTime = maxDateTime ?? DateTime.parse(DATE_PICKER_MAX_DATETIME); + DateTime minTime = minDateTime ?? DateTime.parse(datePickerMinDatetime); + DateTime maxTime = maxDateTime ?? DateTime.parse(datePickerMaxDatetime); assert(minTime.compareTo(maxTime) < 0); this.themeData ??= BrnPickerConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .pickerConfig .merge(this.themeData); } - final DateTime minDateTime, maxDateTime, initDateTime; - final int minuteDivider; - final String dateFormat; + final DateTime? minDateTime, maxDateTime, initDateTime; + final int? minuteDivider; + final String? dateFormat; final DateTimePickerLocale locale; final BrnPickerTitleConfig pickerTitleConfig; - final DateVoidCallback onCancel; - final DateValueCallback onChange, onConfirm; - BrnPickerConfig themeData; + final DateVoidCallback? onCancel; + final DateValueCallback? onChange, onConfirm; + BrnPickerConfig? themeData; @override State createState() => _BrnDateTimeWidgetState( @@ -56,37 +58,37 @@ class BrnDateTimeWidget extends StatefulWidget { class _BrnDateTimeWidgetState extends State { final int _defaultMinuteDivider = 1; - DateTime _minTime, _maxTime; - int _currYear, _currMonth, _currDay, _currHour, _currMinute, _currSecond; - List _yearRange, + late DateTime _minTime, _maxTime; + late int _currYear, _currMonth, _currDay, _currHour, _currMinute, _currSecond; + late List _yearRange, _monthRange, _dayRange, _hourRange, _minuteRange, _secondRange; - FixedExtentScrollController _yearScrollCtrl, + late FixedExtentScrollController _yearScrollCtrl, _monthScrollCtrl, _dayScrollCtrl, _hourScrollCtrl, _minuteScrollCtrl, _secondScrollCtrl; - Map _scrollCtrlMap; - Map> _valueRangeMap; + late Map _scrollCtrlMap; + late Map?> _valueRangeMap; bool _isChangeTimeRange = false; - int _minuteDivider; + int? _minuteDivider; - _BrnDateTimeWidgetState(DateTime minTime, DateTime maxTime, DateTime initTime, - int minuteDivider) { + _BrnDateTimeWidgetState(DateTime? minTime, DateTime? maxTime, DateTime? initTime, + int? minuteDivider) { // check minTime value if (minTime == null) { - minTime = DateTime.parse(DATE_PICKER_MIN_DATETIME); + minTime = DateTime.parse(datePickerMinDatetime); } // check maxTime value if (maxTime == null) { - maxTime = DateTime.parse(DATE_PICKER_MAX_DATETIME); + maxTime = DateTime.parse(datePickerMaxDatetime); } // check initTime value if (initTime == null) { @@ -132,7 +134,7 @@ class _BrnDateTimeWidgetState extends State { this._minuteRange = _calcMinuteRange(); this._currMinute = min(max(_minuteRange.first, _currMinute), _minuteRange.last); - _currMinute -= _currMinute % _minuteDivider; + _currMinute -= _currMinute % _minuteDivider!; // limit the range of second this._secondRange = _calcSecondRange(); @@ -149,7 +151,7 @@ class _BrnDateTimeWidgetState extends State { _hourScrollCtrl = FixedExtentScrollController(initialItem: _currHour - _hourRange.first); _minuteScrollCtrl = FixedExtentScrollController( - initialItem: (_currMinute - _minuteRange.first) ~/ _minuteDivider); + initialItem: (_currMinute - _minuteRange.first) ~/ _minuteDivider!); _secondScrollCtrl = FixedExtentScrollController( initialItem: _currSecond - _secondRange.first); @@ -200,7 +202,7 @@ class _BrnDateTimeWidgetState extends State { /// pressed cancel widget void _onPressedCancel() { if (widget.onCancel != null) { - widget.onCancel(); + widget.onCancel!(); } Navigator.pop(context); } @@ -214,33 +216,33 @@ class _BrnDateTimeWidgetState extends State { /// 如果传入的时间格式不包含 月、天、小时、分钟、秒。则相对应的时间置为 1,1,0,0,0; DateTime dateTime = DateTime( _currYear, - (formatArr?.where((format) => format.contains('M'))?.toList() ?? List()) + (formatArr.where((format) => format.contains('M')).toList()) .length > 0 ? _currMonth : 1, - (formatArr?.where((format) => format.contains('d'))?.toList() ?? List()) + (formatArr.where((format) => format.contains('d')).toList()) .length > 0 ? _currDay : 1, - (formatArr?.where((format) => format.contains('H'))?.toList() ?? List()) + (formatArr.where((format) => format.contains('H')).toList()) .length > 0 ? _currHour : 0, - (formatArr?.where((format) => format.contains('m'))?.toList() ?? List()) + (formatArr.where((format) => format.contains('m')).toList()) .length > 0 ? _currMinute : 0, - (formatArr?.where((format) => format.contains('s'))?.toList() ?? List()) + (formatArr.where((format) => format.contains('s')).toList()) .length > 0 ? _currSecond : 0, ); - widget.onConfirm(dateTime, _calcSelectIndexList()); + widget.onConfirm!(dateTime, _calcSelectIndexList()); } Navigator.pop(context); } @@ -250,13 +252,13 @@ class _BrnDateTimeWidgetState extends State { if (widget.onChange != null) { DateTime dateTime = DateTime( _currYear, _currMonth, _currDay, _currHour, _currMinute, _currSecond); - widget.onChange(dateTime, _calcSelectIndexList()); + widget.onChange!(dateTime, _calcSelectIndexList()); } } /// find scroll controller by specified format - FixedExtentScrollController _findScrollCtrl(String format) { - FixedExtentScrollController scrollCtrl; + FixedExtentScrollController? _findScrollCtrl(String format) { + FixedExtentScrollController? scrollCtrl; _scrollCtrlMap.forEach((key, value) { if (format.contains(key)) { scrollCtrl = value; @@ -266,8 +268,8 @@ class _BrnDateTimeWidgetState extends State { } /// find item value range by specified format - List _findPickerItemRange(String format) { - List valueRange; + List? _findPickerItemRange(String format) { + List? valueRange; _valueRangeMap.forEach((key, value) { if (format.contains(key)) { valueRange = value; @@ -278,13 +280,13 @@ class _BrnDateTimeWidgetState extends State { /// render the picker widget of year、month and day Widget _renderDatePickerWidget() { - List pickers = List(); + List pickers = []; List formatArr = DateTimeFormatter.splitDateFormat(widget.dateFormat); // render time picker column formatArr.forEach((format) { - List valueRange = _findPickerItemRange(format); + List? valueRange = _findPickerItemRange(format); Widget pickerColumn = _renderDatePickerColumnComponent( scrollCtrl: _findScrollCtrl(format), @@ -314,31 +316,31 @@ class _BrnDateTimeWidgetState extends State { } Widget _renderDatePickerColumnComponent( - {@required FixedExtentScrollController scrollCtrl, - @required List valueRange, - @required String format, - @required ValueChanged valueChanged, - int flex, - IndexedWidgetBuilder itemBuilder}) { + {required FixedExtentScrollController? scrollCtrl, + required List? valueRange, + required String format, + required ValueChanged valueChanged, + required int flex, + IndexedWidgetBuilder? itemBuilder}) { Widget columnWidget = Container( width: double.infinity, - height: widget.themeData.pickerHeight, - decoration: BoxDecoration(color: widget.themeData.backgroundColor), + height: widget.themeData!.pickerHeight, + decoration: BoxDecoration(color: widget.themeData!.backgroundColor), child: BrnPicker.builder( - backgroundColor: widget.themeData.backgroundColor, - lineColor: widget.themeData.dividerColor, + backgroundColor: widget.themeData!.backgroundColor, + lineColor: widget.themeData!.dividerColor, scrollController: scrollCtrl, - itemExtent: widget.themeData.itemHeight, + itemExtent: widget.themeData!.itemHeight, onSelectedItemChanged: valueChanged, childCount: format.contains('m') ? _calculateMinuteChildCount(valueRange, _minuteDivider) - : valueRange.last - valueRange.first + 1, + : valueRange!.last - valueRange.first + 1, itemBuilder: itemBuilder ?? (context, index) { - int value = valueRange.first + index; + int value = valueRange!.first + index; if (format.contains('m')) { - value = valueRange.first + _minuteDivider * index; + value = valueRange.first + _minuteDivider! * index; } return _renderDatePickerItemComponent( getColumnType(format), index, value, format); @@ -351,29 +353,29 @@ class _BrnDateTimeWidgetState extends State { ); } - _calculateMinuteChildCount(List valueRange, int divider) { + _calculateMinuteChildCount(List? valueRange, int? divider) { if (divider == 0 || divider == 1) { debugPrint("Cant devide by 0"); - return (valueRange.last - valueRange.first + 1); + return (valueRange!.last - valueRange.first + 1); } - return ((valueRange.last - valueRange.first) ~/ divider) + 1; + return ((valueRange!.last - valueRange.first) ~/ divider!) + 1; } // ignore: missing_return - ColumnType getColumnType(String format) { + ColumnType? getColumnType(String format) { if (format.contains('y')) { - return ColumnType.Year; + return ColumnType.year; } else if (format.contains('M')) { - return ColumnType.Month; + return ColumnType.month; } else if (format.contains('d')) { - return ColumnType.Day; + return ColumnType.day; } else if (format.contains('H')) { - return ColumnType.Hour; + return ColumnType.hour; } else if (format.contains('m')) { - return ColumnType.Minute; + return ColumnType.minute; } else if (format.contains('s')) { - return ColumnType.Second; + return ColumnType.second; } return null; } @@ -463,22 +465,22 @@ class _BrnDateTimeWidgetState extends State { /// render hour、minute、second picker item Widget _renderDatePickerItemComponent( - ColumnType columnType, int index, int value, String format) { - TextStyle textStyle = widget.themeData.itemTextStyle.generateTextStyle(); - if ((ColumnType.Year == columnType && index == _calcSelectIndexList()[0]) || - (ColumnType.Month == columnType && + ColumnType? columnType, int index, int value, String format) { + TextStyle textStyle = widget.themeData!.itemTextStyle.generateTextStyle(); + if ((ColumnType.year == columnType && index == _calcSelectIndexList()[0]) || + (ColumnType.month == columnType && index == _calcSelectIndexList()[1]) || - (ColumnType.Day == columnType && index == _calcSelectIndexList()[2]) || - (ColumnType.Hour == columnType && index == _calcSelectIndexList()[3]) || - (ColumnType.Minute == columnType && + (ColumnType.day == columnType && index == _calcSelectIndexList()[2]) || + (ColumnType.hour == columnType && index == _calcSelectIndexList()[3]) || + (ColumnType.minute == columnType && index == _calcSelectIndexList()[4]) || - (ColumnType.Second == columnType && + (ColumnType.second == columnType && index == _calcSelectIndexList()[5])) { - textStyle = widget.themeData.itemTextSelectedStyle.generateTextStyle(); + textStyle = widget.themeData!.itemTextSelectedStyle.generateTextStyle(); } return Container( - height: widget.themeData.itemHeight, + height: widget.themeData!.itemHeight, alignment: Alignment.center, child: Text( DateTimeFormatter.formatDateTime(value, format, widget.locale), @@ -508,7 +510,7 @@ class _BrnDateTimeWidgetState extends State { /// change the selection of month picker void _changeMinuteSelection(int index) { - int value = _minuteRange.first + index * _minuteDivider; + int value = _minuteRange.first + index * _minuteDivider!; _currMinute = value; _changeTimeRange(); _onSelectedChange(); @@ -574,10 +576,10 @@ class _BrnDateTimeWidgetState extends State { if (minuteRangeChanged) { // CupertinoPicker refresh data not working (https://github.com/flutter/flutter/issues/22999) _minuteScrollCtrl - .jumpToItem((minuteRange.last - minuteRange.first) ~/ _minuteDivider); + .jumpToItem((minuteRange.last - minuteRange.first) ~/ _minuteDivider!); if (_currMinute < minuteRange.last) { _minuteScrollCtrl - .jumpToItem((_currMinute - minuteRange.first) ~/ _minuteDivider); + .jumpToItem((_currMinute - minuteRange.first) ~/ _minuteDivider!); } } @@ -598,7 +600,7 @@ class _BrnDateTimeWidgetState extends State { int monthIndex = _currMonth - _monthRange.first; int dayIndex = _currDay - _dayRange.first; int hourIndex = _currHour - _hourRange.first; - int minuteIndex = (_currMinute - _minuteRange.first) ~/ _minuteDivider; + int minuteIndex = (_currMinute - _minuteRange.first) ~/ _minuteDivider!; int secondIndex = _currSecond - _secondRange.first; return [ yearIndex, @@ -687,10 +689,10 @@ class _BrnDateTimeWidgetState extends State { minHour = _minTime.hour; } - int modValue = _minTime.minute % _minuteDivider; + int modValue = _minTime.minute % _minuteDivider!; int minMinute = modValue == 0 ? _minTime.minute - : (_minTime.minute - modValue + _minuteDivider); + : (_minTime.minute - modValue + _minuteDivider!); if (minMinute == 60) { minHour = minHour + 1 > _maxTime.hour ? _maxTime.hour : minHour + 1; } @@ -715,10 +717,10 @@ class _BrnDateTimeWidgetState extends State { _currDay == _minTime.day && _currHour == _minTime.hour) { // selected minimum day、hour, limit minute range - int modValue = _minTime.minute % _minuteDivider; + int modValue = _minTime.minute % _minuteDivider!; minMinute = modValue == 0 ? _minTime.minute - : (_minTime.minute - modValue + _minuteDivider); + : (_minTime.minute - modValue + _minuteDivider!); if (minMinute == 60) { minMinute = 0; currHour = currHour + 1 > _maxTime.hour ? _maxTime.hour : currHour + 1; @@ -729,7 +731,7 @@ class _BrnDateTimeWidgetState extends State { _currDay == _maxTime.day && _currHour == _maxTime.hour) { // selected maximum day、hour, limit minute range - maxMinute = _maxTime.minute - _maxTime.minute % _minuteDivider; + maxMinute = _maxTime.minute - _maxTime.minute % _minuteDivider!; } return [minMinute, maxMinute]; } diff --git a/lib/src/components/picker/time_picker/date_picker/brn_time_widget.dart b/lib/src/components/picker/time_picker/date_picker/brn_time_widget.dart index d6dd6255..1e9e0491 100755 --- a/lib/src/components/picker/time_picker/date_picker/brn_time_widget.dart +++ b/lib/src/components/picker/time_picker/date_picker/brn_time_widget.dart @@ -1,3 +1,5 @@ + + import 'dart:math'; import 'package:bruno/src/components/picker/base/brn_picker.dart'; @@ -11,17 +13,17 @@ import 'package:flutter/material.dart'; /// TimePicker widget. -enum ColumnType { Hour, Minute, Second } +enum ColumnType { hour, minute, second } // ignore: must_be_immutable class BrnTimeWidget extends StatefulWidget { BrnTimeWidget({ - Key key, + Key? key, this.minDateTime, this.maxDateTime, this.initDateTime, - this.dateFormat: DATETIME_PICKER_TIME_FORMAT, - this.locale: DATETIME_PICKER_LOCALE_DEFAULT, + this.dateFormat: datetimePickerTimeFormat, + this.locale: datetimePickerLocaleDefault, this.pickerTitleConfig: BrnPickerTitleConfig.Default, this.minuteDivider = 1, this.onCancel, @@ -29,25 +31,25 @@ class BrnTimeWidget extends StatefulWidget { this.onConfirm, this.themeData, }) : super(key: key) { - DateTime minTime = minDateTime ?? DateTime.parse(DATE_PICKER_MIN_DATETIME); - DateTime maxTime = maxDateTime ?? DateTime.parse(DATE_PICKER_MAX_DATETIME); + DateTime minTime = minDateTime ?? DateTime.parse(datePickerMinDatetime); + DateTime maxTime = maxDateTime ?? DateTime.parse(datePickerMaxDatetime); assert(minTime.compareTo(maxTime) < 0); this.themeData ??= BrnPickerConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .pickerConfig .merge(this.themeData); } - final DateTime minDateTime, maxDateTime, initDateTime; - final String dateFormat; + final DateTime? minDateTime, maxDateTime, initDateTime; + final String? dateFormat; final DateTimePickerLocale locale; final BrnPickerTitleConfig pickerTitleConfig; - final DateVoidCallback onCancel; - final DateValueCallback onChange, onConfirm; - final int minuteDivider; + final DateVoidCallback? onCancel; + final DateValueCallback? onChange, onConfirm; + final int? minuteDivider; - BrnPickerConfig themeData; + BrnPickerConfig? themeData; @override State createState() => _BrnTimeWidgetState(this.minDateTime, @@ -57,26 +59,26 @@ class BrnTimeWidget extends StatefulWidget { class _BrnTimeWidgetState extends State { static int _defaultMinuteDivider = 1; - DateTime _minTime, _maxTime; - int _currHour, _currMinute, _currSecond; - int _minuteDivider; - List _hourRange, _minuteRange, _secondRange; - FixedExtentScrollController _hourScrollCtrl, + late DateTime _minTime, _maxTime; + late int _currHour, _currMinute, _currSecond; + late int _minuteDivider; + late List _hourRange, _minuteRange, _secondRange; + late FixedExtentScrollController _hourScrollCtrl, _minuteScrollCtrl, _secondScrollCtrl; - Map _scrollCtrlMap; - Map> _valueRangeMap; + late Map _scrollCtrlMap; + late Map> _valueRangeMap; bool _isChangeTimeRange = false; - _BrnTimeWidgetState(DateTime minTime, DateTime maxTime, DateTime initTime, - int minuteDivider) { + _BrnTimeWidgetState(DateTime? minTime, DateTime? maxTime, DateTime? initTime, + int? minuteDivider) { if (minTime == null) { - minTime = DateTime.parse(DATE_PICKER_MIN_DATETIME); + minTime = DateTime.parse(datePickerMinDatetime); } if (maxTime == null) { - maxTime = DateTime.parse(DATE_PICKER_MAX_DATETIME); + maxTime = DateTime.parse(datePickerMaxDatetime); } if (initTime == null) { // init time is now @@ -153,7 +155,7 @@ class _BrnTimeWidgetState extends State { /// pressed cancel widget void _onPressedCancel() { if (widget.onCancel != null) { - widget.onCancel(); + widget.onCancel!(); } Navigator.pop(context); } @@ -164,7 +166,7 @@ class _BrnTimeWidgetState extends State { DateTime now = DateTime.now(); DateTime dateTime = DateTime( now.year, now.month, now.day, _currHour, _currMinute, _currSecond); - widget.onConfirm(dateTime, _calcSelectIndexList()); + widget.onConfirm!(dateTime, _calcSelectIndexList()); } Navigator.pop(context); } @@ -175,13 +177,13 @@ class _BrnTimeWidgetState extends State { DateTime now = DateTime.now(); DateTime dateTime = DateTime( now.year, now.month, now.day, _currHour, _currMinute, _currSecond); - widget.onChange(dateTime, _calcSelectIndexList()); + widget.onChange!(dateTime, _calcSelectIndexList()); } } /// find scroll controller by specified format - FixedExtentScrollController _findScrollCtrl(String format) { - FixedExtentScrollController scrollCtrl; + FixedExtentScrollController? _findScrollCtrl(String format) { + FixedExtentScrollController? scrollCtrl; _scrollCtrlMap.forEach((key, value) { if (format.contains(key)) { scrollCtrl = value; @@ -191,8 +193,8 @@ class _BrnTimeWidgetState extends State { } /// find item value range by specified format - List _findPickerItemRange(String format) { - List valueRange; + List? _findPickerItemRange(String format) { + List? valueRange; _valueRangeMap.forEach((key, value) { if (format.contains(key)) { valueRange = value; @@ -203,11 +205,11 @@ class _BrnTimeWidgetState extends State { /// render the picker widget of year、month and day Widget _renderDatePickerWidget() { - List pickers = List(); + List pickers = []; List formatArr = DateTimeFormatter.splitDateFormat(widget.dateFormat); formatArr.forEach((format) { - List valueRange = _findPickerItemRange(format); + List? valueRange = _findPickerItemRange(format); Widget pickerColumn = _renderDatePickerColumnComponent( scrollCtrl: _findScrollCtrl(format), @@ -230,27 +232,27 @@ class _BrnTimeWidgetState extends State { } Widget _renderDatePickerColumnComponent({ - @required FixedExtentScrollController scrollCtrl, - @required List valueRange, - @required String format, - @required ValueChanged valueChanged, + required FixedExtentScrollController? scrollCtrl, + required List? valueRange, + required String format, + required ValueChanged valueChanged, }) { return Expanded( flex: 1, child: Container( - height: widget.themeData.pickerHeight, - decoration: BoxDecoration(color: widget.themeData.backgroundColor), + height: widget.themeData!.pickerHeight, + decoration: BoxDecoration(color: widget.themeData!.backgroundColor), child: BrnPicker.builder( - backgroundColor: widget.themeData.backgroundColor, - lineColor: widget.themeData.dividerColor, + backgroundColor: widget.themeData!.backgroundColor, + lineColor: widget.themeData!.dividerColor, scrollController: scrollCtrl, - itemExtent: widget.themeData.itemHeight, + itemExtent: widget.themeData!.itemHeight, onSelectedItemChanged: valueChanged, childCount: format.contains('m') ? _calculateMinuteChildCount(valueRange, _minuteDivider) - : valueRange.last - valueRange.first + 1, + : valueRange!.last - valueRange.first + 1, itemBuilder: (context, index) { - int value = valueRange.first + index; + int value = valueRange!.first + index; if (format.contains('m')) { value = _minuteDivider * index; @@ -265,38 +267,38 @@ class _BrnTimeWidgetState extends State { } // ignore: missing_return - ColumnType getColumnType(String format) { + ColumnType? getColumnType(String format) { if (format.contains('H')) { - return ColumnType.Hour; + return ColumnType.hour; } else if (format.contains('m')) { - return ColumnType.Minute; + return ColumnType.minute; } else if (format.contains('s')) { - return ColumnType.Second; + return ColumnType.second; } return null; } - _calculateMinuteChildCount(List valueRange, int divider) { + _calculateMinuteChildCount(List? valueRange, int? divider) { if (divider == 0) { debugPrint("Cant devide by 0"); - return (valueRange.last - valueRange.first + 1); + return (valueRange!.last - valueRange.first + 1); } - return (valueRange.last - valueRange.first + 1) ~/ divider; + return (valueRange!.last - valueRange.first + 1) ~/ divider!; } Widget _renderDatePickerItemComponent( - ColumnType columnType, int index, int value, String format) { - TextStyle textStyle = widget.themeData.itemTextStyle.generateTextStyle(); - if ((ColumnType.Hour == columnType && index == _calcSelectIndexList()[0]) || - (ColumnType.Minute == columnType && + ColumnType? columnType, int index, int value, String format) { + TextStyle textStyle = widget.themeData!.itemTextStyle.generateTextStyle(); + if ((ColumnType.hour == columnType && index == _calcSelectIndexList()[0]) || + (ColumnType.minute == columnType && index == _calcSelectIndexList()[1]) || - (ColumnType.Second == columnType && + (ColumnType.second == columnType && index == _calcSelectIndexList()[2])) { - textStyle = widget.themeData.itemTextSelectedStyle.generateTextStyle(); + textStyle = widget.themeData!.itemTextSelectedStyle.generateTextStyle(); } return Container( - height: widget.themeData.itemHeight, + height: widget.themeData!.itemHeight, alignment: Alignment.center, child: Text( DateTimeFormatter.formatDateTime(value, format, widget.locale), diff --git a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_picker.dart b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_picker.dart index 9ad2b890..023aa757 100755 --- a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_picker.dart +++ b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_picker.dart @@ -37,28 +37,28 @@ class BrnDateRangePicker { static void showDatePicker( BuildContext context, { bool isDismissible = true, - DateTime minDateTime, - DateTime maxDateTime, + DateTime? minDateTime, + DateTime? maxDateTime, bool isLimitTimeRange = true, - DateTime initialStartDateTime, - DateTime initialEndDateTime, - String dateFormat, - int minuteDivider, - DateTimePickerLocale locale: DATETIME_PICKER_LOCALE_DEFAULT, - BrnDateTimeRangePickerMode pickerMode: BrnDateTimeRangePickerMode.date, - BrnPickerTitleConfig pickerTitleConfig: BrnPickerTitleConfig.Default, - DateVoidCallback onCancel, - DateVoidCallback onClose, - DateRangeValueCallback onChange, - DateRangeValueCallback onConfirm, - BrnPickerConfig themeData, + DateTime? initialStartDateTime, + DateTime? initialEndDateTime, + String? dateFormat, + int minuteDivider = 1, + DateTimePickerLocale locale = datetimePickerLocaleDefault, + BrnDateTimeRangePickerMode pickerMode = BrnDateTimeRangePickerMode.date, + BrnPickerTitleConfig pickerTitleConfig = BrnPickerTitleConfig.Default, + DateVoidCallback? onCancel, + DateVoidCallback? onClose, + DateRangeValueCallback? onChange, + DateRangeValueCallback? onConfirm, + BrnPickerConfig? themeData, }) { // handle the range of datetime if (minDateTime == null) { - minDateTime = DateTime.parse(DATE_PICKER_MIN_DATETIME); + minDateTime = DateTime.parse(datePickerMinDatetime); } if (maxDateTime == null) { - maxDateTime = DateTime.parse(DATE_PICKER_MAX_DATETIME); + maxDateTime = DateTime.parse(datePickerMaxDatetime); } // handle initial DateTime @@ -91,27 +91,27 @@ class BrnDateRangePicker { MaterialLocalizations.of(context).modalBarrierDismissLabel, themeData: themeData, ), - ).whenComplete(onClose); + ).whenComplete(onClose ?? () {}); } } class _DatePickerRoute extends PopupRoute { - final DateTime minDateTime, + final DateTime? minDateTime, maxDateTime, initialStartDateTime, initialEndDateTime; final bool isLimitTimeRange; - final String dateFormat; + final String? dateFormat; final DateTimePickerLocale locale; final BrnDateTimeRangePickerMode pickerMode; final BrnPickerTitleConfig pickerTitleConfig; - final VoidCallback onCancel; - final DateRangeValueCallback onChange; - final DateRangeValueCallback onConfirm; + final VoidCallback? onCancel; + final DateRangeValueCallback? onChange; + final DateRangeValueCallback? onConfirm; final int minuteDivider; - final ThemeData theme; - final bool isDismissible; - BrnPickerConfig themeData; + final ThemeData? theme; + final bool? isDismissible; + BrnPickerConfig? themeData; _DatePickerRoute({ this.minDateTime, @@ -121,9 +121,9 @@ class _DatePickerRoute extends PopupRoute { this.initialEndDateTime, this.minuteDivider = 1, this.dateFormat, - this.locale, - this.pickerMode, - this.pickerTitleConfig, + this.locale = datetimePickerLocaleDefault, + this.pickerMode = BrnDateTimeRangePickerMode.date, + this.pickerTitleConfig = BrnPickerTitleConfig.Default, this.onCancel, this.onChange, this.onConfirm, @@ -131,11 +131,11 @@ class _DatePickerRoute extends PopupRoute { this.barrierLabel, this.isDismissible, this.themeData, - RouteSettings settings, + RouteSettings? settings, }) : super(settings: settings) { this.themeData ??= BrnPickerConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .pickerConfig .merge(this.themeData); } @@ -147,27 +147,27 @@ class _DatePickerRoute extends PopupRoute { bool get barrierDismissible => isDismissible ?? true; @override - final String barrierLabel; + final String? barrierLabel; @override Color get barrierColor => Colors.black54; - AnimationController _animationController; + AnimationController? _animationController; @override AnimationController createAnimationController() { assert(_animationController == null); _animationController = - BottomSheet.createAnimationController(navigator.overlay); - return _animationController; + BottomSheet.createAnimationController(navigator!.overlay!); + return _animationController!; } @override Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { - double height = themeData.pickerHeight; + double height = themeData!.pickerHeight; if (pickerTitleConfig.title != null || pickerTitleConfig.showTitle) { - height += themeData.titleHeight; + height += themeData!.titleHeight; } Widget bottomSheet = MediaQuery.removePadding( @@ -180,7 +180,7 @@ class _DatePickerRoute extends PopupRoute { ); if (theme != null) { - bottomSheet = Theme(data: theme, child: bottomSheet); + bottomSheet = Theme(data: theme!, child: bottomSheet); } return bottomSheet; } @@ -190,12 +190,12 @@ class _DatePickerComponent extends StatelessWidget { final _DatePickerRoute route; final double _pickerHeight; - _DatePickerComponent({@required this.route, @required pickerHeight}) + _DatePickerComponent({required this.route, required pickerHeight}) : this._pickerHeight = pickerHeight; @override Widget build(BuildContext context) { - Widget pickerWidget; + Widget? pickerWidget; switch (route.pickerMode) { case BrnDateTimeRangePickerMode.date: pickerWidget = BrnDateRangeWidget( @@ -232,16 +232,15 @@ class _DatePickerComponent extends StatelessWidget { } return GestureDetector( child: AnimatedBuilder( - animation: route.animation, - builder: (BuildContext context, Widget child) { + animation: route.animation!, + builder: (BuildContext context, Widget? child) { return ClipRect( child: CustomSingleChildLayout( - delegate: _BottomPickerLayout(route.animation.value, - contentHeight: _pickerHeight), + delegate: _BottomPickerLayout(route.animation!.value, _pickerHeight), child: BrnPickerClipRRect( borderRadius: BorderRadius.only( - topLeft: Radius.circular(route.themeData.cornerRadius), - topRight: Radius.circular(route.themeData.cornerRadius), + topLeft: Radius.circular(route.themeData!.cornerRadius), + topRight: Radius.circular(route.themeData!.cornerRadius), ), child: pickerWidget, ), @@ -254,7 +253,7 @@ class _DatePickerComponent extends StatelessWidget { } class _BottomPickerLayout extends SingleChildLayoutDelegate { - _BottomPickerLayout(this.progress, {this.contentHeight}); + _BottomPickerLayout(this.progress, this.contentHeight); final double progress; final double contentHeight; diff --git a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_side_widget.dart b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_side_widget.dart index d6eb8871..fb3a4afb 100755 --- a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_side_widget.dart +++ b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_side_widget.dart @@ -10,49 +10,49 @@ import 'package:flutter/material.dart'; /// Solar months of 31 days. const List _solarMonthsOf31Days = const [1, 3, 5, 7, 8, 10, 12]; -enum ColumnType { Year, Month, Day } +enum ColumnType { year, month, day } /// one side widget of DateRangePicker // ignore: must_be_immutable class BrnDateRangeSideWidget extends StatefulWidget { /// 可选最小时间 - final DateTime minDateTime; + final DateTime? minDateTime; /// 可选最大时间 - final DateTime maxDateTime; + final DateTime? maxDateTime; /// 初始开始选中时间 - final DateTime initialStartDateTime; + final DateTime? initialStartDateTime; /// 时间展示格式 - final String dateFormat; + final String? dateFormat; final DateTimePickerLocale locale; /// 时间选择变化时回调 - final DateRangeSideValueCallback onChange; + final DateRangeSideValueCallback? onChange; /// 当前默认选择的时间变化时对外部回调,外部监听该事件同步修改默认初始选中的时间 - final DateRangeSideValueCallback onInitSelectChange; + final DateRangeSideValueCallback? onInitSelectChange; /// 主题定制 - BrnPickerConfig themeData; + BrnPickerConfig? themeData; BrnDateRangeSideWidget({ - Key key, + Key? key, this.minDateTime, this.maxDateTime, this.initialStartDateTime, - this.dateFormat: DATETIME_RANGE_PICKER_DATE_FORMAT, - this.locale: DATETIME_PICKER_LOCALE_DEFAULT, + this.dateFormat = datetimeRangePickerDateFormat, + this.locale = datetimePickerLocaleDefault, this.onInitSelectChange, this.onChange, }) : super(key: key) { - DateTime minTime = minDateTime ?? DateTime.parse(DATE_PICKER_MIN_DATETIME); - DateTime maxTime = maxDateTime ?? DateTime.parse(DATE_PICKER_MAX_DATETIME); + DateTime minTime = minDateTime ?? DateTime.parse(datePickerMinDatetime); + DateTime maxTime = maxDateTime ?? DateTime.parse(datePickerMaxDatetime); assert(minTime.compareTo(maxTime) <= 0); this.themeData ??= BrnPickerConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .pickerConfig .merge(this.themeData); } @@ -66,36 +66,41 @@ class BrnDateRangeSideWidget extends StatefulWidget { } class _DatePickerWidgetState extends State { - DateTime _minDateTime, _maxDateTime; - int _currYear, _currMonth, _currDay; - List _yearRange, _monthRange, _dayRange; - FixedExtentScrollController _yearScrollCtrl, _monthScrollCtrl, _dayScrollCtrl; + late DateTime _minDateTime, _maxDateTime; + late int _currYear, _currMonth, _currDay; + late List _yearRange, _monthRange, _dayRange; + late FixedExtentScrollController _yearScrollCtrl, + _monthScrollCtrl, + _dayScrollCtrl; - Map _scrollCtrlMap; - Map> _valueRangeMap; + late Map _scrollCtrlMap; + late Map> _valueRangeMap; bool _isChangeDateRange = false; bool _scrolledNotDay = false; - DateRangeSideValueCallback _onInitSelectChange; + DateRangeSideValueCallback? _onInitSelectChange; - _DatePickerWidgetState(DateTime minDateTime, DateTime maxDateTime, - DateTime initialDateTime, DateRangeSideValueCallback onInitSelectChange) { + _DatePickerWidgetState( + DateTime? minDateTime, + DateTime? maxDateTime, + DateTime? initialDateTime, + DateRangeSideValueCallback? onInitSelectChange) { _onInitSelectChange = onInitSelectChange; _initData(initialDateTime, minDateTime, maxDateTime); } void _initData( - DateTime initialDateTime, DateTime minDateTime, DateTime maxDateTime) { + DateTime? initialDateTime, DateTime? minDateTime, DateTime? maxDateTime) { DateTime initDateTime = initialDateTime ?? DateTime.now(); this._currYear = initDateTime.year; this._currMonth = initDateTime.month; this._currDay = initDateTime.day; // handle DateTime range - this._minDateTime = minDateTime ?? DateTime.parse(DATE_PICKER_MIN_DATETIME); - this._maxDateTime = maxDateTime ?? DateTime.parse(DATE_PICKER_MAX_DATETIME); + this._minDateTime = minDateTime ?? DateTime.parse(datePickerMinDatetime); + this._maxDateTime = maxDateTime ?? DateTime.parse(datePickerMaxDatetime); // limit the range of year this._yearRange = _calcYearRange(); @@ -130,7 +135,7 @@ class _DatePickerWidgetState extends State { widget.initialStartDateTime, widget.minDateTime, widget.maxDateTime); return GestureDetector( child: Container( - color: widget.themeData.backgroundColor, + color: widget.themeData!.backgroundColor, child: _renderDatePickerWidget()), ); } @@ -139,7 +144,7 @@ class _DatePickerWidgetState extends State { void _onInitSelectedChange() { if (_onInitSelectChange != null) { DateTime dateTime = DateTime(_currYear, _currMonth, _currDay); - _onInitSelectChange(dateTime, _calcSelectIndexList()); + _onInitSelectChange!(dateTime, _calcSelectIndexList()); } } @@ -147,13 +152,13 @@ class _DatePickerWidgetState extends State { void _onSelectedChange() { if (widget.onChange != null) { DateTime dateTime = DateTime(_currYear, _currMonth, _currDay); - widget.onChange(dateTime, _calcSelectIndexList()); + widget.onChange!(dateTime, _calcSelectIndexList()); } } /// find scroll controller by specified format - FixedExtentScrollController _findScrollCtrl(String format) { - FixedExtentScrollController scrollCtrl; + FixedExtentScrollController? _findScrollCtrl(String format) { + FixedExtentScrollController? scrollCtrl; _scrollCtrlMap.forEach((key, value) { if (format.contains(key)) { scrollCtrl = value; @@ -163,8 +168,8 @@ class _DatePickerWidgetState extends State { } /// find item value range by specified format - List _findPickerItemRange(String format) { - List valueRange; + List? _findPickerItemRange(String format) { + List? valueRange; _valueRangeMap.forEach((key, value) { if (format.contains(key)) { valueRange = value; @@ -175,11 +180,11 @@ class _DatePickerWidgetState extends State { /// render the picker widget of year、month and day Widget _renderDatePickerWidget() { - List pickers = List(); + List pickers = []; List formatArr = DateTimeFormatter.splitDateFormat(widget.dateFormat); formatArr.forEach((format) { - List valueRange = _findPickerItemRange(format); + List valueRange = _findPickerItemRange(format)!; Widget pickerColumn = _renderDatePickerColumnComponent( scrollCtrl: _findScrollCtrl(format), @@ -202,10 +207,10 @@ class _DatePickerWidgetState extends State { } Widget _renderDatePickerColumnComponent({ - @required FixedExtentScrollController scrollCtrl, - @required List valueRange, - @required String format, - @required ValueChanged valueChanged, + required FixedExtentScrollController? scrollCtrl, + required List valueRange, + required String format, + required ValueChanged valueChanged, }) { var globalKey; if (_scrolledNotDay && format.contains("d")) { @@ -215,14 +220,14 @@ class _DatePickerWidgetState extends State { return Expanded( flex: 1, child: Container( - height: widget.themeData.pickerHeight, - decoration: BoxDecoration(color: widget.themeData.backgroundColor), + height: widget.themeData!.pickerHeight, + decoration: BoxDecoration(color: widget.themeData!.backgroundColor), child: BrnPicker.builder( key: globalKey, - backgroundColor: widget.themeData.backgroundColor, - lineColor: widget.themeData.dividerColor, + backgroundColor: widget.themeData!.backgroundColor, + lineColor: widget.themeData!.dividerColor, scrollController: scrollCtrl, - itemExtent: widget.themeData.itemHeight, + itemExtent: widget.themeData!.itemHeight, onSelectedItemChanged: (int index) { if (!format.contains("d")) { _scrolledNotDay = true; @@ -232,8 +237,8 @@ class _DatePickerWidgetState extends State { childCount: valueRange.last - valueRange.first + 1, itemBuilder: (context, index) => _renderDatePickerItemComponent( format.contains("y") - ? ColumnType.Year - : (format.contains("M") ? ColumnType.Month : ColumnType.Day), + ? ColumnType.year + : (format.contains("M") ? ColumnType.month : ColumnType.day), index, valueRange.first + index, format), @@ -244,15 +249,15 @@ class _DatePickerWidgetState extends State { Widget _renderDatePickerItemComponent( ColumnType columnType, int index, int value, String format) { - TextStyle textStyle = widget.themeData.itemTextStyle.generateTextStyle(); - if ((ColumnType.Year == columnType && index == _calcSelectIndexList()[0]) || - (ColumnType.Month == columnType && + TextStyle textStyle = widget.themeData!.itemTextStyle.generateTextStyle(); + if ((ColumnType.year == columnType && index == _calcSelectIndexList()[0]) || + (ColumnType.month == columnType && index == _calcSelectIndexList()[1]) || - (ColumnType.Day == columnType && index == _calcSelectIndexList()[2])) { - textStyle = widget.themeData.itemTextSelectedStyle.generateTextStyle(); + (ColumnType.day == columnType && index == _calcSelectIndexList()[2])) { + textStyle = widget.themeData!.itemTextSelectedStyle.generateTextStyle(); } return Container( - height: widget.themeData.itemHeight, + height: widget.themeData!.itemHeight, alignment: Alignment.center, child: Text( DateTimeFormatter.formatDateTime(value, format, widget.locale), diff --git a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_widget.dart b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_widget.dart index cacab725..e5f311b1 100755 --- a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_widget.dart +++ b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_widget.dart @@ -1,3 +1,5 @@ + + import 'dart:math'; import 'package:bruno/src/components/picker/base/brn_picker.dart'; @@ -16,56 +18,56 @@ const List _solarMonthsOf31Days = const [1, 3, 5, 7, 8, 10, 12]; // ignore: must_be_immutable class BrnDateRangeWidget extends StatefulWidget { /// 可选最小时间 - final DateTime minDateTime; + final DateTime? minDateTime; /// 可选最大时间 - final DateTime maxDateTime; + final DateTime? maxDateTime; /// 初始选中的开始时间 - final DateTime initialStartDateTime; + final DateTime? initialStartDateTime; /// 初始选中的结束时间 - final DateTime initialEndDateTime; + final DateTime? initialEndDateTime; /// 时间展示格式 - final String dateFormat; + final String? dateFormat; final DateTimePickerLocale locale; /// cancel 回调 - final DateVoidCallback onCancel; + final DateVoidCallback? onCancel; /// 选中时间变化时的回调,返回选中的开始、结束时间 - final DateRangeValueCallback onChange; + final DateRangeValueCallback? onChange; /// 确定回调,返回选中的开始、结束时间 - final DateRangeValueCallback onConfirm; + final DateRangeValueCallback? onConfirm; /// Picker title 相关内容配置 final BrnPickerTitleConfig pickerTitleConfig; /// Picker 主题配置 - BrnPickerConfig themeData; + BrnPickerConfig? themeData; BrnDateRangeWidget({ - Key key, + Key? key, this.minDateTime, this.maxDateTime, this.initialStartDateTime, this.initialEndDateTime, - this.dateFormat: DATETIME_RANGE_PICKER_DATE_FORMAT, - this.locale: DATETIME_PICKER_LOCALE_DEFAULT, + this.dateFormat: datetimeRangePickerDateFormat, + this.locale: datetimePickerLocaleDefault, this.pickerTitleConfig: BrnPickerTitleConfig.Default, this.onCancel, this.onChange, this.onConfirm, this.themeData, }) : super(key: key) { - DateTime minTime = minDateTime ?? DateTime.parse(DATE_PICKER_MIN_DATETIME); - DateTime maxTime = maxDateTime ?? DateTime.parse(DATE_PICKER_MAX_DATETIME); + DateTime minTime = minDateTime ?? DateTime.parse(datePickerMinDatetime); + DateTime maxTime = maxDateTime ?? DateTime.parse(datePickerMaxDatetime); assert(minTime.compareTo(maxTime) < 0); this.themeData ??= BrnPickerConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .pickerConfig .merge(this.themeData); } @@ -79,28 +81,28 @@ class BrnDateRangeWidget extends StatefulWidget { } class _DatePickerWidgetState extends State { - DateTime _minDateTime, _maxDateTime; - int _currStartYear, _currStartMonth, _currStartDay; - int _currEndYear, _currEndMonth, _currEndDay; + late DateTime _minDateTime, _maxDateTime; + late int _currStartYear, _currStartMonth, _currStartDay; + late int _currEndYear, _currEndMonth, _currEndDay; - List _monthRange, _startDayRange, _endDayRange; - List _startSelectedIndex; - List _endSelectedIndex; - DateTime _startSelectedDateTime; - DateTime _endSelectedDateTime; + late List _monthRange, _startDayRange, _endDayRange; + late List _startSelectedIndex; + late List _endSelectedIndex; + late DateTime _startSelectedDateTime; + late DateTime _endSelectedDateTime; bool _isFirstScroll = false; bool _isSecondScroll = false; - _DatePickerWidgetState(DateTime minDateTime, DateTime maxDateTime, - DateTime initialStartDateTime, DateTime initialEndDateTime) { + _DatePickerWidgetState(DateTime? minDateTime, DateTime? maxDateTime, + DateTime? initialStartDateTime, DateTime? initialEndDateTime) { // handle current selected year、month、day _initData( initialStartDateTime, initialEndDateTime, minDateTime, maxDateTime); } - void _initData(DateTime initialStartDateTime, DateTime initialEndDateTime, - DateTime minDateTime, DateTime maxDateTime) { + void _initData(DateTime? initialStartDateTime, DateTime? initialEndDateTime, + DateTime? minDateTime, DateTime? maxDateTime) { DateTime initStartDateTime = initialStartDateTime ?? DateTime.now(); DateTime initEndDateTime = initialEndDateTime ?? DateTime.now(); @@ -113,8 +115,8 @@ class _DatePickerWidgetState extends State { this._currEndDay = initEndDateTime.day; // handle DateTime range - this._minDateTime = minDateTime ?? DateTime.parse(DATE_PICKER_MIN_DATETIME); - this._maxDateTime = maxDateTime ?? DateTime.parse(DATE_PICKER_MAX_DATETIME); + this._minDateTime = minDateTime ?? DateTime.parse(datePickerMinDatetime); + this._maxDateTime = maxDateTime ?? DateTime.parse(datePickerMaxDatetime); // limit the range of year this._currStartYear = @@ -172,7 +174,7 @@ class _DatePickerWidgetState extends State { /// pressed cancel widget void _onPressedCancel() { if (widget.onCancel != null) { - widget.onCancel(); + widget.onCancel!(); } Navigator.pop(context); } @@ -180,7 +182,7 @@ class _DatePickerWidgetState extends State { /// pressed confirm widget void _onPressedConfirm() { if (widget.onConfirm != null) { - widget.onConfirm(_startSelectedDateTime, _endSelectedDateTime, + widget.onConfirm!(_startSelectedDateTime, _endSelectedDateTime, _startSelectedIndex, _endSelectedIndex); } Navigator.pop(context); @@ -201,12 +203,12 @@ class _DatePickerWidgetState extends State { _isSecondScroll = false; } - List pickers = List(); + List pickers = []; pickers.add(Expanded( flex: 6, child: Container( - height: widget.themeData.pickerHeight, - color: widget.themeData.backgroundColor, + height: widget.themeData!.pickerHeight, + color: widget.themeData!.backgroundColor, child: BrnDateRangeSideWidget( key: firstGlobalKey, dateFormat: widget.dateFormat, @@ -230,8 +232,8 @@ class _DatePickerWidgetState extends State { pickers.add(Expanded( flex: 6, child: Container( - height: widget.themeData.pickerHeight, - color: widget.themeData.backgroundColor, + height: widget.themeData!.pickerHeight, + color: widget.themeData!.backgroundColor, child: BrnDateRangeSideWidget( key: secondGlobalKey, dateFormat: widget.dateFormat, @@ -262,22 +264,22 @@ class _DatePickerWidgetState extends State { return Expanded( flex: 1, child: Container( - height: widget.themeData.pickerHeight, + height: widget.themeData!.pickerHeight, decoration: BoxDecoration( border: Border(left: BorderSide.none, right: BorderSide.none), - color: widget.themeData.backgroundColor), + color: widget.themeData!.backgroundColor), child: BrnPicker.builder( - backgroundColor: widget.themeData.backgroundColor, - lineColor: widget.themeData.dividerColor, - itemExtent: widget.themeData.itemHeight, + backgroundColor: widget.themeData!.backgroundColor, + lineColor: widget.themeData!.dividerColor, + itemExtent: widget.themeData!.itemHeight, childCount: 1, itemBuilder: (context, index) { return Container( - height: widget.themeData.itemHeight, + height: widget.themeData!.itemHeight, alignment: Alignment.center, child: Text( "至", - style: widget.themeData.itemTextStyle.generateTextStyle(), + style: widget.themeData!.itemTextStyle.generateTextStyle(), ), ); }, diff --git a/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_side_widget.dart b/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_side_widget.dart index 47421443..79112dde 100755 --- a/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_side_widget.dart +++ b/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_side_widget.dart @@ -1,3 +1,5 @@ + + import 'dart:math'; import 'package:bruno/src/components/picker/base/brn_picker.dart'; @@ -12,46 +14,49 @@ import 'package:flutter/material.dart'; // ignore: must_be_immutable class BrnTimeRangeSideWidget extends StatefulWidget { /// 可选最小时间 - final DateTime minDateTime; + final DateTime? minDateTime; /// 可选最大时间 - final DateTime maxDateTime; + final DateTime? maxDateTime; /// 初始开始选中时间 - final DateTime initialStartDateTime; + final DateTime? initialStartDateTime; /// 时间展示格式 - final String dateFormat; + final String? dateFormat; final DateTimePickerLocale locale; /// 时间选择变化时回调 - final DateRangeSideValueCallback onChange; + final DateRangeSideValueCallback? onChange; /// 分钟的展示间隔 - final int minuteDivider; + final int? minuteDivider; /// 当前默认选择的时间变化时对外部回调,外部监听该事件同步修改默认初始选中的时间 - final DateRangeSideValueCallback onInitSelectChange; + final DateRangeSideValueCallback? onInitSelectChange; /// 主题定制 - BrnPickerConfig themeData; + BrnPickerConfig? themeData; BrnTimeRangeSideWidget({ - Key key, + Key? key, this.minDateTime, this.maxDateTime, this.initialStartDateTime, - this.dateFormat: DATETIME_RANGE_PICKER_TIME_FORMAT, - this.locale: DATETIME_PICKER_LOCALE_DEFAULT, + this.dateFormat: datetimeRangePickerTimeFormat, + this.locale: datetimePickerLocaleDefault, this.minuteDivider = 1, this.onChange, this.onInitSelectChange, }) : super(key: key) { - DateTime minTime = minDateTime ?? DateTime.parse(DATE_PICKER_MIN_DATETIME); - DateTime maxTime = maxDateTime ?? DateTime.parse(DATE_PICKER_MAX_DATETIME); + DateTime minTime = minDateTime ?? DateTime.parse(datePickerMinDatetime); + DateTime maxTime = maxDateTime ?? DateTime.parse(datePickerMaxDatetime); assert(minTime.compareTo(maxTime) <= 0); this.themeData ??= BrnPickerConfig(); - this.themeData.initThemeConfigPersonal(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .pickerConfig + .merge(this.themeData); } @override @@ -66,38 +71,38 @@ class BrnTimeRangeSideWidget extends StatefulWidget { class _TimePickerWidgetState extends State { final int _defaultMinuteDivider = 1; - DateTime _minTime, _maxTime; - int _currStartHour, _currStartMinute; - int _minuteDivider; - List _hourRange, _minuteRange; - FixedExtentScrollController _startHourScrollCtrl, _startMinuteScrollCtrl; + late DateTime _minTime, _maxTime; + late int _currStartHour, _currStartMinute; + late int _minuteDivider; + late List _hourRange, _minuteRange; + late FixedExtentScrollController _startHourScrollCtrl, _startMinuteScrollCtrl; - Map _startScrollCtrlMap; - Map> _valueRangeMap; + late Map _startScrollCtrlMap; + late Map> _valueRangeMap; bool _isChangeTimeRange = false; bool _scrolledNotMinute = false; - DateRangeSideValueCallback _onInitSelectChange; + DateRangeSideValueCallback? _onInitSelectChange; _TimePickerWidgetState( - DateTime minTime, - DateTime maxTime, - DateTime initStartTime, - int minuteDivider, - DateRangeSideValueCallback onInitSelectChange) { + DateTime? minTime, + DateTime? maxTime, + DateTime? initStartTime, + int? minuteDivider, + DateRangeSideValueCallback? onInitSelectChange) { _onInitSelectChange = onInitSelectChange; _initData(minTime, maxTime, initStartTime, minuteDivider); } - void _initData(DateTime minTime, DateTime maxTime, DateTime initStartTime, - int minuteDivider) { + void _initData(DateTime? minTime, DateTime? maxTime, DateTime? initStartTime, + int? minuteDivider) { if (minTime == null) { - minTime = DateTime.parse(DATE_PICKER_MIN_DATETIME); + minTime = DateTime.parse(datePickerMinDatetime); } if (maxTime == null) { - maxTime = DateTime.parse(DATE_PICKER_MAX_DATETIME); + maxTime = DateTime.parse(datePickerMaxDatetime); } this._minTime = minTime; this._maxTime = maxTime; @@ -113,20 +118,18 @@ class _TimePickerWidgetState extends State { this._minuteDivider = minuteDivider; } - // limit the range of hour + this._currStartHour = initStartTime.hour; this._hourRange = _calcHourRange(); + this._currStartHour = + min(max(_hourRange.first, _currStartHour), _hourRange.last); + + this._currStartMinute = initStartTime.minute; this._minuteRange = _calcMinuteRange(); + this._currStartMinute = + min(max(_minuteRange.first, _currStartMinute), _minuteRange.last); + _currStartMinute -= _currStartMinute % _minuteDivider; - if (_currStartHour == null || _currStartMinute == null) { - this._currStartHour = initStartTime.hour; - this._currStartHour = - min(max(_hourRange.first, _currStartHour), _hourRange.last); - this._currStartMinute = initStartTime.minute; - this._currStartMinute = - min(max(_minuteRange.first, _currStartMinute), _minuteRange.last); - _currStartMinute -= _currStartMinute % _minuteDivider; - } _onInitSelectedChange(); // create scroll controller _startHourScrollCtrl = FixedExtentScrollController( @@ -146,7 +149,7 @@ class _TimePickerWidgetState extends State { _initData(_minTime, _maxTime, widget.initialStartDateTime, _minuteDivider); return GestureDetector( child: Container( - color: widget.themeData.backgroundColor, + color: widget.themeData!.backgroundColor, child: _renderPickerView(context)), ); } @@ -162,7 +165,7 @@ class _TimePickerWidgetState extends State { DateTime now = DateTime.now(); DateTime startDateTime = DateTime( now.year, now.month, now.day, _currStartHour, _currStartMinute); - _onInitSelectChange(startDateTime, _calcStartSelectIndexList()); + _onInitSelectChange!(startDateTime, _calcStartSelectIndexList()); } } @@ -172,13 +175,13 @@ class _TimePickerWidgetState extends State { DateTime now = DateTime.now(); DateTime startDateTime = DateTime( now.year, now.month, now.day, _currStartHour, _currStartMinute); - widget.onChange(startDateTime, _calcStartSelectIndexList()); + widget.onChange!(startDateTime, _calcStartSelectIndexList()); } } /// find start scroll controller by specified format - FixedExtentScrollController _findScrollCtrl(String format) { - FixedExtentScrollController scrollCtrl; + FixedExtentScrollController? _findScrollCtrl(String format) { + FixedExtentScrollController? scrollCtrl; _startScrollCtrlMap.forEach((key, value) { if (format.contains(key)) { scrollCtrl = value; @@ -188,8 +191,8 @@ class _TimePickerWidgetState extends State { } /// find item value range by specified format - List _findPickerItemRange(String format) { - List valueRange; + List? _findPickerItemRange(String format) { + List? valueRange; _valueRangeMap.forEach((key, value) { if (format.contains(key)) { valueRange = value; @@ -200,11 +203,11 @@ class _TimePickerWidgetState extends State { /// render the picker widget of year、month and day Widget _renderDatePickerWidget() { - List pickers = List(); + List pickers = []; List formatArr = DateTimeFormatter.splitDateFormat(widget.dateFormat); formatArr.forEach((format) { - List valueRange = _findPickerItemRange(format); + List? valueRange = _findPickerItemRange(format); Widget pickerColumn = _renderDatePickerColumnComponent( scrollCtrl: _findScrollCtrl(format), @@ -225,10 +228,10 @@ class _TimePickerWidgetState extends State { } Widget _renderDatePickerColumnComponent({ - @required FixedExtentScrollController scrollCtrl, - @required List valueRange, - @required String format, - @required ValueChanged valueChanged, + required FixedExtentScrollController? scrollCtrl, + required List? valueRange, + required String format, + required ValueChanged valueChanged, }) { var globalKey; if (_scrolledNotMinute && format.contains("m")) { @@ -239,14 +242,14 @@ class _TimePickerWidgetState extends State { return Expanded( flex: 1, child: Container( - height: widget.themeData.pickerHeight, - color: widget.themeData.backgroundColor, + height: widget.themeData!.pickerHeight, + color: widget.themeData!.backgroundColor, child: BrnPicker.builder( key: globalKey, - backgroundColor: widget.themeData.backgroundColor, - lineColor: widget.themeData.dividerColor, + backgroundColor: widget.themeData!.backgroundColor, + lineColor: widget.themeData!.dividerColor, scrollController: scrollCtrl, - itemExtent: widget.themeData.itemHeight, + itemExtent: widget.themeData!.itemHeight, onSelectedItemChanged: (int index) { if (!format.contains("m")) { _scrolledNotMinute = true; @@ -255,9 +258,9 @@ class _TimePickerWidgetState extends State { }, childCount: format.contains('m') ? _calculateMinuteChildCount(valueRange, _minuteDivider) - : valueRange.last - valueRange.first + 1, + : valueRange!.last - valueRange.first + 1, itemBuilder: (context, index) { - int value = valueRange.first + index; + int value = valueRange!.first + index; if (format.contains('m')) { value = valueRange.first + _minuteDivider * index; @@ -270,24 +273,24 @@ class _TimePickerWidgetState extends State { ); } - _calculateMinuteChildCount(List valueRange, int divider) { + _calculateMinuteChildCount(List? valueRange, int? divider) { if (divider == 0 || divider == 1) { debugPrint("Cant devide by 0"); - return (valueRange.last - valueRange.first + 1); + return (valueRange!.last - valueRange.first + 1); } - return ((valueRange.last - valueRange.first) ~/ divider) + 1; + return ((valueRange!.last - valueRange.first) ~/ divider!) + 1; } Widget _renderDatePickerItemComponent( int index, bool isMinuteColumn, int value, String format) { - TextStyle textStyle = widget.themeData.itemTextStyle.generateTextStyle(); + TextStyle textStyle = widget.themeData!.itemTextStyle.generateTextStyle(); if ((!isMinuteColumn && (index == _calcStartSelectIndexList()[0])) || ((isMinuteColumn && (index == _calcStartSelectIndexList()[1])))) { - textStyle = widget.themeData.itemTextSelectedStyle.generateTextStyle(); + textStyle = widget.themeData!.itemTextSelectedStyle.generateTextStyle(); } return Container( - height: widget.themeData.itemHeight, + height: widget.themeData!.itemHeight, alignment: Alignment.center, child: Text( DateTimeFormatter.formatDateTime(value, format, widget.locale), diff --git a/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_widget.dart b/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_widget.dart index 0b521810..241b48c9 100755 --- a/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_widget.dart +++ b/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_widget.dart @@ -1,3 +1,5 @@ + + import 'dart:math'; import 'package:bruno/src/components/picker/base/brn_picker.dart'; @@ -14,32 +16,32 @@ import 'package:flutter/material.dart'; // ignore: must_be_immutable class BrnTimeRangeWidget extends StatefulWidget { /// 可选最小时间 - final DateTime minDateTime; + final DateTime? minDateTime; /// 可选最大时间 - final DateTime maxDateTime; + final DateTime? maxDateTime; /// 初始开始选中时间 - final DateTime initialStartDateTime; + final DateTime? initialStartDateTime; /// 初始结束选中时间 - final DateTime initialEndDateTime; + final DateTime? initialEndDateTime; /// 是否限制 Picker 选择的时间范围(开始时间≤结束时间) final isLimitTimeRange; /// 时间格式 - final String dateFormat; + final String? dateFormat; final DateTimePickerLocale locale; /// cancel 回调 - final DateVoidCallback onCancel; + final DateVoidCallback? onCancel; /// 选中时间变化时的回调,返回选中的开始、结束时间 - final DateRangeValueCallback onChange; + final DateRangeValueCallback? onChange; /// 确定回调,返回选中的开始、结束时间 - final DateRangeValueCallback onConfirm; + final DateRangeValueCallback? onConfirm; /// Picker title 相关内容配置 final BrnPickerTitleConfig pickerTitleConfig; @@ -48,20 +50,20 @@ class BrnTimeRangeWidget extends StatefulWidget { final int minuteDivider; /// Picker 主题配置 - BrnPickerConfig themeData; + BrnPickerConfig? themeData; /// 内部变量,记录左右两侧是否触发了滚动 bool _isFirstScroll = false, _isSecondScroll = false; BrnTimeRangeWidget({ - Key key, + Key? key, this.minDateTime, this.maxDateTime, this.isLimitTimeRange = true, this.initialStartDateTime, this.initialEndDateTime, - this.dateFormat: DATETIME_RANGE_PICKER_TIME_FORMAT, - this.locale: DATETIME_PICKER_LOCALE_DEFAULT, + this.dateFormat: datetimeRangePickerTimeFormat, + this.locale: datetimePickerLocaleDefault, this.pickerTitleConfig: BrnPickerTitleConfig.Default, this.minuteDivider = 1, this.onCancel, @@ -69,12 +71,12 @@ class BrnTimeRangeWidget extends StatefulWidget { this.onConfirm, this.themeData, }) : super(key: key) { - DateTime minTime = minDateTime ?? DateTime.parse(DATE_PICKER_MIN_DATETIME); - DateTime maxTime = maxDateTime ?? DateTime.parse(DATE_PICKER_MAX_DATETIME); + DateTime minTime = minDateTime ?? DateTime.parse(datePickerMinDatetime); + DateTime maxTime = maxDateTime ?? DateTime.parse(datePickerMaxDatetime); assert(minTime.compareTo(maxTime) < 0); this.themeData ??= BrnPickerConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .pickerConfig .merge(this.themeData); } @@ -91,28 +93,28 @@ class BrnTimeRangeWidget extends StatefulWidget { class _TimePickerWidgetState extends State { final int _defaultMinuteDivider = 1; - int _minuteDivider; - DateTime _minTime, _maxTime; - int _currStartHour, _currStartMinute; - int _currEndHour, _currEndMinute; - List _hourRange, _minuteRange; - List _startSelectedIndex; - List _endSelectedIndex; - DateTime _startSelectedDateTime; - DateTime _endSelectedDateTime; - - _TimePickerWidgetState(DateTime minTime, DateTime maxTime, - DateTime initStartTime, DateTime initEndTime, int minuteDivider) { + late int _minuteDivider; + late DateTime _minTime, _maxTime; + late int _currStartHour, _currStartMinute; + late int _currEndHour, _currEndMinute; + late List _hourRange, _minuteRange; + late List _startSelectedIndex; + late List _endSelectedIndex; + late DateTime _startSelectedDateTime; + late DateTime _endSelectedDateTime; + + _TimePickerWidgetState(DateTime? minTime, DateTime? maxTime, + DateTime? initStartTime, DateTime? initEndTime, int minuteDivider) { _initData(minTime, maxTime, initStartTime, initEndTime, minuteDivider); } - void _initData(DateTime minTime, DateTime maxTime, DateTime initStartTime, - DateTime initEndTime, int minuteDivider) { + void _initData(DateTime? minTime, DateTime? maxTime, DateTime? initStartTime, + DateTime? initEndTime, int? minuteDivider) { if (minTime == null) { - minTime = DateTime.parse(DATE_PICKER_MIN_DATETIME); + minTime = DateTime.parse(datePickerMinDatetime); } if (maxTime == null) { - maxTime = DateTime.parse(DATE_PICKER_MAX_DATETIME); + maxTime = DateTime.parse(datePickerMaxDatetime); } DateTime now = DateTime.now(); this._minTime = DateTime(now.year, now.month, now.day, minTime.hour, @@ -137,24 +139,20 @@ class _TimePickerWidgetState extends State { } this._currStartHour = initStartTime.hour; - this._currStartMinute = initStartTime.minute; - - this._currEndHour = initEndTime.hour; - this._currEndMinute = initEndTime.minute; - - // limit the range of hour this._hourRange = _calcHourRange(); - this._minuteRange = _calcMinuteRange(); - this._currStartHour = min(max(_hourRange.first, _currStartHour), _hourRange.last); - this._currEndHour = min(_currEndHour, _hourRange.last); - // limit the range of minute + this._currStartMinute = initStartTime.minute; + this._minuteRange = _calcMinuteRange(); this._currStartMinute = min(max(_minuteRange.first, _currStartMinute), _minuteRange.last); _currStartMinute -= _currStartMinute % _minuteDivider; + this._currEndHour = initEndTime.hour; + this._currEndHour = min(_currEndHour, _hourRange.last); + + this._currEndMinute = initEndTime.minute; this._currEndMinute = min(_currEndMinute, _minuteRange.last); _currEndMinute -= _currEndMinute % _minuteDivider; @@ -198,7 +196,7 @@ class _TimePickerWidgetState extends State { /// pressed cancel widget void _onPressedCancel() { if (widget.onCancel != null) { - widget.onCancel(); + widget.onCancel!(); } Navigator.pop(context); } @@ -206,7 +204,7 @@ class _TimePickerWidgetState extends State { /// pressed confirm widget void _onPressedConfirm() { if (widget.onConfirm != null) { - widget.onConfirm(_startSelectedDateTime, _endSelectedDateTime, + widget.onConfirm!(_startSelectedDateTime, _endSelectedDateTime, _startSelectedIndex, _endSelectedIndex); } Navigator.pop(context); @@ -227,12 +225,12 @@ class _TimePickerWidgetState extends State { widget._isSecondScroll = false; } - List pickers = List(); + List pickers = []; pickers.add(Expanded( flex: 6, child: Container( - height: widget.themeData.pickerHeight, - color: widget.themeData.backgroundColor, + height: widget.themeData!.pickerHeight, + color: widget.themeData!.backgroundColor, child: BrnTimeRangeSideWidget( key: firstGlobalKey, dateFormat: widget.dateFormat, @@ -258,8 +256,8 @@ class _TimePickerWidgetState extends State { pickers.add(Expanded( flex: 6, child: Container( - height: widget.themeData.pickerHeight, - color: widget.themeData.backgroundColor, + height: widget.themeData!.pickerHeight, + color: widget.themeData!.backgroundColor, child: BrnTimeRangeSideWidget( key: secondGlobalKey, dateFormat: widget.dateFormat, @@ -334,22 +332,22 @@ class _TimePickerWidgetState extends State { return Expanded( flex: 1, child: Container( - height: widget.themeData.pickerHeight, + height: widget.themeData!.pickerHeight, decoration: BoxDecoration( border: Border(left: BorderSide.none, right: BorderSide.none), - color: widget.themeData.backgroundColor), + color: widget.themeData!.backgroundColor), child: BrnPicker.builder( - backgroundColor: widget.themeData.backgroundColor, - lineColor: widget.themeData.dividerColor, - itemExtent: widget.themeData.itemHeight, + backgroundColor: widget.themeData!.backgroundColor, + lineColor: widget.themeData!.dividerColor, + itemExtent: widget.themeData!.itemHeight, childCount: 1, itemBuilder: (context, index) { return Container( - height: widget.themeData.itemHeight, + height: widget.themeData!.itemHeight, alignment: Alignment.center, child: Text( "至", - style: widget.themeData.itemTextStyle ?? PICKER_ITEM_TEXT_STYLE, + style: widget.themeData!.itemTextStyle.generateTextStyle(), ), ); }, diff --git a/lib/src/components/popup/brn_measure_size.dart b/lib/src/components/popup/brn_measure_size.dart index 93bdc51c..d2e08eaf 100644 --- a/lib/src/components/popup/brn_measure_size.dart +++ b/lib/src/components/popup/brn_measure_size.dart @@ -5,7 +5,7 @@ typedef void OnWidgetSizeChange(Size size); /// 描述: 计算 Widget 宽高的工具类。 class MeasureSizeRenderObject extends RenderProxyBox { - Size oldSize; + Size? oldSize; final OnWidgetSizeChange onChange; MeasureSizeRenderObject(this.onChange); @@ -14,13 +14,18 @@ class MeasureSizeRenderObject extends RenderProxyBox { void performLayout() { super.performLayout(); - Size newSize = child.size; + Size newSize = Size.zero; + if (child != null) { + newSize = child!.size; + } if (oldSize == newSize) return; oldSize = newSize; - WidgetsBinding.instance.addPostFrameCallback((_) { - onChange(newSize); - }); + if (WidgetsBinding.instance != null) { + WidgetsBinding.instance!.addPostFrameCallback((_) { + onChange(newSize); + }); + } } } @@ -28,11 +33,10 @@ class MeasureSize extends SingleChildRenderObjectWidget { final OnWidgetSizeChange onChange; const MeasureSize({ - Key key, - @required this.onChange, - @required Widget child, + Key? key, + required this.onChange, + required Widget child, }) : super(key: key, child: child); - @override RenderObject createRenderObject(BuildContext context) { return MeasureSizeRenderObject(onChange); diff --git a/lib/src/components/popup/brn_overlay_window.dart b/lib/src/components/popup/brn_overlay_window.dart index 6469dbb9..6ba24fe1 100644 --- a/lib/src/components/popup/brn_overlay_window.dart +++ b/lib/src/components/popup/brn_overlay_window.dart @@ -4,7 +4,6 @@ import 'dart:ui'; import 'package:bruno/src/components/popup/brn_measure_size.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// popWindow位于targetView的方向 enum BrnOverlayPopDirection { none, top, bottom, left, right } @@ -14,7 +13,7 @@ class BrnOverlayWindow extends StatefulWidget { final BuildContext context; /// 锚点 Widget 的 key,用于 OverlayWindow 的定位 - final Key targetKey; + final GlobalKey targetKey; /// OverlayWindow 相对于 key 的展示位置, 默认 bottom final BrnOverlayPopDirection popDirection; @@ -23,10 +22,10 @@ class BrnOverlayWindow extends StatefulWidget { final Widget content; const BrnOverlayWindow({ - this.context, - this.targetKey, + required this.context, + required this.targetKey, this.popDirection = BrnOverlayPopDirection.bottom, - this.content, + this.content = const SizedBox.shrink(), }); @override @@ -39,27 +38,27 @@ class BrnOverlayWindow extends StatefulWidget { /// [targetKey] 锚点 Widget 的 key,用于 OverlayWindow 的定位 /// [popDirection] OverlayWindow 相对于 key 的展示位置, 默认 bottom /// [content] 要展示的内容 - /// [autoDismissOnTouchOutSide] 点击 OverlayWindow 外部是否自动消失 + /// [autoDismissOnTouchOutSide] 点击 OverlayWindow 外部是否自动消失,默认为 true /// [onDismiss] OverlayWindow 消失回调 - static BrnOverlayController showOverlayWindow( - BuildContext context, Key targetKey, - {Widget content, - BrnOverlayPopDirection popDirection, - bool autoDismissOnTouchOutSide, - Function onDismiss}) { + static BrnOverlayController? showOverlayWindow( + BuildContext context, GlobalKey? targetKey, + {Widget? content, + BrnOverlayPopDirection popDirection = BrnOverlayPopDirection.bottom, + bool autoDismissOnTouchOutSide = true, + Function? onDismiss}) { assert(content != null); assert(targetKey != null); assert(content != null); if (content == null || targetKey == null) return null; - BrnOverlayController overlayController; + BrnOverlayController? overlayController; OverlayEntry entry = OverlayEntry(builder: (context) { return GestureDetector( - behavior: (autoDismissOnTouchOutSide ?? true) + behavior: (autoDismissOnTouchOutSide) ? HitTestBehavior.opaque : HitTestBehavior.deferToChild, - onTap: (autoDismissOnTouchOutSide ?? true) + onTap: (autoDismissOnTouchOutSide) ? () { overlayController?.removeOverlay(); if (onDismiss != null) { @@ -82,13 +81,16 @@ class BrnOverlayWindow extends StatefulWidget { class _BrnOverlayWindowState extends State { /// targetView的位置 - Rect _showRect; + Rect? _showRect; /// 屏幕的尺寸 - Size _screenSize; + late Size _screenSize; /// overlay 在targetView 四周的偏移位置 - double _left, _right, _top, _bottom; + double _left = 0; + double _right = 0; + double _top = 0; + double _bottom = 0; /// targetView 的 Size Size _targetViewSize = Size.zero; @@ -97,11 +99,14 @@ class _BrnOverlayWindowState extends State { Widget build(BuildContext context) { this._showRect = _getWidgetGlobalRect(widget.targetKey); this._screenSize = window.physicalSize / window.devicePixelRatio; - _calculateOffset(); - return _buildContent(); + if (this._showRect == null) { + return const SizedBox.shrink(); + } + _calculateOffset(this._showRect!); + return _buildContent(this._showRect!); } - Widget _buildContent() { + Widget _buildContent(Rect showRect) { var contentPart = Material( color: Colors.transparent, child: MeasureSize( @@ -115,14 +120,14 @@ class _BrnOverlayWindowState extends State { Widget realContent; double marginTop = - _showRect.top + (_showRect.height - _targetViewSize.height) / 2; + showRect.top + (showRect.height - _targetViewSize.height) / 2; if (_screenSize.height - marginTop < _targetViewSize.height) { marginTop = max(0, _screenSize.height - _targetViewSize.height); } marginTop = max(0, marginTop); double marginLeft = - _showRect.left + (_showRect.width - _targetViewSize.width) / 2; + showRect.left + (showRect.width - _targetViewSize.width) / 2; if (_screenSize.width - marginLeft < _targetViewSize.width) { marginLeft = max(0, _screenSize.width - _targetViewSize.width); } @@ -200,36 +205,40 @@ class _BrnOverlayWindowState extends State { /// /// 获取targetView的位置 /// - Rect _getWidgetGlobalRect(GlobalKey key) { - if (key == null) { - return null; + Rect? _getWidgetGlobalRect(GlobalKey key) { + BuildContext? ctx = key.currentContext; + RenderObject? obj; + if (ctx != null) { + obj = ctx.findRenderObject(); + } + if (obj != null && obj is RenderBox) { + RenderBox renderBox = obj; + var offset = renderBox.localToGlobal(Offset.zero); + return Rect.fromLTWH( + offset.dx, offset.dy, renderBox.size.width, renderBox.size.height); } - RenderBox renderBox = key.currentContext.findRenderObject(); - var offset = renderBox.localToGlobal(Offset.zero); - return Rect.fromLTWH( - offset.dx, offset.dy, renderBox.size.width, renderBox.size.height); + return null; } /// /// 计算popUpWindow显示的位置 /// - void _calculateOffset() { - _right = _left = _top = _bottom = 0; + void _calculateOffset(Rect showRect) { if (widget.popDirection == BrnOverlayPopDirection.left) { - _left = _showRect.left; + _left = showRect.left; } else if (widget.popDirection == BrnOverlayPopDirection.right) { - _right = _showRect.right; + _right = showRect.right; } else if (widget.popDirection == BrnOverlayPopDirection.bottom) { - _bottom = _showRect.bottom; + _bottom = showRect.bottom; } else if (widget.popDirection == BrnOverlayPopDirection.top) { // 在targetView上方 - _top = _showRect.top; + _top = showRect.top; } } } class BrnOverlayController { - OverlayEntry _entry; + OverlayEntry? _entry; BuildContext context; bool _isOverlayShowing = false; @@ -239,8 +248,10 @@ class BrnOverlayController { BrnOverlayController._(this.context, this._entry); showOverlay() { - Overlay.of(context).insert(_entry); - _isOverlayShowing = true; + if (_entry != null) { + Overlay.of(context)?.insert(_entry!); + _isOverlayShowing = true; + } } void removeOverlay() { diff --git a/lib/src/components/popup/brn_popup_window.dart b/lib/src/components/popup/brn_popup_window.dart index 640fe796..738be500 100644 --- a/lib/src/components/popup/brn_popup_window.dart +++ b/lib/src/components/popup/brn_popup_window.dart @@ -6,7 +6,6 @@ import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/utils/brn_text_util.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// popup window 位于 targetView 的方向 enum BrnPopupDirection { @@ -19,99 +18,120 @@ enum BrnPopupDirection { /// 通用 Popup Window 提示,带三角号 class BrnPopupWindow extends StatefulWidget { - /// 依附的组件的Context + /// 依附的组件的 Context final BuildContext context; - /// 箭头的高度 + /// 箭头的高度,默认 6 final double arrowHeight; /// 要显示的文本 - final String text; + final String? text; - /// 依附的组件和BrnPopUpWindow组件共同持有的GlobalKey + /// 依附的组件和 BrnPopUpWindow 组件共同持有的 GlobalKey final GlobalKey popKey; /// 要显示文本的样式 - final TextStyle textStyle; + final TextStyle? textStyle; - /// popUpWindow的背景颜色 - final Color backgroundColor; + /// popUpWindow 的背景颜色,使用 [showPopWindow] 方法时,默认值为 Color(0xFF1A1A1A) + final Color? backgroundColor; - /// 边框颜色 - final Color borderColor; + /// 边框颜色,[showPopWindow] 方法时,默认值为 Colors.transparent + final Color? borderColor; - /// 是否有关闭图标 + /// 是否有关闭图标,默认为 false,不显示 final bool isShowCloseIcon; - /// 距离targetView偏移量 + /// 距离 targetView 偏移量,默认为 0 final double offset; - /// popUpWindow位于targetView的方向 + /// popUpWindow 位于 targetView 的方向,默认为 [BrnPopupDirection.bottom] final BrnPopupDirection popDirection; - /// 自定义widget - final Widget widget; + /// 自定义 widget + final Widget? widget; - /// 容器内边距 + /// 容器内边距,默认为 EdgeInsets.only(left: 18, top: 14, right: 18, bottom: 14) final EdgeInsets paddingInsets; - /// 容器圆角 + /// 容器圆角,默认为 4 final double borderRadius; - /// 是否能多行显示 默认false:单行显示 + /// 是否能多行显,默认 false,单行显示 final bool canWrap; - /// 默认距离TargetView边线的距离,默认:20 + /// 距离 targetView 边线的距离,默认 20 final double spaceMargin; - /// 箭头偏移量 - final double arrowOffset; + /// 箭头图标水平方向的绝对偏移量,为 null 时则自动计算 + final double? arrowOffset; - /// popUpWindow消失回调 - final VoidCallback onDismiss; + /// popUpWindow 消失回调,此回调会在 pop 之后执行 + final VoidCallback? onDismiss; - /// popWindow距离底部的距离小于此值的时候, - /// 自动将popWindow在targetView上面弹出 + /// popWindow 距离底部的距离小于此值的时候, + /// 自动将 popWindow 在 targetView 上面弹出 final double turnOverFromBottom; - const BrnPopupWindow(this.context, - {this.text, - this.popKey, - this.arrowHeight, + BrnPopupWindow(this.context, + {Key? key, + this.text, + required this.popKey, + this.arrowHeight = 6.0, this.textStyle, this.backgroundColor, - this.isShowCloseIcon, - this.offset, - this.popDirection, + this.isShowCloseIcon = false, + this.offset = 0, + this.popDirection = BrnPopupDirection.bottom, this.widget, - this.paddingInsets, - this.borderRadius, + this.paddingInsets = + const EdgeInsets.only(left: 18, top: 14, right: 18, bottom: 14), + this.borderRadius = 4, this.borderColor, this.canWrap = false, - this.spaceMargin, + this.spaceMargin = 20, this.arrowOffset, this.onDismiss, - this.turnOverFromBottom = 50.0}); + this.turnOverFromBottom = 50.0}) + : super(key: key); - // 显示popUpWindow - static void showPopWindow(context, String text, GlobalKey popKey, + /// 显示 popUpWindow + /// [text] 显示的文本内容 + /// [popKey] 依附的组件和 BrnPopUpWindow 组件共同持有的 GlobalKey + /// [popDirection] 箭头的方向 + /// [arrowHeight] 箭头的高度,默认 6 + /// [textStyle] 文本样式 + /// [backgroundColor] popUpWindow 的背景颜色,默认 Color(0xFF1A1A1A) + /// [hasCloseIcon] 是否显示关闭图标,默认为 false,不显示 + /// [offset] 距离 targetView 垂直方向的偏移量 + /// [widget] 自定义 pop 视图 + /// [paddingInsets] 容器内边距,默认为 EdgeInsets.only(left: 18, top: 14, right: 18, bottom: 14) + /// [borderRadius] 容器圆角,默认为 4 + /// [borderColor] 边框颜色,默认为 Colors.transparent + /// [borderWidth] 边框宽度,默认为 1 + /// [canWrap] 是否能多行显,默认 false,单行显示 + /// [spaceMargin] 距离 targetView 边线的距离,默认 20 + /// [arrowOffset] 箭头图标水平方向的绝对偏移量,为 null 时则自动计算 + /// [dismissCallback] popUpWindow 消失回调,此回调会在 pop 之后执行 + /// [turnOverFromBottom] popWindow 小于此值的时候,自动将 popWindow 在 targetView 上面弹出,默认 50 + static void showPopWindow(context, String? text, GlobalKey popKey, {BrnPopupDirection popDirection = BrnPopupDirection.bottom, double arrowHeight = 6.0, - TextStyle textStyle = + TextStyle? textStyle = const TextStyle(fontSize: 16, color: Color(0xFFFFFFFF)), - Color backgroundColor = const Color(0xFF1A1A1A), + Color? backgroundColor = const Color(0xFF1A1A1A), bool hasCloseIcon = false, double offset = 0, - Widget widget, + Widget? widget, EdgeInsets paddingInsets = const EdgeInsets.only(left: 18, top: 14, right: 18, bottom: 14), double borderRadius = 8, - Color borderColor = Colors.transparent, + Color? borderColor = Colors.transparent, double borderWidth = 1, bool canWrap = false, double spaceMargin = 20, - double arrowOffset, - VoidCallback dismissCallback, + double? arrowOffset, + VoidCallback? dismissCallback, double turnOverFromBottom = 50.0}) { Navigator.push( context, @@ -144,10 +164,10 @@ class BrnPopupWindow extends StatefulWidget { class _BrnPopupWindowState extends State { /// targetView的位置 - Rect _showRect; + Rect? _showRect; /// 屏幕的尺寸 - Size _screenSize; + late Size _screenSize; /// 箭头和左右侧边线间距 double _arrowSpacing = 18; @@ -156,65 +176,80 @@ class _BrnPopupWindowState extends State { bool _expandedRight = true; /// popUpWindow在中线两侧的具体位置 - double _left, _right, _top, _bottom; + double _left = 0; + double _right = 0; + double _top = 0; + double _bottom = 0; /// 箭头展示方向 - BrnPopupDirection _popDirection; + late BrnPopupDirection _popDirection; /// 去除透明度的边框色 - Color _borderColor; + late Color _borderColor; /// 去除透明度的背景颜色 - Color _backgroundColor; + late Color _backgroundColor; @override void initState() { super.initState(); this._showRect = _getWidgetGlobalRect(widget.popKey); this._screenSize = window.physicalSize / window.devicePixelRatio; - _borderColor = widget.borderColor.withAlpha(255); - _backgroundColor = widget.backgroundColor.withAlpha(255); + _borderColor = (widget.borderColor ?? Colors.transparent).withAlpha(255); + _backgroundColor = + (widget.backgroundColor ?? Colors.transparent).withAlpha(255); _popDirection = widget.popDirection; - _calculateOffset(); + if (this._showRect != null) { + _calculateOffset(this._showRect!); + } } // 获取targetView的位置 - Rect _getWidgetGlobalRect(GlobalKey key) { - if (key == null) { - return null; + Rect? _getWidgetGlobalRect(GlobalKey key) { + BuildContext? ctx = key.currentContext; + RenderObject? obj; + if (ctx != null) { + obj = ctx.findRenderObject(); } - RenderBox renderBox = key.currentContext.findRenderObject(); - var offset = renderBox.localToGlobal(Offset.zero); - return Rect.fromLTWH( - offset.dx, offset.dy, renderBox.size.width, renderBox.size.height); + if (obj != null && obj is RenderBox) { + RenderBox renderBox = obj; + var offset = renderBox.localToGlobal(Offset.zero); + return Rect.fromLTWH( + offset.dx, offset.dy, renderBox.size.width, renderBox.size.height); + } + return null; } // 计算popUpWindow显示的位置 - void _calculateOffset() { - if (_showRect.center.dx < _screenSize.width / 2) { + void _calculateOffset(Rect showRect) { + if (showRect.center.dx < _screenSize.width / 2) { // popUpWindow向右侧延伸 _expandedRight = true; - _left = _showRect.left + widget.spaceMargin; + _left = showRect.left; } else { // popUpWindow向左侧延伸 _expandedRight = false; - _right = _screenSize.width - _showRect.right + widget.spaceMargin; + _right = _screenSize.width - showRect.right + widget.spaceMargin; } if (_popDirection == BrnPopupDirection.bottom) { // 在targetView下方 - _top = _showRect.height + _showRect.top + widget.offset; + _top = showRect.height + showRect.top + widget.offset; if ((_screenSize.height - _top) < widget.turnOverFromBottom) { _popDirection = BrnPopupDirection.top; - _bottom = _screenSize.height - _showRect.top + widget.offset; + _bottom = _screenSize.height - showRect.top + widget.offset; } } else if (_popDirection == BrnPopupDirection.top) { // 在targetView上方 - _bottom = _screenSize.height - _showRect.top + widget.offset; + _bottom = _screenSize.height - showRect.top + widget.offset; } } @override Widget build(BuildContext context) { + if (this._showRect == null) { + Navigator.pop(context); + return Container(); + } return ExcludeSemantics( excluding: true, child: WillPopScope( @@ -223,7 +258,7 @@ class _BrnPopupWindowState extends State { onTap: () { Navigator.pop(context); if (widget.onDismiss != null) { - widget.onDismiss(); + widget.onDismiss!(); } }, child: Material( @@ -239,7 +274,7 @@ class _BrnPopupWindowState extends State { ), onWillPop: () { if (widget.onDismiss != null) { - widget.onDismiss(); + widget.onDismiss!(); } return Future.value(true); }), @@ -252,7 +287,7 @@ class _BrnPopupWindowState extends State { ? Positioned( left: widget.arrowOffset ?? _left + - (_showRect.width - _arrowSpacing) / 2 - + (_showRect!.width - _arrowSpacing) / 2 - widget.spaceMargin, top: _popDirection == BrnPopupDirection.bottom ? _top - widget.arrowHeight @@ -271,7 +306,7 @@ class _BrnPopupWindowState extends State { : Positioned( right: widget.arrowOffset ?? _right + - (_showRect.width - _arrowSpacing) / 2 - + (_showRect!.width - _arrowSpacing) / 2 - widget.spaceMargin, top: _popDirection == BrnPopupDirection.bottom ? _top - widget.arrowHeight @@ -303,7 +338,7 @@ class _BrnPopupWindowState extends State { decoration: BoxDecoration( color: _backgroundColor, border: Border.all(color: _borderColor, width: 0.5), - borderRadius: BorderRadius.circular(widget.borderRadius ?? 4)), + borderRadius: BorderRadius.circular(widget.borderRadius)), constraints: BoxConstraints( maxWidth: _expandedRight ? _screenSize.width - _left @@ -324,7 +359,7 @@ class _BrnPopupWindowState extends State { child: Padding( padding: EdgeInsets.only(left: 6), child: BrunoTools.getAssetImage( - BrnAsset.ICON_POPUP_CLOSE), + BrnAsset.iconPopupClose), )) : TextSpan(text: "") ])) @@ -334,7 +369,7 @@ class _BrnPopupWindowState extends State { Flexible( fit: FlexFit.loose, child: Text( - widget.text, + widget.text ?? '', maxLines: 1, overflow: TextOverflow.ellipsis, style: widget.textStyle, @@ -344,7 +379,7 @@ class _BrnPopupWindowState extends State { ? Padding( padding: EdgeInsets.only(left: 6), child: BrunoTools.getAssetImage( - BrnAsset.ICON_POPUP_CLOSE), + BrnAsset.iconPopupClose), ) : Text("") ], @@ -360,9 +395,9 @@ class _TrianglePainter extends CustomPainter { Color borderColor; _TrianglePainter({ - this.isDownArrow, - this.color, - this.borderColor, + required this.isDownArrow, + required this.color, + required this.borderColor, }); @override @@ -413,16 +448,16 @@ class BrnPopupRoute extends PopupRoute { final Duration _duration = Duration(milliseconds: 200); Widget child; - BrnPopupRoute({@required this.child}); + BrnPopupRoute({required this.child}); @override - Color get barrierColor => null; + Color? get barrierColor => null; @override bool get barrierDismissible => true; @override - String get barrierLabel => null; + String? get barrierLabel => null; @override Widget buildPage(BuildContext context, Animation animation, @@ -442,7 +477,7 @@ typedef BrnPopupListItemClick = Function(int index, String item); /// popup 用于构造自定义的 Item /// [index] Item 的索引 /// [item] Item 内容 -typedef BrnPopupListItemBuilder = Widget Function(int index, String item); +typedef BrnPopupListItemBuilder = Widget? Function(int index, String item); /// 基于 PopUpWindow 的 弹窗列表工具类 class BrnPopupListWindow { @@ -453,10 +488,10 @@ class BrnPopupListWindow { /// [itemBuilder] 自定义 item 构造方法 /// [onItemClick] item 点击回调 static void showButtonPanelPopList(context, GlobalKey popKey, - {List data, + {List? data, BrnPopupDirection popDirection = BrnPopupDirection.bottom, - BrnPopupListItemBuilder itemBuilder, - BrnPopupListItemClick onItemClick}) { + BrnPopupListItemBuilder? itemBuilder, + BrnPopupListItemClick? onItemClick}) { TextStyle textStyle = TextStyle( color: BrnThemeConfigurator.instance .getConfig() @@ -497,7 +532,7 @@ class BrnPopupListWindow { padding: EdgeInsets.only(top: 6, bottom: 6), child: Column( children: _getItems(context, minWidth, maxWidth, - itemBuilder, textStyle, data, onItemClick, null), + itemBuilder, textStyle, data!, onItemClick, null), ), ), ), @@ -517,18 +552,18 @@ class BrnPopupListWindow { /// [onItemClick] item 点击回调 /// [onDismiss] popUpWindow消失回调 static void showPopListWindow(context, GlobalKey popKey, - {List data, + {List? data, BrnPopupDirection popDirection = BrnPopupDirection.bottom, double offset = 0, - BrnPopupListItemClick onItemClick, - VoidCallback onDismiss}) { + BrnPopupListItemClick? onItemClick, + VoidCallback? onDismiss}) { double arrowHeight = 6.0; double borderRadius = 4; double spaceMargin = 0; double minWidth = 100; double maxWidth = 150; double maxHeight = 200; - double arrowOffset; + double? arrowOffset; Color borderColor = BrnThemeConfigurator.instance.getConfig().commonConfig.dividerColorBase; Color backgroundColor = Colors.white; @@ -565,7 +600,7 @@ class BrnPopupListWindow { padding: EdgeInsets.only(top: 6, bottom: 6), child: Column( children: _getItems(context, minWidth, maxWidth, null, - textStyle, data, onItemClick, onDismiss), + textStyle, data!, onItemClick, onDismiss), ), ), ), @@ -582,13 +617,12 @@ class BrnPopupListWindow { BuildContext context, double minWidth, double maxWidth, - BrnPopupListItemBuilder itemBuilder, + BrnPopupListItemBuilder? itemBuilder, TextStyle textStyle, List data, - BrnPopupListItemClick onItemClick, - VoidCallback onDismiss) { - double textMaxWidth = _getMaxWidth( - textStyle ?? TextStyle(fontSize: 16, color: Color(0xFFFFFFFF)), data); + BrnPopupListItemClick? onItemClick, + VoidCallback? onDismiss) { + double textMaxWidth = _getMaxWidth(textStyle, data); if (textMaxWidth + 52 < minWidth) { textMaxWidth = minWidth; } else if (textMaxWidth + 52 > maxWidth) { @@ -596,34 +630,32 @@ class BrnPopupListWindow { } else { textMaxWidth = textMaxWidth + 52; } - return data?.map((f) { - return GestureDetector( - onTap: () { - if (onItemClick != null) { - dynamic isIntercept = onItemClick(data.indexOf(f), f); - if ((isIntercept is bool) && isIntercept) return; - } - Navigator.pop(context); - if (onDismiss != null) { - onDismiss(); - } - }, - child: Container( - width: textMaxWidth, - alignment: Alignment.center, - color: Colors.transparent, - padding: - EdgeInsets.only(left: 26, right: 26, top: 6, bottom: 6), - child: _getTextWidget(itemBuilder, data, f, textStyle))); - })?.toList() ?? - List(); + return data.map((f) { + return GestureDetector( + onTap: () { + if (onItemClick != null) { + dynamic isIntercept = onItemClick(data.indexOf(f), f); + if ((isIntercept is bool) && isIntercept) return; + } + Navigator.pop(context); + if (onDismiss != null) { + onDismiss(); + } + }, + child: Container( + width: textMaxWidth, + alignment: Alignment.center, + color: Colors.transparent, + padding: EdgeInsets.only(left: 26, right: 26, top: 6, bottom: 6), + child: _getTextWidget(itemBuilder, data, f, textStyle))); + }).toList(); } /// 遍历数据,计算每个 Item 内容,返回所有 Item 可展示的最大宽度 static double _getMaxWidth(TextStyle textStyle, List data) { double maxWidth = 0; if (!BrunoTools.isEmpty(data)) { - Size maxWidthSize; + Size? maxWidthSize; for (String entity in data) { Size size = BrnTextUtil.textSize(entity, textStyle); if (maxWidthSize == null) { @@ -634,12 +666,14 @@ class BrnPopupListWindow { } } } - maxWidth = maxWidthSize.width; + if (maxWidthSize != null) { + maxWidth = maxWidthSize.width; + } } return maxWidth; } - static Widget _getTextWidget(BrnPopupListItemBuilder itemBuilder, + static Widget _getTextWidget(BrnPopupListItemBuilder? itemBuilder, List data, String text, TextStyle textStyle) { if (itemBuilder == null) { return _getDefaultText(text, textStyle); @@ -654,11 +688,7 @@ class BrnPopupListWindow { text, overflow: TextOverflow.ellipsis, maxLines: 1, - style: textStyle ?? - TextStyle( - fontSize: 16, - color: Color(0xFFFFFFFF), - ), + style: textStyle, ); } } diff --git a/lib/src/components/radio/brn_checkbox.dart b/lib/src/components/radio/brn_checkbox.dart index 73d3f7e5..80437ca6 100644 --- a/lib/src/components/radio/brn_checkbox.dart +++ b/lib/src/components/radio/brn_checkbox.dart @@ -21,10 +21,10 @@ class BrnCheckbox extends StatefulWidget { /// 选择按钮的padding /// 默认EdgeInsets.all(5) - final EdgeInsets iconPadding; + final EdgeInsets? iconPadding; /// 配合使用的控件,比如卡片或者text - final Widget child; + final Widget? child; /// 控件是否在选择按钮的右边, /// true时 控件在选择按钮右边 @@ -43,18 +43,18 @@ class BrnCheckbox extends StatefulWidget { /// 默认值HitTestBehavior.translucent控制widget.onRadioItemClick触发的点击范围 final HitTestBehavior behavior; - const BrnCheckbox( - {Key key, - @required this.radioIndex, - @required this.onValueChangedAtIndex, - this.disable = false, - this.isSelected = false, - this.iconPadding, - this.child, - this.childOnRight = true, - this.mainAxisAlignment = MainAxisAlignment.start, - this.mainAxisSize = MainAxisSize.min, - this.behavior = HitTestBehavior.translucent}); + const BrnCheckbox({ + Key? key, + required this.radioIndex, + required this.onValueChangedAtIndex, + this.disable = false, + this.isSelected = false, + this.iconPadding, + this.child, + this.childOnRight = true, + this.mainAxisAlignment = MainAxisAlignment.start, + this.mainAxisSize = MainAxisSize.min, + this.behavior = HitTestBehavior.translucent}); @override State createState() { @@ -63,7 +63,7 @@ class BrnCheckbox extends StatefulWidget { } class BrnCheckboxState extends State { - bool _isSelected; + late bool _isSelected; @override void initState() { @@ -82,12 +82,12 @@ class BrnCheckboxState extends State { mainAxisAlignment: widget.mainAxisAlignment, mainAxisSize: widget.mainAxisSize, selectedImage: BrunoTools.getAssetImageWithBandColor( - BrnAsset.ICON_RADIO_MULTI_SELECTED), - unselectedImage: BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_UNSELECTED), + BrnAsset.iconRadioMultiSelected), + unselectedImage: BrunoTools.getAssetImage(BrnAsset.iconRadioUnSelected), disSelectedImage: - BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_DISABLE_SINGLE_SELECTED), + BrunoTools.getAssetImage(BrnAsset.iconRadioDisableSingleSelected), disUnselectedImage: - BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_DISABLE_UNSELECTED), + BrunoTools.getAssetImage(BrnAsset.iconRadioDisableUnselected), child: widget.child, onRadioItemClick: () { setState(() { diff --git a/lib/src/components/radio/brn_radio_button.dart b/lib/src/components/radio/brn_radio_button.dart index 257bf65a..ef3bd3ec 100644 --- a/lib/src/components/radio/brn_radio_button.dart +++ b/lib/src/components/radio/brn_radio_button.dart @@ -21,10 +21,10 @@ class BrnRadioButton extends StatelessWidget { /// 选择按钮的padding /// 默认EdgeInsets.all(5) - final EdgeInsets iconPadding; + final EdgeInsets? iconPadding; /// 配合使用的控件,比如卡片或者text - final Widget child; + final Widget? child; /// 控件是否在选择按钮的右边, /// true时 控件在选择按钮右边 @@ -43,18 +43,19 @@ class BrnRadioButton extends StatelessWidget { /// 默认值HitTestBehavior.translucent控制widget.onRadioItemClick触发的点击范围 final HitTestBehavior behavior; - const BrnRadioButton( - {Key key, - @required this.radioIndex, - @required this.onValueChangedAtIndex, - this.disable = false, - this.isSelected = false, - this.iconPadding, - this.child, - this.childOnRight = true, - this.mainAxisAlignment = MainAxisAlignment.start, - this.mainAxisSize = MainAxisSize.min, - this.behavior = HitTestBehavior.translucent}); + const BrnRadioButton({ + Key? key, + required this.radioIndex, + required this.onValueChangedAtIndex, + this.disable = false, + this.isSelected = false, + this.iconPadding, + this.child, + this.childOnRight = true, + this.mainAxisAlignment = MainAxisAlignment.start, + this.mainAxisSize = MainAxisSize.min, + this.behavior = HitTestBehavior.translucent + }); @override Widget build(BuildContext context) { @@ -67,12 +68,12 @@ class BrnRadioButton extends StatelessWidget { mainAxisAlignment: mainAxisAlignment, mainAxisSize: mainAxisSize, selectedImage: BrunoTools.getAssetImageWithBandColor( - BrnAsset.ICON_RADIO_SINGLE_SELECTED), - unselectedImage: BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_UNSELECTED), + BrnAsset.iconRadioSingleSelected), + unselectedImage: BrunoTools.getAssetImage(BrnAsset.iconRadioUnSelected), disSelectedImage: - BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_DISABLE_MULTI_SELECTED), + BrunoTools.getAssetImage(BrnAsset.iconRadioDisableMultiSelected), disUnselectedImage: - BrunoTools.getAssetImage(BrnAsset.ICON_RADIO_DISABLE_UNSELECTED), + BrunoTools.getAssetImage(BrnAsset.iconRadioDisableUnselected), child: child, onRadioItemClick: () { onValueChangedAtIndex(radioIndex, true); diff --git a/lib/src/components/radio/brn_radio_core.dart b/lib/src/components/radio/brn_radio_core.dart index 8f5c027a..2d0af1e0 100644 --- a/lib/src/components/radio/brn_radio_core.dart +++ b/lib/src/components/radio/brn_radio_core.dart @@ -1,6 +1,5 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; /// 描述: radio组件 /// 1. 支持单选/多选 @@ -21,10 +20,10 @@ class BrnRadioCore extends StatefulWidget { /// 选择按钮的padding /// 默认EdgeInsets.all(5) - final EdgeInsets iconPadding; + final EdgeInsets? iconPadding; /// 配合使用的控件,比如卡片或者text - final Widget child; + final Widget? child; /// 控件是否在选择按钮的右边, /// true时 控件在选择按钮右边 @@ -40,22 +39,22 @@ class BrnRadioCore extends StatefulWidget { /// 默认值MainAxisSize.min final MainAxisSize mainAxisSize; - final Image selectedImage; + final Image? selectedImage; - final Image unselectedImage; + final Image? unselectedImage; - final Image disSelectedImage; + final Image? disSelectedImage; - final Image disUnselectedImage; + final Image? disUnselectedImage; - final VoidCallback onRadioItemClick; + final VoidCallback? onRadioItemClick; /// 默认值HitTestBehavior.translucent控制widget.onRadioItemClick触发的点击范围 final HitTestBehavior behavior; const BrnRadioCore( - {Key key, - @required this.radioIndex, + {Key? key, + required this.radioIndex, this.disable = false, this.isSelected = false, this.iconPadding, @@ -76,8 +75,8 @@ class BrnRadioCore extends StatefulWidget { } class _BrnRadioCoreState extends State { - bool _isSelected; - bool _disable; + late bool _isSelected; + late bool _disable; @override void initState() { @@ -119,12 +118,12 @@ class _BrnRadioCoreState extends State { // 没设置左右widget的时候就不返回row radioWidget = icon; } else { - List list = List(); + List list = []; if (widget.childOnRight) { list.add(icon); - list.add(widget.child); + list.add(widget.child!); } else { - list.add(widget.child); + list.add(widget.child!); list.add(icon); } radioWidget = Row( @@ -139,7 +138,9 @@ class _BrnRadioCoreState extends State { behavior: widget.behavior, onTap: () { if (widget.disable == true) return; - widget.onRadioItemClick(); + if (widget.onRadioItemClick != null) { + widget.onRadioItemClick!(); + } // if (widget.onValueChangedAtIndex != null) { // if (widget.radioType == BrnRadioType.single) { // // 单选 diff --git a/lib/src/components/rating/brn_rating_star.dart b/lib/src/components/rating/brn_rating_star.dart index f8d1a49c..605121f4 100644 --- a/lib/src/components/rating/brn_rating_star.dart +++ b/lib/src/components/rating/brn_rating_star.dart @@ -40,13 +40,13 @@ class BrnRatingStar extends StatefulWidget { final bool canRatingZero; /// 单颗星星视图的自定义构造器 - final BrnRatingStarBuilder starBuilder; + final BrnRatingStarBuilder? starBuilder; /// 如果设置了,就支持编辑 - final ValueChanged onSelected; + final ValueChanged? onSelected; const BrnRatingStar({ - Key key, + Key? key, this.count = DEFAULT_COUNT, this.selectedCount = 0, this.space = DEFAULT_SPACE, @@ -60,7 +60,7 @@ class BrnRatingStar extends StatefulWidget { } class _BrnRatingStarState extends State { - double currSelected; + late double currSelected; @override void initState() { @@ -84,7 +84,7 @@ class _BrnRatingStarState extends State { } List _getContent() { - List list = List(); + List list = []; for (var i = 0; i < widget.count; i++) { RatingState state; if (i < currSelected.floor()) { @@ -95,7 +95,7 @@ class _BrnRatingStarState extends State { state = RatingState.unselect; } var rating = widget.starBuilder != null - ? widget.starBuilder(state) + ? widget.starBuilder!(state) : _buildRating(state); if (widget.onSelected != null) { @@ -108,7 +108,7 @@ class _BrnRatingStarState extends State { } else { currSelected = (i + 1).toDouble(); } - widget.onSelected(currSelected.toInt()); + widget.onSelected!(currSelected.toInt()); setState(() {}); }, behavior: HitTestBehavior.opaque, @@ -130,12 +130,12 @@ class _BrnRatingStarState extends State { Widget _buildRating(RatingState state) { switch (state) { case RatingState.select: - return BrunoTools.getAssetSizeImage(BrnAsset.ICON_STAR, 16, 16); + return BrunoTools.getAssetSizeImage(BrnAsset.iconStar, 16, 16); case RatingState.half: - return BrunoTools.getAssetSizeImage(BrnAsset.ICON_STAR_HALF, 16, 16); + return BrunoTools.getAssetSizeImage(BrnAsset.iconStarHalf, 16, 16); case RatingState.unselect: default: - return BrunoTools.getAssetSizeImage(BrnAsset.ICON_STAR, 16, 16, + return BrunoTools.getAssetSizeImage(BrnAsset.iconStar, 16, 16, color: Color(0xFFF0F0F0)); } } diff --git a/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart b/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart index 9f0945df..29b3fea2 100644 --- a/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart +++ b/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart @@ -1,3 +1,5 @@ + + import 'dart:async'; import 'dart:ui'; @@ -18,15 +20,15 @@ class BrnAnchorTab extends StatefulWidget { final BrnAnchorTabBarStyle tabBarStyle; final AnchorTabWidgetIndexedBuilder widgetIndexedBuilder; final AnchorTabIndexedBuilder tabIndexedBuilder; - final Widget tabDivider; + final Widget? tabDivider; //设置tab与widget的个数 final int itemCount; BrnAnchorTab( - {@required this.widgetIndexedBuilder, - @required this.tabIndexedBuilder, - @required this.itemCount, + {required this.widgetIndexedBuilder, + required this.tabIndexedBuilder, + required this.itemCount, this.tabDivider, this.tabBarStyle = const BrnAnchorTabBarStyle()}); @@ -38,31 +40,31 @@ class BrnAnchorTab extends StatefulWidget { class _BrnScrollAnchorTabWidgetState extends State with SingleTickerProviderStateMixin { //用于控制 滑动 - ScrollController scrollController; + late ScrollController _scrollController; //用于 滑动 和 tab 之间的通信 - StreamController streamController; + late StreamController _streamController; //用于控制tab - TabController tabController; + late TabController _tabController; //滑动组件的 key - GlobalKey key; + late GlobalKey _key; //当前选中的索引 - int currentIndex; + int currentIndex = 0; //滑动组件的元素、 - List bodyWidgetList; + late List _bodyWidgetList; //滑动组件的元素的key - List bodyKeyList; + late List _bodyKeyList; //每个元素在滑动组件中的位置 - List cardOffsetList; + late List _cardOffsetList; //tab - List tabList; + late List _tabList; //是否点击滑动 bool tab = false; @@ -72,29 +74,28 @@ class _BrnScrollAnchorTabWidgetState extends State @override void initState() { - streamController = StreamController(); - scrollController = ScrollController(); + _streamController = StreamController(); + _scrollController = ScrollController(); - key = GlobalKey(); - cardOffsetList = List.filled(widget.itemCount, -1.0); - bodyWidgetList = List(); - bodyKeyList = List(); - tabList = List(); + _key = GlobalKey(); + _cardOffsetList = List.filled(widget.itemCount, -1.0); + _bodyWidgetList = []; + _bodyKeyList = []; + _tabList = []; - currentIndex = 0; - tabController = TabController(length: widget.itemCount, vsync: this); + _tabController = TabController(length: widget.itemCount, vsync: this); fillKeyList(); fillList(); fillTab(); - WidgetsBinding.instance.addPostFrameCallback((da) { + WidgetsBinding.instance!.addPostFrameCallback((da) { fillOffset(); - scrollController.addListener(() { + _scrollController.addListener(() { updateOffset(); - currentIndex = createIndex(scrollController.offset); + currentIndex = createIndex(_scrollController.offset); //防止再次 发送消息 - if (!tab) streamController.add(currentIndex); + if (!tab) _streamController.add(currentIndex); }); }); @@ -106,11 +107,11 @@ class _BrnScrollAnchorTabWidgetState extends State return Column( mainAxisSize: MainAxisSize.min, children: [ - StreamBuilder( + StreamBuilder( initialData: currentIndex, - stream: streamController.stream, + stream: _streamController.stream, builder: (context, snap) { - tabController.index = currentIndex; + _tabController.index = currentIndex; return BrnTabBar( indicatorColor: widget.tabBarStyle.indicatorColor, indicatorWeight: widget.tabBarStyle.indicatorWeight, @@ -121,14 +122,14 @@ class _BrnScrollAnchorTabWidgetState extends State unselectedLabelColor: widget.tabBarStyle.unselectedLabelColor, unselectedLabelStyle: widget.tabBarStyle.unselectedLabelStyle, dragStartBehavior: widget.tabBarStyle.dragStartBehavior, - controller: tabController, - tabs: tabList, + controller: _tabController, + tabs: _tabList, onTap: (state, index) { state.refreshBadgeState(index); currentIndex = index; tab = true; - scrollController - .animateTo(cardOffsetList[index], + _scrollController + .animateTo(_cardOffsetList[index], duration: Duration(milliseconds: 100), curve: Curves.linear) .whenComplete(() { @@ -147,10 +148,10 @@ class _BrnScrollAnchorTabWidgetState extends State child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, - children: bodyWidgetList, + children: _bodyWidgetList, ), - key: key, - controller: scrollController, + key: _key, + controller: _scrollController, ), ) ], @@ -158,59 +159,55 @@ class _BrnScrollAnchorTabWidgetState extends State } void fillList() { - if (widget.widgetIndexedBuilder != null) { - for (int i = 0, n = widget.itemCount; i < n; i++) { - bodyWidgetList.add( - Container( - key: bodyKeyList[i], - child: widget.widgetIndexedBuilder(context, i)), - ); - } + for (int i = 0, n = widget.itemCount; i < n; i++) { + _bodyWidgetList.add( + Container( + key: _bodyKeyList[i], + child: widget.widgetIndexedBuilder(context, i)), + ); } } void fillKeyList() { for (int i = 0, n = widget.itemCount; i < n; i++) { - bodyKeyList.add(GlobalKey()); + _bodyKeyList.add(GlobalKey()); } } void fillOffset() { - Offset globalToLocal = (key.currentContext.findRenderObject() as RenderBox) + Offset globalToLocal = (_key.currentContext!.findRenderObject() as RenderBox) .localToGlobal(Offset.zero); listDy = globalToLocal.dy; for (int i = 0, n = widget.itemCount; i < n; i++) { - if (cardOffsetList[i] == -1.0) if (bodyKeyList[i].currentContext != + if (_cardOffsetList[i] == -1.0) if (_bodyKeyList[i].currentContext != null) { double cardOffset = - (bodyKeyList[i].currentContext.findRenderObject() as RenderBox) + (_bodyKeyList[i].currentContext!.findRenderObject() as RenderBox) .localToGlobal(Offset.zero) //相对于原点 控件的位置 .dy; //y点坐标 - cardOffsetList[i] = cardOffset + scrollController.offset - listDy; + _cardOffsetList[i] = cardOffset + _scrollController.offset - listDy; } } } void fillTab() { - if (widget.tabIndexedBuilder != null) { for (int i = 0, n = widget.itemCount; i < n; i++) { - tabList.add(widget.tabIndexedBuilder(context, i)); + _tabList.add(widget.tabIndexedBuilder(context, i)); } - } } void updateOffset() { for (int i = 0, n = widget.itemCount; i < n; i++) { - if (cardOffsetList[i] == -1.0) if (bodyKeyList[i].currentContext != + if (_cardOffsetList[i] == -1.0) if (_bodyKeyList[i].currentContext != null) { double cardOffset = - (bodyKeyList[i].currentContext.findRenderObject() as RenderBox) + (_bodyKeyList[i].currentContext!.findRenderObject() as RenderBox) .localToGlobal(Offset.zero) //相对于原点 控件的位置 .dy; //y点坐标 - cardOffsetList[i] = cardOffset + scrollController.offset - listDy; + _cardOffsetList[i] = cardOffset + _scrollController.offset - listDy; } } } @@ -219,7 +216,7 @@ class _BrnScrollAnchorTabWidgetState extends State int createIndex(double offset) { int index = 0; for (int i = 0, n = widget.itemCount; i < n; i++) { - if (offset >= cardOffsetList[i] && (offset <= cardOffsetList[i + 1])) { + if (offset >= _cardOffsetList[i] && (offset <= _cardOffsetList[i + 1])) { return i; } } @@ -229,28 +226,28 @@ class _BrnScrollAnchorTabWidgetState extends State @override void dispose() { super.dispose(); - tabController.dispose(); - streamController.close(); - scrollController.dispose(); + _tabController.dispose(); + _streamController.close(); + _scrollController.dispose(); } } class BrnAnchorTabBarStyle { - final Color indicatorColor; + final Color? indicatorColor; final double indicatorWeight; final EdgeInsetsGeometry indicatorPadding; - final Color labelColor; + final Color? labelColor; - final Color unselectedLabelColor; + final Color? unselectedLabelColor; - final TextStyle labelStyle; + final TextStyle? labelStyle; - final EdgeInsetsGeometry labelPadding; + final EdgeInsetsGeometry? labelPadding; - final TextStyle unselectedLabelStyle; + final TextStyle? unselectedLabelStyle; final DragStartBehavior dragStartBehavior; diff --git a/lib/src/components/selectcity/brn_az_common.dart b/lib/src/components/selectcity/brn_az_common.dart index 6dcb7bcf..82db6329 100644 --- a/lib/src/components/selectcity/brn_az_common.dart +++ b/lib/src/components/selectcity/brn_az_common.dart @@ -2,16 +2,16 @@ import 'package:flutter/material.dart'; /// ISuspension Bean. abstract class ISuspensionBean { - bool isShowSuspension; - String name; - String tag; //Suspension Tag + bool isShowSuspension = false; + String name = ""; + String tag = ""; //Suspension Tag } /// AzListView Header. class AzListViewHeader { AzListViewHeader({ - @required this.height, - @required this.builder, + required this.height, + required this.builder, this.tag = "↑", }); @@ -24,7 +24,7 @@ class AzListViewHeader { class SuspensionUtil { /// sort list by suspension tag. /// 根据[A-Z]排序。 - static void sortListBySuspensionTag(List list) { + static void sortListBySuspensionTag(List? list) { if (list == null || list.isEmpty) return; list.sort((a, b) { if (a.tag == "@" || b.tag == "#") { @@ -39,10 +39,10 @@ class SuspensionUtil { /// get index data list by suspension tag. /// 获取索引列表。 - static List getTagIndexList(List list) { - List indexData = List(); + static List getTagIndexList(List? list) { + List indexData = []; if (list != null && list.isNotEmpty) { - String tempTag; + String? tempTag; for (int i = 0, length = list.length; i < length; i++) { String tag = list[i].tag; if (tag.length > 2) tag = tag.substring(0, 2); @@ -56,11 +56,11 @@ class SuspensionUtil { } /// set show suspension status. - static void setShowSuspensionStatus(List list) { + static void setShowSuspensionStatus(List? list) { if (list == null || list.isEmpty) return; - String tempTag; + String? tempTag; for (int i = 0, length = list.length; i < length; i++) { - String tag = list[i].tag; + String? tag = list[i].tag; if (tempTag != tag) { tempTag = tag; list[i].isShowSuspension = true; diff --git a/lib/src/components/selectcity/brn_az_listview.dart b/lib/src/components/selectcity/brn_az_listview.dart index 0c39ed98..5243f172 100644 --- a/lib/src/components/selectcity/brn_az_listview.dart +++ b/lib/src/components/selectcity/brn_az_listview.dart @@ -18,7 +18,7 @@ typedef Widget IndexHintBuilder(BuildContext context, String hint); /// _Header. class _Header extends ISuspensionBean { - String tag; + String tag = ""; String getSuspensionTag() => tag; @@ -29,15 +29,15 @@ class _Header extends ISuspensionBean { /// AzListView. class AzListView extends StatefulWidget { AzListView( - {Key key, + {Key? key, this.data, this.topData, - this.itemBuilder, + required this.itemBuilder, this.controller, this.physics, this.shrinkWrap = true, this.padding = EdgeInsets.zero, - this.suspensionWidget, + required this.suspensionWidget, this.isUseRealIndex = true, this.itemHeight = 50, this.suspensionHeight = 40, @@ -46,20 +46,19 @@ class AzListView extends StatefulWidget { this.indexBarBuilder, this.indexHintBuilder, this.showIndexHint = true}) - : assert(itemBuilder != null), - super(key: key); + : super(key: key); ///with ISuspensionBean Data - final List data; + final List? data; ///with ISuspensionBean topData, Do not participate in [A-Z] sorting (such as hotList). - final List topData; + final List? topData; final ItemWidgetBuilder itemBuilder; - final ScrollController controller; + final ScrollController? controller; - final ScrollPhysics physics; + final ScrollPhysics? physics; final bool shrinkWrap; @@ -78,13 +77,13 @@ class AzListView extends StatefulWidget { final int suspensionHeight; ///on sus tag change callback. - final ValueChanged onSusTagChanged; + final ValueChanged? onSusTagChanged; - final AzListViewHeader header; + final AzListViewHeader? header; - final IndexBarBuilder indexBarBuilder; + final IndexBarBuilder? indexBarBuilder; - final IndexHintBuilder indexHintBuilder; + final IndexHintBuilder? indexHintBuilder; final bool showIndexHint; @@ -98,12 +97,12 @@ class _AzListViewState extends State { //右侧索引tag 与 距离offset的value,比如 a---0, b---item*个数,c---a+b Map _suspensionSectionMap = Map(); - List _cityList = List(); - List _indexTagList = List(); + List _cityList = []; + List _indexTagList = []; bool _isShowIndexBarHint = false; String _indexBarHint = ""; - ScrollController _scrollController; + late ScrollController _scrollController; @override void initState() { @@ -113,7 +112,7 @@ class _AzListViewState extends State { @override void dispose() { - _scrollController?.dispose(); + _scrollController.dispose(); super.dispose(); } @@ -121,7 +120,7 @@ class _AzListViewState extends State { setState(() { _indexBarHint = model.tag; _isShowIndexBarHint = model.isTouchDown; - int offset = _suspensionSectionMap[model.tag]; + int? offset = _suspensionSectionMap[model.tag]; if (offset != null) { _scrollController.jumpTo(offset .toDouble() @@ -132,10 +131,10 @@ class _AzListViewState extends State { void _init() { _cityList.clear(); - if (widget.topData != null && widget.topData.isNotEmpty) { - _cityList.addAll(widget.topData); + if (widget.topData != null && widget.topData!.isNotEmpty) { + _cityList.addAll(widget.topData!); } - List list = widget.data; + List? list = widget.data; if (list != null && list.isNotEmpty) { // SuspensionUtil.sortListBySuspensionTag(list); _cityList.addAll(list); @@ -144,7 +143,7 @@ class _AzListViewState extends State { SuspensionUtil.setShowSuspensionStatus(_cityList); if (widget.header != null) { - _cityList.insert(0, _Header()..tag = widget.header.tag); + _cityList.insert(0, _Header()..tag = widget.header!.tag); } _indexTagList.clear(); if (widget.isUseRealIndex) { @@ -169,8 +168,8 @@ class _AzListViewState extends State { itemBuilder: (BuildContext context, int index) { if (index == 0 && _cityList[index] is _Header) { return SizedBox( - height: widget.header.height.toDouble(), - child: widget.header.builder(context)); + height: widget.header!.height.toDouble(), + child: widget.header!.builder(context)); } return widget.itemBuilder(context, _cityList[index]); }), @@ -193,7 +192,7 @@ class _AzListViewState extends State { onTouch: _onIndexBarTouch, ); } else { - indexBar = widget.indexBarBuilder( + indexBar = widget.indexBarBuilder!( context, _indexTagList, _onIndexBarTouch, @@ -205,7 +204,7 @@ class _AzListViewState extends State { )); Widget indexHint; if (widget.indexHintBuilder != null) { - indexHint = widget.indexHintBuilder(context, '$_indexBarHint'); + indexHint = widget.indexHintBuilder!(context, '$_indexBarHint'); } else { indexHint = Card( color: Colors.black54, diff --git a/lib/src/components/selectcity/brn_base_azlistview_page.dart b/lib/src/components/selectcity/brn_base_azlistview_page.dart index 04a8a3c4..953bf7bc 100644 --- a/lib/src/components/selectcity/brn_base_azlistview_page.dart +++ b/lib/src/components/selectcity/brn_base_azlistview_page.dart @@ -25,10 +25,10 @@ abstract class BaseAZListViewPage extends StatefulWidget { Widget buildItemWidget(ISuspensionBean item); //悬浮的widget - Widget buildSuspensionWidget(String tag); + Widget buildSuspensionWidget(String? tag); List getTopData() { - return List(); + return []; } //item的高度 默认50 @@ -39,16 +39,19 @@ abstract class BaseAZListViewPage extends StatefulWidget { //每个modal 对应的 tag,默认是拼音来设置 String createTagByModal(ISuspensionBean bean) { - String pinyin = PinyinHelper.getPinyinE(bean.name); - return pinyin.substring(0, 1).toUpperCase(); + if (bean.name.isNotEmpty) { + String pinyin = PinyinHelper.getPinyinE(bean.name); + return pinyin.substring(0, 1).toUpperCase(); + } + return ""; } } class _BaseAZListViewPageState extends State { String suspensionTag = ""; - List _dataList = List(); - StreamController streamController; + List _dataList = []; + late StreamController streamController; @override void initState() { @@ -70,14 +73,15 @@ class _BaseAZListViewPageState extends State { if (snapShot.connectionState == ConnectionState.done) { if (snapShot.hasError) { return BrnAbnormalStateUtils.getEmptyWidgetByState( - context, AbnormalState.networkConnectError, (index) { + context, AbnormalState.networkConnectError, + action: (index) { setState(() {}); }); } else { return buildContentBody(snapShot.data); } } - return null; + return Container(); }, )); } @@ -96,7 +100,7 @@ class _BaseAZListViewPageState extends State { if (_dataList.isEmpty && top.isEmpty) { return BrnAbnormalStateUtils.getEmptyWidgetByState( - context, AbnormalState.noData, (index) {}); + context, AbnormalState.noData); } suspensionTag = top.isEmpty ? _dataList[0].tag : top[0].tag; @@ -107,7 +111,7 @@ class _BaseAZListViewPageState extends State { child: StreamBuilder( initialData: suspensionTag, stream: streamController.stream, - builder: (context, snapShot) { + builder: (context, AsyncSnapshot snapShot) { return AzListView( data: _dataList, topData: top, @@ -126,14 +130,14 @@ class _BaseAZListViewPageState extends State { ); } - Widget _buildSusWidget(String susTag) { + Widget _buildSusWidget(String? susTag) { return Container( height: widget.getSuspensionHeight(), child: widget.buildSuspensionWidget(susTag), ); } - void _handleList(List list) { + void _handleList(List? list) { if (list == null || list.isEmpty) return; for (int i = 0, length = list.length; i < length; i++) { String tag = widget.createTagByModal(list[i]); @@ -152,7 +156,7 @@ class _BaseAZListViewPageState extends State { } Widget _buildListItem(ISuspensionBean model) { - String susTag = model.tag; + String? susTag = model.tag; return Column( children: [ //当offstage为true,当前控件不会被绘制在屏幕上 diff --git a/lib/src/components/selectcity/brn_index_bar.dart b/lib/src/components/selectcity/brn_index_bar.dart index e8ffe23d..a802c71d 100644 --- a/lib/src/components/selectcity/brn_index_bar.dart +++ b/lib/src/components/selectcity/brn_index_bar.dart @@ -5,11 +5,9 @@ typedef void IndexBarTouchCallback(IndexBarDetails model); /// IndexModel. class IndexBarDetails { - String tag; //current touch tag. - int position; //current touch position. - bool isTouchDown; //is touch down. - - IndexBarDetails({this.tag, this.position, this.isTouchDown}); + String tag = ""; //current touch tag. + int position = -1; //current touch position. + bool isTouchDown = false; //is touch down. } ///Default Index data. @@ -46,9 +44,9 @@ const List INDEX_DATA_DEF = const [ /// IndexBar. class IndexBar extends StatefulWidget { IndexBar( - {Key key, + {Key? key, this.data = INDEX_DATA_DEF, - @required this.onTouch, + required this.onTouch, this.width = 30, this.itemHeight = 16, this.color = Colors.transparent, @@ -102,14 +100,12 @@ class _SuspensionListViewIndexBarState extends State { textStyle: widget.textStyle, touchDownTextStyle: widget.touchDownTextStyle, onTouch: (details) { - if (widget.onTouch != null) { - if (_isTouchDown != details.isTouchDown) { - setState(() { - _isTouchDown = details.isTouchDown; - }); - } - widget.onTouch(details); + if (_isTouchDown != details.isTouchDown) { + setState(() { + _isTouchDown = details.isTouchDown; + }); } + widget.onTouch(details); }, ), ); @@ -128,30 +124,29 @@ class _IndexBar extends StatefulWidget { final int itemHeight; /// IndexBar text style. - final TextStyle textStyle; + final TextStyle? textStyle; - final TextStyle touchDownTextStyle; + final TextStyle? touchDownTextStyle; /// Item touch callback. final IndexBarTouchCallback onTouch; _IndexBar( - {Key key, + {Key? key, this.data = INDEX_DATA_DEF, - @required this.onTouch, + required this.onTouch, this.width = 30, this.itemHeight = 16, this.textStyle, this.touchDownTextStyle}) - : assert(onTouch != null), - super(key: key); + : super(key: key); @override _IndexBarState createState() => _IndexBarState(); } class _IndexBarState extends State<_IndexBar> { - List _indexSectionList = List(); + List _indexSectionList = []; int _widgetTop = -1; int _lastIndex = 0; bool _widgetTopChange = false; @@ -174,27 +169,25 @@ class _IndexBarState extends State<_IndexBar> { _indexSectionList.clear(); _indexSectionList.add(0); int tempHeight = 0; - widget.data?.forEach((value) { + widget.data.forEach((value) { tempHeight = tempHeight + widget.itemHeight; _indexSectionList.add(tempHeight); }); } _triggerTouchEvent() { - if (widget.onTouch != null) { - widget.onTouch(_indexModel); - } + widget.onTouch(_indexModel); } @override Widget build(BuildContext context) { - TextStyle _style = widget.textStyle; + TextStyle? _style = widget.textStyle; if (_indexModel.isTouchDown == true) { _style = widget.touchDownTextStyle; } _init(); - List children = List(); + List children = []; widget.data.forEach((v) { children.add(SizedBox( width: widget.width.toDouble(), @@ -207,7 +200,7 @@ class _IndexBarState extends State<_IndexBar> { onVerticalDragDown: (DragDownDetails details) { if (_widgetTop == -1 || _widgetTopChange) { _widgetTopChange = false; - RenderBox box = context.findRenderObject(); + RenderBox box = context.findRenderObject() as RenderBox; Offset topLeftPosition = box.localToGlobal(Offset.zero); _widgetTop = topLeftPosition.dy.toInt(); } diff --git a/lib/src/components/selectcity/brn_select_city_model.dart b/lib/src/components/selectcity/brn_select_city_model.dart index a7af5d68..d8c28a6b 100644 --- a/lib/src/components/selectcity/brn_select_city_model.dart +++ b/lib/src/components/selectcity/brn_select_city_model.dart @@ -1,23 +1,21 @@ import 'package:bruno/src/components/selectcity/brn_az_common.dart'; class BrnSelectCityModel extends ISuspensionBean { - String name; - String tagIndex; - String namePinyin; - String tag; - String cityCode; + String name = ""; + String tagIndex = ""; + String? namePinyin; + String tag = ""; + String cityCode = ""; BrnSelectCityModel({ - this.name, - this.tagIndex, + required this.name, + this.tagIndex = "", this.namePinyin, - this.tag, - this.cityCode, + this.tag = "", + this.cityCode = "", }); - BrnSelectCityModel.fromJson(Map json) - : name = json['name'] == null ? "" : json['name'], - cityCode = json['cityCode'] == null ? "" : json['cityCode']; + BrnSelectCityModel.fromJson(Map json); Map toJson() => { 'name': name, diff --git a/lib/src/components/selectcity/brn_single_select_city_page.dart b/lib/src/components/selectcity/brn_single_select_city_page.dart index 789b9b60..b8b7c961 100644 --- a/lib/src/components/selectcity/brn_single_select_city_page.dart +++ b/lib/src/components/selectcity/brn_single_select_city_page.dart @@ -9,7 +9,7 @@ import 'package:bruno/src/components/sugsearch/brn_search_text.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/constants/brn_strings_constants.dart'; import 'package:bruno/src/utils/brn_tools.dart'; -import 'package:bruno/src/utils/font/brn_font.dart'; +import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:lpinyin/lpinyin.dart'; @@ -18,10 +18,10 @@ import 'package:lpinyin/lpinyin.dart'; /// 功能:多可以自定制导航栏文案,搜索文案信息,定位信息,右侧可快速滑动查看城市 class BrnSingleSelectCityPage extends StatefulWidget { /// 页面标题,默认空 - final String appBarTitle; + final String? appBarTitle; /// 热门推荐标题,默认空 - final String hotCityTitle; + final String? hotCityTitle; /// 是否展示searchBar,默认 true final bool showSearchBar; @@ -30,18 +30,18 @@ class BrnSingleSelectCityPage extends StatefulWidget { final String locationText; /// 城市列表 - final List cityList; + final List? cityList; /// 热门推荐城市列表 final List hotCityList; /// 单选项 点击的回调 - final ValueChanged onValueChanged; + final ValueChanged? onValueChanged; BrnSingleSelectCityPage({ this.appBarTitle = '', this.hotCityTitle = '', - this.hotCityList, + required this.hotCityList, this.cityList, this.showSearchBar = true, this.locationText = '', @@ -55,7 +55,7 @@ class BrnSingleSelectCityPage extends StatefulWidget { } class _BrnSingleSelectCityPageState extends State { - List _cityList = List(); + List _cityList = []; ///搜索框的高度 int _suspensionHeight = 40; @@ -73,7 +73,7 @@ class _BrnSingleSelectCityPageState extends State { String _searchText = ""; /// search的TextController - BrnSearchTextController _brnSearchTextController; + late BrnSearchTextController _brnSearchTextController; @override void initState() { @@ -83,7 +83,7 @@ class _BrnSingleSelectCityPageState extends State { } void _loadData() async { - if (widget.cityList == null || widget.cityList.isEmpty) { + if (widget.cityList == null || widget.cityList!.isEmpty) { //加载城市列表 rootBundle .loadString( @@ -98,13 +98,13 @@ class _BrnSingleSelectCityPageState extends State { setState(() {}); }); } else { - _cityList = widget.cityList; + _cityList = widget.cityList!; _handleList(_cityList); setState(() {}); } } - void _handleList(List list) { + void _handleList(List? list) { if (list == null || list.isEmpty) return; for (int i = 0, length = list.length; i < length; i++) { String pinyin = PinyinHelper.getPinyinE(list[i].name); @@ -151,10 +151,12 @@ class _BrnSingleSelectCityPageState extends State { runAlignment: WrapAlignment.start, spacing: 10.0, children: hotCityList.map((e) { - return OutlineButton( - padding: EdgeInsets.all(0), - borderSide: BorderSide(color: Color(0xFFF8F8F8), width: .5), - color: Color(0xFFF8F8F8), + return OutlinedButton( + style: OutlinedButton.styleFrom( + padding: EdgeInsets.all(0), + side: BorderSide(color: Color(0xFFF8F8F8), width: .5), + backgroundColor: Color(0xFFF8F8F8), + ), child: Container( alignment: Alignment.center, height: 36.0, @@ -166,7 +168,7 @@ class _BrnSingleSelectCityPageState extends State { textAlign: TextAlign.center, style: TextStyle( color: Color(0xFF222222), - fontSize: BrnFont.FONT_12, + fontSize: BrnFonts.f12, fontWeight: FontWeight.w400, ), ), @@ -174,7 +176,7 @@ class _BrnSingleSelectCityPageState extends State { onPressed: () { debugPrint("OnItemClick: $e"); if (widget.onValueChanged != null) { - widget.onValueChanged(e); + widget.onValueChanged!(e); } Navigator.pop(context, e); }, @@ -186,7 +188,7 @@ class _BrnSingleSelectCityPageState extends State { ); } - Widget _buildSusWidget(String susTag) { + Widget _buildSusWidget(String? susTag) { return Container( height: _suspensionHeight.toDouble(), padding: const EdgeInsets.only(left: 15.0), @@ -218,7 +220,7 @@ class _BrnSingleSelectCityPageState extends State { onTap: () { debugPrint("OnItemClick: $model"); if (widget.onValueChanged != null) { - widget.onValueChanged(model); + widget.onValueChanged!(model); } Navigator.pop(context, model); }, @@ -234,7 +236,7 @@ class _BrnSingleSelectCityPageState extends State { hintText: '请输入搜索信息', onTextChange: (text) { _searchText = text; - _showCityStack = (text.length == 0 || text == null) ? true : false; + _showCityStack = text.isEmpty; setState(() {}); }, onTextCommit: (text) { @@ -270,12 +272,13 @@ class _BrnSingleSelectCityPageState extends State { @override Widget build(BuildContext context) { return Scaffold( + resizeToAvoidBottomInset: false, appBar: BrnAppBar(title: widget.appBarTitle ?? '城市选择'), body: Container( decoration: BoxDecoration(color: Colors.white), child: Column( children: [ - widget.locationText.isEmpty || widget.locationText == null + widget.locationText.isEmpty ? Container() : _buildLocationBar(widget.locationText), widget.showSearchBar ? _buildSearchBar() : Container(), @@ -300,13 +303,16 @@ class _BrnSingleSelectCityPageState extends State { headerHeight = 0; } if (_suspensionTag.isEmpty || _suspensionTag == '') { - _suspensionTag = _cityList.first.tag; + if (_cityList.isNotEmpty) { + _suspensionTag = _cityList.first.tag; + } } return Expanded( flex: 1, child: AzListView( data: _cityList, - itemBuilder: (context, model) => _buildListItem(model), + itemBuilder: (context, model) => + _buildListItem(model as BrnSelectCityModel), suspensionWidget: _buildSusWidget(_suspensionTag), isUseRealIndex: true, itemHeight: _itemHeight, @@ -361,7 +367,7 @@ class _BrnSingleSelectCityPageState extends State { ///获取城市搜索结果 List _searchCityList(String searchText) { - List cList = List(); + List cList = []; for (int index = 0; index < _cityList.length; index++) { BrnSelectCityModel cInfo = _cityList[index]; if (cInfo.name.contains(searchText) || diff --git a/lib/src/components/selectcity/brn_suspension_view.dart b/lib/src/components/selectcity/brn_suspension_view.dart index 5282705d..34f0bcbc 100644 --- a/lib/src/components/selectcity/brn_suspension_view.dart +++ b/lib/src/components/selectcity/brn_suspension_view.dart @@ -25,27 +25,25 @@ class SuspensionView extends StatefulWidget { final int itemHeight; /// on sus tag change callback. - final ValueChanged onSusTagChanged; + final ValueChanged? onSusTagChanged; /// on sus section callback. - final OnSusSectionCallBack onSusSectionInited; + final OnSusSectionCallBack? onSusSectionInited; - final AzListViewHeader header; + final AzListViewHeader? header; SuspensionView({ - Key key, - @required this.data, - @required this.contentWidget, - @required this.suspensionWidget, - @required this.controller, + Key? key, + required this.data, + required this.contentWidget, + required this.suspensionWidget, + required this.controller, this.suspensionHeight = 40, this.itemHeight = 50, this.onSusTagChanged, this.onSusSectionInited, this.header, - }) : assert(contentWidget != null), - assert(controller != null), - super(key: key); + }) : super(key: key); @override _SuspensionWidgetState createState() => _SuspensionWidgetState(); @@ -53,25 +51,25 @@ class SuspensionView extends StatefulWidget { class _SuspensionWidgetState extends State { int _suspensionTop = 0; - int _lastIndex; - int _suSectionListLength; + int _lastIndex = -1; + late int _suSectionListLength; - List _suspensionSectionList = List(); + List _suspensionSectionList = []; Map _suspensionSectionMap = Map(); @override void initState() { super.initState(); if (widget.header != null) { - _suspensionTop = -widget.header.height; + _suspensionTop = -widget.header!.height; } - widget.controller?.addListener(_handleScrollerListenerTick); + widget.controller.addListener(_handleScrollerListenerTick); } @override void dispose() { super.dispose(); - widget.controller?.removeListener(_handleScrollerListenerTick); + widget.controller.removeListener(_handleScrollerListenerTick); } void _handleScrollerListenerTick() { @@ -80,17 +78,16 @@ class _SuspensionWidgetState extends State { if (_index != -1 && _lastIndex != _index) { _lastIndex = _index; if (widget.onSusTagChanged != null) { - widget.onSusTagChanged(_suspensionSectionMap.keys.toList()[_index]); + widget.onSusTagChanged!(_suspensionSectionMap.keys.toList()[_index]); } } } int _getIndex(int offset) { - if (widget.header != null && offset < widget.header.height) { - if (_suspensionTop != -widget.header.height && - widget.suspensionWidget != null) { + if (widget.header != null && offset < widget.header!.height) { + if (_suspensionTop != -widget.header!.height) { setState(() { - _suspensionTop = -widget.header.height; + _suspensionTop = -widget.header!.height; }); } return 0; @@ -102,7 +99,7 @@ class _SuspensionWidgetState extends State { } else { space = 0; } - if (_suspensionTop != space && widget.suspensionWidget != null) { + if (_suspensionTop != space) { setState(() { _suspensionTop = space; }); @@ -122,15 +119,15 @@ class _SuspensionWidgetState extends State { void _init() { _suspensionSectionMap.clear(); int offset = 0; - String tag; + String? tag; if (widget.header != null) { - _suspensionSectionMap[widget.header.tag] = 0; - offset = widget.header.height; + _suspensionSectionMap[widget.header!.tag] = 0; + offset = widget.header!.height; } - widget.data?.forEach((v) { + widget.data.forEach((v) { if (tag != v.tag) { tag = v.tag; - _suspensionSectionMap.putIfAbsent(tag, () => offset); + _suspensionSectionMap.putIfAbsent(tag!, () => offset); offset = offset + widget.suspensionHeight + widget.itemHeight; } else { offset = offset + widget.itemHeight; @@ -141,7 +138,7 @@ class _SuspensionWidgetState extends State { ..addAll(_suspensionSectionMap.values); _suSectionListLength = _suspensionSectionList.length; if (widget.onSusSectionInited != null) { - widget.onSusSectionInited(_suspensionSectionMap); + widget.onSusSectionInited!(_suspensionSectionMap); } } @@ -151,15 +148,15 @@ class _SuspensionWidgetState extends State { var children = [ widget.contentWidget, ]; - if (widget.suspensionWidget != null) { - children.add(Positioned( - ///-0.1修复部分手机丢失精度问题 - top: _suspensionTop.toDouble() - 0.1, - left: 0.0, - right: 0.0, - child: widget.suspensionWidget, - )); - } + + children.add(Positioned( + ///-0.1修复部分手机丢失精度问题 + top: _suspensionTop.toDouble() - 0.1, + left: 0.0, + right: 0.0, + child: widget.suspensionWidget, + )); + return Stack(children: children); } } diff --git a/lib/src/components/selection/bean/brn_filter_entity.dart b/lib/src/components/selection/bean/brn_filter_entity.dart index 2d02487b..4f65d98d 100644 --- a/lib/src/components/selection/bean/brn_filter_entity.dart +++ b/lib/src/components/selection/bean/brn_filter_entity.dart @@ -1,14 +1,13 @@ class ItemEntity { - String key; + String? key; String name; - String value; + String? value; - ItemEntity({this.key, this.name, this.value}); + ItemEntity({this.key, this.name = '', this.value}); - ItemEntity.fromJson(Map map) { - if (map == null) return; - key = map['key'] ?? ""; - name = map['title'] ?? ""; - value = map['value'] ?? ""; + ItemEntity.fromJson(Map map) : this.name = '' { + key = map['key'] ?? ''; + name = map['title'] ?? ''; + value = map['value'] ?? ''; } } diff --git a/lib/src/components/selection/bean/brn_selection_common_entity.dart b/lib/src/components/selection/bean/brn_selection_common_entity.dart index 93c84fb9..c4c04c94 100644 --- a/lib/src/components/selection/bean/brn_selection_common_entity.dart +++ b/lib/src/components/selection/bean/brn_selection_common_entity.dart @@ -5,72 +5,69 @@ import 'package:bruno/src/utils/brn_tools.dart'; enum BrnSelectionFilterType { /// 未设置 - None, + none, /// 不限类型 - UnLimit, + unLimit, /// 单选列表、单选项 type 为 radio - Radio, + radio, /// 多选列表、多选项 type 为 checkbox - Checkbox, + checkbox, /// 一般的值范围自定义区间 type 为 range - Range, + range, /// 日期选择,普通筛选时使用 CalendarView 展示选择时间,更多情况下使用 DatePicker 选择时间 - Date, + date, /// 自定义选择日期区间, type 为 dateRange - DateRange, + dateRange, /// 自定义通过 Calendar 选择日期区间,type 为 dateRangeCalendar - DateRangeCalendar, + dateRangeCalendar, /// 标签筛选 type 为 customerTag - CustomHandle, + customHandle, /// 更多列表、多选项 无 type - More, + more, /// 去二级页面 - Layer, + layer, /// 去自定义二级页面 - CustomLayer, + customLayer, } /// 筛选弹窗展示风格 enum BrnSelectionWindowType { /// 列表类型,使用列表 Item 展示 - List, + list, /// 值范围类型,使用 Tag + Range 的 Item 展示 - Range, + range, } class BrnSelectionEntity { /// 类型 是单选、复选还是有自定义输入 - String type; + String? type; /// 回传给服务器的 key - String key; + String? key; /// 回传给服务器的 value - String value; + String? value; /// 默认值 - String defaultValue; + String? defaultValue; /// 显示的文案 String title; /// 显示的文案 - String subTitle; - - /// 单位。例如居室、万,适配自定义区间填写的内容 - String unit; + String? subTitle; /// 扩展字段,目前只有min和max Map extMap; @@ -85,30 +82,30 @@ class BrnSelectionEntity { bool isSelected; /// 自定义输入 - Map customMap; + Map? customMap; /// 用于临时存储原有自定义字段数据,在筛选数据变化后未点击【确定】按钮时还原。 - Map originalCustomMap; + late Map originalCustomMap; /// 最大可选数量 int maxSelectedCount; /// 父级筛选项 - BrnSelectionEntity parent; + BrnSelectionEntity? parent; /// 筛选类型,具体参见 [BrnSelectionFilterType] - BrnSelectionFilterType filterType; + late BrnSelectionFilterType filterType; /// 筛选弹窗展示风格对应的首字母小写的字符串,例如 `range`、`list`,参见 [BrnSelectionWindowType] - String showType; + String? showType; /// 筛选弹窗展示风格,具体参见 [BrnSelectionWindowType] - BrnSelectionWindowType filterShowType; + BrnSelectionWindowType? filterShowType; /// 自定义标题 - String customTitle; + String? customTitle; - ///自定义筛选的 title + ///自定义筛选的 title 是否高亮 bool isCustomTitleHighLight; /// 临时字段用于判断是否要将筛选项 [name] 字段拼接展示 @@ -118,126 +115,127 @@ class BrnSelectionEntity { {this.key, this.value, this.defaultValue, - this.title, + this.title = '', this.subTitle, - this.children, + this.children = const [], this.isSelected = false, - this.unit, - this.extMap, + this.extMap = const {}, this.customMap, this.type, this.showType, - this.maxSelectedCount}) { - this.filterType = this.parserFilterTypeWithType(this.type); - this.filterShowType = this.parserShowType(this.showType); + this.isCustomTitleHighLight = false, + this.maxSelectedCount = BrnSelectionConstant.maxSelectCount}) { + this.filterType = parserFilterTypeWithType(this.type); + this.filterShowType = parserShowType(this.showType); this.originalCustomMap = Map(); - - /// 默认支持最大选中个数为 65535 - this.maxSelectedCount = - maxSelectedCount ?? BrnSelectionConstant.MAX_SELECT_COUNT; } /// 构造简单筛选数据 BrnSelectionEntity.simple({ this.key, this.value, - this.title, + this.title = '', this.type, - }) { - this.filterType = this.parserFilterTypeWithType(this.type); - this.filterShowType = this.parserShowType(this.showType); + }) : this.maxSelectedCount = BrnSelectionConstant.maxSelectCount, + this.isCustomTitleHighLight = false, + this.isSelected = false, + this.children = [], + this.extMap = {} { + this.filterType = parserFilterTypeWithType(this.type); + this.filterShowType = parserShowType(this.showType); this.originalCustomMap = Map(); this.isSelected = false; - - /// 默认支持最大选中个数为 65535 - this.maxSelectedCount = - maxSelectedCount ?? BrnSelectionConstant.MAX_SELECT_COUNT; - } - - BrnSelectionEntity.fromJson(Map map) { - if (map == null) return; - title = map['title'] ?? ""; - subTitle = map['subTitle'] ?? ""; - key = map['key'] ?? ""; - type = map['type'] ?? ""; - defaultValue = map['defaultValue'] ?? ""; - value = map['value'] ?? ""; - if (map['maxSelectedCount'] != null && - int.tryParse(map['maxSelectedCount']) != null) { - maxSelectedCount = int.tryParse(map['maxSelectedCount']); - } else { - maxSelectedCount = BrnSelectionConstant.MAX_SELECT_COUNT; - } - extMap = map['ext'] ?? {}; - children = List() - ..addAll((map['children'] as List ?? []) - .map((o) => BrnSelectionEntity.fromMap(o))); - filterType = parserFilterTypeWithType(map['type'] ?? ""); - isSelected = false; } - /// 建议使用上面构造函数[BrnSelectionEntity.fromJson] + /// 建议使用 [BrnSelectionEntity.fromJson] static BrnSelectionEntity fromMap(Map map) { - if (map == null) return null; BrnSelectionEntity entity = BrnSelectionEntity(); - entity.title = map['title'] ?? ""; - entity.subTitle = map['subTitle'] ?? ""; - entity.key = map['key'] ?? ""; - entity.type = map['type'] ?? ""; + entity.title = map['title'] ?? ''; + entity.subTitle = map['subTitle'] ?? ''; + entity.key = map['key'] ?? ''; + entity.type = map['type'] ?? ''; entity.defaultValue = map['defaultValue'] ?? ""; entity.value = map['value'] ?? ""; if (map['maxSelectedCount'] != null && int.tryParse(map['maxSelectedCount']) != null) { - entity.maxSelectedCount = int.tryParse(map['maxSelectedCount']); + entity.maxSelectedCount = int.tryParse(map['maxSelectedCount']) ?? BrnSelectionConstant.maxSelectCount; } else { - entity.maxSelectedCount = BrnSelectionConstant.MAX_SELECT_COUNT; + entity.maxSelectedCount = BrnSelectionConstant.maxSelectCount; } entity.extMap = map['ext'] ?? {}; - entity.children = List() - ..addAll((map['children'] as List ?? []) + if(map['children'] != null && map['children'] is List) { + entity.children = []..addAll((map['children'] as List) .map((o) => BrnSelectionEntity.fromMap(o))); + } entity.filterType = entity.parserFilterTypeWithType(map['type'] ?? ""); return entity; } + + BrnSelectionEntity.fromJson(Map? map) + : this.title = '', + this.maxSelectedCount = BrnSelectionConstant.maxSelectCount, + this.isCustomTitleHighLight = false, + this.isSelected = false, + this.children = [], + this.extMap = {} { + if (map == null) return; + title = map['title'] ?? ''; + subTitle = map['subTitle'] ?? ''; + key = map['key'] ?? ''; + type = map['type'] ?? ''; + defaultValue = map['defaultValue'] ?? ''; + value = map['value'] ?? ''; + if (map['maxSelectedCount'] != null && int.tryParse(map['maxSelectedCount']) != null) { + maxSelectedCount = + int.tryParse(map['maxSelectedCount']) ?? BrnSelectionConstant.maxSelectCount; + } + extMap = map['ext'] ?? {}; + children = [] + ..addAll((map['children'] ?? []).map((o) => BrnSelectionEntity.fromJson(o))); + filterType = parserFilterTypeWithType(map['type'] ?? ''); + isSelected = false; + } + void configRelationshipAndDefaultValue() { configRelationship(); configDefaultValue(); } void configRelationship() { - if (this.children != null && this.children.length > 0) { - for (BrnSelectionEntity entity in this.children) { + if (children.length > 0) { + for (BrnSelectionEntity entity in children) { entity.parent = this; } - for (BrnSelectionEntity entity in this.children) { + for (BrnSelectionEntity entity in children) { entity.configRelationship(); } } } void configDefaultValue() { - if (this.children != null && this.children.length > 0) { - for (BrnSelectionEntity entity in this.children) { - if (!BrunoTools.isEmpty(this.defaultValue)) { - List values = this.defaultValue.split(','); - entity.isSelected = values != null && values.contains(entity.value); + if (children.length > 0) { + for (BrnSelectionEntity entity in children) { + if (!BrunoTools.isEmpty(defaultValue)) { + List values = defaultValue!.split(','); + entity.isSelected = values.contains(entity.value); } } /// 当 default 不在普通 Item 类型中时,尝试填充 同级别 Range Item. if (children.where((_) => _.isSelected).toList().length == 0) { - BrnSelectionEntity rangeEntity = this.children.firstWhere((_) { - return (_.filterType == BrnSelectionFilterType.Range || - _.filterType == BrnSelectionFilterType.DateRange || - _.filterType == BrnSelectionFilterType.DateRangeCalendar); - }, orElse: () { - return null; - }); - if (rangeEntity != null && !BrunoTools.isEmpty(this.defaultValue)) { - List values = this.defaultValue.split(':'); - if (values != null && - values.length == 2 && + List rangeItems = this.children.where((_) { + return (_.filterType == BrnSelectionFilterType.range || + _.filterType == BrnSelectionFilterType.dateRange || + _.filterType == BrnSelectionFilterType.dateRangeCalendar); + }).toList(); + BrnSelectionEntity? rangeEntity; + if (rangeItems.isNotEmpty) { + rangeEntity = rangeItems[0]; + } + if (rangeEntity != null && !BrunoTools.isEmpty(defaultValue)) { + List values = defaultValue!.split(':'); + if (values.length == 2 && int.tryParse(values[0]) != null && int.tryParse(values[1]) != null) { rangeEntity.customMap = {}; @@ -253,60 +251,58 @@ class BrnSelectionEntity { if (hasCheckBoxBrother()) { isSelected = children.where((_) => _.isSelected).length > 0; } else { - isSelected = - isSelected || children.where((_) => _.isSelected).length > 0; + isSelected = isSelected || children.where((_) => _.isSelected).length > 0; } } } - BrnSelectionWindowType parserShowType(String showType) { + BrnSelectionWindowType parserShowType(String? showType) { if (showType == "list") { - return BrnSelectionWindowType.List; + return BrnSelectionWindowType.list; } else if (showType == "range") { - return BrnSelectionWindowType.Range; + return BrnSelectionWindowType.range; } - return BrnSelectionWindowType.List; + return BrnSelectionWindowType.list; } - BrnSelectionFilterType parserFilterTypeWithType(String type) { - if (type == null) return BrnSelectionFilterType.None; + BrnSelectionFilterType parserFilterTypeWithType(String? type) { if (type == 'unlimit') { - return BrnSelectionFilterType.UnLimit; + return BrnSelectionFilterType.unLimit; } else if (type == "radio") { - return BrnSelectionFilterType.Radio; + return BrnSelectionFilterType.radio; } else if (type == "checkbox") { - return BrnSelectionFilterType.Checkbox; + return BrnSelectionFilterType.checkbox; } else if (type == "range") { - return BrnSelectionFilterType.Range; + return BrnSelectionFilterType.range; } else if (type == "customHandle") { - return BrnSelectionFilterType.CustomHandle; + return BrnSelectionFilterType.customHandle; } else if (type == "more") { - return BrnSelectionFilterType.More; + return BrnSelectionFilterType.more; } else if (type == 'floatinglayer') { - return BrnSelectionFilterType.Layer; + return BrnSelectionFilterType.layer; } else if (type == 'customfloatinglayer') { - return BrnSelectionFilterType.CustomLayer; + return BrnSelectionFilterType.customLayer; } else if (type == 'date') { - return BrnSelectionFilterType.Date; + return BrnSelectionFilterType.date; } else if (type == 'daterange') { - return BrnSelectionFilterType.DateRange; + return BrnSelectionFilterType.dateRange; } else if (type == 'daterangecalendar') { - return BrnSelectionFilterType.DateRangeCalendar; + return BrnSelectionFilterType.dateRangeCalendar; } - return BrnSelectionFilterType.None; + return BrnSelectionFilterType.none; } void clearChildSelection() { - if (this.children != null && this.children.length > 0) { - for (BrnSelectionEntity entity in this.children) { + if (children.length > 0) { + for (BrnSelectionEntity entity in children) { entity.isSelected = false; - if (entity.filterType == BrnSelectionFilterType.Date) { + if (entity.filterType == BrnSelectionFilterType.date) { entity.value = null; } - if (entity.filterType == BrnSelectionFilterType.Range || - entity.filterType == BrnSelectionFilterType.DateRange || - entity.filterType == BrnSelectionFilterType.DateRangeCalendar) { - entity.customMap = null; + if (entity.filterType == BrnSelectionFilterType.range || + entity.filterType == BrnSelectionFilterType.dateRange || + entity.filterType == BrnSelectionFilterType.dateRangeCalendar) { + entity.customMap = Map(); } entity.clearChildSelection(); } @@ -314,18 +310,14 @@ class BrnSelectionEntity { } List selectedLastColumnList() { - List list = List(); - if (this.children != null && this.children.length > 0) { - List firstList = List(); + List list = []; + if (this.children.length > 0) { + List firstList = []; for (BrnSelectionEntity firstEntity in this.children) { - if (firstEntity != null && - firstEntity.children != null && - firstEntity.children.length > 0) { - List secondList = List(); + if (firstEntity.children.length > 0) { + List secondList = []; for (BrnSelectionEntity secondEntity in firstEntity.children) { - if (secondEntity != null && - secondEntity.children != null && - secondEntity.children.length > 0) { + if (secondEntity.children.length > 0) { List thirds = BrnSelectionUtil.currentSelectListForEntity(secondEntity); if (thirds.length > 0) { @@ -333,12 +325,12 @@ class BrnSelectionEntity { } else if (secondEntity.isSelected) { secondList.add(secondEntity); } - } else if (secondEntity != null && secondEntity.isSelected) { + } else if (secondEntity.isSelected) { secondList.add(secondEntity); } } list.addAll(secondList); - } else if (firstEntity != null && firstEntity.isSelected) { + } else if (firstEntity.isSelected) { firstList.add(firstEntity); } } @@ -350,43 +342,38 @@ class BrnSelectionEntity { List selectedListWithoutUnlimit() { List selected = selectedList(); return selected - ?.where((_) => !_.isUnLimit()) - ?.where((_) => - (_.filterType != BrnSelectionFilterType.Range) || - (_.filterType == BrnSelectionFilterType.Range && - !BrunoTools.isEmpty(_.customMap))) - ?.where((_) => - (_.filterType != BrnSelectionFilterType.DateRange) || - (_.filterType == BrnSelectionFilterType.DateRange && + .where((_) => !_.isUnLimit()) + .where((_) => + (_.filterType != BrnSelectionFilterType.range) || + (_.filterType == BrnSelectionFilterType.range && !BrunoTools.isEmpty(_.customMap))) + .where((_) => + (_.filterType != BrnSelectionFilterType.dateRange) || + (_.filterType == BrnSelectionFilterType.dateRange && !BrunoTools.isEmpty(_.customMap))) - ?.where((_) => - (_.filterType != BrnSelectionFilterType.DateRangeCalendar) || - (_.filterType == BrnSelectionFilterType.DateRangeCalendar && + .where((_) => + (_.filterType != BrnSelectionFilterType.dateRangeCalendar) || + (_.filterType == BrnSelectionFilterType.dateRangeCalendar && !BrunoTools.isEmpty(_.customMap))) - ?.toList() ?? - List(); + .toList(); } List selectedList() { - if (BrnSelectionFilterType.More == this.filterType) { + if (BrnSelectionFilterType.more == this.filterType) { return this.selectedLastColumnList(); } else { - List results = List(); - List firstColumn = - BrnSelectionUtil.currentSelectListForEntity(this); + List results = []; + List firstColumn = BrnSelectionUtil.currentSelectListForEntity(this); results.addAll(firstColumn); - if (firstColumn != null && firstColumn.length > 0) { + if (firstColumn.length > 0) { for (BrnSelectionEntity firstEntity in firstColumn) { - if (firstEntity != null) { - List secondColumn = - BrnSelectionUtil.currentSelectListForEntity(firstEntity); - results.addAll(secondColumn); - if (secondColumn != null && secondColumn.length > 0) { - for (BrnSelectionEntity secondEntity in secondColumn) { - List thirdColumn = - BrnSelectionUtil.currentSelectListForEntity(secondEntity); - results.addAll(thirdColumn); - } + List secondColumn = + BrnSelectionUtil.currentSelectListForEntity(firstEntity); + results.addAll(secondColumn); + if (secondColumn.length > 0) { + for (BrnSelectionEntity secondEntity in secondColumn) { + List thirdColumn = + BrnSelectionUtil.currentSelectListForEntity(secondEntity); + results.addAll(thirdColumn); } } } @@ -396,22 +383,19 @@ class BrnSelectionEntity { } List allSelectedList() { - List results = List(); - List firstColumn = - BrnSelectionUtil.currentSelectListForEntity(this); + List results = []; + List firstColumn = BrnSelectionUtil.currentSelectListForEntity(this); results.addAll(firstColumn); - if (firstColumn != null && firstColumn.length > 0) { + if (firstColumn.length > 0) { for (BrnSelectionEntity firstEntity in firstColumn) { - if (firstEntity != null) { - List secondColumn = - BrnSelectionUtil.currentSelectListForEntity(firstEntity); - results.addAll(secondColumn); - if (secondColumn != null && secondColumn.length > 0) { - for (BrnSelectionEntity secondEntity in secondColumn) { - List thirdColumn = - BrnSelectionUtil.currentSelectListForEntity(secondEntity); - results.addAll(thirdColumn); - } + List secondColumn = + BrnSelectionUtil.currentSelectListForEntity(firstEntity); + results.addAll(secondColumn); + if (secondColumn.length > 0) { + for (BrnSelectionEntity secondEntity in secondColumn) { + List thirdColumn = + BrnSelectionUtil.currentSelectListForEntity(secondEntity); + results.addAll(thirdColumn); } } } @@ -429,17 +413,18 @@ class BrnSelectionEntity { BrnSelectionEntity getRootEntity(BrnSelectionEntity rootEntity) { if (rootEntity.parent == null || - rootEntity.parent.maxSelectedCount == - BrnSelectionConstant.MAX_SELECT_COUNT) { + rootEntity.parent!.maxSelectedCount == BrnSelectionConstant.maxSelectCount) { return rootEntity; } else { - return getRootEntity(rootEntity.parent); + return getRootEntity(rootEntity.parent!); } } /// 返回最后一层级【选中状态】 Item 的 个数 int getSelectedChildCount(BrnSelectionEntity entity) { - if (BrunoTools.isEmpty(entity.children)) return entity.isSelected ? 1 : 0; + if (BrunoTools.isEmpty(entity.children)) { + return entity.isSelected ? 1 : 0; + } int count = 0; for (BrnSelectionEntity child in entity.children) { @@ -451,13 +436,11 @@ class BrnSelectionEntity { /// 判断当前的筛选 Item 是否为当前层次中第一个被选中的 Item。 /// 用于展开筛选弹窗时显示选中效果。 int getIndexInCurrentLevel() { - if (parent == null || - parent.children == null || - parent.children.length == 0) return -1; + if (parent == null || parent!.children.length == 0) return -1; - for (BrnSelectionEntity entity in parent.children) { + for (BrnSelectionEntity entity in parent!.children) { if (entity == this) { - return parent.children.indexOf(entity); + return parent!.children.indexOf(entity); } } return -1; @@ -465,12 +448,10 @@ class BrnSelectionEntity { /// 是否在筛选数据的最后一层。 如果最大层次为 3;某个筛选数据层次为 2,但其无子节点。此时认为不在最后一层。 bool isInLastLevel() { - if (parent == null || - parent.children == null || - parent.children.length == 0) return true; + if (parent == null || parent!.children.length == 0) return true; - for (BrnSelectionEntity entity in parent.children) { - if (entity.children != null && entity.children.length > 0) { + for (BrnSelectionEntity entity in parent!.children) { + if (entity.children.length > 0) { return false; } } @@ -479,36 +460,35 @@ class BrnSelectionEntity { /// 检查自己的兄弟结点是否存在 checkbox 类型。 bool hasCheckBoxBrother() { - int count = parent?.children - ?.where((f) => f.filterType == BrnSelectionFilterType.Checkbox) - ?.length; + int? count = + parent?.children.where((f) => f.filterType == BrnSelectionFilterType.checkbox).length; return count == null ? false : count > 0; } /// 在这里简单认为 value 为空【null 或 ''】时为 unlimit. bool isUnLimit() { - return filterType == BrnSelectionFilterType.UnLimit; + return filterType == BrnSelectionFilterType.unLimit; } void clearSelectedEntity() { - List tmp = List(); + List tmp = []; BrnSelectionEntity node = this; tmp.add(node); while (tmp.isNotEmpty) { node = tmp.removeLast(); node.isSelected = false; - node.children?.forEach((data) { + node.children.forEach((data) { tmp.add(data); }); } } List currentTagListForEntity() { - List list = List(); - this.children?.forEach((data) { - if (data.filterType != BrnSelectionFilterType.Range && - data.filterType != BrnSelectionFilterType.DateRange && - data.filterType != BrnSelectionFilterType.DateRangeCalendar) { + List list = []; + children.forEach((data) { + if (data.filterType != BrnSelectionFilterType.range && + data.filterType != BrnSelectionFilterType.dateRange && + data.filterType != BrnSelectionFilterType.dateRangeCalendar) { list.add(data); } }); @@ -535,18 +515,18 @@ class BrnSelectionEntity { /// 接口返回默认展示tag个数 int getDefaultShowCount() { int defaultCount = 3; - if (extMap != null && extMap.containsKey('defaultShowCount')) { + if (extMap.containsKey('defaultShowCount')) { defaultCount = extMap['defaultShowCount'] ?? 3; } return defaultCount; } List currentRangeListForEntity() { - List list = List(); - this.children.forEach((data) { - if (data.filterType == BrnSelectionFilterType.Range || - data.filterType == BrnSelectionFilterType.DateRange || - data.filterType == BrnSelectionFilterType.DateRangeCalendar) { + List list = []; + children.forEach((data) { + if (data.filterType == BrnSelectionFilterType.range || + data.filterType == BrnSelectionFilterType.dateRange || + data.filterType == BrnSelectionFilterType.dateRangeCalendar) { list.add(data); } }); @@ -554,36 +534,34 @@ class BrnSelectionEntity { } bool isValidRange() { - if (this.filterType == BrnSelectionFilterType.Range || - this.filterType == BrnSelectionFilterType.DateRange || - this.filterType == BrnSelectionFilterType.DateRangeCalendar) { - DateTime minTime = DateTime.parse(DATE_PICKER_MIN_DATETIME); - DateTime maxTime = DateTime.parse(DATE_PICKER_MAX_DATETIME); + if (this.filterType == BrnSelectionFilterType.range || + this.filterType == BrnSelectionFilterType.dateRange || + this.filterType == BrnSelectionFilterType.dateRangeCalendar) { + DateTime minTime = DateTime.parse(datePickerMinDatetime); + DateTime maxTime = DateTime.parse(datePickerMaxDatetime); int limitMin = int.tryParse(extMap['min']?.toString() ?? "") ?? - (this.filterType == BrnSelectionFilterType.DateRange || - this.filterType == BrnSelectionFilterType.DateRangeCalendar + (this.filterType == BrnSelectionFilterType.dateRange || + this.filterType == BrnSelectionFilterType.dateRangeCalendar ? minTime.millisecondsSinceEpoch : 0); // 日期最大值没设置 默认是2121年01月01日 08:00:00 int limitMax = int.tryParse(extMap['max']?.toString() ?? "") ?? - (this.filterType == BrnSelectionFilterType.DateRange || - this.filterType == BrnSelectionFilterType.DateRangeCalendar + (this.filterType == BrnSelectionFilterType.dateRange || + this.filterType == BrnSelectionFilterType.dateRangeCalendar ? maxTime.millisecondsSinceEpoch : 9999); - if (customMap != null && customMap.isNotEmpty) { - String min = customMap['min'] ?? ""; - String max = customMap['max'] ?? ""; + if (customMap != null && customMap!.isNotEmpty) { + String min = customMap!['min'] ?? ""; + String max = customMap!['max'] ?? ""; if (min.isEmpty && max.isEmpty) { return true; } - int inputMin = int.tryParse(customMap['min'] ?? ""); - int inputMax = int.tryParse(customMap['max'] ?? ""); + int? inputMin = int.tryParse(customMap!['min'] ?? ""); + int? inputMax = int.tryParse(customMap!['max'] ?? ""); if (inputMax != null && inputMin != null) { - if (inputMin >= limitMin && - inputMax <= limitMax && - inputMax >= inputMin) { + if (inputMin >= limitMin && inputMax <= limitMax && inputMax >= inputMin) { return true; } else { return false; @@ -601,7 +579,7 @@ class BrnSelectionEntity { } int getFirstSelectedChildIndex() { - return this.children.indexWhere((data) { + return children.indexWhere((data) { return data.isSelected; }); } @@ -617,7 +595,6 @@ class BrnSelectionEntity { title == other.title && children == other.children && isSelected == other.isSelected && - unit == other.unit && extMap == other.extMap && customMap == other.customMap && type == other.type && @@ -632,7 +609,6 @@ class BrnSelectionEntity { title.hashCode ^ children.hashCode ^ isSelected.hashCode ^ - unit.hashCode ^ extMap.hashCode ^ customMap.hashCode ^ type.hashCode ^ diff --git a/lib/src/components/selection/brn_flat_selection.dart b/lib/src/components/selection/brn_flat_selection.dart index 9e78535f..e581dde6 100644 --- a/lib/src/components/selection/brn_flat_selection.dart +++ b/lib/src/components/selection/brn_flat_selection.dart @@ -21,70 +21,65 @@ class BrnFlatSelection extends StatefulWidget { final List entityDataList; /// 点击确定回调 - final Function(Map) confirmCallback; + final Function(Map)? confirmCallback; /// 每行展示tag数量 默认真是3个 final int preLineTagSize; - /// 当[BrnSelectionEntity.filterType]为[BrnSelectionFilterType.Layer] or[BrnSelectionFilterType.CustomLayer]时 + /// 当[BrnSelectionEntity.filterType]为[BrnSelectionFilterType.layer] or[BrnSelectionFilterType.customLayer]时 /// 跳转到二级页面的自定义操作 - final BrnOnCustomFloatingLayerClick onCustomFloatingLayerClick; + final BrnOnCustomFloatingLayerClick? onCustomFloatingLayerClick; /// controller.dispose() 操作交由外部处理 - final BrnFlatSelectionController controller; + final BrnFlatSelectionController? controller; /// 是否需要配置子选项 final bool isNeedConfigChild; /// 主题配置 /// 如有对文本样式、圆角、间距等[BrnSelectionConfig]有特定要求可以配置该属性 - BrnSelectionConfig themeData; + BrnSelectionConfig? themeData; BrnFlatSelection( - {this.entityDataList, + {Key? key, + required this.entityDataList, this.confirmCallback, this.onCustomFloatingLayerClick, this.preLineTagSize = 3, this.isNeedConfigChild = true, this.controller, - this.themeData}) { + this.themeData}) + : super(key: key) { this.themeData ??= BrnSelectionConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) + .getConfig(configId: this.themeData!.configId) .selectionConfig - .merge(themeData); + .merge(this.themeData!); } @override _BrnFlatSelectionState createState() => _BrnFlatSelectionState(); } -class _BrnFlatSelectionState extends State - with SingleTickerProviderStateMixin { - List _originalSelectedItemsList; +class _BrnFlatSelectionState extends State with SingleTickerProviderStateMixin { + List _originalSelectedItemsList = []; - StreamController clearController; + StreamController clearController = StreamController.broadcast(); bool isValid = true; - BrnFlatSelectionController _controller; - var _lineWidth = 0.0; + double _lineWidth = 0.0; @override void initState() { super.initState(); - _controller = widget.controller; - if (widget.isNeedConfigChild ?? true) { - widget.entityDataList - ?.forEach((f) => f.configRelationshipAndDefaultValue()); + if (widget.isNeedConfigChild) { + widget.entityDataList.forEach((f) => f.configRelationshipAndDefaultValue()); } - _controller?.addListener(_handleFlatControllerTick); + widget.controller?.addListener(_handleFlatControllerTick); - _originalSelectedItemsList = List(); - _originalSelectedItemsList.clear(); - - List firstColumn = List(); - if (widget.entityDataList != null && widget.entityDataList.length > 0) { + List firstColumn = []; + if (widget.entityDataList.length > 0) { for (BrnSelectionEntity entity in widget.entityDataList) { if (entity.isSelected) { firstColumn.add(entity); @@ -92,18 +87,16 @@ class _BrnFlatSelectionState extends State } } _originalSelectedItemsList.addAll(firstColumn); - if (firstColumn != null && firstColumn.length > 0) { + if (firstColumn.length > 0) { for (BrnSelectionEntity firstEntity in firstColumn) { - if (firstEntity != null) { - List secondColumn = - BrnSelectionUtil.currentSelectListForEntity(firstEntity); - _originalSelectedItemsList.addAll(secondColumn); - if (secondColumn != null && secondColumn.length > 0) { - for (BrnSelectionEntity secondEntity in secondColumn) { - List thirdColumn = - BrnSelectionUtil.currentSelectListForEntity(secondEntity); - _originalSelectedItemsList.addAll(thirdColumn); - } + List secondColumn = + BrnSelectionUtil.currentSelectListForEntity(firstEntity); + _originalSelectedItemsList.addAll(secondColumn); + if (secondColumn.length > 0) { + for (BrnSelectionEntity secondEntity in secondColumn) { + List thirdColumn = + BrnSelectionUtil.currentSelectListForEntity(secondEntity); + _originalSelectedItemsList.addAll(thirdColumn); } } } @@ -112,29 +105,27 @@ class _BrnFlatSelectionState extends State for (BrnSelectionEntity entity in _originalSelectedItemsList) { entity.isSelected = true; if (entity.customMap != null) { - //ori 是存数据 customMap是用来展示ui的 - entity.originalCustomMap = Map.from(entity.customMap); + // originalCustomMap 是用来存临时状态数据, customMap 用来展示 ui + entity.originalCustomMap = Map.from(entity.customMap!); } } - - clearController = StreamController.broadcast(); } void _handleFlatControllerTick() { - if (_controller.isResetSelectedOptions) { + if (widget.controller?.isResetSelectedOptions ?? false) { if (mounted) { setState(() { _resetSelectedOptions(); }); } - _controller.isResetSelectedOptions = false; - } else if (_controller.isCancelSelectedOptions) { + widget.controller?.isResetSelectedOptions = false; + } else if (widget.controller?.isCancelSelectedOptions ?? false) { // 外部关闭调用无UI更新操作 _cancelSelectedOptions(); - _controller.isCancelSelectedOptions = false; - } else if (_controller.isConfirmSelectedOptions) { + widget.controller?.isCancelSelectedOptions = false; + } else if (widget.controller?.isConfirmSelectedOptions ?? false) { _confirmSelectedOptions(); - _controller.isConfirmSelectedOptions = false; + widget.controller?.isConfirmSelectedOptions = false; } } @@ -151,13 +142,13 @@ class _BrnFlatSelectionState extends State @override void dispose() { - _controller?.removeListener(_handleFlatControllerTick); + widget.controller?.removeListener(_handleFlatControllerTick); super.dispose(); } /// 取消 _cancelSelectedOptions() { - if (widget.entityDataList == null || widget.entityDataList.length <= 0) { + if (widget.entityDataList.length <= 0) { return; } for (BrnSelectionEntity entity in widget.entityDataList) { @@ -167,13 +158,11 @@ class _BrnFlatSelectionState extends State _originalSelectedItemsList.forEach((data) { data.isSelected = true; if (data.customMap != null) { - //ori 是存数据 customMap是用来展示ui的 + // originalCustomMap 是用来存临时状态数据, customMap 用来展示 ui data.customMap = Map(); - if (data.originalCustomMap != null) { - data.originalCustomMap.forEach((key, value) { - data.customMap[key.toString()] = value.toString() ?? ""; - }); - } + data.originalCustomMap.forEach((key, value) { + data.customMap![key.toString()] = value.toString(); + }); } }); } @@ -181,7 +170,7 @@ class _BrnFlatSelectionState extends State /// 重置 _resetSelectedOptions() { clearController.add(FlatClearEvent()); - if (widget.entityDataList != null && widget.entityDataList.length > 0) { + if (widget.entityDataList.length > 0) { for (BrnSelectionEntity entity in widget.entityDataList) { _clearUIData(entity); } @@ -203,9 +192,10 @@ class _BrnFlatSelectionState extends State data.isSelected = false; } }); - - widget.confirmCallback( - DefaultSelectionConverter().convertSelectedData(widget.entityDataList)); + if (widget.confirmCallback != null) { + widget + .confirmCallback!(DefaultSelectionConverter().convertSelectedData(widget.entityDataList)); + } } /// 标题+筛选条件的 列表 @@ -223,7 +213,7 @@ class _BrnFlatSelectionState extends State onCustomFloatingLayerClick: widget.onCustomFloatingLayerClick, preLineTagSize: widget.preLineTagSize, parentWidth: _lineWidth, - themeData: widget.themeData, + themeData: widget.themeData!, ); }, itemCount: widget.entityDataList.length, @@ -237,18 +227,16 @@ class _BrnFlatSelectionState extends State void _clearUIData(BrnSelectionEntity entity) { entity.isSelected = false; entity.customMap = Map(); - if (BrnSelectionFilterType.Range == entity.filterType) { - entity.title = null; + if (BrnSelectionFilterType.range == entity.filterType) { + entity.title = ''; } - if (entity.children != null) { - for (BrnSelectionEntity subEntity in entity.children) { - _clearUIData(subEntity); - } + for (BrnSelectionEntity subEntity in entity.children) { + _clearUIData(subEntity); } } void _clearSelectedEntity() { - List tmp = List(); + List tmp = []; BrnSelectionEntity node; tmp.addAll(widget.entityDataList); while (tmp.isNotEmpty) { @@ -258,7 +246,7 @@ class _BrnFlatSelectionState extends State BrnToast.show('您输入的区间有误', context); return; } - node.children?.forEach((data) { + node.children.forEach((data) { tmp.add(data); }); } diff --git a/lib/src/components/selection/brn_more_selection.dart b/lib/src/components/selection/brn_more_selection.dart index 7747b340..95d90c72 100644 --- a/lib/src/components/selection/brn_more_selection.dart +++ b/lib/src/components/selection/brn_more_selection.dart @@ -27,15 +27,17 @@ import 'package:flutter/material.dart'; /// 参考[BrnSelectionEntity]和[BrnSelectionView] class BrnMoreSelectionPage extends StatefulWidget { final BrnSelectionEntity entityData; - final Function(BrnSelectionEntity) confirmCallback; - final BrnOnCustomFloatingLayerClick onCustomFloatingLayerClick; + final Function(BrnSelectionEntity)? confirmCallback; + final BrnOnCustomFloatingLayerClick? onCustomFloatingLayerClick; final BrnSelectionConfig themeData; BrnMoreSelectionPage( - {this.entityData, + {Key? key, + required this.entityData, this.confirmCallback, this.onCustomFloatingLayerClick, - this.themeData}); + required this.themeData}) + : super(key: key); @override _BrnMoreSelectionPageState createState() => _BrnMoreSelectionPageState(); @@ -43,10 +45,10 @@ class BrnMoreSelectionPage extends StatefulWidget { class _BrnMoreSelectionPageState extends State with SingleTickerProviderStateMixin { - List _originalSelectedItemsList; - AnimationController _controller; - Animation animation; - StreamController clearController; + List _originalSelectedItemsList = []; + late AnimationController _controller; + late Animation _animation; + StreamController _clearController = StreamController.broadcast(); bool isValid = true; @override @@ -56,23 +58,17 @@ class _BrnMoreSelectionPageState extends State duration: const Duration(milliseconds: 300), vsync: this, ); - animation = - Tween(end: Offset.zero, begin: Offset(1.0, 0.0)).animate(_controller); + _animation = Tween(end: Offset.zero, begin: Offset(1.0, 0.0)).animate(_controller); _controller.forward(); - _originalSelectedItemsList = List(); - _originalSelectedItemsList.clear(); - _originalSelectedItemsList - .addAll(widget.entityData?.allSelectedList() ?? List()); + _originalSelectedItemsList.addAll(widget.entityData.allSelectedList()); for (BrnSelectionEntity entity in _originalSelectedItemsList) { entity.isSelected = true; if (entity.customMap != null) { - //ori 是存数据 customMap是用来展示ui的 - entity.originalCustomMap = Map.from(entity.customMap); + // originalCustomMap 是用来存临时状态数据, customMap 用来展示 ui + entity.originalCustomMap = Map.from(entity.customMap!); } } - - clearController = StreamController.broadcast(); } /// 页面结构:左侧的透明黑 + 右侧宽为300的内容区域 @@ -87,7 +83,7 @@ class _BrnMoreSelectionPageState extends State animation: _controller, builder: (context, child) { return SlideTransition( - position: animation, + position: _animation, child: child, ); }, @@ -105,7 +101,7 @@ class _BrnMoreSelectionPageState extends State animation: _controller, builder: (context, child) { return SlideTransition( - position: animation, + position: _animation, child: child, ); }, @@ -132,7 +128,8 @@ class _BrnMoreSelectionPageState extends State @override void dispose() { super.dispose(); - _controller?.dispose(); + _controller.dispose(); + _clearController.close(); } /// 左侧为透明黑,点击直接退出页面 @@ -145,13 +142,11 @@ class _BrnMoreSelectionPageState extends State _originalSelectedItemsList.forEach((data) { data.isSelected = true; if (data.customMap != null) { - //ori 是存数据 customMap是用来展示ui的 + // originalCustomMap 是用来存临时状态数据, customMap 用来展示 ui data.customMap = Map(); - if (data.originalCustomMap != null) { - data.originalCustomMap.forEach((key, value) { - data.customMap[key.toString()] = value.toString() ?? ""; - }); - } + data.originalCustomMap.forEach((key, value) { + data.customMap![key.toString()] = value.toString(); + }); } }); Navigator.maybePop(context); @@ -180,7 +175,7 @@ class _BrnMoreSelectionPageState extends State return ListView.builder( itemBuilder: (context, index) { return BrnMoreSelectionWidget( - clearController: clearController, + clearController: _clearController, selectionEntity: widget.entityData.children[index], onCustomFloatingLayerClick: widget.onCustomFloatingLayerClick, themeData: widget.themeData); @@ -196,7 +191,7 @@ class _BrnMoreSelectionPageState extends State themeData: widget.themeData, clearCallback: () { setState(() { - clearController.add(ClearEvent()); + _clearController.add(ClearEvent()); _clearUIData(widget.entityData); }); }, @@ -215,7 +210,7 @@ class _BrnMoreSelectionPageState extends State } }); if (widget.confirmCallback != null) { - widget.confirmCallback(data); + widget.confirmCallback!(data); } Navigator.of(context).pop(); }, @@ -226,13 +221,11 @@ class _BrnMoreSelectionPageState extends State void _clearUIData(BrnSelectionEntity entity) { entity.isSelected = false; entity.customMap = Map(); - if (BrnSelectionFilterType.Range == entity.filterType) { - entity.title = null; + if (BrnSelectionFilterType.range == entity.filterType) { + entity.title = ''; } - if (entity.children != null) { - for (BrnSelectionEntity subEntity in entity.children) { - _clearUIData(subEntity); - } + for (BrnSelectionEntity subEntity in entity.children) { + _clearUIData(subEntity); } } @@ -241,26 +234,24 @@ class _BrnMoreSelectionPageState extends State } void clearSelectedEntity() { - List tmp = List(); + List tmp = []; BrnSelectionEntity node = widget.entityData; tmp.add(node); while (tmp.isNotEmpty) { node = tmp.removeLast(); if (node.isSelected && - (node.filterType == BrnSelectionFilterType.Range || - node.filterType == BrnSelectionFilterType.DateRange || - node.filterType == BrnSelectionFilterType.DateRangeCalendar)) { + (node.filterType == BrnSelectionFilterType.range || + node.filterType == BrnSelectionFilterType.dateRange || + node.filterType == BrnSelectionFilterType.dateRangeCalendar)) { if (node.customMap != null && - ((node.customMap['min'] != null && - node.customMap['min'].length > 0) || - (node.customMap['max'] != null && - node.customMap['max'].length > 0))) { + (BrunoTools.isEmpty(node.customMap!['min']) || + BrunoTools.isEmpty(node.customMap!['max']))) { if (!node.isValidRange()) { isValid = false; - if (node?.filterType == BrnSelectionFilterType.Range) { + if (node.filterType == BrnSelectionFilterType.range) { BrnToast.show('您输入的区间有误', context); - } else if (node?.filterType == BrnSelectionFilterType.DateRange || - node?.filterType == BrnSelectionFilterType.DateRangeCalendar) { + } else if (node.filterType == BrnSelectionFilterType.dateRange || + node.filterType == BrnSelectionFilterType.dateRangeCalendar) { BrnToast.show('您选择的区间有误', context); } return; @@ -269,52 +260,27 @@ class _BrnMoreSelectionPageState extends State node.isSelected = false; } } - node.children?.forEach((data) { + node.children.forEach((data) { tmp.add(data); }); } } } -/// 用于侧边滑动开一个页面 -class SlideRightRoute extends PageRouteBuilder { - final Widget page; - - SlideRightRoute({this.page}) - : super( - opaque: false, - pageBuilder: ( - BuildContext context, - Animation animation, - Animation secondaryAnimation, - ) => - page, - transitionsBuilder: ( - BuildContext context, - Animation animation, - Animation secondaryAnimation, - Widget child, - ) => - SlideTransition( - position: Tween( - begin: const Offset(1, 0), - end: Offset.zero, - ).animate(animation), - child: child, - ), - ); -} - /// 底部的重置+确定 -// ignore: must_be_immutable class MoreBottomSelectionWidget extends StatelessWidget { - final VoidCallback clearCallback; - final Function(BrnSelectionEntity) conformCallback; final BrnSelectionEntity entity; - BrnSelectionConfig themeData; + final VoidCallback? clearCallback; + final Function(BrnSelectionEntity)? conformCallback; + final BrnSelectionConfig themeData; - MoreBottomSelectionWidget( - {this.clearCallback, this.conformCallback, this.entity, this.themeData}); + MoreBottomSelectionWidget({ + Key? key, + required this.entity, + this.clearCallback, + this.conformCallback, + required this.themeData, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -324,7 +290,7 @@ class MoreBottomSelectionWidget extends StatelessWidget { GestureDetector( onTap: () { if (clearCallback != null) { - clearCallback(); + clearCallback!(); } }, child: Container( @@ -351,7 +317,7 @@ class MoreBottomSelectionWidget extends StatelessWidget { title: '确定', onTap: () { if (conformCallback != null) { - conformCallback(entity); + conformCallback!(entity); } }, )), diff --git a/lib/src/components/selection/brn_selection_list_entity.dart b/lib/src/components/selection/brn_selection_list_entity.dart index 89b80bbb..ce2c36dd 100644 --- a/lib/src/components/selection/brn_selection_list_entity.dart +++ b/lib/src/components/selection/brn_selection_list_entity.dart @@ -1,16 +1,14 @@ import 'package:bruno/src/components/selection/bean/brn_selection_common_entity.dart'; class BrnSelectionEntityListBean { - List list; + List? list; BrnSelectionEntityListBean(this.list); - static BrnSelectionEntityListBean fromMap(Map map) { - if (map == null) return null; + static BrnSelectionEntityListBean? fromJson(Map? map) { + if (map == null || map['list'] == null) return null; BrnSelectionEntityListBean bean = BrnSelectionEntityListBean(null); - bean.list = List() - ..addAll((map['list'] as List ?? []) - .map((o) => BrnSelectionEntity.fromMap(o))); + bean.list = (map['list'] as List).map((o) => BrnSelectionEntity.fromMap(o)).toList(); return bean; } } diff --git a/lib/src/components/selection/brn_selection_util.dart b/lib/src/components/selection/brn_selection_util.dart index 7fe2315a..69b488d8 100644 --- a/lib/src/components/selection/brn_selection_util.dart +++ b/lib/src/components/selection/brn_selection_util.dart @@ -9,17 +9,17 @@ class BrnSelectionUtil { /// 处理兄弟结点为未选中状态,将自己置为选中状态 static void processBrotherItemSelectStatus( BrnSelectionEntity selectionEntity) { - if (BrnSelectionFilterType.Checkbox == selectionEntity.filterType) { + if (BrnSelectionFilterType.checkbox == selectionEntity.filterType) { selectionEntity.isSelected = !selectionEntity.isSelected; - List allBrothers = selectionEntity.parent?.children; + List? allBrothers = selectionEntity.parent?.children; if (!BrunoTools.isEmpty(allBrothers)) { - for (BrnSelectionEntity entity in allBrothers) { + for (BrnSelectionEntity entity in allBrothers!) { if (entity != selectionEntity) { - if (entity.filterType == BrnSelectionFilterType.Radio) { + if (entity.filterType == BrnSelectionFilterType.radio) { entity.isSelected = false; } - if (entity.filterType == BrnSelectionFilterType.Date) { + if (entity.filterType == BrnSelectionFilterType.date) { entity.isSelected = false; entity.value = null; } @@ -27,13 +27,13 @@ class BrnSelectionUtil { } } } - if (BrnSelectionFilterType.Radio == selectionEntity.filterType) { - selectionEntity?.parent?.clearChildSelection(); + if (BrnSelectionFilterType.radio == selectionEntity.filterType) { + selectionEntity.parent?.clearChildSelection(); selectionEntity.isSelected = true; } - if (BrnSelectionFilterType.Date == selectionEntity.filterType) { - selectionEntity?.parent?.clearChildSelection(); + if (BrnSelectionFilterType.date == selectionEntity.filterType) { + selectionEntity.parent?.clearChildSelection(); /// 日期类型时在外部 Picker 点击确定时设置 选中状态 selectionEntity.isSelected = true; @@ -45,21 +45,17 @@ class BrnSelectionUtil { int level = 0; BrnSelectionEntity rootEntity = entity; while (rootEntity.parent != null) { - rootEntity = rootEntity.parent; + rootEntity = rootEntity.parent!; } - if (rootEntity != null && - rootEntity.children != null && - rootEntity.children.length > 0) { + if (rootEntity.children.length > 0) { level = level > 1 ? level : 1; for (BrnSelectionEntity firstLevelEntity in rootEntity.children) { - if (firstLevelEntity.children != null && - firstLevelEntity.children.length > 0) { + if (firstLevelEntity.children.length > 0) { level = level > 2 ? level : 2; for (BrnSelectionEntity secondLevelEntity in firstLevelEntity.children) { - if (secondLevelEntity.children != null && - secondLevelEntity.children.length > 0) { + if (secondLevelEntity.children.length > 0) { level = 3; break; } @@ -73,12 +69,10 @@ class BrnSelectionUtil { /// 返回状态为选中的子节点 static List currentSelectListForEntity( BrnSelectionEntity entity) { - List list = List(); - if (entity.children != null && entity.children.length > 0) { - for (BrnSelectionEntity entity in entity.children) { - if (entity.isSelected) { - list.add(entity); - } + List list = []; + for (BrnSelectionEntity entity in entity.children) { + if (entity.isSelected) { + list.add(entity); } } return list; @@ -87,10 +81,10 @@ class BrnSelectionUtil { /// 判断列表中是否有range类型 static bool hasRangeItem(List list) { for (BrnSelectionEntity entity in list) { - if (BrnSelectionFilterType.Range == entity.filterType || - BrnSelectionFilterType.DateRange == entity.filterType || - BrnSelectionFilterType.DateRangeCalendar == entity.filterType || - BrnSelectionWindowType.Range == entity.filterShowType) { + if (BrnSelectionFilterType.range == entity.filterType || + BrnSelectionFilterType.dateRange == entity.filterType || + BrnSelectionFilterType.dateRangeCalendar == entity.filterType || + BrnSelectionWindowType.range == entity.filterShowType) { return true; } } @@ -98,20 +92,19 @@ class BrnSelectionUtil { } /// 判断列表中是否有range类型 - static BrnSelectionEntity getFilledCustomInputItem( + static BrnSelectionEntity? getFilledCustomInputItem( List list) { - BrnSelectionEntity filledCustomInputItem; - if (list == null) return filledCustomInputItem; + BrnSelectionEntity? filledCustomInputItem; for (BrnSelectionEntity entity in list) { if (entity.isSelected && - (BrnSelectionFilterType.Range == entity.filterType || - BrnSelectionFilterType.DateRange == entity.filterType || - BrnSelectionFilterType.DateRangeCalendar == entity.filterType) && + (BrnSelectionFilterType.range == entity.filterType || + BrnSelectionFilterType.dateRange == entity.filterType || + BrnSelectionFilterType.dateRangeCalendar == entity.filterType) && entity.customMap != null) { filledCustomInputItem = entity; break; } - if (entity.children != null && entity.children.length > 0) { + if (entity.children.length > 0) { filledCustomInputItem = getFilledCustomInputItem(entity.children); } if (filledCustomInputItem != null) { @@ -122,7 +115,7 @@ class BrnSelectionUtil { } /// 确定当前 Item 在第几层级 - static int getCurrentListIndex(BrnSelectionEntity currentItem) { + static int getCurrentListIndex(BrnSelectionEntity? currentItem) { int listIndex = -1; if (currentItem != null) { listIndex = 0; @@ -140,22 +133,16 @@ class BrnSelectionUtil { /// !!! 在设置 isSelected = true之前进行 check。 /// 返回 true 符合条件,false 不符合条件 static bool checkMaxSelectionCount(BrnSelectionEntity entity) { - if (entity == null) return false; return entity.getLimitedRootSelectedChildCount() < entity.getLimitedRootMaxSelectedCount(); } //设置数据为未选中状态 static void resetSelectionDatas(BrnSelectionEntity entity) { - if (entity == null) { - return; - } - entity?.isSelected = false; - entity?.customMap = Map(); - if (entity.children != null) { - for (BrnSelectionEntity subEntity in entity.children) { - resetSelectionDatas(subEntity); - } + entity.isSelected = false; + entity.customMap = Map(); + for (BrnSelectionEntity subEntity in entity.children) { + resetSelectionDatas(subEntity); } } } diff --git a/lib/src/components/selection/brn_selection_view.dart b/lib/src/components/selection/brn_selection_view.dart index 3b61d541..6ee37f02 100644 --- a/lib/src/components/selection/brn_selection_view.dart +++ b/lib/src/components/selection/brn_selection_view.dart @@ -18,11 +18,8 @@ typedef BrnConfigTagCountPerRow(int index, BrnSelectionEntity entity); typedef BrnSetCustomSelectionMenuTitle = void Function( {String menuTitle, bool isMenuTitleHighLight}); -typedef BrnOnSelectionChanged = void Function( - int menuIndex, - Map selectedParams, - Map customParams, - BrnSetCustomSelectionMenuTitle setCustomMenuTitle); +typedef BrnOnSelectionChanged = void Function(int menuIndex, Map selectedParams, + Map customParams, BrnSetCustomSelectionMenuTitle setCustomMenuTitle); /// menu 点击拦截回调 /// [index] menu 的索引位置 @@ -36,26 +33,21 @@ typedef BrnOnSelectionPreShow = BrnSelectionWindowType Function( /// 点击【更多】筛选项时的回调, /// [index] 为点击的位置, /// [openMorePage] 为让用户触发的回调用于展开更多筛选页面 -typedef BrnOnMoreSelectionMenuClick = void Function( - int index, BrnOpenMorePage openMorePage); +typedef BrnOnMoreSelectionMenuClick = void Function(int index, BrnOpenMorePage openMorePage); /// 打开更多筛选页面, /// [updateData] 是否要更新更多筛选的数据, /// [moreSelections] 最新的更多筛选数据,是否更新取决于 [updateData] -typedef BrnOpenMorePage = void Function( - {bool updateData, List moreSelections}); +typedef BrnOpenMorePage = void Function({bool updateData, List moreSelections}); /// 自定义类型的 Menu 被点击时 让外部设置选中的 value 进来统一更新 UI,并将 function 传给外部设置筛选值。 -typedef BrnSetCustomSelectionParams = void Function( - Map customParams); +typedef BrnSetCustomSelectionParams = void Function(Map customParams); /// 自定义类型的 menu 被点击的回调, /// [index] 点击位置, /// [customMenuItem] 自定义筛选 menu 原始数据, /// [customSelectionParams] 开放给外部回调给函数,用于更新自定义筛选参数,触发[BrnOnSelectionChanged]。 -typedef BrnOnCustomSelectionMenuClick = Function( - int index, - BrnSelectionEntity customMenuItem, +typedef BrnOnCustomSelectionMenuClick = Function(int index, BrnSelectionEntity customMenuItem, BrnSetCustomSelectionParams customSelectionParams); /// 当更多筛选页面中,类型为 CustomLayer 被回调时,该函数用于回传参数进 BrnSelectionView 中, @@ -70,48 +62,45 @@ typedef BrnSetCustomFloatingLayerSelectionParams = void Function( typedef BrnOnCustomFloatingLayerClick = Function( int index, BrnSelectionEntity customFloatingLayerEntity, - BrnSetCustomFloatingLayerSelectionParams - setCustomFloatingLayerSelectionParams); + BrnSetCustomFloatingLayerSelectionParams setCustomFloatingLayerSelectionParams); -typedef OnDefaultParamsPrepared = void Function( - Map selectedParams); +typedef OnDefaultParamsPrepared = void Function(Map selectedParams); /// 默认筛选参数转换器,对传入的筛选数据做处理,返回 Map 参数对象。 -const BrnSelectionConverterDelegate _defaultConverter = - const DefaultSelectionConverter(); +const BrnSelectionConverterDelegate _defaultConverter = const DefaultSelectionConverter(); // ignore: must_be_immutable class BrnSelectionView extends StatefulWidget { final BrnSelectionConverterDelegate selectionConverterDelegate; - final BrnOnCustomSelectionMenuClick onCustomSelectionMenuClick; - final BrnOnCustomFloatingLayerClick onCustomFloatingLayerClick; - final BrnOnMoreSelectionMenuClick onMoreSelectionMenuClick; + final BrnOnCustomSelectionMenuClick? onCustomSelectionMenuClick; + final BrnOnCustomFloatingLayerClick? onCustomFloatingLayerClick; + final BrnOnMoreSelectionMenuClick? onMoreSelectionMenuClick; final BrnOnSelectionChanged onSelectionChanged; final List originalSelectionData; - final BrnOnMenuItemInterceptor onMenuClickInterceptor; - final BrnOnSelectionPreShow onSelectionPreShow; + final BrnOnMenuItemInterceptor? onMenuClickInterceptor; + final BrnOnSelectionPreShow? onSelectionPreShow; ///筛选所在列表的外部列表滚动需要收起筛选,此处为最外层列表,有点恶心,但是暂时只想到这个方法,有更好方式的一定要告诉我 - final ScrollController extraScrollController; + final ScrollController? extraScrollController; ///指定筛选固定的相对于屏幕的顶部距离,默认null不指定 - final double constantTop; + final double? constantTop; /// 处理完默认选中的参数后给外部回调 - final OnDefaultParamsPrepared onDefaultParamsPrepared; + final OnDefaultParamsPrepared? onDefaultParamsPrepared; /// 用于对 SelectionWindowType.Range 类型的列数做配置的回调。 - final BrnConfigTagCountPerRow configRowCount; + final BrnConfigTagCountPerRow? configRowCount; - BrnSelectionViewController selectionViewController; + BrnSelectionViewController? selectionViewController; - BrnSelectionConfig themeData; + BrnSelectionConfig? themeData; BrnSelectionView( - {Key key, - this.originalSelectionData, + {Key? key, + required this.originalSelectionData, this.selectionViewController, - @required this.onSelectionChanged, + required this.onSelectionChanged, this.configRowCount, this.selectionConverterDelegate = _defaultConverter, this.onMenuClickInterceptor, @@ -124,12 +113,11 @@ class BrnSelectionView extends StatefulWidget { this.extraScrollController, this.themeData}) : super(key: key) { - selectionViewController ??= BrnSelectionViewController(); this.themeData ??= BrnSelectionConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) + .getConfig(configId: this.themeData!.configId) .selectionConfig - .merge(themeData); + .merge(this.themeData!); } @override @@ -140,57 +128,49 @@ class BrnSelectionView extends StatefulWidget { } class BrnSelectionViewState extends State { - List _selectionData; Map _customParams = Map(); - BrnSelectionConverterDelegate _selectionConverterDelegate; - OnDefaultParamsPrepared _onDefaultParamsPrepared; - + BrnSelectionViewController? _selectionViewController; @override void initState() { super.initState(); - _selectionData = widget.originalSelectionData; - _selectionData?.forEach((f) => f.configRelationshipAndDefaultValue()); - - _selectionConverterDelegate = widget.selectionConverterDelegate; - _onDefaultParamsPrepared = widget.onDefaultParamsPrepared; + _selectionViewController = widget.selectionViewController ?? BrnSelectionViewController(); + widget.originalSelectionData.forEach((f) => f.configRelationshipAndDefaultValue()); - if (_onDefaultParamsPrepared != null) { - _onDefaultParamsPrepared( - _selectionConverterDelegate?.convertSelectedData(_selectionData)); + if (widget.onDefaultParamsPrepared != null) { + widget.onDefaultParamsPrepared!( + widget.selectionConverterDelegate.convertSelectedData(widget.originalSelectionData)); } } @override Widget build(BuildContext context) { - if (_selectionData != null && _selectionData.length > 0) { - _selectionData?.forEach((f) => f.configRelationship()); + if (widget.originalSelectionData.length > 0) { + widget.originalSelectionData.forEach((f) => f.configRelationship()); return BrnSelectionMenuWidget( context: context, - data: _selectionData, - themeData: widget.themeData, + data: widget.originalSelectionData, + themeData: widget.themeData!, extraScrollController: widget.extraScrollController, constantTop: widget.constantTop, configRowCount: widget.configRowCount, onMenuItemClick: (int menuIndex) { - if (widget.onMenuClickInterceptor != null && - widget.onMenuClickInterceptor(menuIndex)) { + if (widget.onMenuClickInterceptor != null && widget.onMenuClickInterceptor!(menuIndex)) { return true; } if (widget.onSelectionPreShow != null) { - _selectionData[menuIndex].filterShowType = - widget.onSelectionPreShow(menuIndex, _selectionData[menuIndex]); + widget.originalSelectionData[menuIndex].filterShowType = + widget.onSelectionPreShow!(menuIndex, widget.originalSelectionData[menuIndex]); } /// 自定义 Menu 的时候, /// 1、外部设置选中的 key-value 参数。 /// 2、触发更新 UI。 /// 3、触发 _onSelectionChanged 统一回调给外部 - if (_selectionData[menuIndex].filterType == - BrnSelectionFilterType.CustomHandle && + if (widget.originalSelectionData[menuIndex].filterType == + BrnSelectionFilterType.customHandle && widget.onCustomSelectionMenuClick != null) { - widget.onCustomSelectionMenuClick( - menuIndex, _selectionData[menuIndex], + widget.onCustomSelectionMenuClick!(menuIndex, widget.originalSelectionData[menuIndex], (Map customParams) { _customParams.clear(); if (customParams != null) { @@ -202,28 +182,24 @@ class BrnSelectionViewState extends State { } /// 自定义 Menu 的时候,让外部设置选中的 value 进来统一更新 UI。 然后触发 _onSelectionChanged 统一回调给外部 - if (_selectionData[menuIndex].filterType == - BrnSelectionFilterType.More && + if (widget.originalSelectionData[menuIndex].filterType == BrnSelectionFilterType.more && widget.onMoreSelectionMenuClick != null) { - widget.onMoreSelectionMenuClick(menuIndex, ( - {bool updateData = false, - List moreSelections}) { - if (updateData != null && updateData) { - List moreSelectionEntities = moreSelections; - _selectionData[menuIndex].children = moreSelectionEntities; - _selectionData[menuIndex].configRelationshipAndDefaultValue(); + widget.onMoreSelectionMenuClick!(menuIndex, ( + {bool updateData = false, List? moreSelections}) { + if (updateData) { + List moreSelectionEntities = moreSelections ?? []; + widget.originalSelectionData[menuIndex].children = moreSelectionEntities; + widget.originalSelectionData[menuIndex].configRelationshipAndDefaultValue(); } setState(() {}); - _openMore(_selectionData[menuIndex], - onCustomFloatingLayerClick: - widget.onCustomFloatingLayerClick); + _openMore(widget.originalSelectionData[menuIndex], + onCustomFloatingLayerClick: widget.onCustomFloatingLayerClick); }); } return false; }, - onConfirm: (BrnSelectionEntity results, int firstIndex, int secondIndex, - int thirdIndex) { - _onSelectionChanged(_selectionData.indexOf(results)); + onConfirm: (BrnSelectionEntity results, int firstIndex, int secondIndex, int thirdIndex) { + _onSelectionChanged(widget.originalSelectionData.indexOf(results)); }, ); } @@ -233,38 +209,37 @@ class BrnSelectionViewState extends State { void _onSelectionChanged(int menuIndex) { widget.onSelectionChanged( menuIndex, - widget.selectionConverterDelegate.convertSelectedData(_selectionData), - _customParams, ({String menuTitle, bool isMenuTitleHighLight}) { + widget.selectionConverterDelegate.convertSelectedData(widget.originalSelectionData), + _customParams, ({String? menuTitle, bool isMenuTitleHighLight = false}) { /// 说明没有 menu 被选中,不需要更新。 if (menuIndex >= 0) { - _selectionData[menuIndex].isCustomTitleHighLight = - isMenuTitleHighLight ?? false; - _selectionData[menuIndex].customTitle = menuTitle; + widget.originalSelectionData[menuIndex].isCustomTitleHighLight = isMenuTitleHighLight; + widget.originalSelectionData[menuIndex].customTitle = menuTitle; } /// 当设置了自定义的参数时: /// 1、执行关闭筛选页面动作(会将menu 中的箭头置为朝下的非激活状态); /// 2、刷新 Menu title; - widget.selectionViewController?.closeSelectionView(); - widget.selectionViewController?.refreshSelectionTitle(); + _selectionViewController?.closeSelectionView(); + _selectionViewController?.refreshSelectionTitle(); setState(() {}); }); setState(() {}); } void _openMore(BrnSelectionEntity entity, - {BrnOnCustomFloatingLayerClick onCustomFloatingLayerClick}) { + {BrnOnCustomFloatingLayerClick? onCustomFloatingLayerClick}) { if (entity.children.length > 0) { Navigator.of(context).push(PageRouteBuilder( opaque: false, pageBuilder: (context, animation, second) { return BrnMoreSelectionPage( entityData: entity, - themeData: widget.themeData, + themeData: widget.themeData!, onCustomFloatingLayerClick: onCustomFloatingLayerClick, confirmCallback: (_) { EventBus.instance.fire(RefreshMenuTitleEvent()); - _onSelectionChanged(_selectionData.indexOf(entity)); + _onSelectionChanged(widget.originalSelectionData.indexOf(entity)); }, ); })); diff --git a/lib/src/components/selection/brn_simple_selection.dart b/lib/src/components/selection/brn_simple_selection.dart index 8931d4a7..bf21351c 100644 --- a/lib/src/components/selection/brn_simple_selection.dart +++ b/lib/src/components/selection/brn_simple_selection.dart @@ -4,10 +4,9 @@ import 'package:bruno/src/components/selection/brn_selection_view.dart'; import 'package:bruno/src/constants/brn_constants.dart'; import 'package:flutter/material.dart'; -typedef BrnSimpleSelectionOnSelectionChanged = void Function( - List selectedParams); +typedef BrnSimpleSelectionOnSelectionChanged = void Function(List selectedParams); -const String defaultMenuKey = "defaultMenuKey"; +const String _defaultMenuKey = "defaultMenuKey"; // ignore: must_be_immutable class BrnSimpleSelection extends StatefulWidget { @@ -18,7 +17,7 @@ class BrnSimpleSelection extends StatefulWidget { final String menuKey; /// 默认选中选项值 - final String defaultValue; + final String? defaultValue; /// 最大选中个数 默认 radio模式 65535 checkbox模式外部传入 final int maxSelectedCount; @@ -30,33 +29,33 @@ class BrnSimpleSelection extends StatefulWidget { final BrnSimpleSelectionOnSelectionChanged onSimpleSelectionChanged; /// 菜单点击事件 - final Function onMenuItemClick; + final Function? onMenuItemClick; /// 是否单选 默认 radio模式 is true , checkbox模式 is false final bool isRadio; /// 单选构造函数 BrnSimpleSelection.radio({ - Key key, - this.menuName, - this.menuKey = defaultMenuKey, + Key? key, + required this.menuName, + this.menuKey = _defaultMenuKey, this.defaultValue, - this.items, - @required this.onSimpleSelectionChanged, + required this.items, + required this.onSimpleSelectionChanged, this.onMenuItemClick, }) : this.isRadio = true, - this.maxSelectedCount = BrnSelectionConstant.MAX_SELECT_COUNT, + this.maxSelectedCount = BrnSelectionConstant.maxSelectCount, super(key: key); /// 多选构造函数 BrnSimpleSelection.checkbox({ - this.menuName, - this.menuKey, + Key? key, + required this.menuName, + this.menuKey = _defaultMenuKey, this.defaultValue, - this.maxSelectedCount, - this.items, - Key key, - @required this.onSimpleSelectionChanged, + this.maxSelectedCount = BrnSelectionConstant.maxSelectCount, + required this.items, + required this.onSimpleSelectionChanged, this.onMenuItemClick, }) : this.isRadio = false, super(key: key); @@ -68,7 +67,7 @@ class BrnSimpleSelection extends StatefulWidget { } class BrnSimpleSelectionState extends State { - List selectionEntityList; + late List selectionEntityList; @override void initState() { @@ -78,9 +77,9 @@ class BrnSimpleSelectionState extends State { /// 将筛选数据转换成通用筛选数据 List _convertFilterToBrnSelection() { - List list = List(); - if (widget.items != null && widget.items.isNotEmpty) { - List children = List(); + List list = []; + if (widget.items.isNotEmpty) { + List children = []; for (var filter in widget.items) { children.add(BrnSelectionEntity.simple( key: filter.key, @@ -104,32 +103,24 @@ class BrnSimpleSelectionState extends State { Widget build(BuildContext context) { return BrnSelectionView( originalSelectionData: selectionEntityList, - onSelectionChanged: - (menuIndex, selectedParams, customParams, setCustomTitleFunction) { - if (widget.onSimpleSelectionChanged != null && selectedParams != null) { - List selectedItems = List(); - String valueStr = selectedParams[widget.menuKey ?? defaultMenuKey]; - if (valueStr != null) { - List values = valueStr.split(','); - - ///遍历获取选中的items - for (String value in values) { - for (ItemEntity item in widget.items) { - if (item.value != null && - value != null && - item.value == value) { - selectedItems.add(item); - break; - } - } + onSelectionChanged: (menuIndex, selectedParams, customParams, setCustomTitleFunction) { + List results = []; + String valueStr = selectedParams[widget.menuKey] ?? ''; + List values = valueStr.split(','); + ///遍历获取选中的items + for (String value in values) { + for (ItemEntity item in widget.items) { + if (item.value != null && item.value == value) { + results.add(item); + break; } } - widget.onSimpleSelectionChanged(selectedItems); } + widget.onSimpleSelectionChanged(results); }, onMenuClickInterceptor: (index) { if (widget.onMenuItemClick != null) { - widget.onMenuItemClick(); + widget.onMenuItemClick!(); } return false; }, diff --git a/lib/src/components/selection/controller/brn_selection_view_controller.dart b/lib/src/components/selection/controller/brn_selection_view_controller.dart index 721d73fe..2dc25955 100644 --- a/lib/src/components/selection/controller/brn_selection_view_controller.dart +++ b/lib/src/components/selection/controller/brn_selection_view_controller.dart @@ -3,13 +3,17 @@ import "package:flutter/foundation.dart"; import 'package:flutter/material.dart'; class BrnSelectionListViewController extends ChangeNotifier { - double listViewTop; //下拉筛选列表顶部坐标 - double screenHeight; int menuIndex; + bool isShow; //是否显示下拉筛选列表 - bool isShow = false; //是否显示下拉筛选列表 + double? listViewTop; //下拉筛选列表顶部坐标 + double? screenHeight; + OverlayEntry? entry; //显示下拉筛选列表的图层 - OverlayEntry entry; //显示下拉筛选列表的图层 + BrnSelectionListViewController({ + this.menuIndex = -1, + this.isShow = false, + }); void show(int index) { isShow = true; @@ -19,6 +23,8 @@ class BrnSelectionListViewController extends ChangeNotifier { void hide() { isShow = false; + entry?.remove(); + entry = null; notifyListeners(); } } diff --git a/lib/src/components/selection/controller/brn_selection_view_date_picker_controller.dart b/lib/src/components/selection/controller/brn_selection_view_date_picker_controller.dart index e198900e..81376f9d 100644 --- a/lib/src/components/selection/controller/brn_selection_view_date_picker_controller.dart +++ b/lib/src/components/selection/controller/brn_selection_view_date_picker_controller.dart @@ -2,10 +2,13 @@ import "package:flutter/foundation.dart"; import 'package:flutter/material.dart'; class BrnSelectionDatePickerController extends ChangeNotifier { - bool isShow = false; //是否显示下拉筛选列表 - OverlayEntry entry; + bool isShow; //是否显示下拉筛选列表 + OverlayEntry? entry; - double screenHeight; //显示下拉筛选列表的图层 + BrnSelectionDatePickerController({ + this.isShow = false, + this.entry, +}); void show() { isShow = true; @@ -13,5 +16,7 @@ class BrnSelectionDatePickerController extends ChangeNotifier { void hide() { isShow = false; + entry?.remove(); + entry = null; } } diff --git a/lib/src/components/selection/converter/brn_selection_converter.dart b/lib/src/components/selection/converter/brn_selection_converter.dart index 76681e69..f9b3ce12 100644 --- a/lib/src/components/selection/converter/brn_selection_converter.dart +++ b/lib/src/components/selection/converter/brn_selection_converter.dart @@ -4,16 +4,14 @@ import 'package:bruno/src/utils/brn_tools.dart'; abstract class BrnSelectionConverterDelegate { /// 统一的数据结构 转换为 用户需要的数据结构,并通过 [BrnSelectionOnSelectionChanged] 回传给用户使用。 - Map convertSelectedData( - List selectedResults); + Map convertSelectedData(List selectedResults); } class DefaultSelectionConverter implements BrnSelectionConverterDelegate { const DefaultSelectionConverter(); @override - Map convertSelectedData( - List selectedResults) { + Map convertSelectedData(List selectedResults) { return getSelectionParams(selectedResults); } } @@ -22,50 +20,45 @@ class DefaultMoreSelectionConverter implements BrnSelectionConverterDelegate { const DefaultMoreSelectionConverter(); @override - Map convertSelectedData( - List selectedResults) { + Map convertSelectedData(List selectedResults) { return getSelectionParams(selectedResults); } } -class DefaultSelectionQuickFilterConverter - implements BrnSelectionConverterDelegate { +class DefaultSelectionQuickFilterConverter implements BrnSelectionConverterDelegate { const DefaultSelectionQuickFilterConverter(); @override - Map convertSelectedData( - List selectedResults) { + Map convertSelectedData(List selectedResults) { return getSelectionParams(selectedResults); } } /// 注意,此方法仅在初始化筛选项之前调用。如果再筛选之后使用会影响筛选View 的展示以及筛选结果。 -Map getSelectionParamsWithConfigChild( - List selectedResults) { +Map getSelectionParamsWithConfigChild(List? selectedResults) { Map params = Map(); if (selectedResults == null) return params; - selectedResults?.forEach((f) => f.configRelationshipAndDefaultValue()); + selectedResults.forEach((f) => f.configRelationshipAndDefaultValue()); return getSelectionParams(selectedResults); } -Map getSelectionParams( - List selectedResults) { +Map getSelectionParams(List? selectedResults) { Map params = Map(); if (selectedResults == null) return params; for (BrnSelectionEntity menuItemEntity in selectedResults) { - if (menuItemEntity.filterType == BrnSelectionFilterType.More) { + if (menuItemEntity.filterType == BrnSelectionFilterType.more) { params.addAll(getSelectionParams(menuItemEntity.children)); } else { /// 1、首先找出 自定义范围的筛选项参数。 - BrnSelectionEntity selectedCustomInputItem = + BrnSelectionEntity? selectedCustomInputItem = BrnSelectionUtil.getFilledCustomInputItem(menuItemEntity.children); if (selectedCustomInputItem != null && !BrunoTools.isEmpty(selectedCustomInputItem.customMap)) { - String key = selectedCustomInputItem.parent.key; + String? key = selectedCustomInputItem.parent?.key; if (!BrunoTools.isEmpty(key)) { - params[key] = selectedCustomInputItem.customMap["min"] + + params[key!] = (selectedCustomInputItem.customMap!["min"] ?? '') + ':' + - selectedCustomInputItem.customMap["max"]; + (selectedCustomInputItem.customMap!["max"] ?? ''); } } @@ -75,13 +68,13 @@ Map getSelectionParams( params.addAll(getCurrentSelectionEntityParams(menuItemEntity)); } else if (levelCount == 2) { params.addAll(getCurrentSelectionEntityParams(menuItemEntity)); - menuItemEntity.children?.forEach((firstLevelItem) => - params.addAll(getCurrentSelectionEntityParams(firstLevelItem))); + menuItemEntity.children.forEach( + (firstLevelItem) => params.addAll(getCurrentSelectionEntityParams(firstLevelItem))); } else if (levelCount == 3) { params.addAll(getCurrentSelectionEntityParams(menuItemEntity)); - menuItemEntity.children?.forEach((firstLevelItem) { + menuItemEntity.children.forEach((firstLevelItem) { params.addAll(getCurrentSelectionEntityParams(firstLevelItem)); - firstLevelItem.children?.forEach((secondLevelItem) { + firstLevelItem.children.forEach((secondLevelItem) { params.addAll(getCurrentSelectionEntityParams(secondLevelItem)); }); }); @@ -91,19 +84,17 @@ Map getSelectionParams( return params; } -Map getCurrentSelectionEntityParams( - BrnSelectionEntity selectionEntity) { +Map getCurrentSelectionEntityParams(BrnSelectionEntity selectionEntity) { Map params = Map(); - String parentKey = selectionEntity.key; - var selectedEntity = selectionEntity.children - ?.where((BrnSelectionEntity f) => f.isSelected) - ?.where((BrnSelectionEntity f) => !BrunoTools.isEmpty(f.value)) - ?.map((BrnSelectionEntity f) => f.value) - ?.toList(); - String selectedParams = - selectedEntity == null ? "" : selectedEntity.join(","); + String? parentKey = selectionEntity.key; + List selectedEntity = selectionEntity.children + .where((BrnSelectionEntity f) => f.isSelected) + .where((BrnSelectionEntity f) => !BrunoTools.isEmpty(f.value)) + .map((BrnSelectionEntity f) => f.value) + .toList(); + String selectedParams = selectedEntity.isEmpty ? '' : selectedEntity.join(','); if (!BrunoTools.isEmpty(selectedParams) && !BrunoTools.isEmpty(parentKey)) { - params[parentKey] = selectedParams; + params[parentKey!] = selectedParams; } return params; } diff --git a/lib/src/components/selection/widget/brn_flat_selection_item.dart b/lib/src/components/selection/widget/brn_flat_selection_item.dart index cf5d89d3..3f8ffc80 100644 --- a/lib/src/components/selection/widget/brn_flat_selection_item.dart +++ b/lib/src/components/selection/widget/brn_flat_selection_item.dart @@ -21,17 +21,16 @@ import 'package:flutter/cupertino.dart'; ///主要是分为两种:标签和跳到其他页面的layer ///标签类型包罗了:标题、有无更多的展开收起、自定义输入、标签项 ///页面类型保罗了:标题、选择框 -// ignore: must_be_immutable class BrnFlatMoreSelection extends StatefulWidget { /// 数据源 final BrnSelectionEntity selectionEntity; /// 清空已选项 一般跟重置功能搭配使用 - final StreamController clearController; + final StreamController? clearController; - /// 当[BrnSelectionEntity.filterType]为[BrnSelectionFilterType.Layer] or[BrnSelectionFilterType.CustomLayer]时 + /// 当[BrnSelectionEntity.filterType]为[BrnSelectionFilterType.layer] or[BrnSelectionFilterType.customLayer]时 /// 跳转到二级页面的自定义操作 - final BrnOnCustomFloatingLayerClick onCustomFloatingLayerClick; + final BrnOnCustomFloatingLayerClick? onCustomFloatingLayerClick; /// 每行tag数 默认3个 final int preLineTagSize; @@ -41,16 +40,17 @@ class BrnFlatMoreSelection extends StatefulWidget { final double parentWidth; /// 主题配置 - BrnSelectionConfig themeData; + final BrnSelectionConfig themeData; BrnFlatMoreSelection({ - this.selectionEntity, + Key? key, + required this.selectionEntity, this.clearController, this.onCustomFloatingLayerClick, this.preLineTagSize = 3, this.parentWidth = 0, - this.themeData, - }); + required this.themeData, + }): super(key: key); @override _BrnFlatMoreSelectionState createState() => _BrnFlatMoreSelectionState(); @@ -60,9 +60,8 @@ class _BrnFlatMoreSelectionState extends State { @override Widget build(BuildContext context) { //弹出浮层 - if (widget.selectionEntity.filterType == BrnSelectionFilterType.Layer || - widget.selectionEntity.filterType == - BrnSelectionFilterType.CustomLayer) { + if (widget.selectionEntity.filterType == BrnSelectionFilterType.layer || + widget.selectionEntity.filterType == BrnSelectionFilterType.customLayer) { return FilterLayerTypeWidget( selectionEntity: widget.selectionEntity, onCustomFloatingLayerClick: widget.onCustomFloatingLayerClick, @@ -85,31 +84,30 @@ class _BrnFlatMoreSelectionState extends State { class _FilterCommonTypeWidget extends StatefulWidget { //楼层 final BrnSelectionEntity selectionEntity; - final StreamController clearController; + final StreamController? clearController; final int preLineTagSize; final double parentWidth; - BrnSelectionConfig themeData; + final BrnSelectionConfig themeData; _FilterCommonTypeWidget( - {this.selectionEntity, + {required this.selectionEntity, this.clearController, this.preLineTagSize = 3, this.parentWidth = 0, - this.themeData}); + required this.themeData}); @override - __FilterCommonTypeWidgetState createState() => - __FilterCommonTypeWidgetState(); + __FilterCommonTypeWidgetState createState() => __FilterCommonTypeWidgetState(); } class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { bool isExpanded = false; ///展开收起的通知 - ValueNotifier valueNotifier; + late ValueNotifier _valueNotifier; ///用于 range和 tag 之间通信 - StreamController streamController; + late StreamController _streamController; /// 标签宽度 double _tagWidth = 0; @@ -123,19 +121,17 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { @override void initState() { super.initState(); - streamController = StreamController.broadcast(); + _streamController = StreamController.broadcast(); //如果是输入事件 //如果是单选的情况,将选中的tag清空 //如果是多选则,不作处理 - streamController.stream.listen((event) { + _streamController.stream.listen((event) { if (event is InputEvent) { setState(() { if (!event.filter) { //将所有tag设置为未选中 - event.rangeEntity.parent - ?.currentTagListForEntity() - ?.forEach((data) { + event.rangeEntity.parent?.currentTagListForEntity().forEach((data) { data.clearSelectedEntity(); }); } @@ -144,10 +140,10 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { }); //展开收起的事件 - valueNotifier = ValueNotifier(isExpanded); - valueNotifier.addListener(() { + _valueNotifier = ValueNotifier(isExpanded); + _valueNotifier.addListener(() { setState(() { - isExpanded = valueNotifier.value; + isExpanded = _valueNotifier.value; }); }); } @@ -155,14 +151,11 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { @override Widget build(BuildContext context) { try { - _tagWidth = (widget.parentWidth - - _spacing * (widget.preLineTagSize - 1) - - _padding * 2) / + _tagWidth = (widget.parentWidth - _spacing * (widget.preLineTagSize - 1) - _padding * 2) / widget.preLineTagSize; //保留小数点后3位 - _tagWidth = double.parse(_tagWidth - .toStringAsFixed(4) - .substring(0, _tagWidth.toStringAsFixed(4).length - 1)); + _tagWidth = double.parse( + _tagWidth.toStringAsFixed(4).substring(0, _tagWidth.toStringAsFixed(4).length - 1)); _tagWidth = _tagWidth < 75 ? 75 : _tagWidth; } catch (e) { debugPrint('get tag width error'); @@ -180,10 +173,7 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { child: _buildTitleWidget(), ), Visibility( - visible: widget.selectionEntity - .currentShowTagByExpanded(isExpanded) - .length > - 0, + visible: widget.selectionEntity.currentShowTagByExpanded(isExpanded).length > 0, child: Container( padding: EdgeInsets.only(top: 12), child: _buildOptionWidgets(), @@ -197,7 +187,7 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { visible: widget.selectionEntity.currentTagListForEntity().length > widget.selectionEntity.getDefaultShowCount(), child: _MoreArrow( - valueNotifier: valueNotifier, + valueNotifier: _valueNotifier, themeData: widget.themeData, ), ), @@ -216,7 +206,7 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { children: [ Expanded( child: Text( - widget.selectionEntity.title ?? "", + widget.selectionEntity.title, style: widget.themeData.titleForMoreTextStyle.generateTextStyle(), ), ), @@ -232,7 +222,7 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { width: 0, ) : _MoreRangeWidget( - streamController: streamController, + streamController: _streamController, clearController: widget.clearController, rangeEntity: widget.selectionEntity.currentRangeListForEntity()[0], themeData: widget.themeData, @@ -249,12 +239,12 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { return GestureDetector( onTap: () { setState(() { - if (data.filterType == BrnSelectionFilterType.Radio) { - data.parent.clearSelectedEntity(); + if (data.filterType == BrnSelectionFilterType.radio) { + data.parent?.clearSelectedEntity(); data.isSelected = true; //用于发送 标签点击事件 - streamController.add(SelectEvent()); - } else if (data.filterType == BrnSelectionFilterType.Checkbox) { + _streamController.add(SelectEvent()); + } else if (data.filterType == BrnSelectionFilterType.checkbox) { if (!data.isSelected) { if (!BrnSelectionUtil.checkMaxSelectionCount(data)) { BrnToast.show('您选择的筛选条件数量已达上限', context); @@ -262,13 +252,13 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { } } - data.parent.children - ?.where((_) => _.filterType == BrnSelectionFilterType.Radio) - ?.forEach((f) => f.isSelected = false); + data.parent?.children + .where((_) => _.filterType == BrnSelectionFilterType.radio) + .forEach((f) => f.isSelected = false); data.isSelected = !data.isSelected; //用于发送 标签点击事件 - streamController.add(SelectEvent()); - } else if (data.filterType == BrnSelectionFilterType.Date) { + _streamController.add(SelectEvent()); + } else if (data.filterType == BrnSelectionFilterType.date) { _showDatePicker(data); } }); @@ -283,7 +273,7 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { /// 当默认显示tag数<= tag总数时,仅展示tag /// 当点击更多时全部展示 Widget _buildOptionWidgets() { - List widgets = List(); + List widgets = []; widgets.addAll(_buildSelectionTag()); if (isExpanded || (widget.selectionEntity.currentRangeListForEntity().isNotEmpty && @@ -299,20 +289,17 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { } Widget _buildSingleTag(BrnSelectionEntity data) { - bool isDate = data.filterType == BrnSelectionFilterType.Date; + bool isDate = data.filterType == BrnSelectionFilterType.date; String showName; if (isDate) { - if (data.value == null || data.value.isEmpty) { + if (data.value == null || data.value!.isEmpty) { showName = data.title; } else { - int time = int.tryParse(data.value ?? "") ?? - DateTime.now().millisecondsSinceEpoch; + int time = int.tryParse(data.value ?? "") ?? DateTime.now().millisecondsSinceEpoch; showName = DateTimeFormatter.formatDate( - DateTime.fromMillisecondsSinceEpoch(time), - 'yyyy/MMMM/dd', - DateTimePickerLocale.zh_cn); + DateTime.fromMillisecondsSinceEpoch(time), 'yyyy/MMMM/dd', DateTimePickerLocale.zh_cn); } } else { showName = data.title; @@ -344,8 +331,7 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { } void _showDatePicker(BrnSelectionEntity data) { - int time = - int.tryParse(data.value ?? "") ?? DateTime.now().millisecondsSinceEpoch; + int time = int.tryParse(data.value ?? "") ?? DateTime.now().millisecondsSinceEpoch; BrnDatePicker.showDatePicker(context, pickerMode: BrnDateTimePickerMode.date, pickerTitleConfig: BrnPickerTitleConfig.Default, @@ -353,7 +339,7 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { dateFormat: 'yyyy年,MMMM月,dd日', onConfirm: (dateTime, list) { if (mounted) { setState(() { - data.parent.clearSelectedEntity(); + data.parent?.clearSelectedEntity(); data.isSelected = true; data.value = dateTime.millisecondsSinceEpoch.toString(); }); @@ -363,13 +349,12 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { } /// 更多和箭头widget -// ignore: must_be_immutable class _MoreArrow extends StatefulWidget { ///用于通知 展开和收起 - final ValueNotifier valueNotifier; - BrnSelectionConfig themeData; + final ValueNotifier? valueNotifier; + final BrnSelectionConfig themeData; - _MoreArrow({this.valueNotifier, this.themeData}); + _MoreArrow({this.valueNotifier, required this.themeData}); @override __MoreArrowState createState() => __MoreArrowState(); @@ -381,7 +366,7 @@ class __MoreArrowState extends State<_MoreArrow> { @override Widget build(BuildContext context) { String asset = - isExpanded ? BrnAsset.ICON_UP_ARROW : BrnAsset.ICON_DOWN_ARROW; + isExpanded ? BrnAsset.iconUpArrow : BrnAsset.iconDownArrow; return GestureDetector( behavior: HitTestBehavior.opaque, @@ -389,7 +374,7 @@ class __MoreArrowState extends State<_MoreArrow> { setState(() { isExpanded = !isExpanded; if (widget.valueNotifier != null) { - widget.valueNotifier.value = isExpanded; + widget.valueNotifier!.value = isExpanded; } }); }, @@ -398,8 +383,7 @@ class __MoreArrowState extends State<_MoreArrow> { child: Row( mainAxisSize: MainAxisSize.min, children: [ - Text('更多', - style: widget.themeData.moreTextStyle.generateTextStyle()), + Text('更多', style: widget.themeData.moreTextStyle.generateTextStyle()), Container( height: 16, width: 16, @@ -419,59 +403,55 @@ class __MoreArrowState extends State<_MoreArrow> { // ignore: must_be_immutable class _MoreRangeWidget extends StatefulWidget { ///用于标签和自定义输入 通信 - final StreamController streamController; + final StreamController? streamController; ///用于自定义的筛选条件 最大值最小值 final BrnSelectionEntity rangeEntity; ///用于监听重置事件 - final StreamController clearController; + final StreamController? clearController; final double width; - BrnSelectionConfig themeData; + final BrnSelectionConfig themeData; - _MoreRangeWidget( - {this.streamController, - this.rangeEntity, - this.clearController, - this.themeData, - this.width = 0, - Key key}) - : super(key: key); + _MoreRangeWidget({ + Key? key, + required this.rangeEntity, + this.streamController, + this.clearController, + this.width = 0, + required this.themeData, + }) : super(key: key); @override __MoreRangeWidgetState createState() => __MoreRangeWidgetState(); } class __MoreRangeWidgetState extends State<_MoreRangeWidget> { - //最小值 输入框监听 - TextEditingController minController; + /// 最小值 输入框监听 + TextEditingController minController = TextEditingController(); - //最大值 输入框监听 - TextEditingController maxController; + /// 最大值 输入框监听 + TextEditingController maxController = TextEditingController(); - //最小值 焦点监听 - FocusNode minFocusNode; + /// 最小值 焦点监听 + FocusNode minFocusNode = FocusNode(); - //最大值 焦点监听 - FocusNode maxFocusNode; + /// 最大值 焦点监听 + FocusNode maxFocusNode = FocusNode(); //默认的最大值 - int max; + int max = 9999; //默认的最小值 - int min; + int min = 0; @override void initState() { super.initState(); - minFocusNode = FocusNode(); - maxFocusNode = FocusNode(); - minController = TextEditingController(); - maxController = TextEditingController(); - widget?.clearController?.stream?.listen((event) { + widget.clearController?.stream.listen((event) { minController.clear(); maxController.clear(); }); @@ -480,30 +460,28 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { widget.rangeEntity.customMap = Map(); } - minController.text = (widget.rangeEntity.customMap['min'] != null) - ? widget.rangeEntity.customMap['min']?.toString() - : null; - maxController.text = (widget.rangeEntity.customMap['max'] != null) - ? widget.rangeEntity.customMap['max']?.toString() - : null; + minController.text = (widget.rangeEntity.customMap!['min'] != null) + ? widget.rangeEntity.customMap!['min']?.toString() ?? '' + : ''; + maxController.text = (widget.rangeEntity.customMap!['max'] != null) + ? widget.rangeEntity.customMap!['max']?.toString() ?? '' + : ''; - min = - int.tryParse(widget.rangeEntity?.extMap['min']?.toString() ?? "") ?? 0; - max = int.tryParse(widget.rangeEntity?.extMap['max']?.toString() ?? "") ?? - 9999; + min = int.tryParse(widget.rangeEntity.extMap['min']?.toString() ?? '') ?? 0; + max = int.tryParse(widget.rangeEntity.extMap['max']?.toString() ?? '') ?? 9999; ///处理的逻辑: /// 1:将输入框的 文本写入 customMap中 /// 2:如果最大值和最小值满足条件 则将range选中 minController.addListener(() { - String maxInput = maxController.text ?? ""; - String minInput = minController.text ?? ""; + String maxInput = maxController.text; + String minInput = minController.text; - widget.rangeEntity.customMap['min'] = minInput; + widget.rangeEntity.customMap!['min'] = minInput; if (minInput.isNotEmpty && maxInput.isNotEmpty) { - int inputMin = int.tryParse(minController.text ?? ""); - int inputMax = int.tryParse(maxController.text ?? ""); + int? inputMin = int.tryParse(minController.text); + int? inputMax = int.tryParse(maxController.text); if (inputMin != null && inputMin >= min && @@ -520,13 +498,13 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { }); maxController.addListener(() { - String maxInput = maxController.text ?? ""; - String minInput = minController.text ?? ""; - widget.rangeEntity.customMap['max'] = maxInput; + String maxInput = maxController.text; + String minInput = minController.text; + widget.rangeEntity.customMap!['max'] = maxInput; if (minInput.isNotEmpty && maxInput.isNotEmpty) { - int inputMin = int.tryParse(minController.text ?? "") ?? -1; - int inputMax = int.tryParse(maxController.text ?? "") ?? -1; + int inputMin = int.tryParse(minController.text) ?? -1; + int inputMax = int.tryParse(maxController.text) ?? -1; if (inputMin >= min && inputMax <= max && inputMin <= inputMax) { widget.rangeEntity.isSelected = true; } else { @@ -542,21 +520,19 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { /// 如果是多选 则不处理 minFocusNode.addListener(() { if (minFocusNode.hasFocus) { - widget.streamController - .add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); + widget.streamController?.add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); } }); maxFocusNode.addListener(() { if (maxFocusNode.hasFocus) { - widget.streamController - .add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); + widget.streamController?.add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); } }); ///用于监听tab的点击事件 ///如果父亲是单选 则将输入框清空并失去焦点,并且将自定义筛选设置为 未选中,以及更新用于显示的map - widget.streamController.stream.listen((event) { + widget.streamController?.stream.listen((event) { if (event is SelectEvent) { maxController.clear(); minController.clear(); @@ -574,8 +550,7 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _buildRangeField( - '最小值', minController, minFocusNode, widget.width, widget.themeData), + _buildRangeField('最小值', minController, minFocusNode, widget.width, widget.themeData), Padding( padding: EdgeInsets.only(left: 2), ), @@ -587,8 +562,7 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { Padding( padding: EdgeInsets.only(right: 2), ), - _buildRangeField( - '最大值', maxController, maxFocusNode, widget.width, widget.themeData), + _buildRangeField('最大值', maxController, maxFocusNode, widget.width, widget.themeData), ], ); } @@ -602,8 +576,7 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { ) { return Container( decoration: BoxDecoration( - color: Color(0xFFF9F9F9), - borderRadius: BorderRadius.all(Radius.circular(4.0))), + color: Color(0xFFF9F9F9), borderRadius: BorderRadius.all(Radius.circular(4.0))), height: 32, width: width, child: Center( @@ -624,15 +597,13 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { } /// 浮层类型的项 : 标题 + 点击跳转的layout -// ignore: must_be_immutable class FilterLayerTypeWidget extends StatefulWidget { //entity是 商圈 final BrnSelectionEntity selectionEntity; - final BrnOnCustomFloatingLayerClick onCustomFloatingLayerClick; - BrnSelectionConfig themeData; + final BrnOnCustomFloatingLayerClick? onCustomFloatingLayerClick; + final BrnSelectionConfig themeData; - FilterLayerTypeWidget( - {this.selectionEntity, this.onCustomFloatingLayerClick, this.themeData}); + FilterLayerTypeWidget({required this.selectionEntity, this.onCustomFloatingLayerClick, required this.themeData}); @override _FilterLayerTypeWidgetState createState() => _FilterLayerTypeWidgetState(); @@ -641,7 +612,7 @@ class FilterLayerTypeWidget extends StatefulWidget { class _FilterLayerTypeWidgetState extends State { @override Widget build(BuildContext context) { - widget.selectionEntity?.configDefaultValue(); + widget.selectionEntity.configDefaultValue(); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -656,8 +627,7 @@ class _FilterLayerTypeWidgetState extends State { padding: const EdgeInsets.only(left: 20, right: 20, top: 6), child: GestureDetector( onTap: () { - if (widget.selectionEntity.filterType == - BrnSelectionFilterType.Layer) { + if (widget.selectionEntity.filterType == BrnSelectionFilterType.layer) { Navigator.of(context) .push(PageRouteBuilder( opaque: false, @@ -670,22 +640,18 @@ class _FilterLayerTypeWidgetState extends State { .then((data) { updateContent(); }); - } else if (widget.selectionEntity.filterType == - BrnSelectionFilterType.CustomLayer) { + } else if (widget.selectionEntity.filterType == BrnSelectionFilterType.customLayer) { if (widget.onCustomFloatingLayerClick != null) { int entityIndex = -1; if (widget.selectionEntity.parent != null && - widget.selectionEntity.parent.children != null) { - entityIndex = widget.selectionEntity.parent.children - .indexOf(widget.selectionEntity); + widget.selectionEntity.parent!.children.isNotEmpty) { + entityIndex = + widget.selectionEntity.parent!.children.indexOf(widget.selectionEntity); } - widget.onCustomFloatingLayerClick( - entityIndex, widget.selectionEntity, + widget.onCustomFloatingLayerClick!(entityIndex, widget.selectionEntity, (List customFloatingLayerParams) { - widget.selectionEntity.children?.clear(); - widget.selectionEntity.children = []; - widget.selectionEntity.children - .addAll(customFloatingLayerParams); + widget.selectionEntity.children.clear(); + widget.selectionEntity.children.addAll(customFloatingLayerParams); widget.selectionEntity.configDefaultValue(); setState(() {}); }); @@ -699,13 +665,12 @@ class _FilterLayerTypeWidgetState extends State { child: Text(isEmptyCondition() ? '请选择' : getCondition(), style: isEmptyCondition() ? widget.themeData.hintTextStyle.generateTextStyle() - : widget.themeData.optionTextStyle - .generateTextStyle()), + : widget.themeData.optionTextStyle.generateTextStyle()), ), Container( height: 16, width: 16, - child: BrunoTools.getAssetImage(BrnAsset.ICON_RIGHT_ARROW), + child: BrunoTools.getAssetImage(BrnAsset.iconRightArrow), ) ], ), @@ -722,14 +687,13 @@ class _FilterLayerTypeWidgetState extends State { bool isEmptyCondition() { String condition = getCondition(); - return condition == null || condition.isEmpty; + return condition.isEmpty; } String getCondition() { String tmp = ""; //返回所有选中的 - List selectedList = - widget.selectionEntity.selectedList(); + List selectedList = widget.selectionEntity.selectedList(); //判断步骤: //第一步:取出来所有选中的: 房山 不限 小白楼 西城 不限 @@ -773,5 +737,5 @@ class InputEvent extends Event { BrnSelectionEntity rangeEntity; bool filter; - InputEvent({this.rangeEntity, this.filter}); + InputEvent({required this.rangeEntity, required this.filter}); } diff --git a/lib/src/components/selection/widget/brn_layer_more_selection_page.dart b/lib/src/components/selection/widget/brn_layer_more_selection_page.dart index 06ec0098..f345c1cb 100644 --- a/lib/src/components/selection/widget/brn_layer_more_selection_page.dart +++ b/lib/src/components/selection/widget/brn_layer_more_selection_page.dart @@ -6,7 +6,6 @@ import 'package:bruno/src/components/toast/brn_toast.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_selection_config.dart'; -import 'package:bruno/src/theme/img/brn_theme_default_utils.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -14,48 +13,47 @@ import 'package:flutter/services.dart'; /// 用于展示浮层的筛选项 如商圈 /// 左侧是:二级筛选项 右侧是三级筛选项 /// 默认将第一个元素选中 -// ignore: must_be_immutable class BrnLayerMoreSelectionPage extends StatefulWidget { - //entity是商圈 final BrnSelectionEntity entityData; - BrnSelectionConfig themeData; + final BrnSelectionConfig themeData; - BrnLayerMoreSelectionPage({this.entityData, this.themeData}); + BrnLayerMoreSelectionPage({ + Key? key, + required this.entityData, + required this.themeData, + }): super(key: key); @override - _BrnLayerMoreSelectionPageState createState() => - _BrnLayerMoreSelectionPageState(); + _BrnLayerMoreSelectionPageState createState() => _BrnLayerMoreSelectionPageState(); } class _BrnLayerMoreSelectionPageState extends State with SingleTickerProviderStateMixin { - List firstList; + List _firstList = []; - List _originalSelectedItemsList; + late List _originalSelectedItemsList; ///当前选中的 一级筛选条件 - BrnSelectionEntity currentFirstEntity; + BrnSelectionEntity? _currentFirstEntity; ///当前选中的 一级筛选条件的索引 - int currentIndex; + int _currentIndex = 0; - AnimationController _controller; - Animation animation; + late AnimationController _controller; + late Animation _animation; @override void initState() { super.initState(); - + WidgetsBinding.instance?.addPostFrameCallback((_) { + SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark); + }); _controller = AnimationController( duration: const Duration(milliseconds: 300), vsync: this, ); - animation = - Tween(end: Offset.zero, begin: Offset(1.0, 0.0)).animate(_controller); + _animation = Tween(end: Offset.zero, begin: Offset(1.0, 0.0)).animate(_controller); _controller.forward(); - - currentIndex = 0; - firstList = List(); _originalSelectedItemsList = widget.entityData.selectedList(); _initData(); @@ -63,9 +61,6 @@ class _BrnLayerMoreSelectionPageState extends State @override Widget build(BuildContext context) { - WidgetsBinding.instance.addPostFrameCallback((_) { - SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark); - }); return Scaffold( backgroundColor: Colors.transparent, body: Row( @@ -75,7 +70,7 @@ class _BrnLayerMoreSelectionPageState extends State animation: _controller, builder: (context, child) { return SlideTransition( - position: animation, + position: _animation, child: child, ); }, @@ -89,7 +84,7 @@ class _BrnLayerMoreSelectionPageState extends State @override void dispose() { super.dispose(); - _controller?.dispose(); + _controller.dispose(); } ///左侧是黑色浮层 @@ -130,10 +125,7 @@ class _BrnLayerMoreSelectionPageState extends State leading: IconButton( icon: Icon( Icons.arrow_back, - color: BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .colorTextBase, + color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, ), onPressed: () { //将选中的筛选项返回 @@ -148,10 +140,7 @@ class _BrnLayerMoreSelectionPageState extends State title: Text( '选择${widget.entityData.title}', style: TextStyle( - color: BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .colorTextBase, + color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, fontSize: 16, fontWeight: FontWeight.w600), ), @@ -189,7 +178,7 @@ class _BrnLayerMoreSelectionPageState extends State itemBuilder: (context, index) { return _buildRightItem(index); }, - itemCount: currentFirstEntity.children.length, + itemCount: _currentFirstEntity?.children.length ?? 0, ), ), ) @@ -209,45 +198,46 @@ class _BrnLayerMoreSelectionPageState extends State // 如果是选中的情况,则将已选中的兄弟节点清除 // 如果是未选的情况,则直接选中 - if (index == currentIndex) { + if (index == _currentIndex) { return; } - if (firstList[index].filterType == BrnSelectionFilterType.Radio) { + if (_firstList[index].filterType == BrnSelectionFilterType.radio) { setState(() { - currentIndex = index; - currentFirstEntity = firstList[index]; - if (currentFirstEntity.isSelected) { - currentFirstEntity.clearSelectedEntity(); - } else { - currentFirstEntity.parent.clearSelectedEntity(); - //设置不限 - setInitialSecondShowingItem(); + _currentIndex = index; + _currentFirstEntity = _firstList[index]; + if (_currentFirstEntity != null) { + if (_currentFirstEntity!.isSelected) { + _currentFirstEntity!.clearSelectedEntity(); + } else { + _currentFirstEntity!.parent?.clearSelectedEntity(); + //设置不限 + setInitialSecondShowingItem(_currentFirstEntity!); + } } }); } else { - firstList[index].parent?.children?.where((data) { - return data.filterType != BrnSelectionFilterType.Checkbox; - })?.forEach((data) { + _firstList[index].parent?.children.where((data) { + return data.filterType != BrnSelectionFilterType.checkbox; + }).forEach((data) { data.isSelected = false; data.clearChildSelection(); }); - if (!this.firstList[index].isSelected) { - if (!BrnSelectionUtil.checkMaxSelectionCount( - firstList[index])) { + if (!this._firstList[index].isSelected) { + if (!BrnSelectionUtil.checkMaxSelectionCount(_firstList[index])) { BrnToast.show('您选择的筛选条件数量已达上限', context); setState(() {}); return; } else { - currentIndex = index; - currentFirstEntity = firstList[index]; + _currentIndex = index; + _currentFirstEntity = _firstList[index]; //一级选中的情况,初始化二级 - setInitialSecondShowingItem(); + setInitialSecondShowingItem(_currentFirstEntity!); setState(() {}); } } else { - currentIndex = index; - currentFirstEntity = firstList[index]; + _currentIndex = index; + _currentFirstEntity = _firstList[index]; setState(() {}); } } @@ -255,7 +245,7 @@ class _BrnLayerMoreSelectionPageState extends State child: _buildLeftItem(index), ); }, - itemCount: firstList.length, + itemCount: _firstList.length, ); } @@ -300,20 +290,18 @@ class _BrnLayerMoreSelectionPageState extends State Widget _buildLeftItem(int index) { //如果房山 被选中了或者房山处于正在选择的状态 则加粗 - TextStyle textStyle = - widget.themeData.flayNormalTextStyle.generateTextStyle(); - if (index == currentIndex) { - textStyle = widget.themeData.flatSelectedTextStyle.generateTextStyle(); - } else if ((firstList[index].isSelected) && - firstList[index].selectedList().isNotEmpty) { - textStyle = widget.themeData.flatBoldTextStyle.generateTextStyle(); + TextStyle textStyle = widget.themeData.flayerNormalTextStyle.generateTextStyle(); + if (index == _currentIndex) { + textStyle = widget.themeData.flayerSelectedTextStyle.generateTextStyle(); + } else if ((_firstList[index].isSelected) && _firstList[index].selectedList().isNotEmpty) { + textStyle = widget.themeData.flayerBoldTextStyle.generateTextStyle(); } - List list = firstList[index].selectedList(); + List list = _firstList[index].selectedList(); //如果选中了不限 则展示 房山全部 //如果选中了某几个 // 如果可以跨区域 则显示数量 否则只加粗 - String name = firstList[index].title; + String name = _firstList[index].title; if (list.isNotEmpty) { if (list.every((data) { @@ -321,12 +309,11 @@ class _BrnLayerMoreSelectionPageState extends State })) { name += '(全部)'; } else { - bool containsCheck = firstList[index].hasCheckBoxBrother(); + bool containsCheck = _firstList[index].hasCheckBoxBrother(); bool containsCheckChildren = false; - if (firstList[index].children.isNotEmpty) { - containsCheckChildren = - firstList[index].children[0].hasCheckBoxBrother(); + if (_firstList[index].children.isNotEmpty) { + containsCheckChildren = _firstList[index].children[0].hasCheckBoxBrother(); } if (containsCheck && containsCheckChildren) { name += '(${list.length})'; @@ -336,7 +323,7 @@ class _BrnLayerMoreSelectionPageState extends State return Container( alignment: Alignment.centerLeft, height: 48, - color: index == currentIndex ? Colors.white : Color(0xff8F8F8), + color: index == _currentIndex ? Colors.white : Color(0xff8F8F8), child: Padding( padding: const EdgeInsets.only(left: 20), child: Text( @@ -348,41 +335,41 @@ class _BrnLayerMoreSelectionPageState extends State } Widget _buildRightItem(int index) { - bool isSingle = (currentFirstEntity.children[index].filterType == - BrnSelectionFilterType.Radio) || - (currentFirstEntity.children[index].filterType == - BrnSelectionFilterType.UnLimit); + bool isSingle = + (_currentFirstEntity?.children[index].filterType == BrnSelectionFilterType.radio) || + (_currentFirstEntity?.children[index].filterType == BrnSelectionFilterType.unLimit); return GestureDetector( onTap: () { setState(() { - if (isSingle) { - currentFirstEntity.clearSelectedEntity(); - currentFirstEntity.isSelected = true; - currentFirstEntity.children[index].isSelected = true; - //Navigator.pop(context, widget.entityData); - } else { - currentFirstEntity.children?.where((data) { - return data.filterType != BrnSelectionFilterType.Checkbox; - })?.forEach((data) { - data.isSelected = false; - }); - if (!currentFirstEntity.children[index].isSelected) { - if (!BrnSelectionUtil.checkMaxSelectionCount( - this.currentFirstEntity.children[index])) { - BrnToast.show('您选择的筛选条件数量已达上限', context); - return; + if (_currentFirstEntity != null) { + if (isSingle) { + _currentFirstEntity!.clearSelectedEntity(); + _currentFirstEntity!.isSelected = true; + _currentFirstEntity!.children[index].isSelected = true; + } else { + _currentFirstEntity!.children.where((data) { + return data.filterType != BrnSelectionFilterType.checkbox; + }).forEach((data) { + data.isSelected = false; + }); + if (!_currentFirstEntity!.children[index].isSelected) { + if (!BrnSelectionUtil.checkMaxSelectionCount( + this._currentFirstEntity!.children[index])) { + BrnToast.show('您选择的筛选条件数量已达上限', context); + return; + } } + this._currentFirstEntity!.children[index].isSelected = + !this._currentFirstEntity!.children[index].isSelected; } - this.currentFirstEntity.children[index].isSelected = - !this.currentFirstEntity.children[index].isSelected; - } - //如果二级没有任何选中的,那么一级为不选中 - if (currentFirstEntity.selectedList().isEmpty) { - currentFirstEntity.isSelected = false; - } else { - currentFirstEntity.isSelected = true; + //如果二级没有任何选中的,那么一级为不选中 + if (_currentFirstEntity!.selectedList().isEmpty) { + _currentFirstEntity!.isSelected = false; + } else { + _currentFirstEntity!.isSelected = true; + } } }); }, @@ -393,8 +380,8 @@ class _BrnLayerMoreSelectionPageState extends State child: Padding( padding: const EdgeInsets.only(left: 20, right: 20), child: isSingle - ? _buildRightSingleItem(currentFirstEntity.children[index]) - : _buildRightMultiItem(currentFirstEntity.children[index]), + ? _buildRightSingleItem(_currentFirstEntity?.children[index]) + : _buildRightMultiItem(_currentFirstEntity?.children[index]), ), ), ); @@ -402,61 +389,71 @@ class _BrnLayerMoreSelectionPageState extends State void _initData() { //填充一级筛选数据 - firstList = widget.entityData.children ?? List(); + _firstList = widget.entityData.children; //找到一级需要显示 的索引 - for (int i = 0; i < firstList.length; i++) { - if (firstList[i].selectedList().isNotEmpty) { - firstList[i].isSelected = true; + for (int i = 0; i < _firstList.length; i++) { + if (_firstList[i].selectedList().isNotEmpty) { + _firstList[i].isSelected = true; } } - currentIndex = firstList.indexWhere((data) { + _currentIndex = _firstList.indexWhere((data) { return data.isSelected; }); - if (currentIndex >= firstList.length || currentIndex == -1) { - currentIndex = 0; + if (_currentIndex >= _firstList.length || _currentIndex == -1) { + _currentIndex = 0; } //当前选中的一级筛选条件 - currentFirstEntity = firstList[currentIndex]; - currentFirstEntity.isSelected = true; + _currentFirstEntity = _firstList[_currentIndex]; + _currentFirstEntity?.isSelected = true; //找到第二级需要默认选中的索引 - setInitialSecondShowingItem(); + if (_currentFirstEntity != null) { + setInitialSecondShowingItem(_currentFirstEntity!); + } } - Widget _buildRightMultiItem(BrnSelectionEntity tmp) { - return Row( - children: [ - Expanded( - child: Text( - tmp.title.toString(), - style: tmp.isSelected - ? widget.themeData.flatSelectedTextStyle.generateTextStyle() - : widget.themeData.flayNormalTextStyle.generateTextStyle(), + Widget _buildRightMultiItem(BrnSelectionEntity? entity) { + if (entity == null) { + return SizedBox.shrink(); + } else { + return Row( + children: [ + Expanded( + child: Text( + entity.title, + style: entity.isSelected + ? widget.themeData.flayerSelectedTextStyle.generateTextStyle() + : widget.themeData.flayerNormalTextStyle.generateTextStyle(), + ), ), - ), - Container( - height: 16, - width: 16, - child: tmp.isSelected - ? BrnThemeImg.instance.CHECKED_STATUS + Container( + height: 16, + width: 16, + child: entity.isSelected + ? BrunoTools.getAssetImageWithBandColor(BrnAsset.selectCheckedStatus) : BrunoTools.getAssetImage(BrnAsset.iconUnSelect), - ) - ], - ); + ) + ], + ); + } } - Widget _buildRightSingleItem(BrnSelectionEntity tmp) { - return Text(tmp.title.toString(), - textAlign: TextAlign.left, - style: tmp.isSelected - ? widget.themeData.flatSelectedTextStyle.generateTextStyle() - : widget.themeData.flayNormalTextStyle.generateTextStyle()); + Widget _buildRightSingleItem(BrnSelectionEntity? entity) { + if (entity == null) { + return SizedBox.shrink(); + } else { + return Text(entity.title, + textAlign: TextAlign.left, + style: entity.isSelected + ? widget.themeData.flayerSelectedTextStyle.generateTextStyle() + : widget.themeData.flayerNormalTextStyle.generateTextStyle()); + } } //初始化二级的选中(小白楼) //规则:如果二级没有选中的,那么 选中二级的不限 - void setInitialSecondShowingItem() { + void setInitialSecondShowingItem(BrnSelectionEntity currentFirstEntity) { //设置初始化的二级筛选条件 -1没有 int secondIndex = currentFirstEntity.getFirstSelectedChildIndex(); @@ -464,7 +461,7 @@ class _BrnLayerMoreSelectionPageState extends State if (secondIndex == -1 && currentFirstEntity.children.isNotEmpty) { for (int i = 0, n = currentFirstEntity.children.length; i < n; i++) { if (currentFirstEntity.children[i].isUnLimit() && - currentFirstEntity.filterType == BrnSelectionFilterType.Checkbox) { + currentFirstEntity.filterType == BrnSelectionFilterType.checkbox) { currentFirstEntity.children[i].isSelected = true; break; } diff --git a/lib/src/components/selection/widget/brn_selection_animate_widget.dart b/lib/src/components/selection/widget/brn_selection_animate_widget.dart index 1683a157..88516ae1 100644 --- a/lib/src/components/selection/widget/brn_selection_animate_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_animate_widget.dart @@ -8,38 +8,33 @@ class BrnSelectionAnimationWidget extends StatefulWidget { final Widget view; final int animationMilliseconds; - const BrnSelectionAnimationWidget( - {Key key, - @required this.controller, - @required this.view, - this.animationMilliseconds = 100}) - : super(key: key); + const BrnSelectionAnimationWidget({ + Key? key, + required this.controller, + required this.view, + this.animationMilliseconds = 100, + }) : super(key: key); @override - _BrnSelectionAnimationWidgetState createState() => - _BrnSelectionAnimationWidgetState(); + _BrnSelectionAnimationWidgetState createState() => _BrnSelectionAnimationWidgetState(); } -class _BrnSelectionAnimationWidgetState - extends State +class _BrnSelectionAnimationWidgetState extends State with SingleTickerProviderStateMixin { bool _isControllerDisposed = false; - Animation _animation; - AnimationController _controller; + late AnimationController _animationController; @override void initState() { super.initState(); - widget.controller.addListener(_onController); - _controller = AnimationController( - duration: Duration(milliseconds: widget.animationMilliseconds), - vsync: this); + _animationController = AnimationController( + duration: Duration(milliseconds: widget.animationMilliseconds), vsync: this); } dispose() { - widget.controller?.removeListener(_onController); - _controller.dispose(); + widget.controller.removeListener(_onController); + _animationController.dispose(); _isControllerDisposed = true; super.dispose(); } @@ -50,30 +45,28 @@ class _BrnSelectionAnimationWidgetState @override Widget build(BuildContext context) { - _controller.duration = Duration(milliseconds: widget.animationMilliseconds); + _animationController.duration = Duration(milliseconds: widget.animationMilliseconds); return _buildListViewWidget(); } _showListViewWidget() { - if (widget.view == null) { - return; - } - - _animation = Tween( + Animation animation = Tween( begin: 0.0, - end: widget.controller.screenHeight - widget.controller.listViewTop) - .animate(_controller) + end: MediaQuery.of(context).size.height - (widget.controller.listViewTop ?? 0)) + .animate(_animationController) ..addListener(() { //这行如果不写,没有动画效果 setState(() {}); }); - if (_isControllerDisposed) return; + if (_isControllerDisposed) { + return; + } - if (_animation.status == AnimationStatus.completed) { - _controller.reverse(); + if (animation.status == AnimationStatus.completed) { + _animationController.reverse(); } else { - _controller.forward(); + _animationController.forward(); } } @@ -85,8 +78,7 @@ class _BrnSelectionAnimationWidgetState color: Color(0xB3000000), child: Container( width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height - - widget.controller.listViewTop, + height: MediaQuery.of(context).size.height - (widget.controller.listViewTop ?? 0), child: Padding( padding: EdgeInsets.all(0), child: widget.view, diff --git a/lib/src/components/selection/widget/brn_selection_common_item_widget.dart b/lib/src/components/selection/widget/brn_selection_common_item_widget.dart index c4156d71..1feaa7d6 100644 --- a/lib/src/components/selection/widget/brn_selection_common_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_common_item_widget.dart @@ -8,43 +8,40 @@ import 'package:flutter/material.dart'; typedef void ItemSelectFunction(BrnSelectionEntity entity); -// ignore: must_be_immutable class BrnSelectionCommonItemWidget extends StatelessWidget { final BrnSelectionEntity item; - final Color backgroundColor; - final Color selectedBackgroundColor; + final Color? backgroundColor; + final Color? selectedBackgroundColor; final bool isCurrentFocused; final bool isFirstLevel; - final bool isMoreSelectionListType; - final ItemSelectFunction itemSelectFunction; + final ItemSelectFunction? itemSelectFunction; - BrnSelectionConfig themeData; + final BrnSelectionConfig? themeData; BrnSelectionCommonItemWidget({ - @required this.item, + Key? key, + required this.item, this.backgroundColor, this.isFirstLevel = false, this.isMoreSelectionListType = false, this.itemSelectFunction, this.selectedBackgroundColor, - this.isCurrentFocused, + this.isCurrentFocused = false, this.themeData, - }); + }): super(key: key); @override Widget build(BuildContext context) { var checkbox; - if (!item.isUnLimit() && - (item.children == null || item.children.length == 0)) { + if (!item.isUnLimit() && (item.children.length == 0)) { if (item.isInLastLevel() && item.hasCheckBoxBrother()) { checkbox = Container( padding: EdgeInsets.only(left: 6), width: 21, child: (item.isSelected) - ? BrunoTools.getAssetImageWithBandColor( - BrnAsset.iconMultiSelected) + ? BrunoTools.getAssetImageWithBandColor(BrnAsset.iconMultiSelected) : BrunoTools.getAssetImage(BrnAsset.iconUnSelect), ); } else { @@ -57,7 +54,7 @@ class BrnSelectionCommonItemWidget extends StatelessWidget { return GestureDetector( onTap: () { if (itemSelectFunction != null) { - itemSelectFunction(item); + itemSelectFunction!(item); } }, child: Container( @@ -88,14 +85,13 @@ class BrnSelectionCommonItemWidget extends StatelessWidget { Visibility( visible: !BrunoTools.isEmpty(item.subTitle), child: Padding( - padding: - EdgeInsets.only(right: item.isInLastLevel() ? 21 : 0), + padding: EdgeInsets.only(right: item.isInLastLevel() ? 21 : 0), child: BrnCSS2Text.toTextView(item.subTitle ?? '', defaultStyle: TextStyle( fontSize: 12, fontWeight: FontWeight.normal, decoration: TextDecoration.none, - color: themeData.commonConfig.colorTextSecondary), + color: themeData?.commonConfig.colorTextSecondary), maxLines: 1, textOverflow: TextOverflow.ellipsis), ), @@ -107,7 +103,7 @@ class BrnSelectionCommonItemWidget extends StatelessWidget { ); } - Color getItemBGColor() { + Color? getItemBGColor() { if (isCurrentFocused) { return this.selectedBackgroundColor; } else { @@ -135,28 +131,25 @@ class BrnSelectionCommonItemWidget extends StatelessWidget { } } - TextStyle getItemTextStyle() { + TextStyle? getItemTextStyle() { if (isHighLight(item)) { - return themeData.itemSelectedTextStyle.generateTextStyle(); + return themeData?.itemSelectedTextStyle.generateTextStyle(); } else if (isBold(item)) { - return themeData.itemBoldTextStyle.generateTextStyle(); + return themeData?.itemBoldTextStyle.generateTextStyle(); } - return themeData.itemNormalTextStyle.generateTextStyle(); + return themeData?.itemNormalTextStyle.generateTextStyle(); } String getSelectedItemCount(BrnSelectionEntity item) { String itemCount = ""; - if ((BrnSelectionUtil.getTotalLevel(item) < 3 || !isFirstLevel) && - item.children != null) { - int count = - item.children.where((f) => f.isSelected && !f.isUnLimit()).length; + if ((BrnSelectionUtil.getTotalLevel(item) < 3 || !isFirstLevel) && item.children.isNotEmpty) { + int count = item.children.where((f) => f.isSelected && !f.isUnLimit()).length; if (count > 1) { return '($count)'; } else if (count == 1 && item.hasCheckBoxBrother()) { return '($count)'; } else { - var unLimited = - item.children.where((f) => f.isSelected && f.isUnLimit()).toList(); + var unLimited = item.children.where((f) => f.isSelected && f.isUnLimit()).toList(); if (unLimited.length > 0) { return '(全部)'; } diff --git a/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart b/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart index 5684019f..e00fea96 100644 --- a/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart @@ -13,21 +13,15 @@ import 'package:flutter/services.dart'; typedef void OnRangeChangedFunction(String minInput, String maxInput); typedef void OnTappedFunction(); +const String _defaultDateFormat = 'yyyy年MM月dd日'; + // ignore: must_be_immutable class BrnSelectionDateRangeItemWidget extends StatefulWidget { final BrnSelectionEntity item; - /// 选中色 - final Color confirmColor; - - /// 背景色 - final Color backgroundColor; - /// 输入框显示文字大小 final double showTextSize; - final bool isShouldClearText; - /// 是否需要标题 final bool isNeedTitle; @@ -37,51 +31,43 @@ class BrnSelectionDateRangeItemWidget extends StatefulWidget { final TextEditingController minTextEditingController; final TextEditingController maxTextEditingController; - final OnTappedFunction onTapped; + final OnTappedFunction? onTapped; BrnSelectionConfig themeData; BrnSelectionDateRangeItemWidget( - {this.item, - @required this.minTextEditingController, - @required this.maxTextEditingController, - this.confirmColor, - this.backgroundColor = Colors.white, - this.isShouldClearText = false, + {Key? key, + required this.item, + required this.minTextEditingController, + required this.maxTextEditingController, this.isNeedTitle = true, this.showTextSize = 16, - this.dateFormat, + this.dateFormat = _defaultDateFormat, this.onTapped, - this.themeData}); + required this.themeData}) + : super(key: key); - _BrnSelectionDateRangeItemWidgetState createState() => - _BrnSelectionDateRangeItemWidgetState(); + _BrnSelectionDateRangeItemWidgetState createState() => _BrnSelectionDateRangeItemWidgetState(); } -class _BrnSelectionDateRangeItemWidgetState - extends State { - BrnSelectionDatePickerController _datePickerController = - BrnSelectionDatePickerController(); +class _BrnSelectionDateRangeItemWidgetState extends State { + BrnSelectionDatePickerController _datePickerController = BrnSelectionDatePickerController(); @override void initState() { var minDateTime; - if (widget.item.customMap != null && widget.item.customMap['min'] != null) { - minDateTime = DateTimeFormatter.convertIntValueToDateTime( - widget.item?.customMap['min']); + if (widget.item.customMap != null && widget.item.customMap!['min'] != null) { + minDateTime = DateTimeFormatter.convertIntValueToDateTime(widget.item.customMap!['min']); } var maxDateTime; - if (widget.item.customMap != null && widget.item.customMap['max'] != null) { - maxDateTime = DateTimeFormatter.convertIntValueToDateTime( - widget.item?.customMap['max']); + if (widget.item.customMap != null && widget.item.customMap!['max'] != null) { + maxDateTime = DateTimeFormatter.convertIntValueToDateTime(widget.item.customMap!['max']); } widget.minTextEditingController.text = minDateTime != null - ? DateTimeFormatter.formatDate(minDateTime, - widget.dateFormat ?? 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn) + ? DateTimeFormatter.formatDate(minDateTime, widget.dateFormat, DateTimePickerLocale.zh_cn) : ''; widget.maxTextEditingController.text = maxDateTime != null - ? DateTimeFormatter.formatDate(maxDateTime, - widget.dateFormat ?? 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn) + ? DateTimeFormatter.formatDate(maxDateTime, widget.dateFormat, DateTimePickerLocale.zh_cn) : ''; super.initState(); } @@ -89,7 +75,6 @@ class _BrnSelectionDateRangeItemWidgetState @override Widget build(BuildContext context) { return Container( - // color: widget.backgroundColor, child: Padding( padding: EdgeInsets.only(left: 20, right: 20, bottom: 20), child: Column( @@ -99,10 +84,9 @@ class _BrnSelectionDateRangeItemWidgetState margin: EdgeInsets.only(bottom: 5), alignment: Alignment.centerLeft, child: Text( - widget.item.title != null ? widget.item.title : '自定义区间', + widget.item.title.isEmpty ? '自定义区间' : widget.item.title, textAlign: TextAlign.left, - style: widget.themeData.rangeTitleTextStyle - ?.generateTextStyle(), + style: widget.themeData.rangeTitleTextStyle.generateTextStyle(), ), ) : Container(), @@ -112,7 +96,7 @@ class _BrnSelectionDateRangeItemWidgetState Container( child: Text( "至", - style: widget.themeData.inputTextStyle?.generateTextStyle(), + style: widget.themeData.inputTextStyle.generateTextStyle(), ), ), getDateRangeTextField(true), @@ -130,22 +114,22 @@ class _BrnSelectionDateRangeItemWidgetState enableInteractiveSelection: false, readOnly: true, onTap: () { - widget.onTapped(); + if (widget.onTapped != null) { + widget.onTapped!(); + } onTextTapped(isMax); }, - style: widget.themeData.inputTextStyle?.generateTextStyle(), + style: widget.themeData.inputTextStyle.generateTextStyle(), inputFormatters: [FilteringTextInputFormatter.digitsOnly], keyboardType: TextInputType.numberWithOptions(), onChanged: (input) { widget.item.isSelected = true; }, - controller: isMax - ? widget.maxTextEditingController - : widget.minTextEditingController, + controller: isMax ? widget.maxTextEditingController : widget.minTextEditingController, cursorColor: widget.themeData.commonConfig.brandPrimary, textAlign: TextAlign.center, decoration: InputDecoration( - hintStyle: widget.themeData.hintTextStyle?.generateTextStyle(), + hintStyle: widget.themeData.hintTextStyle.generateTextStyle(), hintText: (!isMax ? '开始日期' : '结束日期'), enabledBorder: UnderlineInputBorder( borderSide: BorderSide( @@ -164,27 +148,24 @@ class _BrnSelectionDateRangeItemWidgetState } void onTextTapped(bool isMax) { - if (_datePickerController?.isShow ?? false) return; + if (_datePickerController.isShow) return; String format = 'yyyy年,MM月,dd日'; - DateTime minDate = DateTimeFormatter.convertIntValueToDateTime( - (widget.item?.extMap ?? Map())['min']); - DateTime maxDate = DateTimeFormatter.convertIntValueToDateTime( - (widget.item?.extMap ?? Map())['max']); + DateTime? minDate = + DateTimeFormatter.convertIntValueToDateTime((widget.item.extMap )['min']); + DateTime? maxDate = + DateTimeFormatter.convertIntValueToDateTime((widget.item.extMap)['max']); - DateTime minSelectedDateTime = BrunoTools.isEmpty(widget.item?.customMap) + DateTime? minSelectedDateTime = BrunoTools.isEmpty(widget.item.customMap) ? null - : DateTimeFormatter.convertIntValueToDateTime( - widget.item?.customMap['min']); - DateTime maxSelectedDateTime = BrunoTools.isEmpty(widget.item?.customMap) + : DateTimeFormatter.convertIntValueToDateTime(widget.item.customMap!['min']); + DateTime? maxSelectedDateTime = BrunoTools.isEmpty(widget.item.customMap) ? null - : DateTimeFormatter.convertIntValueToDateTime( - widget.item?.customMap['max']); + : DateTimeFormatter.convertIntValueToDateTime(widget.item.customMap!['max']); - DateTime _minDateTime; - DateTime _maxDateTime; - if (widget.item?.customMap == null || - (widget.item?.customMap['min'] == null && - widget.item?.customMap['max'] == null)) { + DateTime? _minDateTime; + DateTime? _maxDateTime; + if (widget.item.customMap == null || + (widget.item.customMap!['min'] == null && widget.item.customMap!['max'] == null)) { // 如果开始时间和结束时间均未选择 _minDateTime = minDate; _maxDateTime = maxDate; @@ -208,45 +189,38 @@ class _BrnSelectionDateRangeItemWidgetState }, onConfirm: (DateTime selectedDate, List selectedIndex) { widget.item.isSelected = true; - String selectedDateStr = DateTimeFormatter.formatDate(selectedDate, - widget.dateFormat ?? 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn); + String selectedDateStr = DateTimeFormatter.formatDate( + selectedDate, widget.dateFormat, DateTimePickerLocale.zh_cn); if (isMax) { widget.maxTextEditingController.text = selectedDateStr; } else { widget.minTextEditingController.text = selectedDateStr; } if (widget.item.customMap == null) { - widget.item.customMap = {}; + widget.item.customMap = Map(); } - widget.item.customMap[isMax ? 'max' : 'min'] = + widget.item.customMap![isMax ? 'max' : 'min'] = selectedDate.millisecondsSinceEpoch.toString(); closeSelectionPopupWindow(); - if (!isMax && - BrunoTools.isEmpty(widget.maxTextEditingController.text)) { + if (!isMax && BrunoTools.isEmpty(widget.maxTextEditingController.text)) { onTextTapped(true); } setState(() {}); }, ); - _datePickerController.screenHeight = MediaQuery.of(context).size.height; - _createDatePickerEntry(context, content); - Overlay.of(context).insert(_datePickerController.entry); + OverlayEntry entry = _createDatePickerEntry(context, content); + Overlay.of(context)?.insert(entry); + _datePickerController.entry = entry; _datePickerController.show(); } - void _createDatePickerEntry(BuildContext context, Widget content) { - OverlayEntry entry = OverlayEntry(builder: (context) { + OverlayEntry _createDatePickerEntry(BuildContext context, Widget content) { + return OverlayEntry(builder: (context) { return GestureDetector( onTap: () { closeSelectionPopupWindow(); }, -// onVerticalDragStart: (_) { -// closeSelectionPopupWindow(); -// }, -// onHorizontalDragStart: (_) { -// closeSelectionPopupWindow(); -// }, child: Container( color: Color(0xB3000000), height: MediaQuery.of(context).size.height, @@ -256,26 +230,18 @@ class _BrnSelectionDateRangeItemWidgetState ), ); }); - - _datePickerController.entry = entry; } void closeSelectionPopupWindow() { - if (_datePickerController?.isShow ?? false) { - _datePickerController?.isShow = false; - _datePickerController?.hide(); - _datePickerController?.entry?.remove(); - _datePickerController?.entry = null; + if (_datePickerController.isShow) { + _datePickerController.hide(); } } @override void dispose() { // TODO: implement dispose - _datePickerController?.isShow = false; - _datePickerController?.hide(); - _datePickerController?.entry?.remove(); - _datePickerController?.entry = null; + _datePickerController.hide(); super.dispose(); } } diff --git a/lib/src/components/selection/widget/brn_selection_datepicker_animate_widget.dart b/lib/src/components/selection/widget/brn_selection_datepicker_animate_widget.dart index a6c4b866..cb5d211f 100644 --- a/lib/src/components/selection/widget/brn_selection_datepicker_animate_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_datepicker_animate_widget.dart @@ -9,9 +9,9 @@ class BrnSelectionDatePickerAnimationWidget extends StatefulWidget { final int animationMilliseconds; const BrnSelectionDatePickerAnimationWidget( - {Key key, - @required this.controller, - @required this.view, + {Key? key, + required this.controller, + required this.view, this.animationMilliseconds = 100}) : super(key: key); @@ -24,8 +24,8 @@ class _BrnSelectionDatePickerAnimationWidgetState extends State with SingleTickerProviderStateMixin { bool _isControllerDisposed = false; - Animation _animation; - AnimationController _controller; + Animation? _animation; + late AnimationController _controller; @override void initState() { @@ -38,7 +38,7 @@ class _BrnSelectionDatePickerAnimationWidgetState } dispose() { - widget.controller?.removeListener(_onController); + widget.controller.removeListener(_onController); _controller.dispose(); _isControllerDisposed = true; super.dispose(); @@ -55,20 +55,16 @@ class _BrnSelectionDatePickerAnimationWidgetState } _showListViewWidget() { - if (widget.view == null) { - return; - } - - _animation = Tween(begin: widget.controller.screenHeight, end: 300.0) + _animation = Tween(begin: MediaQuery.of(context).size.height, end: 300.0) .animate(_controller) - ..addListener(() { - //这行如果不写,没有动画效果 - setState(() {}); - }); + ..addListener(() { + //这行如果不写,没有动画效果 + setState(() {}); + }); if (_isControllerDisposed) return; - if (_animation.status == AnimationStatus.completed) { + if (_animation!.status == AnimationStatus.completed) { _controller.reverse(); } else { _controller.forward(); diff --git a/lib/src/components/selection/widget/brn_selection_list_widget.dart b/lib/src/components/selection/widget/brn_selection_list_widget.dart index 72016083..2a716df4 100644 --- a/lib/src/components/selection/widget/brn_selection_list_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_list_widget.dart @@ -10,8 +10,7 @@ import 'package:bruno/src/theme/configs/brn_selection_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -typedef void SingleListItemSelect( - int listIndex, int index, BrnSelectionEntity entity); +typedef void SingleListItemSelect(int listIndex, int index, BrnSelectionEntity entity); typedef void ListBgClickFunction(); @@ -20,19 +19,19 @@ class BrnListSelectionGroupWidget extends StatefulWidget { final BrnSelectionEntity entity; final double maxContentHeight; final bool showSelectedCount; - final ListBgClickFunction bgClickFunction; - final BrnOnRangeSelectionConfirm onSelectionConfirm; + final ListBgClickFunction? bgClickFunction; + final BrnOnRangeSelectionConfirm? onSelectionConfirm; BrnSelectionConfig themeData; - BrnListSelectionGroupWidget( - {Key key, - @required this.entity, - this.maxContentHeight = DESIGN_SELECTION_HEIGHT, - this.showSelectedCount = false, - this.bgClickFunction, - this.onSelectionConfirm, - this.themeData}) - : super(key: key); + BrnListSelectionGroupWidget({ + Key? key, + required this.entity, + this.maxContentHeight = DESIGN_SELECTION_HEIGHT, + this.showSelectedCount = false, + this.bgClickFunction, + this.onSelectionConfirm, + required this.themeData, + }) : super(key: key); @override _BrnSelectionGroupViewState createState() => _BrnSelectionGroupViewState(); @@ -41,13 +40,13 @@ class BrnListSelectionGroupWidget extends StatefulWidget { class _BrnSelectionGroupViewState extends State { final int maxShowCount = 6; - List _firstList = List(); - List _secondList = List(); - List _thirdList = List(); - List _originalSelectedItemsList = List(); - int _firstIndex; - int _secondIndex; - int _thirdIndex; + List _firstList = []; + List _secondList = []; + List _thirdList = []; + List _originalSelectedItemsList = []; + int _firstIndex = -1; + int _secondIndex = -1; + int _thirdIndex = -1; int totalLevel = 0; @@ -62,7 +61,7 @@ class _BrnSelectionGroupViewState extends State { @override void dispose() { if (!_isConfirmClick) { - _resetSelectionDatas(widget.entity); + _resetSelectionData(widget.entity); _restoreOriginalData(); } super.dispose(); @@ -89,22 +88,19 @@ class _BrnSelectionGroupViewState extends State { //pragma mark -- config widgets List _configWidgets() { - List widgetList = List(); + List widgetList = []; widgetList.add(_listWidget()); // TODO 判断是否添加 Bottom - if (_firstList != null) { - if (totalLevel == 1 && - widget.entity.filterType == BrnSelectionFilterType.Radio) { - } else { - widgetList.add(_bottomWidget()); - } + if (totalLevel == 1 && widget.entity.filterType == BrnSelectionFilterType.radio) { + } else { + widgetList.add(_bottomWidget()); } return widgetList; } Widget _listWidget() { - List widgets = List(); + List widgets = []; if (!BrunoTools.isEmpty(_firstList) && BrunoTools.isEmpty(_secondList) && @@ -114,16 +110,14 @@ class _BrnSelectionGroupViewState extends State { widgets.add(BrnSelectionSingleListWidget( items: _firstList, themeData: widget.themeData, - backgroundColor: getBgByListIndex(1), - selectedBackgroundColor: getSelectBgByListIndex(1), + backgroundColor: _getBgByListIndex(1), + selectedBackgroundColor: _getSelectBgByListIndex(1), maxHeight: widget.maxContentHeight, - flex: getFlexByListIndex(1), + flex: _getFlexByListIndex(1), focusedIndex: _firstIndex, - singleListItemSelect: - (int listIndex, int index, BrnSelectionEntity entity) { + singleListItemSelect: (int listIndex, int index, BrnSelectionEntity entity) { _setFirstIndex(index); - if (totalLevel == 1 && - widget.entity.filterType == BrnSelectionFilterType.Radio) { + if (totalLevel == 1 && widget.entity.filterType == BrnSelectionFilterType.radio) { _confirmButtonClickEvent(); } })); @@ -134,24 +128,22 @@ class _BrnSelectionGroupViewState extends State { widgets.add(BrnSelectionSingleListWidget( items: _firstList, themeData: widget.themeData, - backgroundColor: getBgByListIndex(1), - selectedBackgroundColor: getSelectBgByListIndex(1), - flex: getFlexByListIndex(1), + backgroundColor: _getBgByListIndex(1), + selectedBackgroundColor: _getSelectBgByListIndex(1), + flex: _getFlexByListIndex(1), focusedIndex: _firstIndex, - singleListItemSelect: - (int listIndex, int index, BrnSelectionEntity entity) { + singleListItemSelect: (int listIndex, int index, BrnSelectionEntity entity) { _setFirstIndex(index); })); widgets.add(BrnSelectionSingleListWidget( items: _secondList, themeData: widget.themeData, - backgroundColor: getBgByListIndex(2), - selectedBackgroundColor: getSelectBgByListIndex(2), - flex: getFlexByListIndex(2), + backgroundColor: _getBgByListIndex(2), + selectedBackgroundColor: _getSelectBgByListIndex(2), + flex: _getFlexByListIndex(2), focusedIndex: _secondIndex, - singleListItemSelect: - (int listIndex, int index, BrnSelectionEntity entity) { + singleListItemSelect: (int listIndex, int index, BrnSelectionEntity entity) { _setSecondIndex(index); })); } else if (!BrunoTools.isEmpty(_firstList) && @@ -161,35 +153,32 @@ class _BrnSelectionGroupViewState extends State { widgets.add(BrnSelectionSingleListWidget( items: _firstList, themeData: widget.themeData, - backgroundColor: getBgByListIndex(1), - selectedBackgroundColor: getSelectBgByListIndex(1), - flex: getFlexByListIndex(1), + backgroundColor: _getBgByListIndex(1), + selectedBackgroundColor: _getSelectBgByListIndex(1), + flex: _getFlexByListIndex(1), focusedIndex: _firstIndex, - singleListItemSelect: - (int listIndex, int index, BrnSelectionEntity entity) { + singleListItemSelect: (int listIndex, int index, BrnSelectionEntity entity) { _setFirstIndex(index); })); widgets.add(BrnSelectionSingleListWidget( items: _secondList, themeData: widget.themeData, - backgroundColor: getBgByListIndex(2), - selectedBackgroundColor: getSelectBgByListIndex(2), - flex: getFlexByListIndex(2), + backgroundColor: _getBgByListIndex(2), + selectedBackgroundColor: _getSelectBgByListIndex(2), + flex: _getFlexByListIndex(2), focusedIndex: _secondIndex, - singleListItemSelect: - (int listIndex, int index, BrnSelectionEntity entity) { + singleListItemSelect: (int listIndex, int index, BrnSelectionEntity entity) { _setSecondIndex(index); })); widgets.add(BrnSelectionSingleListWidget( items: _thirdList, themeData: widget.themeData, - backgroundColor: getBgByListIndex(3), - selectedBackgroundColor: getSelectBgByListIndex(3), - flex: getFlexByListIndex(3), + backgroundColor: _getBgByListIndex(3), + selectedBackgroundColor: _getSelectBgByListIndex(3), + flex: _getFlexByListIndex(3), focusedIndex: _thirdIndex, - singleListItemSelect: - (int listIndex, int index, BrnSelectionEntity entity) { + singleListItemSelect: (int listIndex, int index, BrnSelectionEntity entity) { if (entity.isSelected) { _thirdIndex = index; } else { @@ -213,7 +202,7 @@ class _BrnSelectionGroupViewState extends State { ), ), // 目前列表最大高度为 240,每个 Item 高度为 40。顾最大展示个数是 6,大于 6 则显示阴影。 - getMostListCount(widgets.length) > maxShowCount + _getListMaxCount(widgets.length) > maxShowCount ? IgnorePointer( child: Container( height: 40, @@ -258,13 +247,11 @@ class _BrnSelectionGroupViewState extends State { Container( height: 24, width: 24, - child: BrunoTools.getAssetImage( - BrnAsset.iconSelectionReset), + child: BrunoTools.getAssetImage(BrnAsset.iconSelectionReset), ), Text( "重置", - style: - widget.themeData.resetTextStyle.generateTextStyle(), + style: widget.themeData.resetTextStyle.generateTextStyle(), ) ], ), @@ -295,13 +282,12 @@ class _BrnSelectionGroupViewState extends State { _processFilterDataOnConfirm(); if (widget.onSelectionConfirm != null) { //更多和无tips等外部调用的多选需要传递此值selectedLastColumnArray - widget.onSelectionConfirm( - widget.entity, _firstIndex, _secondIndex, _thirdIndex); + widget.onSelectionConfirm!(widget.entity, _firstIndex, _secondIndex, _thirdIndex); } } void _clearAllSelectedItems() { - _resetSelectionDatas(widget.entity); + _resetSelectionData(widget.entity); setState(() { _configDefaultInitSelectIndex(); _refreshDataSource(); @@ -310,15 +296,14 @@ class _BrnSelectionGroupViewState extends State { //pragma mark -- private methods - // 初始化数据 - + /// 初始化数据 void _initData() { // 生成筛选节点树 _originalSelectedItemsList = widget.entity.selectedList(); for (BrnSelectionEntity entity in _originalSelectedItemsList) { entity.isSelected = true; if (entity.customMap != null) { - entity.originalCustomMap = Map.from(entity.customMap); + entity.originalCustomMap = Map.from(entity.customMap!); } } @@ -343,59 +328,55 @@ class _BrnSelectionGroupViewState extends State { if (_secondIndex >= 0 && _secondList.length > _secondIndex) { _thirdList = _secondList[_secondIndex].children; } else { - _thirdList = null; + _thirdList = []; } } else { - _secondList = null; - _thirdList = null; + _secondList = []; + _thirdList = []; } } void _configDefaultSelectedData() { _firstList = widget.entity.children; //是否已选择的item里面有第一列的 - if (_firstList == null) { + if (_firstList.isEmpty) { _secondIndex = -1; - _secondList = null; + _secondList = []; _thirdIndex = -1; - _thirdList = null; + _thirdList = []; return; } - _firstIndex = getInitialSelectIndex(_firstList); + _firstIndex = _getInitialSelectIndex(_firstList); if (_firstIndex >= 0 && _firstIndex < _firstList.length) { _secondList = _firstList[_firstIndex].children; - if (_secondList != null) { - _secondIndex = getInitialSelectIndex(_secondList); - } + _secondIndex = _getInitialSelectIndex(_secondList); } - if (_secondList == null) { + if (_secondList.isEmpty) { _thirdIndex = -1; - _thirdList = null; + _thirdList = []; return; } if (_secondIndex >= 0 && _secondIndex < _secondList.length) { _thirdList = _secondList[_secondIndex].children; - if (_thirdList != null) { - _thirdIndex = getInitialSelectIndex(_thirdList); + if (_thirdList.isNotEmpty) { + _thirdIndex = _getInitialSelectIndex(_thirdList); } } } ///还原数据选中状态 - void _resetSelectionDatas(BrnSelectionEntity entity) { + void _resetSelectionData(BrnSelectionEntity entity) { entity.isSelected = false; - entity.customMap = null; - if (BrnSelectionFilterType.Range == entity.filterType) { - entity.title = null; + entity.customMap = Map(); + if (BrnSelectionFilterType.range == entity.filterType) { + entity.title = ''; } - if (entity.children != null) { - for (BrnSelectionEntity subEntity in entity.children) { - _resetSelectionDatas(subEntity); - } + for (BrnSelectionEntity subEntity in entity.children) { + _resetSelectionData(subEntity); } } @@ -403,26 +384,18 @@ class _BrnSelectionGroupViewState extends State { void _restoreOriginalData() { for (BrnSelectionEntity commonEntity in _originalSelectedItemsList) { commonEntity.isSelected = true; - if (commonEntity.originalCustomMap != null) { - commonEntity.customMap = Map.from(commonEntity.originalCustomMap); - } + commonEntity.customMap = Map.from(commonEntity.originalCustomMap); } } - - //pragma mark -- getter and setter - + void _setFirstIndex(int firstIndex) { _firstIndex = firstIndex; _secondIndex = -1; if (widget.entity.children.length > _firstIndex) { - List seconds = - widget.entity.children[_firstIndex].children; - if (seconds != null) { - _secondIndex = getInitialSelectIndex(seconds); - - if (_secondIndex >= 0) { - _setSecondIndex(_secondIndex); - } + List seconds = widget.entity.children[_firstIndex].children; + _secondIndex = _getInitialSelectIndex(seconds); + if (_secondIndex >= 0) { + _setSecondIndex(_secondIndex); } } setState(() { @@ -433,12 +406,11 @@ class _BrnSelectionGroupViewState extends State { void _setSecondIndex(int secondIndex) { _secondIndex = secondIndex; _thirdIndex = -1; - List seconds = - widget.entity.children[_firstIndex].children; + List seconds = widget.entity.children[_firstIndex].children; if (seconds.length > _secondIndex) { List thirds = seconds[_secondIndex].children; - if (thirds != null) { - _thirdIndex = getInitialSelectIndex(thirds); + if (thirds.isNotEmpty) { + _thirdIndex = _getInitialSelectIndex(thirds); } } setState(() { @@ -446,9 +418,9 @@ class _BrnSelectionGroupViewState extends State { }); } - int getInitialSelectIndex(List levelList) { + int _getInitialSelectIndex(List levelList) { int index = -1; - if (levelList == null || levelList.length == 0) { + if (levelList.length == 0) { return index; } @@ -464,7 +436,7 @@ class _BrnSelectionGroupViewState extends State { for (BrnSelectionEntity entity in levelList) { if (entity.isUnLimit() && BrnSelectionUtil.getTotalLevel(entity) > 1 && - !entity.parent.hasCheckBoxBrother()) { + !(entity.parent?.hasCheckBoxBrother() ?? false)) { index = levelList.indexOf(entity); break; } @@ -476,7 +448,7 @@ class _BrnSelectionGroupViewState extends State { /// 默认占比为 1, /// 其中一列、两列情况下,占比都是 1 /// 当为三列数据时,占比随着 listIndex 增加而增大。为 3:3:4 比例水平占据屏幕 - int getFlexByListIndex(int listIndex) { + int _getFlexByListIndex(int listIndex) { int flex = 1; if (totalLevel == 1 || totalLevel == 2) { flex = 1; @@ -484,7 +456,7 @@ class _BrnSelectionGroupViewState extends State { if (listIndex == 1) { flex = 3; } else if (listIndex == 2) { - if (_thirdList == null) { + if (_thirdList.isEmpty) { flex = 7; } else { flex = 3; @@ -496,7 +468,7 @@ class _BrnSelectionGroupViewState extends State { return flex; } - Color getSelectBgByListIndex(int listIndex) { + Color _getSelectBgByListIndex(int listIndex) { Color deepSelectBgColor = widget.themeData.deepSelectBgColor; Color middleSelectBgColor = widget.themeData.middleSelectBgColor; Color lightSelectBgColor = widget.themeData.lightSelectBgColor; @@ -520,7 +492,7 @@ class _BrnSelectionGroupViewState extends State { return lightSelectBgColor; } - Color getBgByListIndex(int listIndex) { + Color _getBgByListIndex(int listIndex) { Color deepNormalBgColor = widget.themeData.deepNormalBgColor; Color middleNormalBgColor = widget.themeData.middleNormalBgColor; Color lightNormalBgColor = widget.themeData.lightNormalBgColor; @@ -549,7 +521,7 @@ class _BrnSelectionGroupViewState extends State { _resetSelectStatus(); if (widget.bgClickFunction != null) { //执行回调 - widget.bgClickFunction(); + widget.bgClickFunction!(); } } @@ -558,44 +530,37 @@ class _BrnSelectionGroupViewState extends State { //数据还原 for (BrnSelectionEntity commonEntity in _originalSelectedItemsList) { commonEntity.isSelected = true; - if (commonEntity.originalCustomMap != null) { - commonEntity.customMap = Map.from(commonEntity.originalCustomMap); - } + commonEntity.customMap = Map.from(commonEntity.originalCustomMap); } } /// 提交前对筛选数据做进一步处理, /// !!! 只有子筛选项存在被选中的 Item 才可以被设置为 true。 void _processFilterDataOnConfirm() { - if (widget.entity?.children != null) { - _processSelectedStatus(widget.entity); - } + _processSelectedStatus(widget.entity); } _processSelectedStatus(BrnSelectionEntity entity) { - if (entity != null && - entity.children != null && - entity.children.length > 0) { + if (entity.children.length > 0) { entity.children.forEach((f) => _processSelectedStatus(f)); if (entity.hasCheckBoxBrother()) { - entity.isSelected = - entity.children.where((_) => _.isSelected).length > 0; + entity.isSelected = entity.children.where((_) => _.isSelected).length > 0; } } } - int getMostListCount(int length) { + int _getListMaxCount(int length) { int mostCount = 0; if (length == 1) { - mostCount = _firstList?.length ?? 0; + mostCount = _firstList.length; } else if (length == 2) { - int firstCount = _firstList?.length ?? 0; - int secondCount = _secondList?.length ?? 0; + int firstCount = _firstList.length; + int secondCount = _secondList.length; mostCount = max(firstCount, secondCount); } else if (length == 3) { - int firstCount = _firstList?.length ?? 0; - int secondCount = _secondList?.length ?? 0; - int thirdCount = _secondList?.length ?? 0; + int firstCount = _firstList.length; + int secondCount = _secondList.length; + int thirdCount = _secondList.length; mostCount = max(firstCount, max(secondCount, thirdCount)); } return mostCount; diff --git a/lib/src/components/selection/widget/brn_selection_menu_item_widget.dart b/lib/src/components/selection/widget/brn_selection_menu_item_widget.dart index c9703753..cf74bb03 100644 --- a/lib/src/components/selection/widget/brn_selection_menu_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_menu_item_widget.dart @@ -9,19 +9,19 @@ typedef void ItemClickFunction(); class BrnSelectionMenuItemWidget extends StatelessWidget { final String title; final bool isHighLight; - final int index; final bool active; - final ItemClickFunction itemClickFunction; + final ItemClickFunction? itemClickFunction; BrnSelectionConfig themeData; BrnSelectionMenuItemWidget( - {@required this.title, + {Key? key, + required this.title, this.isHighLight = false, - this.index, this.active = false, this.itemClickFunction, - this.themeData}); + required this.themeData}) + : super(key: key); @override Widget build(BuildContext context) { @@ -45,8 +45,8 @@ class BrnSelectionMenuItemWidget extends StatelessWidget { maxLines: 1, softWrap: true, style: isHighLight - ? themeData.menuSelectedTextStyle?.generateTextStyle() - : themeData.menuNormalTextStyle?.generateTextStyle(), + ? themeData.menuSelectedTextStyle.generateTextStyle() + : themeData.menuNormalTextStyle.generateTextStyle(), ), )), Padding( @@ -54,16 +54,16 @@ class BrnSelectionMenuItemWidget extends StatelessWidget { child: isHighLight ? (active ? BrunoTools.getAssetImageWithBandColor( - BrnAsset.ICON_ARROWUP_SELECT, + BrnAsset.iconArrowUpSelect, configId: themeData.configId) : BrunoTools.getAssetImageWithBandColor( - BrnAsset.ICON_ARROWDOWN_SELECT)) + BrnAsset.iconArrowDownSelect)) : (active ? BrunoTools.getAssetImageWithBandColor( - BrnAsset.ICON_ARROWUP_SELECT, + BrnAsset.iconArrowUpSelect, configId: themeData.configId) : BrunoTools.getAssetImage( - BrnAsset.ICON_ARROWDOWN_UNSELECT))) + BrnAsset.iconArrowDownUnSelect))) ], ), ), @@ -74,7 +74,7 @@ class BrnSelectionMenuItemWidget extends StatelessWidget { void _menuItemTapped() { if (this.itemClickFunction != null) { - this.itemClickFunction(); + this.itemClickFunction!(); } } } diff --git a/lib/src/components/selection/widget/brn_selection_menu_widget.dart b/lib/src/components/selection/widget/brn_selection_menu_widget.dart index fb3b6b66..b7a9d332 100644 --- a/lib/src/components/selection/widget/brn_selection_menu_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_menu_widget.dart @@ -2,46 +2,44 @@ import 'dart:async'; import 'package:bruno/src/components/picker/time_picker/brn_date_time_formatter.dart'; import 'package:bruno/src/components/selection/bean/brn_selection_common_entity.dart'; +import 'package:bruno/src/components/selection/brn_selection_util.dart'; import 'package:bruno/src/components/selection/brn_selection_view.dart'; import 'package:bruno/src/components/selection/controller/brn_selection_view_controller.dart'; -import 'package:bruno/src/components/selection/brn_selection_util.dart'; import 'package:bruno/src/components/selection/widget/brn_selection_animate_widget.dart'; import 'package:bruno/src/components/selection/widget/brn_selection_list_widget.dart'; import 'package:bruno/src/components/selection/widget/brn_selection_menu_item_widget.dart'; import 'package:bruno/src/components/selection/widget/brn_selection_range_widget.dart'; import 'package:bruno/src/theme/configs/brn_selection_config.dart'; -import 'package:bruno/src/utils/brn_tools.dart'; import 'package:bruno/src/utils/brn_event_bus.dart'; +import 'package:bruno/src/utils/brn_tools.dart'; import 'package:bruno/src/utils/i18n/brn_date_picker_i18n.dart'; import 'package:flutter/material.dart'; typedef bool BrnOnMenuItemClick(int index); -typedef void BrnOnRangeSelectionConfirm(BrnSelectionEntity results, - int firstIndex, int secondIndex, int thirdIndex); +typedef void BrnOnRangeSelectionConfirm( + BrnSelectionEntity results, int firstIndex, int secondIndex, int thirdIndex); class BrnSelectionMenuWidget extends StatefulWidget { final List data; final BuildContext context; final double height; - final double width; - final BrnOnRangeSelectionConfirm onConfirm; - final BrnOnMenuItemClick onMenuItemClick; - final BrnConfigTagCountPerRow configRowCount; + final double? width; + final BrnOnRangeSelectionConfirm? onConfirm; + final BrnOnMenuItemClick? onMenuItemClick; + final BrnConfigTagCountPerRow? configRowCount; ///筛选所在列表的外部列表滚动需要收起筛选,此处为最外层列表,有点恶心,但是暂时只想到这个方法,有更好方式的一定要告诉我 - final ScrollController extraScrollController; + final ScrollController? extraScrollController; ///指定筛选固定的相对于屏幕的顶部距离,默认null不指定 - final double constantTop; - - BrnSelectionViewController selectionViewController; + final double? constantTop; - BrnSelectionConfig themeData; + final BrnSelectionConfig themeData; BrnSelectionMenuWidget( - {@required this.data, - @required this.context, + { Key? key,required this.context, + required this.data, this.height = 50.0, this.width, this.onMenuItemClick, @@ -49,8 +47,7 @@ class BrnSelectionMenuWidget extends StatefulWidget { this.configRowCount, this.extraScrollController, this.constantTop, - this.selectionViewController, - this.themeData}); + required this.themeData}): super(key: key); @override _BrnSelectionMenuWidgetState createState() => _BrnSelectionMenuWidgetState(); @@ -58,55 +55,46 @@ class BrnSelectionMenuWidget extends StatefulWidget { class _BrnSelectionMenuWidgetState extends State { bool _needRefreshTitle = true; - List result; - List titles = List(); - List menuItemActiveState = List(); - List menuItemHighlightState = List(); - BrnSelectionListViewController listViewController = - BrnSelectionListViewController(); - ScrollController _scrollController; + List result = []; + List titles = []; + List menuItemActiveState = []; + List menuItemHighlightState = []; + BrnSelectionListViewController listViewController = BrnSelectionListViewController(); + ScrollController? _scrollController; - StreamSubscription _refreshTitleSubscription; + late StreamSubscription _refreshTitleSubscription; - StreamSubscription _closeSelectionPopupWindowSubscription; + late StreamSubscription _closeSelectionPopupWindowSubscription; @override void initState() { super.initState(); - _refreshTitleSubscription = EventBus.instance - .on() - .listen((RefreshMenuTitleEvent event) { + _refreshTitleSubscription = + EventBus.instance.on().listen((RefreshMenuTitleEvent event) { _needRefreshTitle = true; setState(() {}); }); - _closeSelectionPopupWindowSubscription = EventBus.instance - .on() - .listen((CloseSelectionViewEvent event) { + _closeSelectionPopupWindowSubscription = + EventBus.instance.on().listen((CloseSelectionViewEvent event) { _closeSelectionPopupWindow(); }); if (widget.extraScrollController != null) { - _scrollController = widget.extraScrollController; - _scrollController.addListener(_closeSelectionPopupWindow); + _scrollController = widget.extraScrollController!; + _scrollController!.addListener(_closeSelectionPopupWindow); } - result = List(); - if (widget.data != null) { - for (BrnSelectionEntity parentEntity in widget.data) { - titles.add(parentEntity.title); - menuItemActiveState.add(false); - menuItemHighlightState.add(false); - } + for (BrnSelectionEntity parentEntity in widget.data) { + titles.add(parentEntity.title); + menuItemActiveState.add(false); + menuItemHighlightState.add(false); } } void _closeSelectionPopupWindow() { - if (listViewController?.isShow ?? false) { - listViewController.isShow = false; + if (listViewController.isShow) { listViewController.hide(); - listViewController.entry?.remove(); - listViewController.entry = null; setState(() { for (int i = 0; i < menuItemActiveState.length; i++) { if (i != listViewController.menuIndex) { @@ -124,50 +112,39 @@ class _BrnSelectionMenuWidgetState extends State { dispose() { _scrollController?.removeListener(_closeSelectionPopupWindow); - _refreshTitleSubscription?.cancel(); - _closeSelectionPopupWindowSubscription?.cancel(); - listViewController?.isShow = false; - listViewController?.hide(); - listViewController?.entry?.remove(); - listViewController?.entry = null; + _refreshTitleSubscription.cancel(); + _closeSelectionPopupWindowSubscription.cancel(); + listViewController.hide(); super.dispose(); } /// 根据【Filter组】 创建 widget。 - void _createEntry(BrnSelectionEntity entity) { - var content = isRange(entity) - ? _createRangeView(entity) - : _createSelectionListView(entity); - OverlayEntry entry = OverlayEntry(builder: (context) { + OverlayEntry _createEntry(BrnSelectionEntity entity) { + var content = _isRange(entity) ? _createRangeView(entity) : _createSelectionListView(entity); + return OverlayEntry(builder: (context) { return GestureDetector( onTap: () { _closeSelectionPopupWindow(); }, child: Container( padding: EdgeInsets.only( - top: listViewController.listViewTop, + top: listViewController.listViewTop ?? 0, ), child: Stack( children: [ - BrnSelectionAnimationWidget( - controller: listViewController, view: content) + BrnSelectionAnimationWidget(controller: listViewController, view: content) ], ), ), ); }); - - listViewController.screenHeight = MediaQuery.of(widget.context).size.height; - listViewController.entry = entry; } @override Widget build(BuildContext context) { return Container( height: widget.height, - width: (widget.width != null) - ? widget.width - : MediaQuery.of(context).size.width, + width: (widget.width != null) ? widget.width : MediaQuery.of(context).size.width, color: Colors.white, child: Column( mainAxisAlignment: MainAxisAlignment.start, @@ -192,13 +169,13 @@ class _BrnSelectionMenuWidgetState extends State { } List _configMenuItems() { - List itemViewList = List(); + List itemViewList = []; itemViewList.add(Padding( padding: EdgeInsets.only(left: 14), )); for (int index = 0; index < titles.length; index++) { if (_needRefreshTitle) { - refreshSelectionMenuTitle(index, widget.data[index]); + _refreshSelectionMenuTitle(index, widget.data[index]); if (index == titles.length - 1) { _needRefreshTitle = false; } @@ -210,49 +187,44 @@ class _BrnSelectionMenuWidgetState extends State { title: titles[index], themeData: widget.themeData, active: menuItemActiveState[index], - isHighLight: - menuItemActiveState[index] || menuItemHighlightState[index], + isHighLight: menuItemActiveState[index] || menuItemHighlightState[index], itemClickFunction: () { if (widget.onMenuItemClick != null) { /// 拦截 menuItem 点击。 - if (widget.onMenuItemClick(index)) { + if (widget.onMenuItemClick!(index)) { return; } } - final RenderBox dropDownItemRenderBox = context.findRenderObject(); - - var position = - dropDownItemRenderBox.localToGlobal(Offset.zero, ancestor: null); - var size = dropDownItemRenderBox.size; + RenderBox? dropDownItemRenderBox; + if (context.findRenderObject() != null && context.findRenderObject() is RenderBox) { + dropDownItemRenderBox = context.findRenderObject() as RenderBox; + } + Offset? position = dropDownItemRenderBox?.localToGlobal(Offset.zero, ancestor: null); + Size? size = dropDownItemRenderBox?.size; listViewController.listViewTop = - size.height + (widget.constantTop ?? position.dy); - if (listViewController.isShow && - listViewController.menuIndex != index) { + (size?.height ?? 0) + (widget.constantTop ?? position?.dy ?? 0); + if (listViewController.isShow && listViewController.menuIndex != index) { listViewController.hide(); - listViewController.entry?.remove(); - listViewController.entry = null; } if (listViewController.isShow) { listViewController.hide(); - listViewController.entry?.remove(); - listViewController.entry = null; } else { /// 点击不是 More、自定义类型,则直接展开。 - if (widget.data[index].filterType != BrnSelectionFilterType.More && - widget.data[index].filterType != - BrnSelectionFilterType.CustomHandle) { + if (widget.data[index].filterType != BrnSelectionFilterType.more && + widget.data[index].filterType != BrnSelectionFilterType.customHandle) { /// 创建 筛选组件的的入口 - _createEntry(widget.data[index]); - Overlay.of(widget.context).insert(listViewController.entry); + OverlayEntry entry = _createEntry(widget.data[index]); + Overlay.of(widget.context)?.insert(entry); + + listViewController.entry = entry; listViewController.show(index); - } else if (widget.data[index].filterType == - BrnSelectionFilterType.CustomHandle) { + } else if (widget.data[index].filterType == BrnSelectionFilterType.customHandle) { /// 记录自定义筛选 menu 的点击状态,当点击自定义的 menu 时,menu 文案默认高亮。 listViewController.show(index); - refreshSelectionMenuTitle(index, widget.data[index]); + _refreshSelectionMenuTitle(index, widget.data[index]); } else { - refreshSelectionMenuTitle(index, widget.data[index]); + _refreshSelectionMenuTitle(index, widget.data[index]); } } @@ -283,36 +255,31 @@ class _BrnSelectionMenuWidgetState extends State { /// 1、子筛选项包含自定义范围的时候,使用 Tag 模式展示。 /// 2、被指定为 Tag 模式展示。 /// 3、只有一列筛选数据,且为多选时,使用 Tag 模式展示 - bool isRange(BrnSelectionEntity entity) { - if (entity.children != null) { - if (BrnSelectionUtil.hasRangeItem(entity.children) || - entity.filterShowType == BrnSelectionWindowType.Range) { - return true; - } - var totalLevel = BrnSelectionUtil.getTotalLevel(entity); - if (totalLevel == 1 && - entity.filterType == BrnSelectionFilterType.Checkbox) { - return true; - } + bool _isRange(BrnSelectionEntity entity) { + if (BrnSelectionUtil.hasRangeItem(entity.children) || + entity.filterShowType == BrnSelectionWindowType.range) { + return true; + } + var totalLevel = BrnSelectionUtil.getTotalLevel(entity); + if (totalLevel == 1 && entity.filterType == BrnSelectionFilterType.checkbox) { + return true; } return false; } Widget _createRangeView(BrnSelectionEntity entity) { - int rowCount; + int? rowCount; if (widget.configRowCount != null) { - rowCount = widget.configRowCount(widget.data.indexOf(entity), entity) ?? - rowCount; + rowCount = widget.configRowCount!(widget.data.indexOf(entity), entity) ?? rowCount; } return BrnRangeSelectionGroupWidget( entity: entity, - marginTop: listViewController.listViewTop, - maxContentHeight: DESIGN_SELECTION_HEIGHT / - DESIGN_SCREEN_HEIGHT * - MediaQuery.of(context).size.height, + marginTop: listViewController.listViewTop ?? 0, + maxContentHeight: + DESIGN_SELECTION_HEIGHT / DESIGN_SCREEN_HEIGHT * MediaQuery.of(context).size.height, // UI 给出的内容高度比例 248:812 themeData: widget.themeData, - rowount: rowCount, + rowCount: rowCount, bgClickFunction: () { setState(() { menuItemActiveState[listViewController.menuIndex] = false; @@ -320,14 +287,12 @@ class _BrnSelectionMenuWidgetState extends State { menuItemHighlightState[listViewController.menuIndex] = true; } listViewController.hide(); - listViewController.entry?.remove(); - listViewController.entry = null; }); }, - onSelectionConfirm: (BrnSelectionEntity result, int firstIndex, - int secondIndex, int thirdIndex) { + onSelectionConfirm: + (BrnSelectionEntity result, int firstIndex, int secondIndex, int thirdIndex) { setState(() { - onConfirmSelect(entity, result, firstIndex, secondIndex, thirdIndex); + _onConfirmSelect(entity, result, firstIndex, secondIndex, thirdIndex); }); }, ); @@ -337,9 +302,8 @@ class _BrnSelectionMenuWidgetState extends State { /// 顶层筛选 Tab return BrnListSelectionGroupWidget( entity: entity, - maxContentHeight: DESIGN_SELECTION_HEIGHT / - DESIGN_SCREEN_HEIGHT * - MediaQuery.of(context).size.height, + maxContentHeight: + DESIGN_SELECTION_HEIGHT / DESIGN_SCREEN_HEIGHT * MediaQuery.of(context).size.height, themeData: widget.themeData, // UI 给出的内容高度比例 248:812 bgClickFunction: () { @@ -349,139 +313,119 @@ class _BrnSelectionMenuWidgetState extends State { menuItemHighlightState[listViewController.menuIndex] = true; } listViewController.hide(); - listViewController.entry?.remove(); - listViewController.entry = null; }); }, - onSelectionConfirm: (BrnSelectionEntity result, int firstIndex, - int secondIndex, int thirdIndex) { + onSelectionConfirm: + (BrnSelectionEntity result, int firstIndex, int secondIndex, int thirdIndex) { setState(() { - onConfirmSelect(entity, result, firstIndex, secondIndex, thirdIndex); + _onConfirmSelect(entity, result, firstIndex, secondIndex, thirdIndex); }); }, ); } - void onConfirmSelect(BrnSelectionEntity entity, BrnSelectionEntity result, - int firstIndex, int secondIndex, int thirdIndex) { + void _onConfirmSelect(BrnSelectionEntity entity, BrnSelectionEntity result, int firstIndex, + int secondIndex, int thirdIndex) { if (listViewController.menuIndex < titles.length) { if (widget.onConfirm != null) { - widget.onConfirm(result, firstIndex, secondIndex, thirdIndex); + widget.onConfirm!(result, firstIndex, secondIndex, thirdIndex); } menuItemActiveState[listViewController.menuIndex] = false; - refreshSelectionMenuTitle(listViewController.menuIndex, entity); + _refreshSelectionMenuTitle(listViewController.menuIndex, entity); listViewController.hide(); - listViewController.entry?.remove(); - listViewController.entry = null; } } /// 筛选 Title 展示规则 - String getSelectedResultTitle(BrnSelectionEntity entity) { + String? _getSelectedResultTitle(BrnSelectionEntity entity) { /// 更多筛选不改变 title.故返回 null - if (entity.filterType == BrnSelectionFilterType.More) { + if (entity.filterType == BrnSelectionFilterType.more) { return null; } if (BrunoTools.isEmpty(entity.customTitle)) { - return getTitle(entity); + return _getTitle(entity); } else { return entity.customTitle; } } - String getTitle(BrnSelectionEntity entity) { - String title; - if (entity != null) { - List firstColumn = - BrnSelectionUtil.currentSelectListForEntity(entity); - List secondColumn = List(); - List thirdColumn = List(); - if (firstColumn != null && firstColumn.length > 0) { - for (BrnSelectionEntity firstEntity in firstColumn) { - if (firstEntity != null) { - secondColumn.addAll( - BrnSelectionUtil.currentSelectListForEntity(firstEntity)); - if (secondColumn != null && secondColumn.length > 0) { - for (BrnSelectionEntity secondEntity in secondColumn) { - thirdColumn.addAll( - BrnSelectionUtil.currentSelectListForEntity(secondEntity)); - } - } + String? _getTitle(BrnSelectionEntity entity) { + String? title; + List firstColumn = BrnSelectionUtil.currentSelectListForEntity(entity); + List secondColumn = []; + List thirdColumn = []; + if (firstColumn.length > 0) { + for (BrnSelectionEntity firstEntity in firstColumn) { + secondColumn.addAll(BrnSelectionUtil.currentSelectListForEntity(firstEntity)); + if (secondColumn.length > 0) { + for (BrnSelectionEntity secondEntity in secondColumn) { + thirdColumn.addAll(BrnSelectionUtil.currentSelectListForEntity(secondEntity)); } } } + } - if (firstColumn.length == 0 || firstColumn.length > 1) { + if (firstColumn.length == 0 || firstColumn.length > 1) { + title = entity.title; + } else { + /// 第一列选中了一个,为【不限】类型,使用上一级别的名字展示。 + if (firstColumn[0].isUnLimit()) { title = entity.title; + } else if (firstColumn[0].filterType == BrnSelectionFilterType.range || + firstColumn[0].filterType == BrnSelectionFilterType.date || + firstColumn[0].filterType == BrnSelectionFilterType.dateRange || + firstColumn[0].filterType == BrnSelectionFilterType.dateRangeCalendar) { + title = _getDateAndRangeTitle(firstColumn, entity); } else { - /// 第一列选中了一个,为【不限】类型,使用上一级别的名字展示。 - if (firstColumn[0].isUnLimit()) { - title = entity.title; - } else if (firstColumn[0].filterType == BrnSelectionFilterType.Range || - firstColumn[0].filterType == BrnSelectionFilterType.Date || - firstColumn[0].filterType == BrnSelectionFilterType.DateRange || - firstColumn[0].filterType == - BrnSelectionFilterType.DateRangeCalendar) { - title = getDateAndRangeTitle(firstColumn, entity); + if (secondColumn.length == 0 || secondColumn.length > 1) { + title = firstColumn[0].title; } else { - if (secondColumn.length == 0 || secondColumn.length > 1) { + /// 第二列选中了一个,为【不限】类型,使用上一级别的名字展示。 + if (secondColumn[0].isUnLimit()) { title = firstColumn[0].title; + } else if (secondColumn[0].filterType == BrnSelectionFilterType.range || + secondColumn[0].filterType == BrnSelectionFilterType.date || + secondColumn[0].filterType == BrnSelectionFilterType.dateRange || + secondColumn[0].filterType == BrnSelectionFilterType.dateRangeCalendar) { + title = _getDateAndRangeTitle(secondColumn, firstColumn[0]); } else { - /// 第二列选中了一个,为【不限】类型,使用上一级别的名字展示。 - if (secondColumn[0].isUnLimit()) { - title = firstColumn[0].title; - } else if (secondColumn[0].filterType == - BrnSelectionFilterType.Range || - secondColumn[0].filterType == BrnSelectionFilterType.Date || - secondColumn[0].filterType == - BrnSelectionFilterType.DateRange || - secondColumn[0].filterType == - BrnSelectionFilterType.DateRangeCalendar) { - title = getDateAndRangeTitle(secondColumn, firstColumn[0]); + if (thirdColumn.length == 0 || thirdColumn.length > 1) { + title = secondColumn[0].title; } else { - if (thirdColumn.length == 0 || thirdColumn.length > 1) { + /// 第三列选中了一个,为【不限】类型,使用上一级别的名字展示。 + if (thirdColumn[0].isUnLimit()) { title = secondColumn[0].title; + } else if (thirdColumn[0].filterType == BrnSelectionFilterType.range || + thirdColumn[0].filterType == BrnSelectionFilterType.date || + thirdColumn[0].filterType == BrnSelectionFilterType.dateRange || + thirdColumn[0].filterType == BrnSelectionFilterType.dateRangeCalendar) { + title = _getDateAndRangeTitle(thirdColumn, secondColumn[0]); } else { - /// 第三列选中了一个,为【不限】类型,使用上一级别的名字展示。 - if (thirdColumn[0].isUnLimit()) { - title = secondColumn[0].title; - } else if (thirdColumn[0].filterType == - BrnSelectionFilterType.Range || - thirdColumn[0].filterType == BrnSelectionFilterType.Date || - thirdColumn[0].filterType == - BrnSelectionFilterType.DateRange || - thirdColumn[0].filterType == - BrnSelectionFilterType.DateRangeCalendar) { - title = getDateAndRangeTitle(thirdColumn, secondColumn[0]); - } else { - title = thirdColumn[0].title; - } + title = thirdColumn[0].title; } } } } } - String joinTitle = - getJoinTitle(entity, firstColumn, secondColumn, thirdColumn); - title = BrunoTools.isEmpty(joinTitle) ? title : joinTitle; } + String joinTitle = _getJoinTitle(entity, firstColumn, secondColumn, thirdColumn); + title = BrunoTools.isEmpty(joinTitle) ? title : joinTitle; return title; } - String getDateAndRangeTitle( - List list, BrnSelectionEntity entity) { - String title = ""; + String? _getDateAndRangeTitle(List list, BrnSelectionEntity entity) { + String? title = ''; if (!BrunoTools.isEmpty(list[0].customMap)) { - if (list[0].filterType == BrnSelectionFilterType.Range) { + if (list[0].filterType == BrnSelectionFilterType.range) { title = - '${list[0].customMap['min']}-${list[0].customMap['max']}(${list[0].extMap['unit']?.toString()})'; - } else if (list[0].filterType == BrnSelectionFilterType.DateRange || - list[0].filterType == BrnSelectionFilterType.DateRangeCalendar) { - title = getDateRangeTitle(list); + '${list[0].customMap!['min']}-${list[0].customMap!['max']}(${list[0].extMap['unit']?.toString()})'; + } else if (list[0].filterType == BrnSelectionFilterType.dateRange || + list[0].filterType == BrnSelectionFilterType.dateRangeCalendar) { + title = _getDateRangeTitle(list); } } else { - if (list[0].filterType == BrnSelectionFilterType.Date) { - title = getDateTimeTitle(list); + if (list[0].filterType == BrnSelectionFilterType.date) { + title = _getDateTimeTitle(list); } else { title = entity.title; } @@ -489,62 +433,60 @@ class _BrnSelectionMenuWidgetState extends State { return title; } - String getDateRangeTitle(List list) { - String minDateTime = ""; - String maxDateTime = ""; + String _getDateRangeTitle(List list) { + String minDateTime = ''; + String maxDateTime = ''; + if (list[0].customMap != null && - list[0].customMap['min'] != null && - int.tryParse(list[0].customMap['min']) != null) { - minDateTime = DateTimeFormatter.formatDate( - DateTimeFormatter.convertIntValueToDateTime(list[0].customMap['min']), - 'yyyy年MM月dd日', - DateTimePickerLocale.zh_cn); + list[0].customMap!['min'] != null && + int.tryParse(list[0].customMap!['min'] ?? '') != null) { + DateTime? minDate = DateTimeFormatter.convertIntValueToDateTime(list[0].customMap!['min']); + if (minDate != null) { + minDateTime = + DateTimeFormatter.formatDate(minDate, 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn); + } } if (list[0].customMap != null && - list[0].customMap['max'] != null && - int.tryParse(list[0].customMap['max']) != null) { - maxDateTime = DateTimeFormatter.formatDate( - DateTimeFormatter.convertIntValueToDateTime(list[0].customMap['max']), - 'yyyy年MM月dd日', - DateTimePickerLocale.zh_cn); + list[0].customMap!['max'] != null && + int.tryParse(list[0].customMap!['max'] ?? '') != null) { + DateTime? maxDate = DateTimeFormatter.convertIntValueToDateTime(list[0].customMap!['max']); + if (maxDate != null) { + maxDateTime = + DateTimeFormatter.formatDate(maxDate, 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn); + } } return '$minDateTime-$maxDateTime'; } - String getDateTimeTitle(List list) { - String title = ""; - int msDateTime = int.tryParse(list[0].value ?? ""); + String? _getDateTimeTitle(List list) { + String? title = ""; + int? msDateTime = int.tryParse(list[0].value ?? ''); title = msDateTime != null - ? DateTimeFormatter.formatDate( - DateTime.fromMillisecondsSinceEpoch(msDateTime), - 'yyyy年MM月dd日', - DateTimePickerLocale.zh_cn) + ? DateTimeFormatter.formatDate(DateTime.fromMillisecondsSinceEpoch(msDateTime), + 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn) : list[0].title; return title; } - String getJoinTitle( - BrnSelectionEntity entity, - List firstColumn, - List secondColumn, - List thirdColumn) { + String _getJoinTitle(BrnSelectionEntity entity, List firstColumn, + List secondColumn, List thirdColumn) { String title = ""; if (entity.canJoinTitle) { if (firstColumn.length == 1) { - title = firstColumn[0].title ?? ""; + title = firstColumn[0].title; } if (secondColumn.length == 1) { - title += secondColumn[0].title ?? ""; + title += secondColumn[0].title; } if (thirdColumn.length == 1) { - title += thirdColumn[0].title ?? ""; + title += thirdColumn[0].title; } } return title; } - void refreshSelectionMenuTitle(int index, BrnSelectionEntity entity) { - if (entity.filterType == BrnSelectionFilterType.More) { + void _refreshSelectionMenuTitle(int index, BrnSelectionEntity entity) { + if (entity.filterType == BrnSelectionFilterType.more) { if (entity.allSelectedList().length > 0) { menuItemHighlightState[index] = true; } else { @@ -552,7 +494,7 @@ class _BrnSelectionMenuWidgetState extends State { } return; } - String title = getSelectedResultTitle(entity); + String? title = _getSelectedResultTitle(entity); if (title != null) { titles[index] = title; } diff --git a/lib/src/components/selection/widget/brn_selection_more_item_widget.dart b/lib/src/components/selection/widget/brn_selection_more_item_widget.dart index 465ecb34..528b7d36 100644 --- a/lib/src/components/selection/widget/brn_selection_more_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_more_item_widget.dart @@ -8,8 +8,8 @@ import 'package:bruno/src/components/picker/time_picker/date_picker/brn_date_pic import 'package:bruno/src/components/selection/bean/brn_selection_common_entity.dart'; import 'package:bruno/src/components/selection/brn_more_selection.dart'; import 'package:bruno/src/components/selection/brn_selection_util.dart'; -import 'package:bruno/src/components/selection/widget/brn_layer_more_selection_page.dart'; import 'package:bruno/src/components/selection/brn_selection_view.dart'; +import 'package:bruno/src/components/selection/widget/brn_layer_more_selection_page.dart'; import 'package:bruno/src/components/selection/widget/brn_selection_date_range_item_widget.dart'; import 'package:bruno/src/components/toast/brn_toast.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; @@ -28,15 +28,17 @@ import 'package:flutter/services.dart'; class BrnMoreSelectionWidget extends StatefulWidget { //entity 是商圈、钥匙等 final BrnSelectionEntity selectionEntity; - final StreamController clearController; - final BrnOnCustomFloatingLayerClick onCustomFloatingLayerClick; + final StreamController? clearController; + final BrnOnCustomFloatingLayerClick? onCustomFloatingLayerClick; BrnSelectionConfig themeData; BrnMoreSelectionWidget( - {this.selectionEntity, + {Key? key, + required this.selectionEntity, this.clearController, this.onCustomFloatingLayerClick, - this.themeData}); + required this.themeData}) + : super(key: key); @override _BrnMoreSelectionWidgetState createState() => _BrnMoreSelectionWidgetState(); @@ -46,9 +48,8 @@ class _BrnMoreSelectionWidgetState extends State { @override Widget build(BuildContext context) { //弹出浮层 - if (widget.selectionEntity.filterType == BrnSelectionFilterType.Layer || - widget.selectionEntity.filterType == - BrnSelectionFilterType.CustomLayer) { + if (widget.selectionEntity.filterType == BrnSelectionFilterType.layer || + widget.selectionEntity.filterType == BrnSelectionFilterType.customLayer) { return FilterLayerTypeWidget( selectionEntity: widget.selectionEntity, onCustomFloatingLayerClick: widget.onCustomFloatingLayerClick, @@ -65,29 +66,31 @@ class _BrnMoreSelectionWidgetState extends State { } /// 展示标签的布局:标题+更多+标签+自定义 -// ignore: must_be_immutable class _FilterCommonTypeWidget extends StatefulWidget { //楼层 final BrnSelectionEntity selectionEntity; - final StreamController clearController; - BrnSelectionConfig themeData; + final StreamController? clearController; + final BrnSelectionConfig themeData; - _FilterCommonTypeWidget( - {this.selectionEntity, this.clearController, this.themeData}); + _FilterCommonTypeWidget({ + Key? key, + required this.selectionEntity, + this.clearController, + required this.themeData, + }) : super(key: key); @override - __FilterCommonTypeWidgetState createState() => - __FilterCommonTypeWidgetState(); + __FilterCommonTypeWidgetState createState() => __FilterCommonTypeWidgetState(); } class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { bool isExpanded = false; ///展开收起的通知 - ValueNotifier valueNotifier; + late ValueNotifier valueNotifier; ///用于 range和 tag 之间通信 - StreamController streamController; + late StreamController streamController; @override void initState() { @@ -102,9 +105,7 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { setState(() { if (!event.filter) { //将所有tag设置为未选中 - event.rangeEntity.parent - ?.currentTagListForEntity() - ?.forEach((data) { + event.rangeEntity.parent?.currentTagListForEntity().forEach((data) { data.clearSelectedEntity(); }); } @@ -131,18 +132,14 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: - EdgeInsets.only(top: 20, right: _isVisibleMore() ? 40 : 0), + padding: EdgeInsets.only(top: 20, right: _isVisibleMore() ? 40 : 0), child: _buildTitleWidget(), ), //自定义输入框 _buildRangeWidget(), //标签的筛选条件 Visibility( - visible: widget.selectionEntity - .currentShowTagByExpanded(isExpanded) - .length > - 0, + visible: widget.selectionEntity.currentShowTagByExpanded(isExpanded).length > 0, child: Padding( padding: EdgeInsets.only(top: 12), child: _buildSelectionTag(), @@ -179,7 +176,7 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { children: [ Expanded( child: Text( - widget.selectionEntity.title ?? "", + widget.selectionEntity.title, style: widget.themeData.titleForMoreTextStyle.generateTextStyle(), ), ), @@ -220,12 +217,12 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { return GestureDetector( onTap: () { setState(() { - if (data.filterType == BrnSelectionFilterType.Radio) { - data.parent.clearSelectedEntity(); + if (data.filterType == BrnSelectionFilterType.radio) { + data.parent?.clearSelectedEntity(); data.isSelected = true; //用于发送 标签点击事件 streamController.add(SelectEvent()); - } else if (data.filterType == BrnSelectionFilterType.Checkbox) { + } else if (data.filterType == BrnSelectionFilterType.checkbox) { if (!data.isSelected) { if (!BrnSelectionUtil.checkMaxSelectionCount(data)) { BrnToast.show('您选择的筛选条件数量已达上限', context); @@ -233,13 +230,13 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { } } - data.parent.children - ?.where((_) => _.filterType == BrnSelectionFilterType.Radio) - ?.forEach((f) => f.isSelected = false); + data.parent?.children + .where((_) => _.filterType == BrnSelectionFilterType.radio) + .forEach((f) => f.isSelected = false); data.isSelected = !data.isSelected; //用于发送 标签点击事件 streamController.add(SelectEvent()); - } else if (data.filterType == BrnSelectionFilterType.Date) { + } else if (data.filterType == BrnSelectionFilterType.date) { _showDatePicker(data); } }); @@ -250,29 +247,26 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { ); } - Widget _buildSingleTag(BrnSelectionEntity data) { - bool isDate = data.filterType == BrnSelectionFilterType.Date; + Widget _buildSingleTag(BrnSelectionEntity entity) { + bool isDate = entity.filterType == BrnSelectionFilterType.date; - String showName; + String? showName; if (isDate) { - if (data.value == null || data.value.isEmpty) { - showName = data.title; + if (BrunoTools.isEmpty(entity.value)) { + showName = entity.title; } else { - int time = int.tryParse(data.value ?? "") ?? - DateTime.now().millisecondsSinceEpoch; + int time = int.tryParse(entity.value ?? "") ?? DateTime.now().millisecondsSinceEpoch; showName = DateTimeFormatter.formatDate( - DateTime.fromMillisecondsSinceEpoch(time), - 'yyyy/MMMM/dd', - DateTimePickerLocale.zh_cn); + DateTime.fromMillisecondsSinceEpoch(time), 'yyyy/MMMM/dd', DateTimePickerLocale.zh_cn); } } else { - showName = data.title; + showName = entity.title; } return Container( alignment: Alignment.center, decoration: BoxDecoration( - color: data.isSelected + color: entity.isSelected ? widget.themeData.tagSelectedBackgroundColor : widget.themeData.tagNormalBackgroundColor, borderRadius: BorderRadius.circular(widget.themeData.tagRadius)), @@ -281,22 +275,21 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { showName, maxLines: 2, textAlign: TextAlign.center, - style: data.isSelected ? _selectedTextStyle() : _tagTextStyle(), + style: entity.isSelected ? _selectedTextStyle() : _tagTextStyle(), ), ); } TextStyle _tagTextStyle() { - return widget.themeData.tagNormalTextStyle?.generateTextStyle(); + return widget.themeData.tagNormalTextStyle.generateTextStyle(); } TextStyle _selectedTextStyle() { - return widget.themeData.tagSelectedTextStyle?.generateTextStyle(); + return widget.themeData.tagSelectedTextStyle.generateTextStyle(); } void _showDatePicker(BrnSelectionEntity data) { - int time = - int.tryParse(data.value ?? "") ?? DateTime.now().millisecondsSinceEpoch; + int time = int.tryParse(data.value ?? "") ?? DateTime.now().millisecondsSinceEpoch; BrnDatePicker.showDatePicker(context, pickerMode: BrnDateTimePickerMode.date, pickerTitleConfig: BrnPickerTitleConfig.Default, @@ -304,7 +297,7 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { dateFormat: 'yyyy年,MMMM月,dd日', onConfirm: (dateTime, list) { if (mounted) { setState(() { - data.parent.clearSelectedEntity(); + data.parent?.clearSelectedEntity(); data.isSelected = true; data.value = dateTime.millisecondsSinceEpoch.toString(); }); @@ -314,14 +307,17 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { } /// 更多和箭头widget -// ignore: must_be_immutable class _MoreArrow extends StatefulWidget { ///用于通知 展开和收起 - final ValueNotifier valueNotifier; + final ValueNotifier? valueNotifier; - BrnSelectionConfig themeData; + final BrnSelectionConfig? themeData; - _MoreArrow({this.valueNotifier, this.themeData}); + _MoreArrow({ + Key? key, + this.valueNotifier, + this.themeData, + }) : super(key: key); @override __MoreArrowState createState() => __MoreArrowState(); @@ -332,8 +328,7 @@ class __MoreArrowState extends State<_MoreArrow> { @override Widget build(BuildContext context) { - String asset = - isExpanded ? BrnAsset.ICON_UP_ARROW : BrnAsset.ICON_DOWN_ARROW; + String asset = isExpanded ? BrnAsset.iconUpArrow : BrnAsset.iconDownArrow; return GestureDetector( behavior: HitTestBehavior.opaque, @@ -341,7 +336,7 @@ class __MoreArrowState extends State<_MoreArrow> { setState(() { isExpanded = !isExpanded; if (widget.valueNotifier != null) { - widget.valueNotifier.value = isExpanded; + widget.valueNotifier!.value = isExpanded; } }); }, @@ -352,7 +347,7 @@ class __MoreArrowState extends State<_MoreArrow> { children: [ Text( '更多', - style: widget.themeData.moreTextStyle.generateTextStyle(), + style: widget.themeData?.moreTextStyle.generateTextStyle(), ), Container( height: 16, @@ -370,26 +365,25 @@ class __MoreArrowState extends State<_MoreArrow> { } /// 自定义筛选条件 -// ignore: must_be_immutable class _MoreRangeWidget extends StatefulWidget { ///用于标签和自定义输入 通信 - final StreamController streamController; + final StreamController? streamController; ///用于自定义的筛选条件 最大值最小值 final BrnSelectionEntity rangeEntity; ///用于监听重置事件 - final StreamController clearController; + final StreamController? clearController; - BrnSelectionConfig themeData; + final BrnSelectionConfig themeData; - _MoreRangeWidget( - {this.streamController, - this.rangeEntity, - this.clearController, - this.themeData, - Key key}) - : super(key: key); + _MoreRangeWidget({ + Key? key, + required this.rangeEntity, + this.streamController, + this.clearController, + required this.themeData, + }) : super(key: key); @override __MoreRangeWidgetState createState() => __MoreRangeWidgetState(); @@ -397,32 +391,28 @@ class _MoreRangeWidget extends StatefulWidget { class __MoreRangeWidgetState extends State<_MoreRangeWidget> { //最小值 输入框监听 - TextEditingController minController; + TextEditingController minController = TextEditingController(); //最大值 输入框监听 - TextEditingController maxController; + TextEditingController maxController = TextEditingController(); //最小值 焦点监听 - FocusNode minFocusNode; + FocusNode minFocusNode = FocusNode(); //最大值 焦点监听 - FocusNode maxFocusNode; + FocusNode maxFocusNode = FocusNode(); //默认的最大值 - int max; + late int max; //默认的最小值 - int min; + late int min; @override void initState() { super.initState(); - minFocusNode = FocusNode(); - maxFocusNode = FocusNode(); - minController = TextEditingController(); - maxController = TextEditingController(); - widget?.clearController?.stream?.listen((event) { + widget.clearController?.stream.listen((event) { minController.clear(); maxController.clear(); }); @@ -431,46 +421,40 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { widget.rangeEntity.customMap = Map(); } - minController.text = (widget.rangeEntity.customMap['min'] != null) - ? widget.rangeEntity.customMap['min']?.toString() - : null; - maxController.text = (widget.rangeEntity.customMap['max'] != null) - ? widget.rangeEntity.customMap['max']?.toString() - : null; + minController.text = widget.rangeEntity.customMap!['min']?.toString() ?? ''; + maxController.text = widget.rangeEntity.customMap!['max']?.toString() ?? ''; - min = - int.tryParse(widget.rangeEntity?.extMap['min']?.toString() ?? "") ?? 0; - max = int.tryParse(widget.rangeEntity?.extMap['max']?.toString() ?? "") ?? - 9999; + min = int.tryParse(widget.rangeEntity.extMap['min']?.toString() ?? "") ?? 0; + max = int.tryParse(widget.rangeEntity.extMap['max']?.toString() ?? "") ?? 9999; ///处理的逻辑: /// 1:将输入框的 文本写入 customMap中 /// 2:如果最大值和最小值满足条件 则将range选中 minController.addListener(() { - if (widget.rangeEntity.filterType != BrnSelectionFilterType.Range) { + if (widget.rangeEntity.filterType != BrnSelectionFilterType.range) { return; } - String minInput = minController.text ?? ""; + String minInput = minController.text; if (widget.rangeEntity.customMap == null) { widget.rangeEntity.customMap = {}; } - widget.rangeEntity.customMap['min'] = minInput; + widget.rangeEntity.customMap!['min'] = minInput; widget.rangeEntity.isSelected = true; }); maxController.addListener(() { - if (widget.rangeEntity.filterType != BrnSelectionFilterType.Range) { + if (widget.rangeEntity.filterType != BrnSelectionFilterType.range) { return; } - String maxInput = maxController.text ?? ""; + String maxInput = maxController.text; if (widget.rangeEntity.customMap == null) { widget.rangeEntity.customMap = {}; } - widget.rangeEntity.customMap['max'] = maxInput; + widget.rangeEntity.customMap!['max'] = maxInput; widget.rangeEntity.isSelected = true; }); @@ -480,21 +464,19 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { /// 如果是多选 则不处理 minFocusNode.addListener(() { if (minFocusNode.hasFocus) { - widget.streamController - .add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); + widget.streamController?.add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); } }); maxFocusNode.addListener(() { if (maxFocusNode.hasFocus) { - widget.streamController - .add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); + widget.streamController?.add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); } }); ///用于监听tab的点击事件 ///如果父亲是单选 则将输入框清空并失去焦点,并且将自定义筛选设置为 未选中,以及更新用于显示的map - widget.streamController.stream.listen((event) { + widget.streamController?.stream.listen((event) { if (event is SelectEvent) { maxController.clear(); minController.clear(); @@ -508,27 +490,25 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { @override Widget build(BuildContext context) { - if (widget.rangeEntity.filterType == BrnSelectionFilterType.DateRange) { + if (widget.rangeEntity.filterType == BrnSelectionFilterType.dateRange) { return BrnSelectionDateRangeItemWidget( item: widget.rangeEntity, isNeedTitle: false, showTextSize: 14, - dateFormat: DATETIME_PICKER_DATE_FORMAT, + dateFormat: datetimePickerDateFormat, minTextEditingController: minController, maxTextEditingController: maxController, themeData: widget.themeData, onTapped: () { //点击选择框通知标签清空 - widget.streamController.add( - InputEvent(filter: false, rangeEntity: widget.rangeEntity)); + widget.streamController?.add(InputEvent(filter: false, rangeEntity: widget.rangeEntity)); }); } else { return Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( - child: _buildRangeField( - '最小值', minController, minFocusNode, widget.themeData), + child: _buildRangeField('最小值', minController, minFocusNode, widget.themeData), ), Container( // height: 38, @@ -540,8 +520,7 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { ), ), Expanded( - child: _buildRangeField( - '最大值', maxController, maxFocusNode, widget.themeData), + child: _buildRangeField('最大值', maxController, maxFocusNode, widget.themeData), ), ], ); @@ -560,27 +539,20 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { focusNode: focusNode, textAlign: TextAlign.center, controller: textEditingController, - cursorColor: BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .brandPrimary, + cursorColor: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, inputFormatters: [FilteringTextInputFormatter.digitsOnly], style: widget.themeData.inputTextStyle.generateTextStyle(), decoration: InputDecoration( hintText: hint, hintStyle: widget.themeData.hintTextStyle.generateTextStyle(), enabledBorder: UnderlineInputBorder( - borderRadius: - BorderRadius.circular(widget.themeData.tagRadius), - borderSide: BorderSide( - width: 1, - color: widget.themeData.commonConfig.borderColorBase)), + borderRadius: BorderRadius.circular(widget.themeData.tagRadius), + borderSide: + BorderSide(width: 1, color: widget.themeData.commonConfig.borderColorBase)), focusedBorder: UnderlineInputBorder( - borderRadius: - BorderRadius.circular(widget.themeData.tagRadius), - borderSide: BorderSide( - width: 1, - color: widget.themeData.commonConfig.borderColorBase))), + borderRadius: BorderRadius.circular(widget.themeData.tagRadius), + borderSide: + BorderSide(width: 1, color: widget.themeData.commonConfig.borderColorBase))), ), ), ); @@ -588,15 +560,18 @@ class __MoreRangeWidgetState extends State<_MoreRangeWidget> { } /// 浮层类型的项 : 标题 + 点击跳转的layout -// ignore: must_be_immutable class FilterLayerTypeWidget extends StatefulWidget { //entity是 商圈 final BrnSelectionEntity selectionEntity; - final BrnOnCustomFloatingLayerClick onCustomFloatingLayerClick; - BrnSelectionConfig themeData; + final BrnOnCustomFloatingLayerClick? onCustomFloatingLayerClick; + final BrnSelectionConfig themeData; - FilterLayerTypeWidget( - {this.selectionEntity, this.onCustomFloatingLayerClick, this.themeData}); + FilterLayerTypeWidget({ + Key? key, + required this.selectionEntity, + this.onCustomFloatingLayerClick, + required this.themeData, + }) : super(key: key); @override _FilterLayerTypeWidgetState createState() => _FilterLayerTypeWidgetState(); @@ -619,8 +594,7 @@ class _FilterLayerTypeWidgetState extends State { padding: const EdgeInsets.only(left: 20, right: 20, top: 6), child: GestureDetector( onTap: () { - if (widget.selectionEntity.filterType == - BrnSelectionFilterType.Layer) { + if (widget.selectionEntity.filterType == BrnSelectionFilterType.layer) { Navigator.of(context) .push(PageRouteBuilder( opaque: false, @@ -631,24 +605,20 @@ class _FilterLayerTypeWidgetState extends State { ); })) .then((data) { - updateContent(); + setState(() {}); }); - } else if (widget.selectionEntity.filterType == - BrnSelectionFilterType.CustomLayer) { + } else if (widget.selectionEntity.filterType == BrnSelectionFilterType.customLayer) { if (widget.onCustomFloatingLayerClick != null) { int entityIndex = -1; - if (widget.selectionEntity.parent != null && - widget.selectionEntity.parent.children != null) { - entityIndex = widget.selectionEntity.parent.children - .indexOf(widget.selectionEntity); + if (widget.selectionEntity.parent != null) { + entityIndex = + widget.selectionEntity.parent!.children.indexOf(widget.selectionEntity); } - widget.onCustomFloatingLayerClick( - entityIndex, widget.selectionEntity, + widget.onCustomFloatingLayerClick!(entityIndex, widget.selectionEntity, (List customFloatingLayerParams) { - widget.selectionEntity.children?.clear(); + widget.selectionEntity.children.clear(); widget.selectionEntity.children = []; - widget.selectionEntity.children - .addAll(customFloatingLayerParams); + widget.selectionEntity.children.addAll(customFloatingLayerParams); widget.selectionEntity.configDefaultValue(); setState(() {}); }); @@ -659,16 +629,15 @@ class _FilterLayerTypeWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( - child: Text(isEmptyCondition() ? '请选择' : getCondition(), - style: isEmptyCondition() + child: Text(_isEmptyCondition() ? '请选择' : _getCondition(), + style: _isEmptyCondition() ? widget.themeData.hintTextStyle.generateTextStyle() - : widget.themeData.optionTextStyle - .generateTextStyle()), + : widget.themeData.optionTextStyle.generateTextStyle()), ), Container( height: 16, width: 16, - child: BrunoTools.getAssetImage(BrnAsset.ICON_RIGHT_ARROW), + child: BrunoTools.getAssetImage(BrnAsset.iconRightArrow), ) ], ), @@ -679,20 +648,14 @@ class _FilterLayerTypeWidgetState extends State { ); } - void updateContent() { - setState(() {}); - } - - bool isEmptyCondition() { - String condition = getCondition(); - return condition == null || condition.isEmpty; + bool _isEmptyCondition() { + return _getCondition().isEmpty; } - String getCondition() { + String _getCondition() { String tmp = ""; //返回所有选中的 - List selectedList = - widget.selectionEntity.selectedList(); + List selectedList = widget.selectionEntity.selectedList(); //判断步骤: //第一步:取出来所有选中的: 房山 不限 小白楼 西城 不限 @@ -715,9 +678,11 @@ class _FilterLayerTypeWidgetState extends State { }).toList(); for (int i = 0; i < result.length; i++) { - tmp += result[i].title; - if (i != result.length - 1) { - tmp += '、'; + if (result[i].title.isNotEmpty) { + tmp += result[i].title; + if (i != result.length - 1) { + tmp += '、'; + } } } return tmp; @@ -733,8 +698,8 @@ class SelectEvent extends Event {} /// 输入框的事件:携带 自定义的筛选条件 和 过滤标识位 /// 由于点击标签之后,会清空筛选条件,清空的时候,textField的监听也会执行一遍,因此需要过滤 class InputEvent extends Event { - BrnSelectionEntity rangeEntity; - bool filter; + final BrnSelectionEntity rangeEntity; + final bool filter; - InputEvent({this.rangeEntity, this.filter}); + InputEvent({required this.rangeEntity, this.filter = false}); } diff --git a/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart b/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart index 4af722b5..baecf63f 100644 --- a/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart @@ -10,86 +10,83 @@ typedef void OnFocusChangedFunction(bool focus); /// 清空自定义范围输入框焦点的事件类 class ClearSelectionFocusEvent {} -// ignore: must_be_immutable class BrnSelectionRangeItemWidget extends StatefulWidget { final BrnSelectionEntity item; - final OnRangeChangedFunction onRangeChanged; - final OnFocusChangedFunction onFocusChanged; + final OnRangeChangedFunction? onRangeChanged; + final OnFocusChangedFunction? onFocusChanged; final bool isShouldClearText; final TextEditingController minTextEditingController; final TextEditingController maxTextEditingController; - BrnSelectionConfig themeData; + final BrnSelectionConfig themeData; - BrnSelectionRangeItemWidget( - {this.item, - @required this.minTextEditingController, - @required this.maxTextEditingController, - this.isShouldClearText = false, - this.themeData, - this.onRangeChanged, - this.onFocusChanged}); + BrnSelectionRangeItemWidget({ + Key? key, + required this.item, + required this.minTextEditingController, + required this.maxTextEditingController, + this.isShouldClearText = false, + this.onRangeChanged, + this.onFocusChanged, + required this.themeData, + }): super(key: key); - _BrnSelectionRangeItemWidgetState createState() => - _BrnSelectionRangeItemWidgetState(); + _BrnSelectionRangeItemWidgetState createState() => _BrnSelectionRangeItemWidgetState(); } -class _BrnSelectionRangeItemWidgetState - extends State { +class _BrnSelectionRangeItemWidgetState extends State { FocusNode _minFocusNode = FocusNode(); FocusNode _maxFocusNode = FocusNode(); @override void initState() { widget.minTextEditingController.text = - (widget.item.customMap != null && widget.item.customMap['min'] != null) - ? widget.item.customMap['min']?.toString() - : null; + (widget.item.customMap != null && widget.item.customMap!['min'] != null) + ? widget.item.customMap!['min']?.toString() ?? '' + : ''; widget.maxTextEditingController.text = - (widget.item.customMap != null && widget.item.customMap['max'] != null) - ? widget.item.customMap['max']?.toString() - : null; + (widget.item.customMap != null && widget.item.customMap!['max'] != null) + ? widget.item.customMap!['max']?.toString() ?? '' + : ''; //输入框焦点 _minFocusNode.addListener(() { if (widget.onFocusChanged != null) { - widget.onFocusChanged(_minFocusNode.hasFocus || _maxFocusNode.hasFocus); + widget.onFocusChanged!(_minFocusNode.hasFocus || _maxFocusNode.hasFocus); } }); _maxFocusNode.addListener(() { if (widget.onFocusChanged != null) { - widget.onFocusChanged(_minFocusNode.hasFocus || _maxFocusNode.hasFocus); + widget.onFocusChanged!(_minFocusNode.hasFocus || _maxFocusNode.hasFocus); } }); widget.minTextEditingController.addListener(() { - String minInput = widget.minTextEditingController.text ?? ""; + String minInput = widget.minTextEditingController.text; if (widget.item.customMap == null) { widget.item.customMap = {}; } - widget.item.customMap['min'] = minInput; + widget.item.customMap!['min'] = minInput; widget.item.isSelected = true; }); widget.maxTextEditingController.addListener(() { - String maxInput = widget.maxTextEditingController.text ?? ""; + String maxInput = widget.maxTextEditingController.text; if (widget.item.customMap == null) { widget.item.customMap = {}; } - widget.item.customMap['max'] = maxInput; + widget.item.customMap!['max'] = maxInput; widget.item.isSelected = true; }); - EventBus.instance - .on() - .listen((ClearSelectionFocusEvent event) { - _minFocusNode?.unfocus(); - _maxFocusNode?.unfocus(); + EventBus.instance.on().listen((ClearSelectionFocusEvent event) { + _minFocusNode.unfocus(); + _maxFocusNode.unfocus(); }); super.initState(); @@ -106,13 +103,12 @@ class _BrnSelectionRangeItemWidgetState margin: EdgeInsets.only(bottom: 5), alignment: Alignment.centerLeft, child: Text( - (widget.item.title != null ? widget.item.title : '自定义区间') + + (widget.item.title.isNotEmpty ? widget.item.title : '自定义区间') + "(" + - widget.item.extMap['unit']?.toString() + + (widget.item.extMap['unit']?.toString() ?? '') + ")", textAlign: TextAlign.left, - style: - widget.themeData.rangeTitleTextStyle?.generateTextStyle(), + style: widget.themeData.rangeTitleTextStyle.generateTextStyle(), ), ), Row( @@ -121,7 +117,7 @@ class _BrnSelectionRangeItemWidgetState Container( child: Text( "至", - style: widget.themeData.inputTextStyle?.generateTextStyle(), + style: widget.themeData.inputTextStyle.generateTextStyle(), ), ), getRangeTextField(true), @@ -136,20 +132,18 @@ class _BrnSelectionRangeItemWidgetState Widget getRangeTextField(bool isMax) { return Expanded( child: TextFormField( - style: widget.themeData.inputTextStyle?.generateTextStyle(), + style: widget.themeData.inputTextStyle.generateTextStyle(), inputFormatters: [FilteringTextInputFormatter.digitsOnly], keyboardType: TextInputType.numberWithOptions(), onChanged: (input) { widget.item.isSelected = true; }, focusNode: isMax ? _maxFocusNode : _minFocusNode, - controller: isMax - ? widget.maxTextEditingController - : widget.minTextEditingController, + controller: isMax ? widget.maxTextEditingController : widget.minTextEditingController, cursorColor: widget.themeData.commonConfig.brandPrimary, textAlign: TextAlign.center, decoration: InputDecoration( - hintStyle: widget.themeData.hintTextStyle?.generateTextStyle(), + hintStyle: widget.themeData.hintTextStyle.generateTextStyle(), hintText: (isMax ? '最大值' : '最小值'), enabledBorder: UnderlineInputBorder( borderSide: BorderSide( diff --git a/lib/src/components/selection/widget/brn_selection_range_tag_widget.dart b/lib/src/components/selection/widget/brn_selection_range_tag_widget.dart index 8e734255..52ee7fd3 100644 --- a/lib/src/components/selection/widget/brn_selection_range_tag_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_range_tag_widget.dart @@ -1,5 +1,3 @@ -import 'dart:ui'; - import 'package:bruno/src/components/picker/time_picker/brn_date_time_formatter.dart'; import 'package:bruno/src/components/selection/bean/brn_selection_common_entity.dart'; import 'package:bruno/src/components/selection/brn_selection_util.dart'; @@ -12,46 +10,42 @@ import 'package:flutter/material.dart'; /// /// /// /// /// /// /// /// /// / /// 描述: 多选 tag 组件 /// /// /// /// /// /// /// /// /// / -// ignore: must_be_immutable class BrnSelectionRangeTagWidget extends StatefulWidget { //tag 显示的文本 @required final List tagFilterList; //初始选中的 Index 列表 - final List initSelectStatus; + final List? initSelectStatus; //选择tag的回调 - final void Function(int, bool) onSelect; + final void Function(int, bool)? onSelect; final double spacing; final double verticalSpacing; final int tagWidth; final double tagHeight; - final int initFocusedindex; + final int initFocusedIndex; - BrnSelectionConfig themeData; + final BrnSelectionConfig themeData; BrnSelectionRangeTagWidget( - {Key key, - @required this.tagFilterList, + {Key? key, + required this.tagFilterList, this.initSelectStatus, this.onSelect, this.spacing = 12, this.verticalSpacing = 10, this.tagWidth = 75, this.tagHeight = 34, - this.themeData, - this.initFocusedindex = -1}) - : assert(tagFilterList != null), - super(key: key); + required this.themeData, + this.initFocusedIndex = -1}) + : super(key: key); @override - _BrnSelectionRangeTagWidgetState createState() => - _BrnSelectionRangeTagWidgetState(); + _BrnSelectionRangeTagWidgetState createState() => _BrnSelectionRangeTagWidgetState(); } -class _BrnSelectionRangeTagWidgetState - extends State { +class _BrnSelectionRangeTagWidgetState extends State { @override Widget build(BuildContext context) { return Wrap( @@ -62,16 +56,14 @@ class _BrnSelectionRangeTagWidgetState } List _tagWidgetList(context) { - List list = List(); - for (int nameIndex = 0; - nameIndex < widget.tagFilterList.length; - nameIndex++) { + List list = []; + for (int nameIndex = 0; nameIndex < widget.tagFilterList.length; nameIndex++) { Widget tagWidget = _tagWidgetAtIndex(nameIndex); GestureDetector gdt = GestureDetector( child: tagWidget, onTap: () { var selectedEntity = widget.tagFilterList[nameIndex]; - if (BrnSelectionFilterType.Checkbox == selectedEntity.filterType && + if (BrnSelectionFilterType.checkbox == selectedEntity.filterType && !selectedEntity.isSelected) { if (!BrnSelectionUtil.checkMaxSelectionCount(selectedEntity)) { BrnToast.show("您选择的筛选条件数量已达上限", context); @@ -80,7 +72,7 @@ class _BrnSelectionRangeTagWidgetState } BrnSelectionUtil.processBrotherItemSelectStatus(selectedEntity); if (null != widget.onSelect) { - widget.onSelect(nameIndex, selectedEntity.isSelected); + widget.onSelect!(nameIndex, selectedEntity.isSelected); } setState(() {}); }); @@ -90,45 +82,42 @@ class _BrnSelectionRangeTagWidgetState } Widget _tagWidgetAtIndex(int nameIndex) { - bool selected = widget.tagFilterList[nameIndex].isSelected || - nameIndex == widget.initFocusedindex; + bool selected = + widget.tagFilterList[nameIndex].isSelected || nameIndex == widget.initFocusedIndex; String text = widget.tagFilterList[nameIndex].title; - if (widget.tagFilterList[nameIndex].filterType == - BrnSelectionFilterType.Date && + if (widget.tagFilterList[nameIndex].filterType == BrnSelectionFilterType.date && !BrunoTools.isEmpty(widget.tagFilterList[nameIndex].value)) { - if (int.tryParse(widget.tagFilterList[nameIndex].value) != null) { - text = DateTimeFormatter.formatDate( - DateTimeFormatter.convertIntValueToDateTime( - widget.tagFilterList[nameIndex].value), - 'yyyy年MM月dd日', - DateTimePickerLocale.zh_cn); + if (int.tryParse(widget.tagFilterList[nameIndex].value ?? '') != null) { + DateTime? dateTime = + DateTimeFormatter.convertIntValueToDateTime(widget.tagFilterList[nameIndex].value); + if (dateTime != null) { + text = DateTimeFormatter.formatDate(dateTime, 'yyyy年MM月dd日', DateTimePickerLocale.zh_cn); + } + } else { + text = widget.tagFilterList[nameIndex].value ?? ''; } - text = widget.tagFilterList[nameIndex].value; } - Text tx = Text( - text, - style: selected ? _selectedTextStyle() : _tagTextStyle(), - ); - Container cntn = Container( + Text tx = Text(text, style: selected ? _selectedTextStyle() : _tagTextStyle()); + Container tagItem = Container( alignment: Alignment.center, decoration: BoxDecoration( color: selected ? widget.themeData.tagSelectedBackgroundColor : widget.themeData.tagNormalBackgroundColor, borderRadius: BorderRadius.circular(widget.themeData.tagRadius)), - width: widget.tagWidth?.toDouble(), + width: widget.tagWidth.toDouble(), height: widget.tagHeight, child: tx, ); - return cntn; + return tagItem; } TextStyle _tagTextStyle() { - return widget.themeData.tagNormalTextStyle?.generateTextStyle(); + return widget.themeData.tagNormalTextStyle.generateTextStyle(); } TextStyle _selectedTextStyle() { - return widget.themeData.tagSelectedTextStyle?.generateTextStyle(); + return widget.themeData.tagSelectedTextStyle.generateTextStyle(); } } diff --git a/lib/src/components/selection/widget/brn_selection_range_widget.dart b/lib/src/components/selection/widget/brn_selection_range_widget.dart index 20e3baf6..a4ef0536 100644 --- a/lib/src/components/selection/widget/brn_selection_range_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_range_widget.dart @@ -22,51 +22,46 @@ import 'package:flutter/widgets.dart'; typedef void BrnOnRangeSelectionBgClick(); -// ignore: must_be_immutable class BrnRangeSelectionGroupWidget extends StatefulWidget { - static final double screenWidth = - window.physicalSize.width / window.devicePixelRatio; + static final double screenWidth = window.physicalSize.width / window.devicePixelRatio; final BrnSelectionEntity entity; final double maxContentHeight; final bool showSelectedCount; - final BrnOnRangeSelectionBgClick bgClickFunction; - final BrnOnRangeSelectionConfirm onSelectionConfirm; + final BrnOnRangeSelectionBgClick? bgClickFunction; + final BrnOnRangeSelectionConfirm? onSelectionConfirm; - final int rowount; + final int? rowCount; final double marginTop; - BrnSelectionConfig themeData; + final BrnSelectionConfig themeData; BrnRangeSelectionGroupWidget( - {Key key, - @required this.entity, + {Key? key, + required this.entity, this.maxContentHeight = DESIGN_SELECTION_HEIGHT, - this.rowount, + this.rowCount, this.showSelectedCount = false, this.bgClickFunction, this.onSelectionConfirm, this.marginTop = 0, - this.themeData}); + required this.themeData}): super(key: key); @override - _BrnRangeSelectionGroupWidgetState createState() => - _BrnRangeSelectionGroupWidgetState(); + _BrnRangeSelectionGroupWidgetState createState() => _BrnRangeSelectionGroupWidgetState(); } -class _BrnRangeSelectionGroupWidgetState - extends State +class _BrnRangeSelectionGroupWidgetState extends State with SingleTickerProviderStateMixin { - List _originalSelectedItemsList = List(); - List _firstList = List(); - List _secondList = List(); - int _firstIndex; - int _secondIndex; + List _originalSelectedItemsList = []; + List _firstList = []; + List _secondList = []; + int _firstIndex = -1; + int _secondIndex = -1; int totalLevel = 0; - TabController _tabController; - List tabs; + late TabController _tabController; TextEditingController _minTextEditingController = TextEditingController(); TextEditingController _maxTextEditingController = TextEditingController(); @@ -82,21 +77,17 @@ class _BrnRangeSelectionGroupWidgetState } _tabController.addListener(() { _clearAllSelectedItems(); - clearNotTagItem(totalLevel == 1 - ? _firstList - : _firstList[_tabController.index].children); + _clearNotTagItem(totalLevel == 1 ? _firstList : _firstList[_tabController.index].children); }); super.initState(); } @override void dispose() { - _tabController?.dispose(); + _tabController.dispose(); if (!_isConfirmClick) { _resetSelectionDatas(widget.entity); - clearNotTagItem(totalLevel == 1 - ? _firstList - : _firstList[_tabController.index].children); + _clearNotTagItem(totalLevel == 1 ? _firstList : _firstList[_tabController.index].children); _resetCustomMapData(); } super.dispose(); @@ -124,50 +115,45 @@ class _BrnRangeSelectionGroupWidgetState //pragma mark -- config widgets List _configWidgets() { - List widgetList = List(); + List widgetList = []; widgetList.add(_listWidget()); return widgetList; } Widget _listWidget() { - Widget rangeWidget; + Widget? rangeWidget; - if (_firstList != null && _secondList == null) { + if (_firstList.isNotEmpty && _secondList.isEmpty) { /// 1、仅有一级的情况 /// 1.2 一级多选 || 存在自定义范围的情况 - rangeWidget = _createNewTagAndRangeWidget(_firstList, null, Colors.white); - } else if (_firstList != null && _secondList != null) { + rangeWidget = _createNewTagAndRangeWidget(_firstList, Colors.white); + } else if (_firstList.isNotEmpty && _secondList.isNotEmpty) { /// 2、有二级的情况 - rangeWidget = - _createNewTagAndRangeWidget(_firstList, _secondList, Colors.white); + rangeWidget = _createNewTagAndRangeWidget(_firstList, Colors.white); } return Container( color: Colors.white, width: MediaQuery.of(context).size.width, - constraints: hasCalendarItem(widget.entity) + constraints: _hasCalendarItem(widget.entity) ? BoxConstraints( maxHeight: MediaQuery.of(context).size.height - MediaQuery.of(context).padding.bottom - widget.marginTop) - : BoxConstraints( - maxHeight: widget.maxContentHeight + DESIGN_BOTTOM_HEIGHT), + : BoxConstraints(maxHeight: widget.maxContentHeight + DESIGN_BOTTOM_HEIGHT), child: rangeWidget, ); } - Widget _createNewTagAndRangeWidget(List firstList, - List secondList, Color white) { - if (firstList != null && - BrnSelectionUtil.getTotalLevel(widget.entity) == 1) { + Widget _createNewTagAndRangeWidget(List firstList, Color white) { + if (firstList.isNotEmpty && BrnSelectionUtil.getTotalLevel(widget.entity) == 1) { return Column( mainAxisSize: MainAxisSize.min, children: [ Flexible( child: SingleChildScrollView( child: Column( - mainAxisSize: MainAxisSize.min, - children: getOneTabContent(widget.entity)), + mainAxisSize: MainAxisSize.min, children: _getOneTabContent(widget.entity)), ), ), BrnLine( @@ -176,8 +162,7 @@ class _BrnRangeSelectionGroupWidgetState _bottomWidget() ], ); - } else if (firstList != null && - BrnSelectionUtil.getTotalLevel(widget.entity) == 2) { + } else if (firstList.isNotEmpty && BrnSelectionUtil.getTotalLevel(widget.entity) == 2) { var tabBar = BrnTabBar( tabHeight: 50, controller: _tabController, @@ -186,7 +171,7 @@ class _BrnRangeSelectionGroupWidgetState var tabContent = SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, - children: getOneTabContent(firstList[_tabController.index]))); + children: _getOneTabContent(firstList[_tabController.index]))); return Column( mainAxisSize: MainAxisSize.min, @@ -206,42 +191,34 @@ class _BrnRangeSelectionGroupWidgetState } } - List getOneTabContent(BrnSelectionEntity filterItem) { + List _getOneTabContent(BrnSelectionEntity filterItem) { List subFilterList = filterItem.children; /// TODO 还要添加 Date DateRange 类型的判断。 List tagFilterList = subFilterList .where((f) => - f.filterType != BrnSelectionFilterType.Range && - f.filterType != BrnSelectionFilterType.Date && - f.filterType != BrnSelectionFilterType.DateRange && - f.filterType != BrnSelectionFilterType.DateRangeCalendar) + f.filterType != BrnSelectionFilterType.range && + f.filterType != BrnSelectionFilterType.date && + f.filterType != BrnSelectionFilterType.dateRange && + f.filterType != BrnSelectionFilterType.dateRangeCalendar) .toList(); - Size maxWidthSize; + Size maxWidthSize = Size.zero; for (BrnSelectionEntity entity in subFilterList) { - Size size = BrnTextUtil.textSize(entity.title, - widget.themeData.tagNormalTextStyle.generateTextStyle()); - if (maxWidthSize == null) { + Size size = BrnTextUtil.textSize( + entity.title, widget.themeData.tagNormalTextStyle.generateTextStyle()); + if (maxWidthSize.width < size.width) { maxWidthSize = size; - } else { - if (maxWidthSize.width < size.width) { - maxWidthSize = size; - } } } int tagWidth; ///如果指定展示列,则按照指定列展示,否则动态计算宽度。最大不超过四列。 - if (widget.rowount == null) { - int oneCountTagWidth = - (BrnRangeSelectionGroupWidget.screenWidth - 40 - 12 * (1 - 1)) ~/ 1; - int twoCountTagWidth = - (BrnRangeSelectionGroupWidget.screenWidth - 40 - 12 * (2 - 1)) ~/ 2; - int threeCountTagWidth = - (BrnRangeSelectionGroupWidget.screenWidth - 40 - 12 * (3 - 1)) ~/ 3; - int fourCountTagWidth = - (BrnRangeSelectionGroupWidget.screenWidth - 40 - 12 * (4 - 1)) ~/ 4; + if (widget.rowCount == null) { + int oneCountTagWidth = (BrnRangeSelectionGroupWidget.screenWidth - 40 - 12 * (1 - 1)) ~/ 1; + int twoCountTagWidth = (BrnRangeSelectionGroupWidget.screenWidth - 40 - 12 * (2 - 1)) ~/ 2; + int threeCountTagWidth = (BrnRangeSelectionGroupWidget.screenWidth - 40 - 12 * (3 - 1)) ~/ 3; + int fourCountTagWidth = (BrnRangeSelectionGroupWidget.screenWidth - 40 - 12 * (4 - 1)) ~/ 4; if (maxWidthSize.width > twoCountTagWidth) { tagWidth = oneCountTagWidth; } else if (threeCountTagWidth < maxWidthSize.width && @@ -254,28 +231,25 @@ class _BrnRangeSelectionGroupWidgetState tagWidth = fourCountTagWidth; } } else { - tagWidth = (BrnRangeSelectionGroupWidget.screenWidth - - 40 - - 12 * (widget.rowount - 1)) ~/ - widget.rowount; + tagWidth = (BrnRangeSelectionGroupWidget.screenWidth - 40 - 12 * (widget.rowCount! - 1)) ~/ + widget.rowCount!; } - var tagContainer = (tagFilterList?.length ?? 0) > 0 + var tagContainer = (tagFilterList.length) > 0 ? Container( alignment: Alignment.centerLeft, padding: EdgeInsets.only(left: 20, right: 20, top: 20, bottom: 20), child: BrnSelectionRangeTagWidget( tagWidth: tagWidth, tagFilterList: tagFilterList, - initFocusedindex: getInitFocusedIndex(subFilterList), + initFocusedIndex: _getInitFocusedIndex(subFilterList), themeData: widget.themeData, onSelect: (index, isSelected) { setState(() { _setFirstIndex(_tabController.index); _setSecondIndex(index); - clearNotTagItem(totalLevel == 1 - ? _firstList - : _firstList[_tabController.index].children); + _clearNotTagItem( + totalLevel == 1 ? _firstList : _firstList[_tabController.index].children); _clearEditRangeText(); }); }), @@ -284,7 +258,7 @@ class _BrnRangeSelectionGroupWidgetState var content; for (BrnSelectionEntity item in subFilterList) { - if (item.filterType == BrnSelectionFilterType.Range) { + if (item.filterType == BrnSelectionFilterType.range) { content = BrnSelectionRangeItemWidget( item: item, minTextEditingController: _minTextEditingController, @@ -294,12 +268,12 @@ class _BrnRangeSelectionGroupWidgetState item.isSelected = focus; if (focus) { setState(() { - clearTagSelectStatus(subFilterList); + _clearTagSelectStatus(subFilterList); }); } }); break; - } else if (item.filterType == BrnSelectionFilterType.DateRange) { + } else if (item.filterType == BrnSelectionFilterType.dateRange) { content = BrnSelectionDateRangeItemWidget( item: item, minTextEditingController: _minTextEditingController, @@ -307,52 +281,46 @@ class _BrnRangeSelectionGroupWidgetState themeData: widget.themeData, onTapped: () { setState(() { - clearTagSelectStatus(subFilterList); + _clearTagSelectStatus(subFilterList); }); }); break; - } else if (item.filterType == BrnSelectionFilterType.Date) { - DateTime initialStartDate = - DateTimeFormatter.convertIntValueToDateTime(item.value); - DateTime initialEndDate = - DateTimeFormatter.convertIntValueToDateTime(item.value); - content = BrnCalendarView( + } else if (item.filterType == BrnSelectionFilterType.date) { + DateTime? initialStartDate = DateTimeFormatter.convertIntValueToDateTime(item.value); + DateTime? initialEndDate = DateTimeFormatter.convertIntValueToDateTime(item.value); + content = BrnCalendarView.single( key: GlobalKey(), - selectMode: SelectMode.SINGLE, initStartSelectedDate: initialStartDate, initEndSelectedDate: initialEndDate, initDisplayDate: initialEndDate, - startEndDateChange: (DateTime startDate, DateTime endDate) { - item.value = startDate.millisecondsSinceEpoch.toString(); + dateChange: (DateTime date) { + item.value = date.millisecondsSinceEpoch.toString(); item.isSelected = true; setState(() { - clearTagSelectStatus(subFilterList); + _clearTagSelectStatus(subFilterList); }); }, ); - } else if (item.filterType == BrnSelectionFilterType.DateRangeCalendar) { - DateTime initialStartDate = item.customMap == null + } else if (item.filterType == BrnSelectionFilterType.dateRangeCalendar) { + DateTime? initialStartDate = item.customMap == null ? null - : DateTimeFormatter.convertIntValueToDateTime( - item.customMap['min']); - DateTime initialEndDate = item.customMap == null + : DateTimeFormatter.convertIntValueToDateTime(item.customMap!['min']); + DateTime? initialEndDate = item.customMap == null ? null - : DateTimeFormatter.convertIntValueToDateTime( - item.customMap['max']); - content = BrnCalendarView( + : DateTimeFormatter.convertIntValueToDateTime(item.customMap!['max']); + content = BrnCalendarView.range( key: GlobalKey(), - selectMode: SelectMode.RANGE, initStartSelectedDate: initialStartDate, initEndSelectedDate: initialEndDate, - startEndDateChange: (DateTime startDate, DateTime endDate) { + rangeDateChange: (DateTimeRange range) { item.customMap = {}; item.customMap = { - 'min': startDate?.millisecondsSinceEpoch?.toString(), - 'max': endDate?.millisecondsSinceEpoch?.toString() + 'min': range.start.millisecondsSinceEpoch.toString(), + 'max': range.end.millisecondsSinceEpoch.toString() }; item.isSelected = true; setState(() { - clearTagSelectStatus(subFilterList); + _clearTagSelectStatus(subFilterList); }); }, ); @@ -379,8 +347,7 @@ class _BrnRangeSelectionGroupWidgetState Container( height: 24, width: 24, - child: - BrunoTools.getAssetImage(BrnAsset.iconSelectionReset), + child: BrunoTools.getAssetImage(BrnAsset.iconSelectionReset), ), Text( '重置', @@ -414,8 +381,7 @@ class _BrnRangeSelectionGroupWidgetState if (totalLevel == 2) { List subFilterList = widget.entity.children[_tabController.index].children; - List selectItems = - subFilterList.where((f) => f.isSelected).toList(); + List selectItems = subFilterList.where((f) => f.isSelected).toList(); if (selectItems.length > 0) { _firstList[_tabController.index].isSelected = true; } else { @@ -424,23 +390,18 @@ class _BrnRangeSelectionGroupWidgetState } // 处理Range类型的校验 - BrnSelectionEntity rangeEntity = getSelectRangeItem(totalLevel == 1 - ? _firstList - : _firstList[_tabController.index].children); + BrnSelectionEntity? rangeEntity = _getSelectRangeItem( + totalLevel == 1 ? _firstList : _firstList[_tabController.index].children); if (rangeEntity != null) { if (rangeEntity.customMap != null && - ((rangeEntity.customMap['min'] != null && - rangeEntity.customMap['min'].length > 0) || - (rangeEntity.customMap['max'] != null && - rangeEntity.customMap['max'].length > 0))) { + (!BrunoTools.isEmpty(rangeEntity.customMap!['min']) || + !BrunoTools.isEmpty(rangeEntity.customMap!['max']))) { if (!rangeEntity.isValidRange()) { FocusScope.of(context).requestFocus(FocusNode()); - if (rangeEntity?.filterType == BrnSelectionFilterType.Range) { + if (rangeEntity.filterType == BrnSelectionFilterType.range) { BrnToast.show('您输入的区间有误', context); - } else if (rangeEntity?.filterType == - BrnSelectionFilterType.DateRange || - rangeEntity?.filterType == - BrnSelectionFilterType.DateRangeCalendar) { + } else if (rangeEntity.filterType == BrnSelectionFilterType.dateRange || + rangeEntity.filterType == BrnSelectionFilterType.dateRangeCalendar) { BrnToast.show('您选择的区间有误', context); } return; @@ -451,15 +412,13 @@ class _BrnRangeSelectionGroupWidgetState } if (widget.onSelectionConfirm != null) { - widget.onSelectionConfirm(widget.entity, _firstIndex, _secondIndex, -1); + widget.onSelectionConfirm!(widget.entity, _firstIndex, _secondIndex, -1); } } void _clearAllSelectedItems() { _resetSelectionDatas(widget.entity); - clearNotTagItem(totalLevel == 1 - ? _firstList - : _firstList[_tabController.index].children); + _clearNotTagItem(totalLevel == 1 ? _firstList : _firstList[_tabController.index].children); _clearEditRangeText(); setState(() { _configDefaultInitSelectIndex(); @@ -474,7 +433,7 @@ class _BrnRangeSelectionGroupWidgetState for (BrnSelectionEntity entity in _originalSelectedItemsList) { entity.isSelected = true; if (entity.customMap != null) { - entity.originalCustomMap = Map.from(entity.customMap); + entity.originalCustomMap = Map.from(entity.customMap!); } } // 初始化每列的选中 index 为 -1,未选中。 @@ -494,9 +453,8 @@ class _BrnRangeSelectionGroupWidgetState _firstIndex = firstIndex; _secondIndex = -1; if (widget.entity.children.length > _firstIndex) { - List seconds = - widget.entity.children[_firstIndex].children; - if (seconds != null) { + List seconds = widget.entity.children[_firstIndex].children; + if (seconds.isNotEmpty) { for (BrnSelectionEntity entity in seconds) { if (entity.isSelected) { _setSecondIndex(seconds.indexOf(entity)); @@ -523,16 +481,16 @@ class _BrnRangeSelectionGroupWidgetState if (_firstIndex >= 0 && _firstList.length > _firstIndex) { _secondList = _firstList[_firstIndex].children; } else { - _secondList = null; + _secondList = []; } } void _configDefaultSelectedData() { _firstList = widget.entity.children; //是否已选择的item里面有第一列的 - if (_firstList == null) { + if (_firstList.isEmpty) { _secondIndex = -1; - _secondList = null; + _secondList = []; return; } for (BrnSelectionEntity entity in _firstList) { @@ -544,7 +502,7 @@ class _BrnRangeSelectionGroupWidgetState if (_firstIndex >= 0 && _firstIndex < _firstList.length) { _secondList = _firstList[_firstIndex].children; - if (_secondList != null) { + if (_secondList.isNotEmpty) { for (BrnSelectionEntity entity in _secondList) { if (entity.isSelected) { _secondIndex = _secondList.indexOf(entity); @@ -558,24 +516,22 @@ class _BrnRangeSelectionGroupWidgetState //设置数据为未选中状态 void _resetSelectionDatas(BrnSelectionEntity entity) { entity.isSelected = false; - entity.customMap = null; - if (entity.children != null) { - for (BrnSelectionEntity subEntity in entity.children) { - _resetSelectionDatas(subEntity); - } + entity.customMap = Map(); + for (BrnSelectionEntity subEntity in entity.children) { + _resetSelectionDatas(subEntity); } } - void clearNotTagItem(List subFilterList) { + void _clearNotTagItem(List subFilterList) { subFilterList - ?.where((f) => - f.filterType == BrnSelectionFilterType.Range || - f.filterType == BrnSelectionFilterType.Date || - f.filterType == BrnSelectionFilterType.DateRange || - f.filterType == BrnSelectionFilterType.DateRangeCalendar) - ?.forEach((f) { + .where((f) => + f.filterType == BrnSelectionFilterType.range || + f.filterType == BrnSelectionFilterType.date || + f.filterType == BrnSelectionFilterType.dateRange || + f.filterType == BrnSelectionFilterType.dateRangeCalendar) + .forEach((f) { f.isSelected = false; - f.customMap = null; + f.customMap = Map(); f.value = null; }); } @@ -586,27 +542,27 @@ class _BrnRangeSelectionGroupWidgetState EventBus.instance.fire(ClearSelectionFocusEvent()); } - void clearTagSelectStatus(List subFilterList) { + void _clearTagSelectStatus(List subFilterList) { subFilterList - .where((f) => f.filterType != BrnSelectionFilterType.Range) - .where((f) => f.filterType != BrnSelectionFilterType.Date) - .where((f) => f.filterType != BrnSelectionFilterType.DateRange) - .where((f) => f.filterType != BrnSelectionFilterType.DateRangeCalendar) + .where((f) => f.filterType != BrnSelectionFilterType.range) + .where((f) => f.filterType != BrnSelectionFilterType.date) + .where((f) => f.filterType != BrnSelectionFilterType.dateRange) + .where((f) => f.filterType != BrnSelectionFilterType.dateRangeCalendar) .forEach((f) { f.isSelected = false; - f.customMap = null; + f.customMap = Map(); }); } /// 获取针对 Range 类型进行value 检查。 DateRange、DateRangeCalendar 类型不需要检查,因为在选择时间的时候已经做了时间范围限制。 - BrnSelectionEntity getSelectRangeItem(List filterList) { + BrnSelectionEntity? _getSelectRangeItem(List filterList) { List ranges = filterList - ?.where((f) => - (f.filterType == BrnSelectionFilterType.Range || - f.filterType == BrnSelectionFilterType.DateRange || - f.filterType == BrnSelectionFilterType.DateRangeCalendar) && + .where((f) => + (f.filterType == BrnSelectionFilterType.range || + f.filterType == BrnSelectionFilterType.dateRange || + f.filterType == BrnSelectionFilterType.dateRangeCalendar) && f.isSelected) - ?.toList(); + .toList(); if (ranges.length > 0) { return ranges[0]; @@ -617,7 +573,7 @@ class _BrnRangeSelectionGroupWidgetState void _backgroundTap() { _resetSelectStatus(); if (widget.bgClickFunction != null) { - widget.bgClickFunction(); + widget.bgClickFunction!(); } } @@ -630,31 +586,29 @@ class _BrnRangeSelectionGroupWidgetState void _resetCustomMapData() { for (BrnSelectionEntity commonEntity in _originalSelectedItemsList) { commonEntity.isSelected = true; - if (commonEntity.originalCustomMap != null) { - commonEntity.customMap = Map.from(commonEntity.originalCustomMap); - } + commonEntity.customMap = Map.from(commonEntity.originalCustomMap); } } /// 如果自定义输入和默认选中都没有,则尝试默认高亮【不限】这种类型的 Tag。 - int getInitFocusedIndex(List subFilterList) { + int _getInitFocusedIndex(List subFilterList) { bool isCustomInputSelected = false; for (BrnSelectionEntity entity in subFilterList) { - if (BrnSelectionFilterType.Range == entity.filterType || - BrnSelectionFilterType.DateRange == entity.filterType || - BrnSelectionFilterType.DateRangeCalendar == entity.filterType) { + if (BrnSelectionFilterType.range == entity.filterType || + BrnSelectionFilterType.dateRange == entity.filterType || + BrnSelectionFilterType.dateRangeCalendar == entity.filterType) { isCustomInputSelected = entity.isSelected; break; } } var selectedItem = subFilterList - ?.where((f) => - f.filterType != BrnSelectionFilterType.Range && - f.filterType != BrnSelectionFilterType.DateRange && - f.filterType != BrnSelectionFilterType.DateRangeCalendar && + .where((f) => + f.filterType != BrnSelectionFilterType.range && + f.filterType != BrnSelectionFilterType.dateRange && + f.filterType != BrnSelectionFilterType.dateRangeCalendar && f.isSelected) - ?.toList(); + .toList(); if (!isCustomInputSelected && BrunoTools.isEmpty(selectedItem)) { for (BrnSelectionEntity item in subFilterList) { if (item.isUnLimit()) { @@ -666,32 +620,27 @@ class _BrnRangeSelectionGroupWidgetState return -1; } - bool hasCalendarItem(BrnSelectionEntity entity) { + bool _hasCalendarItem(BrnSelectionEntity entity) { bool hasCalendarItem = false; - if (entity != null && entity.children != null) { - /// 查找第一层级 - hasCalendarItem = entity.children - .where((_) => - _.filterType == BrnSelectionFilterType.Date || - _.filterType == BrnSelectionFilterType.DateRangeCalendar) - .toList() - .length > - 0; - - /// 查找第二层级 - if (!hasCalendarItem) { - for (BrnSelectionEntity subItem in entity.children) { - int count = subItem.children - ?.where((_) => - _.filterType == BrnSelectionFilterType.Date || - _.filterType == BrnSelectionFilterType.DateRangeCalendar) - ?.toList() - ?.length ?? - 0; - if (count > 0) { - hasCalendarItem = true; - break; - } + hasCalendarItem = entity.children + .where((_) => + _.filterType == BrnSelectionFilterType.date || + _.filterType == BrnSelectionFilterType.dateRangeCalendar) + .toList() + .length > 0; + + /// 查找第二层级 + if (!hasCalendarItem) { + for (BrnSelectionEntity subItem in entity.children) { + int count = subItem.children + .where((_) => + _.filterType == BrnSelectionFilterType.date || + _.filterType == BrnSelectionFilterType.dateRangeCalendar) + .toList() + .length; + if (count > 0) { + hasCalendarItem = true; + break; } } } diff --git a/lib/src/components/selection/widget/brn_selection_single_list_widget.dart b/lib/src/components/selection/widget/brn_selection_single_list_widget.dart index 2e084623..e578d08a 100644 --- a/lib/src/components/selection/widget/brn_selection_single_list_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_single_list_widget.dart @@ -8,67 +8,55 @@ import 'package:flutter/material.dart'; // ignore: must_be_immutable class BrnSelectionSingleListWidget extends StatefulWidget { - List _selectedItems; - int focusedIndex = -1; + late List _selectedItems; + late int currentListIndex; + List items; - Color backgroundColor; - Color selectedBackgroundColor; int flex; - SingleListItemSelect singleListItemSelect; - int currentListIndex; + int focusedIndex; double maxHeight; + + Color? backgroundColor; + Color? selectedBackgroundColor; + SingleListItemSelect? singleListItemSelect; + BrnSelectionConfig themeData; BrnSelectionSingleListWidget({ - @required this.items, + Key? key, + required this.items, + required this.flex, + this.focusedIndex = -1, this.maxHeight = 0, this.backgroundColor, this.selectedBackgroundColor, - this.flex, - this.focusedIndex, this.singleListItemSelect, - this.themeData, - }) { - if (items == null) { - items = List(); - } else { - /// 自定义 Item 不在 list 样式中显示 - items = items - .where((_) => - _.filterType != BrnSelectionFilterType.Range && - _.filterType != BrnSelectionFilterType.Date && - _.filterType != BrnSelectionFilterType.DateRange && - _.filterType != BrnSelectionFilterType.DateRangeCalendar) - .toList(); - } + required this.themeData, + }) : super(key: key) { + items = items + .where((_) => + _.filterType != BrnSelectionFilterType.range && + _.filterType != BrnSelectionFilterType.date && + _.filterType != BrnSelectionFilterType.dateRange && + _.filterType != BrnSelectionFilterType.dateRangeCalendar) + .toList(); /// 当前 Items 所在的层级 - currentListIndex = BrnSelectionUtil.getCurrentListIndex( - items.length > 0 ? items[0] : null); - - _selectedItems = items?.where((f) => f.isSelected)?.toList(); - if (_selectedItems == null) { - _selectedItems = List(); - } + currentListIndex = BrnSelectionUtil.getCurrentListIndex(items.length > 0 ? items[0] : null); + _selectedItems = items.where((f) => f.isSelected).toList(); } @override - _BrnSelectionSingleListWidgetState createState() => - _BrnSelectionSingleListWidgetState(); - - List getSelectedItems() { - return _selectedItems; - } + _BrnSelectionSingleListWidgetState createState() => _BrnSelectionSingleListWidgetState(); } -class _BrnSelectionSingleListWidgetState - extends State { +class _BrnSelectionSingleListWidgetState extends State { @override Widget build(BuildContext context) { return Expanded( flex: widget.flex, child: Container( - constraints: (widget.maxHeight == null || widget.maxHeight == 0) + constraints: (widget.maxHeight == 0) ? BoxConstraints.expand() : BoxConstraints(maxHeight: widget.maxHeight), color: widget.backgroundColor, @@ -93,21 +81,14 @@ class _BrnSelectionSingleListWidgetState isMoreSelectionListType: false, isFirstLevel: (1 == widget.currentListIndex) ? true : false, itemSelectFunction: (BrnSelectionEntity entity) { - if ((entity.filterType == BrnSelectionFilterType.Checkbox && - !entity.isSelected) || - entity.filterType != BrnSelectionFilterType.Checkbox) { + if ((entity.filterType == BrnSelectionFilterType.checkbox && !entity.isSelected) || + entity.filterType != BrnSelectionFilterType.checkbox) { if (entity.hasCheckBoxBrother()) { if (entity.isUnLimit() && - entity.parent.children - .where((f) => f.isSelected) - .length > - 0 || - entity.parent.children - .where((f) => f.isSelected && f.isUnLimit()) - .length > - 0) { - ///点击的是不限类型,且不限类型同级别已经有选中的 Item 则不用检查数量。 - /// 不限类型已经选中,选择非不限类型时,什么也不做, + (entity.parent?.children.where((f) => f.isSelected).length ?? 0) > 0) { + /// 点击的是不限类型,且不限类型同级别已经有选中的 item,不检查数量限制。 + } else if((entity.parent?.children.where((f) => f.isSelected && f.isUnLimit()).length ?? 0) > 0){ + /// 同级别中,存在不限类型已经选中情况,选择非不限类型 item,不检查数量限制 } else if (entity.isInLastLevel() && !BrnSelectionUtil.checkMaxSelectionCount(entity)) { BrnToast.show("您选择的筛选条件数量已达上限", context); @@ -121,8 +102,9 @@ class _BrnSelectionSingleListWidgetState } } _processFilterData(entity); - widget.singleListItemSelect( - widget.currentListIndex, index, entity); + if(widget.singleListItemSelect != null) { + widget.singleListItemSelect!(widget.currentListIndex, index, entity); + } }, ); }, @@ -147,7 +129,7 @@ class _BrnSelectionSingleListWidgetState int totalLevel = BrnSelectionUtil.getTotalLevel(selectedEntity); if (selectedEntity.isUnLimit()) { - selectedEntity.parent.clearChildSelection(); + selectedEntity.parent?.clearChildSelection(); } /// 设置选中数据。 @@ -162,11 +144,9 @@ class _BrnSelectionSingleListWidgetState /// Warning !!! /// (两列、三列时)第一列节点是否被选中取决于它的子节点是否被选中, /// 只有当它子节点被选中时才会认为第一列的节点相应被选中。 - if (widget.items != null && widget.items.length > 0) { - widget.items[0].parent?.isSelected = widget.items[0].parent.children - .where((BrnSelectionEntity f) => f.isSelected) - .length > - 0; + if (widget.items.length > 0) { + widget.items[0].parent?.isSelected = + (widget.items[0].parent?.children.where((BrnSelectionEntity f) => f.isSelected).length ?? 0)> 0; } for (BrnSelectionEntity item in widget.items) { @@ -183,22 +163,22 @@ class _BrnSelectionSingleListWidgetState } void configOneLevelList(BrnSelectionEntity selectedEntity) { - if (BrnSelectionFilterType.Radio == selectedEntity.filterType) { + if (BrnSelectionFilterType.radio == selectedEntity.filterType) { /// 单选,清除同一级别选中的状态,则其他的设置为未选中。 - selectedEntity.parent.clearChildSelection(); + selectedEntity.parent?.clearChildSelection(); selectedEntity.isSelected = true; - } else if (BrnSelectionFilterType.Checkbox == selectedEntity.filterType) { + } else if (BrnSelectionFilterType.checkbox == selectedEntity.filterType) { /// 选中【不限】清除同一级别其他的状态 if (selectedEntity.isUnLimit()) { - selectedEntity.parent.clearChildSelection(); + selectedEntity.parent?.clearChildSelection(); selectedEntity.isSelected = true; } else { ///清除【不限】类型。 - var brotherItems; + List brotherItems; if (selectedEntity.parent == null) { brotherItems = widget.items; } else { - brotherItems = selectedEntity.parent.children; + brotherItems = selectedEntity.parent?.children ?? []; } for (BrnSelectionEntity entity in brotherItems) { if (entity.isUnLimit()) { @@ -210,34 +190,29 @@ class _BrnSelectionSingleListWidgetState } } - void configMultiLevelList( - BrnSelectionEntity selectedEntity, int currentListIndex) { + void configMultiLevelList(BrnSelectionEntity selectedEntity, int currentListIndex) { /// 单选,清除同一级别选中的状态,则其他的设置为未选中。 - if (BrnSelectionFilterType.Radio == selectedEntity.filterType) { - selectedEntity.parent?.children - ?.where((f) => f != selectedEntity) - ?.forEach((f) { + if (BrnSelectionFilterType.radio == selectedEntity.filterType) { + selectedEntity.parent?.children.where((f) => f != selectedEntity).forEach((f) { f.clearChildSelection(); f.isSelected = false; }); selectedEntity.isSelected = true; - } else if (BrnSelectionFilterType.Checkbox == selectedEntity.filterType) { + } else if (BrnSelectionFilterType.checkbox == selectedEntity.filterType) { /// 选中【不限】清除同一级别其他的状态 if (selectedEntity.isUnLimit()) { - selectedEntity.parent?.children - ?.where((f) => f != selectedEntity) - ?.forEach((f) { + selectedEntity.parent?.children.where((f) => f != selectedEntity).forEach((f) { f.clearChildSelection(); f.isSelected = false; }); selectedEntity.isSelected = true; } else { ///清除【不限】类型。 - var brotherItems; + List brotherItems; if (selectedEntity.parent == null) { brotherItems = widget.items; } else { - brotherItems = selectedEntity.parent.children; + brotherItems = selectedEntity.parent?.children ?? []; } for (BrnSelectionEntity entity in brotherItems) { if (entity.isUnLimit()) { diff --git a/lib/src/components/step/brn_horizontal_steps.dart b/lib/src/components/step/brn_horizontal_steps.dart index 996f6b3f..07c4749c 100644 --- a/lib/src/components/step/brn_horizontal_steps.dart +++ b/lib/src/components/step/brn_horizontal_steps.dart @@ -1,138 +1,103 @@ +import 'package:bruno/src/components/line/brn_line.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; +const double _kItemSidePadding = 5; /// 描述: 横向步骤条,是一种常见的导航形式,它具有导航通用的属性:告知用户”我在哪/我能去哪“, /// 步骤数目就相当于告知用户--能去哪或者说流程将要经历什么。 /// 通用组件步骤条分为三个状态:完成态/进行态/等待态,三种状态在样式上均加以区分 /// 注意事项:横向步骤条内的步骤总数最多只支持5个 -class BrnHorizontalStepsManager { - int maxCount = 0; - BrnStepsController controller = BrnStepsController(); - - /// - /// 构建步骤条widget - /// steps: 步骤条中元素的列表 - /// currentIndex: 指示当前进行态的步骤 - /// isCompleted: 整个流程是否完成 - /// doingIcon: 自定义正在进行状态的icon - /// completedIcon: 自定义已完成状态的icon - /// - Widget buildSteps( - {List steps, - int currentIndex, - bool isCompleted, - Widget doingIcon, - Widget completedIcon}) { - if (steps != null) { - maxCount = steps.length; - } - if (currentIndex != null) { - controller.currentIndex = currentIndex; - } - if (isCompleted != null) { - controller.isCompleted = isCompleted; - } - return Container( - child: BrnHorizontalSteps( - steps: steps, - controller: controller, - doingIcon: doingIcon, - completedIcon: completedIcon), - ); - } - - /// - /// 设置步骤条当前活跃的index - /// - void setCurrentIndex(int index) { - controller.setCurrentIndex(index); - } - - /// - /// 设置整个流程是否完成 - /// - void setIsCompleted(bool isCompleted) { - controller.setIsCompleted(isCompleted); - } - - /// - /// 向前一步 - /// - void forwardStep() { - if (controller.currentIndex < maxCount) { - controller.setCurrentIndex(controller.currentIndex + 1); - } - } - - /// - /// 向后一步 - /// - void backStep() { - int backIndex = - controller.currentIndex <= 0 ? 0 : controller.currentIndex - 1; - controller.setCurrentIndex(backIndex); - } -} - -// ignore: must_be_immutable class BrnHorizontalSteps extends StatefulWidget { /// The steps of the stepper whose titles, subtitles, icons always get shown. /// - /// The length of [steps] must not change. + /// 步骤条中元素的列表 final List steps; - BrnStepsController controller; + /// 控制类 + final BrnStepsController? controller; + + /// 自定义正在进行状态的icon + final Widget? doingIcon; - final Widget doingIcon; - final Widget completedIcon; + /// 自定义已完成状态的icon + final Widget? completedIcon; - BrnHorizontalSteps( - {this.steps, this.controller, this.doingIcon, this.completedIcon}) - : assert(steps.length < 6); + const BrnHorizontalSteps({ + Key? key, + required this.steps, + this.controller, + this.doingIcon, + this.completedIcon, + }) : assert(steps.length < 6), + super(key: key); @override - State createState() { - return BrnHorizontalStepsState(); - } + State createState() => BrnHorizontalStepsState(); } class BrnHorizontalStepsState extends State { - @override - void initState() { - super.initState(); - widget.controller?.addListener(_handleStepStateListenerTick); + Color get _primary { + return BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary; + } + + int get _currentIndex { + return widget.controller?.currentIndex ?? 0; + } + + Color _getStepContentTextColor(int index) { + return index > _currentIndex ? const Color(0xFFCCCCCC) : const Color(0xFF222222); } void _handleStepStateListenerTick() { setState(() {}); } + void _initController() { + widget.controller?._setMaxCount(widget.steps.length); + widget.controller?.addListener(_handleStepStateListenerTick); + } + + @override + void initState() { + super.initState(); + _initController(); + } + @override void dispose() { - super.dispose(); widget.controller?.removeListener(_handleStepStateListenerTick); + super.dispose(); } @override - Widget build(BuildContext context) { - return _buildHorizontalSteps(); + void didUpdateWidget(covariant BrnHorizontalSteps oldWidget) { + super.didUpdateWidget(oldWidget); + final bool isControllerDiff = + oldWidget.controller != null && widget.controller != oldWidget.controller; + final bool isCountDiff = widget.steps.length != oldWidget.steps.length; + if (isControllerDiff || isCountDiff) { + oldWidget.controller?.removeListener(_handleStepStateListenerTick); + _initController(); + } } - Widget _buildHorizontalSteps() { - Widget content; //单独一个widget组件,用于返回需要生成的内容widget + @override + Widget build(BuildContext context) { + /// 单独一个widget组件,用于返回需要生成的内容widget + Widget content; final List childrenList = []; - for (int i = 0; i < widget.steps.length; i += 1) { - childrenList.add(_applyStepItem(widget.steps[i], i)); - if (i < widget.steps.length - 1) { - childrenList.add(_applyLineItem(i)); - } + final List steps = widget.steps; + final int length = steps.length; + final int lastIndex = length - 1; + for (int i = 0; i < length; i += 1) { + childrenList.add(_applyStepItem(steps[i], i)); } content = Container( height: 78, - padding: EdgeInsets.fromLTRB(28, 0, 28, 0), child: Row( + mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: childrenList, ), @@ -140,15 +105,40 @@ class BrnHorizontalStepsState extends State { return content; } + Widget _applyStepItem(BrunoStep step, int index) { + return Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + _applyStepAndLine(step, index), + _applyStepContent(step, index), + ], + ), + ); + } + + Widget _applyStepAndLine(BrunoStep step, int index) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + index == 0 ? Expanded(child: SizedBox.shrink()) : _applyLineItem(index, true), + _applyStepIcon(step, index), + index == widget.steps.length - 1 + ? Expanded(child: SizedBox.shrink()) + : _applyLineItem(index, false), + ], + ); + } + Widget _applyStepIcon(BrunoStep step, int index) { Widget icon; - if (widget.controller.isCompleted) { + if (widget.controller?.isCompleted == true) { return _getCompletedIcon(step); } if (step.state != null) { switch (step.state) { case BrunoStepState.indexed: - icon = getIndexIcon(index); + icon = _getIndexIcon(index); break; case BrunoStepState.complete: icon = _getCompletedIcon(step); @@ -161,117 +151,111 @@ class BrnHorizontalStepsState extends State { break; } } else { - int currentIndex = widget.controller.currentIndex; - if (index < currentIndex) { + if (index < _currentIndex) { // 当前index小于指定的活跃index icon = _getCompletedIcon(step); - } else if (index == currentIndex) { + } else if (index == _currentIndex) { icon = _getDoingIcon(step); - } else if (index > currentIndex) { - icon = getIndexIcon(index); + } else { + icon = _getIndexIcon(index); } } return icon; } - Widget _applyStepItem(BrunoStep step, int index) { - return Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - _applyStepIcon(step, index), - _applyStepContent(step, index), - ], - ), - ); - } - - Widget _applyLineItem(int index) { + Widget _applyLineItem(int index, bool isLeft) { return Expanded( child: Container( - margin: EdgeInsets.fromLTRB(0, 0, 0, 28), - color: index >= widget.controller.currentIndex - ? Color(0xFFE7E7E7) - : BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .brandPrimary, - height: 1, + alignment: Alignment.center, + child: BrnLine( + height: 1, + leftInset: isLeft ? 0 : _kItemSidePadding, + rightInset: isLeft ? _kItemSidePadding : 0, + color: _getLineColor(index, isLeft), + ), ), ); } - Widget getIndexIcon(int index) { + Color _getLineColor(int index, bool isLeft) { + if (index < _currentIndex) { + return _primary; + } else if (_currentIndex == index && isLeft) { + return _primary; + } + return const Color(0xFFE7E7E7); + } + + Widget _getIndexIcon(int index) { Widget icon; switch (index) { case 1: - icon = BrunoTools.getAssetSizeImage(BrnAsset.ICON_STEP_2, 20, 20); + icon = BrunoTools.getAssetSizeImage(BrnAsset.iconStep2, 20, 20); break; case 2: - icon = BrunoTools.getAssetSizeImage(BrnAsset.ICON_STEP_3, 20, 20); + icon = BrunoTools.getAssetSizeImage(BrnAsset.iconStep3, 20, 20); break; case 3: - icon = BrunoTools.getAssetSizeImage(BrnAsset.ICON_STEP_4, 20, 20); + icon = BrunoTools.getAssetSizeImage(BrnAsset.iconStep4, 20, 20); break; case 4: - icon = BrunoTools.getAssetSizeImage(BrnAsset.ICON_STEP_5, 20, 20); + icon = BrunoTools.getAssetSizeImage(BrnAsset.iconStep5, 20, 20); break; default: - icon = BrunoTools.getAssetSizeImage(BrnAsset.ICON_STEP_DOING, 20, 20); + icon = BrunoTools.getAssetSizeImage(BrnAsset.iconStepDoing, 20, 20); break; } return icon; } - _applyStepContent(BrunoStep step, int index) { - if (step.stepContent != null) { - return step.stepContent; + Widget _applyStepContent(BrunoStep step, int index) { + Widget? stepContent = step.stepContent; + if (stepContent != null) { + return stepContent; } return Container( - margin: EdgeInsets.only(top: 6), - child: Text( - step.stepContentText, - style: TextStyle( - fontSize: 14, - color: index > widget.controller.currentIndex - ? Color(0xFFCCCCCC) - : Color(0xFF222222), - ), - )); + margin: const EdgeInsets.only(top: 6, left: _kItemSidePadding, right: _kItemSidePadding), + child: Text( + step.stepContentText ?? '', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 14, + color: _getStepContentTextColor(index), + ), + ), + ); } Widget _getCompletedIcon(BrunoStep step) { - if (step.completedIcon != null) { - // 如果Step中自定义completedIcon不为空,则使用自定义的icon - return step.completedIcon; + Widget? completedIcon = step.completedIcon; + if (completedIcon != null) { + /// 如果Step中自定义completedIcon不为空,则使用自定义的icon + return completedIcon; } - if (widget.completedIcon != null) { - // 如果自定义completedIcon不为空,则使用自定义的icon - return widget.completedIcon; + completedIcon = widget.completedIcon; + if (completedIcon != null) { + /// 如果自定义completedIcon不为空,则使用自定义的icon + return completedIcon; } - // 使用组件默认的icon - return BrunoTools.getAssetSizeImage(BrnAsset.ICON_STEP_COMPLETED, 20, 20, - color: BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .brandPrimary); + + /// 使用组件默认的icon + return BrunoTools.getAssetSizeImage(BrnAsset.iconStepCompleted, 20, 20, color: _primary); } Widget _getDoingIcon(BrunoStep step) { - if (step.doingIcon != null) { - // 如果Step中自定义doingIcon不为空,则使用自定义的icon - return step.doingIcon; + Widget? doingIcon = step.doingIcon; + if (doingIcon != null) { + /// 如果Step中自定义doingIcon不为空,则使用自定义的icon + return doingIcon; } - if (widget.doingIcon != null) { - // 如果自定义doingIcon不为空,则使用自定义的icon - return widget.doingIcon; + doingIcon = widget.doingIcon; + if (doingIcon != null) { + /// 如果自定义doingIcon不为空,则使用自定义的icon + return doingIcon; } // 使用组件默认的icon - return BrunoTools.getAssetSizeImage(BrnAsset.ICON_STEP_DOING, 20, 20, - color: BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .brandPrimary); + return BrunoTools.getAssetSizeImage(BrnAsset.iconStepDoing, 20, 20, color: _primary); } } @@ -286,49 +270,75 @@ enum BrunoStepState { complete } -@immutable class BrunoStep { /// Creates a step for a [Stepper]. /// - /// The [stepContent], [doingIcon] arguments must not be null. + /// The [stepContent], [doingIcon] arguments can be null. const BrunoStep({ this.stepContent, - this.stepContentText, this.doingIcon, + this.stepContentText, this.completedIcon, this.state, }); /// The String title of the step that typically describes it. - final String stepContentText; + final String? stepContentText; /// The title of the step that typically describes it. - final Widget stepContent; + final Widget? stepContent; /// The doingIcon of the step - final Widget doingIcon; + final Widget? doingIcon; /// The completedIcon of the step - final Widget completedIcon; + final Widget? completedIcon; /// The state of the step which determines the styling of its components /// and whether steps are interactive. - final BrunoStepState state; + final BrunoStepState? state; } class BrnStepsController with ChangeNotifier { - int currentIndex = 0; - bool isCompleted = false; + /// 指示当前进行态的步骤 + int currentIndex; - BrnStepsController({this.currentIndex, this.isCompleted}); + /// 整个流程是否完成 + bool isCompleted; - void setCurrentIndex(int index) { - currentIndex = index; - notifyListeners(); + /// 最大个数(最多只支持5个) + int _maxCount = 0; + + BrnStepsController({this.currentIndex = 0, this.isCompleted = false}); + + /// 只有在当前包内调用,不开放给外部调用 + void _setMaxCount(int _maxCount) { + this._maxCount = _maxCount; } - void setIsCompleted(bool isCompleted) { - this.isCompleted = isCompleted; + /// 设置当前步骤条的 index,从 0 开始。 + void setCurrentIndex(int currentIndex) { + if (this.currentIndex == currentIndex || currentIndex > _maxCount) return; + isCompleted = currentIndex == _maxCount; + this.currentIndex = currentIndex; notifyListeners(); } + + /// 整个链路完成 + void setCompleted() { + setCurrentIndex(_maxCount); + } + + /// 向前一步 + void forwardStep() { + if (currentIndex < _maxCount) { + setCurrentIndex(currentIndex + 1); + } + } + + /// 向后一步 + void backStep() { + final int backIndex = currentIndex <= 0 ? 0 : currentIndex - 1; + setCurrentIndex(backIndex); + } } diff --git a/lib/src/components/step/brn_step_line.dart b/lib/src/components/step/brn_step_line.dart index 1d4081a4..9567d8da 100644 --- a/lib/src/components/step/brn_step_line.dart +++ b/lib/src/components/step/brn_step_line.dart @@ -5,10 +5,10 @@ import 'package:flutter/material.dart'; ///[timeAxisSize]时间轴的大小必须要的。 /// ///线条顶部小圆点的大小 -final double _roundSize = 12; +const double _roundSize = 12; /// 线条和小圆点之间的间距 -final int _roundSpace = 4; +const double _roundSpace = 4; /// 在[contentWidget]的左侧自动添加 竖向步骤条的组件 /// @@ -85,7 +85,7 @@ class BrnStepLine extends StatefulWidget { ///整体是否是灰色,true 则使用normalColor,否则使用highlightColor final bool isGrey; - ///边框线的颜色:必须是Color 或者 List,如果未null,则会根据isGrey来使用normalColor或highlightColor + ///边框线的颜色:必须是Color 或者 List,如果为null,则会根据isGrey来使用normalColor或highlightColor final dynamic lineColor; /// 边框包裹的widget @@ -110,17 +110,17 @@ class BrnStepLine extends StatefulWidget { final double contentLeftPadding; /// 普通状态(isGrey=true)的颜色,默认值: Color(0xffeeeeee) - final Color normalColor; + final Color? normalColor; /// 高亮状态(isGrey=false)的颜色,默认值,主题色 - final Color highlightColor; + final Color? highlightColor; /// 自定义icon的widget - final Widget iconWidget; + final Widget? iconWidget; const BrnStepLine({ - Key key, - @required this.contentWidget, + Key? key, + required this.contentWidget, this.isGrey = false, this.lineColor, this.lineWidth = 2, @@ -129,10 +129,10 @@ class BrnStepLine extends StatefulWidget { this.dashLength = 4, this.dashSpace = 4, this.contentLeftPadding = 12, - this.normalColor = const Color(0xffeeeeee), + this.normalColor, this.highlightColor, this.iconWidget, - }); + }) : super(key: key); @override State createState() { @@ -147,12 +147,13 @@ class _BrnStepLineState extends State { children: [ CustomPaint( painter: _BrnStepLinePainter( - paintWidth: widget.lineWidth, - iconTopPadding: widget.iconTopPadding, - lineColor: _buildLineColor(), - isDash: widget.isDashLine, - dashLength: widget.dashLength, - dashSpace: widget.dashSpace), + paintWidth: widget.lineWidth, + iconTopPadding: widget.iconTopPadding, + lineColor: _buildLineColor(), + isDash: widget.isDashLine, + dashLength: widget.dashLength, + dashSpace: widget.dashSpace, + ), child: Container( padding: EdgeInsets.only(left: widget.contentLeftPadding), child: Container( @@ -169,7 +170,7 @@ class _BrnStepLineState extends State { } List _buildLineColor() { - List lineColor = List(); + List lineColor = []; if (widget.lineColor != null) { if (widget.lineColor is Color) { @@ -191,19 +192,18 @@ class _BrnStepLineState extends State { } } else { if (widget.isGrey) { - return List()..add(widget.normalColor ?? Color(0xffeeeeee)); + return [widget.normalColor ?? const Color(0xffeeeeee)]; } - return List() - ..add(widget.highlightColor ?? - BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .brandPrimary); + return [ + widget.highlightColor ?? + BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary + ]; } } Widget _buildGreyCircle() { - return _buildColorCircleWidget(widget.normalColor ?? Color(0xffeeeeee)); + return _buildColorCircleWidget( + widget.normalColor ?? const Color(0xffeeeeee)); } Widget _buildHighLightCircle() { @@ -235,38 +235,39 @@ class _BrnStepLineState extends State { class _BrnStepLinePainter extends CustomPainter { final List lineColor; - //边框的宽度 + /// 边框的宽度 final double paintWidth; - //icon距离顶部的padding + /// icon距离顶部的padding final double iconTopPadding; - //是否绘制虚线 + /// 是否绘制虚线 final bool isDash; - //虚线的间隔 + /// 虚线的间隔 final double dashSpace; - //虚线的长度 + /// 虚线的长度 final double dashLength; _BrnStepLinePainter( - {this.lineColor, - this.paintWidth = 1, - this.iconTopPadding, - this.isDash, - this.dashSpace, - this.dashLength}); + {required this.lineColor, + this.paintWidth = 1, + required this.iconTopPadding, + required this.isDash, + required this.dashSpace, + required this.dashLength}); - Paint _paint = Paint() - ..strokeCap = StrokeCap.round //画笔笔触类型 - ..isAntiAlias = true; //是否启动抗锯齿; //画笔的宽度 + final Paint _paint = Paint() + ..strokeCap = StrokeCap.round // 画笔笔触类型 + ..isAntiAlias = true; // 是否启动抗锯齿; @override void paint(Canvas canvas, Size size) { _paint.style = PaintingStyle.stroke; // 画线模式 - _paint.strokeWidth = this.paintWidth; - // 总长度 16是icon的长度 4是线条不通栏 + _paint.strokeWidth = paintWidth; + + /// 总长度 16是icon的长度 4是线条不通栏 double height = size.height - 16 - 4; if (height <= 0) { return; @@ -288,7 +289,7 @@ class _BrnStepLinePainter extends CustomPainter { int count = (height / (dashLength + dashSpace)).ceil(); for (int i = 0, n = count; i < n; i++) { - Path path = new Path(); + Path path = Path(); path.moveTo(_roundSize / 2, temp); if (temp + dashLength < size.height - _roundSpace) { temp += dashLength; @@ -312,7 +313,8 @@ class _BrnStepLinePainter extends CustomPainter { void _drawFillLine(double height, Canvas canvas) { double selection = height / lineColor.length; - //起始的位置 12是icon的长度 4是线条不通栏 化线的起点:icon的长度+自定义的icon的偏移量 + + /// 起始的位置 12是icon的长度 4是线条不通栏 化线的起点:icon的长度+自定义的icon的偏移量 double temp = 12 + 4 + iconTopPadding; for (int i = 0, n = lineColor.length; i < n; ++i) { _paint.color = lineColor[i]; diff --git a/lib/src/components/sugsearch/brn_search_text.dart b/lib/src/components/sugsearch/brn_search_text.dart index ec7531eb..ebd7befb 100644 --- a/lib/src/components/sugsearch/brn_search_text.dart +++ b/lib/src/components/sugsearch/brn_search_text.dart @@ -1,5 +1,4 @@ import 'package:bruno/src/constants/brn_asset_constants.dart'; -import 'package:bruno/src/constants/brn_strings_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/foundation.dart'; @@ -17,16 +16,16 @@ typedef BrnOnTextClear = bool Function(); /// 基本IOS风格搜索框, 提供输入回调 class BrnSearchText extends StatefulWidget { /// 提示语 - final String hintText; + final String? hintText; /// 提示语样式 - final TextStyle hintStyle; + final TextStyle? hintStyle; /// 输入框样式 - final TextStyle textStyle; + final TextStyle? textStyle; /// 用于设置搜索框前端的 Icon - final Widget prefixIcon; + final Widget? prefixIcon; /// 包裹搜索框的容器背景色 final Color outSideColor; @@ -38,7 +37,7 @@ class BrnSearchText extends StatefulWidget { final int maxLines; /// 最大输入长度 - final int maxLength; + final int? maxLength; /// 输入框最大高度,默认 60 final double maxHeight; @@ -47,44 +46,44 @@ class BrnSearchText extends StatefulWidget { final EdgeInsets innerPadding; ///普通状态的 border - final BoxBorder normalBorder; + final BoxBorder? normalBorder; /// 激活状态的 Border, 默认和 border 一致 - final BoxBorder activeBorder; + final BoxBorder? activeBorder; /// 输入框圆角 final BorderRadius borderRadius; /// 右侧操作 widget - final Widget action; + final Widget? action; /// 是否自动获取焦点 final bool autoFocus; /// 用于控制键盘动作 - final TextInputAction textInputAction; - final TextEditingController controller; - final FocusNode focusNode; + final TextInputAction? textInputAction; + final TextEditingController? controller; + final FocusNode? focusNode; /// 文本变化的回调 - final BrnOnSearchTextChange onTextChange; + final BrnOnSearchTextChange? onTextChange; /// 提交文本时的回调 - final BrnOnCommit onTextCommit; + final BrnOnCommit? onTextCommit; /// 右侧 action 区域点击的回调 - final VoidCallback onActionTap; + final VoidCallback? onActionTap; /// 清除按钮的回调 如果用户设置了该属性 /// 如果返回值为true,表明用户想要拦截,则不会走默认的清除行为 /// 如果返回值为false,表明用户不想要拦截,在执行了用户的行为之后,还会走默认的行为 - final BrnOnTextClear onTextClear; + final BrnOnTextClear? onTextClear; /// 用于控制清除 Icon 和右侧 Action 的显示与隐藏。等其他复杂的操作。 - final BrnSearchTextController searchController; + final BrnSearchTextController? searchController; const BrnSearchText({ - Key key, + Key? key, this.searchController, this.controller, this.maxLines = 1, @@ -118,12 +117,12 @@ class BrnSearchText extends StatefulWidget { } class _SearchTextState extends State { - FocusNode focusNode; - TextEditingController textEditingController; - BoxBorder border; - BrnSearchTextController searchTextController; + FocusNode? focusNode; + TextEditingController? textEditingController; + BoxBorder? border; + BrnSearchTextController? searchTextController; - BrnSearchTextController tmpController; + BrnSearchTextController? tmpController; @override void initState() { @@ -133,7 +132,7 @@ class _SearchTextState extends State { tmpController = BrnSearchTextController(); } searchTextController = widget.searchController ?? tmpController; - searchTextController.addListener(() { + searchTextController!.addListener(() { if (mounted) { setState(() {}); } @@ -146,7 +145,7 @@ class _SearchTextState extends State { color: widget.innerColor, ); - focusNode.addListener(_handleFocusNodeChangeListenerTick); + focusNode!.addListener(_handleFocusNodeChangeListenerTick); } @override @@ -154,12 +153,12 @@ class _SearchTextState extends State { // TODO: implement dispose super.dispose(); tmpController?.dispose(); - focusNode.removeListener(_handleFocusNodeChangeListenerTick); + focusNode!.removeListener(_handleFocusNodeChangeListenerTick); } /// 焦点状态回到,用于刷新当前 UI void _handleFocusNodeChangeListenerTick() { - if (focusNode.hasFocus) { + if (focusNode!.hasFocus) { border = widget.activeBorder ?? border; } else { border = widget.normalBorder ?? border; @@ -194,13 +193,8 @@ class _SearchTextState extends State { Padding( padding: const EdgeInsets.only(left: 14), child: Center( - child: Container( - child: Image.asset( - 'assets/${BrnAsset.ICON_SEARCH}', - package: BrnStrings.flutterPackageName, - height: 16, - width: 16, - )), + child: BrunoTools.getAssetSizeImage( + BrnAsset.iconSearch, 16, 16), ), ), Expanded( @@ -254,39 +248,38 @@ class _SearchTextState extends State { // 在改变属性,当正在编辑的文本发生更改时调用。 onChanged: (content) { if (widget.onTextChange != null) { - widget.onTextChange(content); + widget.onTextChange!(content); } setState(() {}); }, onSubmitted: (content) { if (widget.onTextCommit != null) { - widget.onTextCommit(content); + widget.onTextCommit!(content); } }), ), Visibility( - visible: searchTextController.isClearShow, + visible: searchTextController!.isClearShow, child: GestureDetector( onTap: () { if (widget.onTextClear != null) { - bool isIntercept = widget.onTextClear() ?? false; + bool isIntercept = widget.onTextClear!(); if (isIntercept) return; } - textEditingController.clear(); + textEditingController!.clear(); if (this.widget.onTextChange != null) { - this - .widget - .onTextChange(textEditingController.value.text); + this.widget.onTextChange!( + textEditingController!.value.text); } setState(() {}); }, child: Visibility( - visible: textEditingController.text.isNotEmpty, + visible: textEditingController!.text.isNotEmpty, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12.0), child: BrunoTools.getAssetImage( - BrnAsset.ICON_DELETE_TEXT, + BrnAsset.iconDeleteText, ), ), ), @@ -297,12 +290,12 @@ class _SearchTextState extends State { ), ), Visibility( - visible: searchTextController.isActionShow, + visible: searchTextController!.isActionShow, child: widget.action ?? GestureDetector( onTap: () { if (widget.onActionTap != null) { - widget.onActionTap(); + widget.onActionTap!(); } }, child: Container( diff --git a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart index 5a527bf1..0e8422a9 100644 --- a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart +++ b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart @@ -1,3 +1,5 @@ + + import 'dart:ui' show Color; import 'package:flutter/material.dart'; @@ -7,15 +9,14 @@ import 'package:flutter/material.dart'; /// 特别注意:Tab的右上角小红点可能不符合UI规范,可以使用BrnBadge小红点组件 class BrnBottomTabBarItem { const BrnBottomTabBarItem({ - @required this.icon, + required this.icon, this.title, - Widget activeIcon, + Widget? activeIcon, this.backgroundColor, this.badge, this.badgeNo, this.maxBadgeNo = 99, - }) : activeIcon = activeIcon ?? icon, - assert(icon != null); + }) : activeIcon = activeIcon ?? icon; /// 未选中时的icon final Widget icon; @@ -24,16 +25,16 @@ class BrnBottomTabBarItem { final Widget activeIcon; /// Tab标题名 - final Widget title; + final Widget? title; /// 背景色 - final Color backgroundColor; + final Color? backgroundColor; /// 未读信息 - final Widget badge; + final Widget? badge; /// 未读信息个数 - final String badgeNo; + final String? badgeNo; /// 未读消息最大个数 final int maxBadgeNo; diff --git a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart index 9ec1c5d3..40cb9016 100644 --- a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart +++ b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart @@ -1,3 +1,5 @@ + + import 'dart:collection' show Queue; import 'dart:math' as math; @@ -10,9 +12,9 @@ const double _kActiveFontSize = 10.0; const double _kInactiveFontSize = 9.0; const double _kTopMargin = 6.0; const double _kBottomMargin = 0.0; -const double _kmiddleInterval = 4.0; +const double _kMiddleInterval = 4.0; -/// Tabbar显示状态 +/// tabBar显示状态 enum BrnBottomTabBarDisplayType { /// 固定显示状态 fixed, @@ -26,8 +28,8 @@ enum BrnBottomTabBarDisplayType { /// 特别注意:默认关闭点击动画,为固定显示状态 class BrnBottomTabBar extends StatefulWidget { BrnBottomTabBar({ - Key key, - @required this.items, + Key? key, + required this.items, this.onTap, this.currentIndex = 0, BrnBottomTabBarDisplayType type = BrnBottomTabBarDisplayType.fixed, @@ -36,25 +38,22 @@ class BrnBottomTabBar extends StatefulWidget { this.isAnimation = false, this.badgeColor, this.isInkResponse = false, - }) : assert(items != null), - assert(items.length >= 1), + }) : assert(items.length >= 1), assert( items.every((BrnBottomTabBarItem item) => item.title != null) == true, 'Every item must have a non-null title', ), assert(0 <= currentIndex && currentIndex < items.length), - assert(iconSize != null), - type = type ?? - (items.length <= 3 + type = items.length <= 3 ? BrnBottomTabBarDisplayType.fixed - : BrnBottomTabBarDisplayType.shifting), + : BrnBottomTabBarDisplayType.shifting, super(key: key); /// 动画是否可见,默认:true final bool isAnimation; /// 未读弹窗背景颜色,默认:fixedColor - final Color badgeColor; + final Color? badgeColor; /// InkResponse:是否可访问, 默认:true final bool isInkResponse; @@ -63,7 +62,7 @@ class BrnBottomTabBar extends StatefulWidget { final List items; /// Tab点击之后的回调函数 - final ValueChanged onTap; + final ValueChanged? onTap; /// 当前活动项的索引值 final int currentIndex; @@ -72,7 +71,7 @@ class BrnBottomTabBar extends StatefulWidget { final BrnBottomTabBarDisplayType type; /// 底部Tab所选中时的颜色 - final Color fixedColor; + final Color? fixedColor; /// Tab中图标的大小 final double iconSize; @@ -96,29 +95,29 @@ class _BottomNavigationTile extends StatelessWidget { this.isAnimation = true, this.isInkResponse = true, this.badgeColor, - }) : assert(selected != null); + }) ; final BrnBottomTabBarDisplayType type; final BrnBottomTabBarItem item; final Animation animation; final double iconSize; - final VoidCallback onTap; - final ColorTween colorTween; - final double flex; + final VoidCallback? onTap; + final ColorTween? colorTween; + final double? flex; final bool selected; - final String indexLabel; + final String? indexLabel; final bool isAnimation; final bool isInkResponse; - final Color badgeColor; + final Color? badgeColor; /// 构建icon Widget _buildIcon() { - double tweenStart; - Color iconColor; + double? tweenStart; + Color? iconColor; switch (type) { case BrnBottomTabBarDisplayType.fixed: tweenStart = 8.0; - iconColor = colorTween.evaluate(animation); + iconColor = colorTween?.evaluate(animation); break; case BrnBottomTabBarDisplayType.shifting: tweenStart = 16.0; @@ -148,7 +147,7 @@ class _BottomNavigationTile extends StatelessWidget { ); } - /// 构建固定Lable + /// 构建固定Label /// 修改icon与text间距在这里修改 Widget _buildFixedLabel() { double scale = isAnimation @@ -162,11 +161,11 @@ class _BottomNavigationTile extends StatelessWidget { heightFactor: 1.0, child: Container( margin: const EdgeInsets.only( - bottom: _kBottomMargin, top: _kmiddleInterval), + bottom: _kBottomMargin, top: _kMiddleInterval), child: DefaultTextStyle.merge( style: TextStyle( fontSize: _kActiveFontSize, - color: colorTween.evaluate(animation), + color: colorTween?.evaluate(animation), ), /// 使用矩阵变化控制字体大小 @@ -184,7 +183,7 @@ class _BottomNavigationTile extends StatelessWidget { ); } - /// 构建可变Lable + /// 构建可变Label Widget _buildShiftingLabel() { return Align( alignment: Alignment.bottomCenter, @@ -206,7 +205,7 @@ class _BottomNavigationTile extends StatelessWidget { fontSize: _kActiveFontSize, color: Colors.blue, ), - child: item.title, + child: item.title!, ), ), ), @@ -214,8 +213,8 @@ class _BottomNavigationTile extends StatelessWidget { } /// 构建未读消息弹窗 - Widget _buildBadge() { - if (item.badge == null && (item.badgeNo == null || item.badgeNo.isEmpty)) { + Widget? _buildBadge() { + if (item.badge == null && (item.badgeNo == null || item.badgeNo!.isEmpty)) { return Container(); } if (item.badge != null) { @@ -231,15 +230,27 @@ class _BottomNavigationTile extends StatelessWidget { borderRadius: BorderRadius.all(Radius.circular(10))), child: Text( /// 设置未读数 > item.maxBadgeNo 则报加+ 默认 99 - '${int.parse(item.badgeNo) > item.maxBadgeNo ? '${item.maxBadgeNo}+' : item.badgeNo}', + _getUnReadText(), style: TextStyle(fontSize: 10, color: Colors.white), ), ); } + String _getUnReadText(){ + int _badgeNo = 0; + try { + if (item.badgeNo != null) { + _badgeNo = int.parse(item.badgeNo!); + } + } catch (e) { + debugPrint('badgeNo has FormatException'); + } + return '${_badgeNo > item.maxBadgeNo ? '${item.maxBadgeNo}+' : _badgeNo}'; + } + /// 构建底字体缩放动画 /// label: 传入的文字组件 - Widget _buildInkWidget(Widget label) { + Widget _buildInkWidget(Widget? label) { if (isInkResponse) { return InkResponse( onTap: onTap, @@ -249,7 +260,7 @@ class _BottomNavigationTile extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ _buildIcon(), - label, + label!, ], ), ); @@ -262,7 +273,7 @@ class _BottomNavigationTile extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ _buildIcon(), - label, + label!, ], )); } @@ -273,15 +284,15 @@ class _BottomNavigationTile extends StatelessWidget { /// 需要将flex分配中的更改划分为更小的块 /// 制作流畅的动画。我们通过将flex值相乘来实现这一点 /// (这是一个整数)乘以一个大数。 - int size; - Widget label; + late int size; + Widget? label; switch (type) { case BrnBottomTabBarDisplayType.fixed: size = 1; label = _buildFixedLabel(); break; case BrnBottomTabBarDisplayType.shifting: - size = (flex * 1000.0).round(); + size = (flex! * 1000.0).round(); label = _buildShiftingLabel(); break; } @@ -294,7 +305,7 @@ class _BottomNavigationTile extends StatelessWidget { selected: selected, child: Stack( children: [ - Positioned(right: 4, top: 4, child: _buildBadge()), + Positioned(right: 4, top: 4, child: _buildBadge()!), _buildInkWidget(label), Semantics( label: indexLabel, @@ -310,13 +321,13 @@ class _BottomNavigationTile extends StatelessWidget { class _BottomTabBarState extends State with TickerProviderStateMixin { List _controllers = []; - List _animations; + late List _animations; /// 当前正在执行图标变色逻辑的队列 final Queue<_Circle> _circles = Queue<_Circle>(); /// 执行完动画之后的背景颜色 - Color _backgroundColor; + Color? _backgroundColor; static final Animatable _flexTween = Tween(begin: 1.0, end: 1.5); @@ -373,7 +384,7 @@ class _BottomTabBarState extends State _Circle( state: this, index: index, - color: widget.items[index].backgroundColor, + color: widget.items[index].backgroundColor!, vsync: this, )..controller.addStatusListener( (AnimationStatus status) { @@ -427,13 +438,12 @@ class _BottomTabBarState extends State List _createTiles() { final MaterialLocalizations localizations = MaterialLocalizations.of(context); - assert(localizations != null); final List children = []; switch (widget.type) { case BrnBottomTabBarDisplayType.fixed: final ThemeData themeData = Theme.of(context); final TextTheme textTheme = themeData.textTheme; - Color themeColor; + Color? themeColor; switch (themeData.brightness) { case Brightness.light: themeColor = themeData.primaryColor; @@ -443,7 +453,7 @@ class _BottomTabBarState extends State break; } final ColorTween colorTween = ColorTween( - begin: textTheme.caption.color, + begin: textTheme.caption!.color, end: widget.fixedColor ?? themeColor, ); for (int i = 0; i < widget.items.length; i += 1) { @@ -454,7 +464,7 @@ class _BottomTabBarState extends State _animations[i], widget.iconSize, onTap: () { - if (widget.onTap != null) widget.onTap(i); + if (widget.onTap != null) widget.onTap!(i); }, colorTween: colorTween, selected: i == widget.currentIndex, @@ -478,7 +488,7 @@ class _BottomTabBarState extends State _animations[i], widget.iconSize, onTap: () { - if (widget.onTap != null) widget.onTap(i); + if (widget.onTap != null) widget.onTap!(i); }, flex: _evaluateFlex(_animations[i]), selected: i == widget.currentIndex, @@ -518,7 +528,7 @@ class _BottomTabBarState extends State /// 下标题距底部距离 final double additionalBottomPadding = math.max(MediaQuery.of(context).padding.bottom - _kBottomMargin, 0.0); - Color backgroundColor; + Color? backgroundColor; switch (widget.type) { case BrnBottomTabBarDisplayType.fixed: break; @@ -577,13 +587,11 @@ class _BottomTabBarState extends State /// 功能:实现点击飞溅动画 class _Circle { _Circle({ - @required this.state, - @required this.index, - @required this.color, - @required TickerProvider vsync, - }) : assert(state != null), - assert(index != null), - assert(color != null) { + required this.state, + required this.index, + required this.color, + required TickerProvider vsync, + }) { controller = AnimationController( duration: kThemeAnimationDuration, vsync: vsync, @@ -598,8 +606,8 @@ class _Circle { final _BottomTabBarState state; final int index; final Color color; - AnimationController controller; - CurvedAnimation animation; + late AnimationController controller; + late CurvedAnimation animation; double get horizontalLeadingOffset { double weightSum(Iterable> animations) { @@ -629,10 +637,9 @@ class _Circle { /// 绘制动画色彩飞溅的圆圈 class _RadialPainter extends CustomPainter { _RadialPainter({ - @required this.circles, - @required this.textDirection, - }) : assert(circles != null), - assert(textDirection != null); + required this.circles, + required this.textDirection, + }); final List<_Circle> circles; final TextDirection textDirection; @@ -661,7 +668,7 @@ class _RadialPainter extends CustomPainter { final Paint paint = Paint()..color = circle.color; final Rect rect = Rect.fromLTWH(0.0, 0.0, size.width, size.height); canvas.clipRect(rect); - double leftFraction; + late double leftFraction; switch (textDirection) { case TextDirection.rtl: leftFraction = 1.0 - circle.horizontalLeadingOffset; diff --git a/lib/src/components/tabbar/indicator/brn_custom_width_indicator.dart b/lib/src/components/tabbar/indicator/brn_custom_width_indicator.dart index e2c80176..a3d36225 100644 --- a/lib/src/components/tabbar/indicator/brn_custom_width_indicator.dart +++ b/lib/src/components/tabbar/indicator/brn_custom_width_indicator.dart @@ -1,3 +1,5 @@ + + import 'package:flutter/material.dart'; class CustomWidthUnderlineTabIndicator extends Decoration { @@ -25,35 +27,35 @@ class CustomWidthUnderlineTabIndicator extends Decoration { final double width; @override - Decoration lerpFrom(Decoration a, double t) { + Decoration? lerpFrom(Decoration? a, double t) { if (a is CustomWidthUnderlineTabIndicator) { return CustomWidthUnderlineTabIndicator( borderSide: BorderSide.lerp(a.borderSide, borderSide, t), - insets: EdgeInsetsGeometry.lerp(a.insets, insets, t), + insets: EdgeInsetsGeometry.lerp(a.insets, insets, t)!, ); } return super.lerpFrom(a, t); } @override - Decoration lerpTo(Decoration b, double t) { + Decoration? lerpTo(Decoration? b, double t) { if (b is CustomWidthUnderlineTabIndicator) { return CustomWidthUnderlineTabIndicator( borderSide: BorderSide.lerp(borderSide, b.borderSide, t), - insets: EdgeInsetsGeometry.lerp(insets, b.insets, t), + insets: EdgeInsetsGeometry.lerp(insets, b.insets, t)!, ); } return super.lerpTo(b, t); } @override - _UnderlinePainter createBoxPainter([VoidCallback onChanged]) { + _UnderlinePainter createBoxPainter([VoidCallback? onChanged]) { return _UnderlinePainter(this, width, onChanged); } } class _UnderlinePainter extends BoxPainter { - _UnderlinePainter(this.decoration, this.width, VoidCallback onChanged) + _UnderlinePainter(this.decoration, this.width, VoidCallback? onChanged) : assert(decoration != null), super(onChanged); @@ -70,7 +72,7 @@ class _UnderlinePainter extends BoxPainter { assert(textDirection != null); final Rect indicator = insets.resolve(textDirection).deflateRect(rect); //希望的宽度 - double wantWidth = width ?? 24; + double wantWidth = width; //取中间坐标 double cw = (indicator.left + indicator.right) / 2; return Rect.fromLTWH(cw - wantWidth / 2, @@ -81,8 +83,8 @@ class _UnderlinePainter extends BoxPainter { void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { assert(configuration != null); assert(configuration.size != null); - final Rect rect = offset & configuration.size; - final TextDirection textDirection = configuration.textDirection; + final Rect rect = offset & configuration.size!; + final TextDirection textDirection = configuration.textDirection!; final Rect indicator = _indicatorRectFor(rect, textDirection).deflate(borderSide.width / 2.0); final Paint paint = borderSide.toPaint()..strokeCap = StrokeCap.round; diff --git a/lib/src/components/tabbar/indicator/brn_fixed_underline_decoration.dart b/lib/src/components/tabbar/indicator/brn_fixed_underline_decoration.dart index 5ed7dc14..f0a27e8a 100644 --- a/lib/src/components/tabbar/indicator/brn_fixed_underline_decoration.dart +++ b/lib/src/components/tabbar/indicator/brn_fixed_underline_decoration.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. + + import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; @@ -46,35 +48,35 @@ class BrnFixedUnderlineIndicator extends Decoration { final Color color; @override - Decoration lerpFrom(Decoration a, double t) { + Decoration? lerpFrom(Decoration? a, double t) { if (a is BrnFixedUnderlineIndicator) { return BrnFixedUnderlineIndicator( borderSide: BorderSide.lerp(a.borderSide, borderSide, t), - insets: EdgeInsetsGeometry.lerp(a.insets, insets, t), + insets: EdgeInsetsGeometry.lerp(a.insets, insets, t)!, ); } return super.lerpFrom(a, t); } @override - Decoration lerpTo(Decoration b, double t) { + Decoration? lerpTo(Decoration? b, double t) { if (b is BrnFixedUnderlineIndicator) { return BrnFixedUnderlineIndicator( borderSide: BorderSide.lerp(borderSide, b.borderSide, t), - insets: EdgeInsetsGeometry.lerp(insets, b.insets, t), + insets: EdgeInsetsGeometry.lerp(insets, b.insets, t)!, ); } return super.lerpTo(b, t); } @override - _FixedUnderlinePainter createBoxPainter([VoidCallback onChanged]) { + _FixedUnderlinePainter createBoxPainter([VoidCallback? onChanged]) { return _FixedUnderlinePainter(this, onChanged); } } class _FixedUnderlinePainter extends BoxPainter { - _FixedUnderlinePainter(this.decoration, VoidCallback onChanged) + _FixedUnderlinePainter(this.decoration, VoidCallback? onChanged) : assert(decoration != null), super(onChanged); @@ -100,8 +102,8 @@ class _FixedUnderlinePainter extends BoxPainter { void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { assert(configuration != null); assert(configuration.size != null); - final Rect rect = offset & configuration.size; - final TextDirection textDirection = configuration.textDirection; + final Rect rect = offset & configuration.size!; + final TextDirection textDirection = configuration.textDirection!; final Rect indicator = _indicatorRectFor(rect, textDirection).deflate(borderSide.width / 2.0); final Paint paint = borderSide.toPaint()..strokeCap = StrokeCap.square; diff --git a/lib/src/components/tabbar/indicator/brn_triangle_decoration.dart b/lib/src/components/tabbar/indicator/brn_triangle_decoration.dart index 3b500068..60bccfb6 100644 --- a/lib/src/components/tabbar/indicator/brn_triangle_decoration.dart +++ b/lib/src/components/tabbar/indicator/brn_triangle_decoration.dart @@ -2,19 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. + + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; /// 三角形指示器 参考ShapeDecoration class BrnTriangleIndicator extends Decoration { - final Color color; // 指示器颜色 + final Color? color; // 指示器颜色 final double lineWidth; final double triWidth; // 三角形底边长 final double triHeight; // 三角形高 - final Gradient gradient; - final DecorationImage image; - final List shadows; - final ShapeBorder shape; + final Gradient? gradient; + final DecorationImage? image; + final List? shadows; + final ShapeBorder? shape; const BrnTriangleIndicator({ this.color = Colors.white, @@ -28,23 +30,23 @@ class BrnTriangleIndicator extends Decoration { }); factory BrnTriangleIndicator.fromBoxDecoration(BoxDecoration source) { - ShapeBorder shape; + ShapeBorder? shape; assert(source.shape != null); switch (source.shape) { case BoxShape.circle: if (source.border != null) { - assert(source.border.isUniform); - shape = CircleBorder(side: source.border.top); + assert(source.border!.isUniform); + shape = CircleBorder(side: source.border!.top); } else { shape = const CircleBorder(); } break; case BoxShape.rectangle: if (source.borderRadius != null) { - assert(source.border == null || source.border.isUniform); + assert(source.border == null || source.border!.isUniform); shape = RoundedRectangleBorder( side: source.border?.top ?? BorderSide.none, - borderRadius: source.borderRadius, + borderRadius: source.borderRadius!, ); } else { shape = source.border ?? const Border(); @@ -65,35 +67,35 @@ class BrnTriangleIndicator extends Decoration { /// /// This value may be misleading. See the discussion at [ShapeBorder.dimensions]. @override - EdgeInsets get padding => shape.dimensions; + EdgeInsets get padding => shape!.dimensions as EdgeInsets; @override bool get isComplex => shadows != null; @override - BrnTriangleIndicator lerpFrom(Decoration a, double t) { + BrnTriangleIndicator? lerpFrom(Decoration? a, double t) { if (a is BoxDecoration) { return BrnTriangleIndicator.lerp( BrnTriangleIndicator.fromBoxDecoration(a), this, t); } else if (a == null || a is BrnTriangleIndicator) { - return BrnTriangleIndicator.lerp(a, this, t); + return BrnTriangleIndicator.lerp(a as BrnTriangleIndicator?, this, t); } - return super.lerpFrom(a, t); + return super.lerpFrom(a, t) as BrnTriangleIndicator?; } @override - BrnTriangleIndicator lerpTo(Decoration b, double t) { + BrnTriangleIndicator? lerpTo(Decoration? b, double t) { if (b is BoxDecoration) { return BrnTriangleIndicator.lerp( this, BrnTriangleIndicator.fromBoxDecoration(b), t); } else if (b == null || b is BrnTriangleIndicator) { - return BrnTriangleIndicator.lerp(this, b, t); + return BrnTriangleIndicator.lerp(this, b as BrnTriangleIndicator?, t); } - return super.lerpTo(b, t); + return super.lerpTo(b, t) as BrnTriangleIndicator?; } - static BrnTriangleIndicator lerp( - BrnTriangleIndicator a, BrnTriangleIndicator b, double t) { + static BrnTriangleIndicator? lerp( + BrnTriangleIndicator? a, BrnTriangleIndicator? b, double t) { assert(t != null); if (a == null && b == null) return null; if (a != null && b != null) { @@ -103,7 +105,7 @@ class BrnTriangleIndicator extends Decoration { return BrnTriangleIndicator( color: Color.lerp(a?.color, b?.color, t), gradient: Gradient.lerp(a?.gradient, b?.gradient, t), - image: t < 0.5 ? a.image : b.image, + image: t < 0.5 ? a?.image : b?.image, shadows: BoxShadow.lerpList(a?.shadows, b?.shadows, t), shape: ShapeBorder.lerp(a?.shape, b?.shape, t), ); @@ -154,14 +156,14 @@ class BrnTriangleIndicator extends Decoration { } @override - bool hitTest(Size size, Offset position, {TextDirection textDirection}) { - return shape + bool hitTest(Size size, Offset position, {TextDirection? textDirection}) { + return shape! .getOuterPath(Offset.zero & size, textDirection: textDirection) .contains(position); } @override - _TriangleDecorationPainter createBoxPainter([VoidCallback onChanged]) { + _TriangleDecorationPainter createBoxPainter([VoidCallback? onChanged]) { assert(onChanged != null || image == null); Path path = Path(); Paint paint = Paint()..isAntiAlias = true; @@ -172,7 +174,7 @@ class BrnTriangleIndicator extends Decoration { /// An object that paints a [BrnTriangleIndicator] into a canvas. class _TriangleDecorationPainter extends BoxPainter { _TriangleDecorationPainter( - this._decoration, this._path, this._paint, VoidCallback onChanged) + this._decoration, this._path, this._paint, VoidCallback? onChanged) : assert(_decoration != null), super(onChanged); @@ -195,7 +197,7 @@ class _TriangleDecorationPainter extends BoxPainter { _path.lineTo(_vertexX + width / 2, _vertexY + height / 2); _path.close(); - _paint..color = _decoration.color; + _paint..color = _decoration.color!; _paint..strokeWidth = _decoration.lineWidth; canvas.drawPath(_path, _paint); @@ -211,7 +213,7 @@ class _TriangleDecorationPainter extends BoxPainter { void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { assert(configuration != null); assert(configuration.size != null); - final Rect rect = offset & configuration.size; + final Rect rect = offset & configuration.size!; _paintTriangle(canvas, offset, rect, configuration); } diff --git a/lib/src/components/tabbar/normal/brn_sub_switch_title.dart b/lib/src/components/tabbar/normal/brn_sub_switch_title.dart index 0eb3b1a9..47d43f5c 100644 --- a/lib/src/components/tabbar/normal/brn_sub_switch_title.dart +++ b/lib/src/components/tabbar/normal/brn_sub_switch_title.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:flutter/material.dart'; @@ -12,18 +14,18 @@ class BrnSubSwitchTitle extends StatefulWidget { final int defaultSelectIndex; /// 选中回调 - final void Function(int index) onSelect; + final void Function(int index)? onSelect; /// 二级标题的padding /// 默认 EdgeInsets.only(right: 20) - final EdgeInsets padding; + final EdgeInsets? padding; /// tab切换控制器,默认不需要传递 - final TabController controller; + final TabController? controller; const BrnSubSwitchTitle({ - Key key, - @required this.nameList, + Key? key, + required this.nameList, this.defaultSelectIndex = 0, this.onSelect, this.padding, @@ -36,9 +38,9 @@ class BrnSubSwitchTitle extends StatefulWidget { class _BrnSubSwitchTitleState extends State with TickerProviderStateMixin { - List widgetList; + List? widgetList; - TabController _controller; + TabController? _controller; int _defaultSelectIndex = 0; @@ -49,7 +51,7 @@ class _BrnSubSwitchTitleState extends State _controller = widget.controller ?? TabController( initialIndex: _defaultSelectIndex, - length: widget.nameList?.length ?? 0, + length: widget.nameList.length, vsync: this, ); } @@ -59,7 +61,7 @@ class _BrnSubSwitchTitleState extends State super.didUpdateWidget(oldWidget); _defaultSelectIndex = widget.defaultSelectIndex; if (_controller != null) { - _controller.index = _defaultSelectIndex; + _controller!.index = _defaultSelectIndex; } } @@ -69,7 +71,7 @@ class _BrnSubSwitchTitleState extends State } Widget _toggleButtonsWidget(context) { - if (widget.nameList == null || widget.nameList.isEmpty) { + if (widget.nameList.isEmpty) { return Container( height: 0, width: 0, @@ -115,7 +117,7 @@ class _BrnSubSwitchTitleState extends State ), onTap: (index) { if (null != widget.onSelect) { - widget.onSelect(index); + widget.onSelect!(index); } }, ); diff --git a/lib/src/components/tabbar/normal/brn_switch_title.dart b/lib/src/components/tabbar/normal/brn_switch_title.dart index 4b955a82..2ddcdba4 100644 --- a/lib/src/components/tabbar/normal/brn_switch_title.dart +++ b/lib/src/components/tabbar/normal/brn_switch_title.dart @@ -1,3 +1,5 @@ + + import 'package:bruno/src/components/line/brn_line.dart'; import 'package:bruno/src/components/tabbar/indicator/brn_custom_width_indicator.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; @@ -15,7 +17,7 @@ class BrnSwitchTitle extends StatefulWidget { /// 选中时的回调 /// index 选中的title的索引 - final void Function(int index) onSelect; + final void Function(int index)? onSelect; /// 标题的 padding,默认 `EdgeInsets.fromLTRB(0, 14, 20, 14)` final EdgeInsets padding; @@ -28,17 +30,17 @@ class BrnSwitchTitle extends StatefulWidget { /// 控制tab切换,默认不需要传递 /// 只在需要外部控制tab切换时传递 - final TabController controller; + final TabController? controller; /// 选中时的标题样式,默认 `TextStyle(fontWeight: FontWeight.w600,fontSize: 18)` - final TextStyle selectedTextStyle; + final TextStyle? selectedTextStyle; /// 未选中时的标题样式,默认 `TextStyle(fontWeight: FontWeight.w600,fontSize: 18)` - final TextStyle unselectedTextStyle; + final TextStyle? unselectedTextStyle; const BrnSwitchTitle( - {Key key, - @required this.nameList, + {Key? key, + required this.nameList, this.defaultSelectIndex = 0, this.onSelect, this.indicatorWeight = 2.0, @@ -57,7 +59,7 @@ class _BrnSwitchTitleState extends State with TickerProviderStateMixin { static final Color _color = Color(0XFF243238); - TabController _controller; + TabController? _controller; int _defaultSelectIndex = 0; @@ -66,7 +68,7 @@ class _BrnSwitchTitleState extends State super.didUpdateWidget(oldWidget); _defaultSelectIndex = widget.defaultSelectIndex; if (_controller != null) { - _controller.index = _defaultSelectIndex; + _controller!.index = _defaultSelectIndex; } } @@ -84,7 +86,7 @@ class _BrnSwitchTitleState extends State @override Widget build(BuildContext context) { - if (widget.nameList != null && widget.nameList.length > 1) { + if (widget.nameList.length > 1) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -110,7 +112,7 @@ class _BrnSwitchTitleState extends State Text tx = Text(name); /// 有下划线的时候,需要将下划线的高度3减去 - double tempBottomPadding = widget.padding?.bottom ?? 0; + double tempBottomPadding = widget.padding.bottom; double bottomPadding = widget.nameList.length == 1 ? tempBottomPadding : tempBottomPadding - 3; @@ -120,20 +122,20 @@ class _BrnSwitchTitleState extends State return Container( padding: EdgeInsets.fromLTRB( - widget.padding?.left ?? 0, - widget.padding?.top ?? 0, - widget.padding?.right ?? 0, + widget.padding.left, + widget.padding.top, + widget.padding.right, bottomPadding), child: tx, ); }).toList(); Decoration _indicator = CustomWidthUnderlineTabIndicator( - width: widget.indicatorWidth ?? 24.0, + width: widget.indicatorWidth, insets: EdgeInsets.only( - left: widget.padding?.left ?? 0, right: widget.padding?.right ?? 0), + left: widget.padding.left, right: widget.padding.right), borderSide: BorderSide( - width: widget.indicatorWeight ?? 2.0, + width: widget.indicatorWeight, color: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, ), @@ -173,7 +175,7 @@ class _BrnSwitchTitleState extends State indicatorWeight: 0, onTap: (index) { if (null != widget.onSelect && widget.nameList.length > 1) { - widget.onSelect(index); + widget.onSelect!(index); } }, ), diff --git a/lib/src/components/tabbar/normal/brn_tab_bar.dart b/lib/src/components/tabbar/normal/brn_tab_bar.dart index 825605ce..121eb38a 100644 --- a/lib/src/components/tabbar/normal/brn_tab_bar.dart +++ b/lib/src/components/tabbar/normal/brn_tab_bar.dart @@ -15,12 +15,12 @@ import 'package:flutter/rendering.dart'; /// [state]:当前组件的State对象,[BrnTabBarState] /// [index]:当前组件的角标 typedef BrnTabBarOnTap = Function(BrnTabBarState state, int index); - +const double _tagDefaultSize = 75.0; /// 带小红点的Tabbar // ignore: must_be_immutable class BrnTabBar extends StatefulWidget { /// BrnTabBarBadge填充的数据,长度匹配控制器的TabController.length - final List tabs; + final List? tabs; /// [BrnTabBar] 的tab模式 /// 默认:[BrnTabBarBadgeMode.average](按照屏幕平均分配模式) @@ -30,51 +30,51 @@ class BrnTabBar extends StatefulWidget { final bool isScroll; /// Tabbar的整体高度 - final double tabHeight; + final double? tabHeight; /// TabBar的padding final EdgeInsetsGeometry padding; /// 控制Tab的切换 - final TabController controller; + final TabController? controller; /// TabBar背景颜色 final Color backgroundcolor; /// 指示器的颜色 - final Color indicatorColor; + final Color? indicatorColor; /// 指示器的高度 - final double indicatorWeight; + final double? indicatorWeight; /// 指示器的宽度 - final double indicatorWidth; + final double? indicatorWidth; final EdgeInsetsGeometry indicatorPadding; /// 选中Tab文本的颜色 - final Color labelColor; + final Color? labelColor; /// 选中Tab文本的样式 - final TextStyle labelStyle; + final TextStyle? labelStyle; /// Tab文本的Padding final EdgeInsetsGeometry labelPadding; /// 未选中Tab文本的颜色 - final Color unselectedLabelColor; + final Color? unselectedLabelColor; /// 未中Tab文本的样式 - final TextStyle unselectedLabelStyle; + final TextStyle? unselectedLabelStyle; /// 处理拖拽开始行为方式,默认DragStartBehavior.start final DragStartBehavior dragStartBehavior; /// Tab的选中点击事件 - final BrnTabBarOnTap onTap; + final BrnTabBarOnTap? onTap; /// 添加的Tab的宽度(指定tabWidth就不会均分屏幕宽度) - final double tabWidth; + final double? tabWidth; /// 是否显示分隔线 final bool hasDivider; @@ -86,27 +86,27 @@ class BrnTabBar extends StatefulWidget { final bool showMore; /// 展开更多弹框标题 - final String moreWindowText; + final String? moreWindowText; /// 更多弹框弹出的时候 - final VoidCallback onMorePop; + final VoidCallback? onMorePop; /// 更多弹框关闭控制器 - final BrnCloseWindowController closeController; + final BrnCloseWindowController? closeController; /// tag间距 - final double tagSpacing; + final double? tagSpacing; /// 每行tag数 - final int preLineTagCount; + final int? preLineTagCount; /// tag高度 - final double tagHeight; + final double? tagHeight; - BrnTabBarConfig themeData; + BrnTabBarConfig? themeData; BrnTabBar({ - @required this.tabs, + required this.tabs, this.mode = BrnTabBarBadgeMode.average, this.isScroll = false, this.tabHeight, @@ -137,18 +137,19 @@ class BrnTabBar extends StatefulWidget { this.tagHeight, }) : assert(tabs == null || tabs is List) { this.themeData ??= BrnTabBarConfig(); - this.themeData = this.themeData.merge(BrnTabBarConfig( - tabHeight: tabHeight, - indicatorHeight: indicatorWeight, - indicatorWidth: indicatorWidth, - labelStyle: BrnTextStyle.withStyle(labelStyle), - unselectedLabelStyle: BrnTextStyle.withStyle(unselectedLabelStyle), - tagSpacing: tagSpacing, - preLineTagCount: preLineTagCount, - tagHeight: tagHeight, - )); + this.themeData = this.themeData!.merge(BrnTabBarConfig( + backgroundColor: backgroundcolor, + tabHeight: tabHeight, + indicatorHeight: indicatorWeight, + indicatorWidth: indicatorWidth, + labelStyle: BrnTextStyle.withStyle(labelStyle), + unselectedLabelStyle: BrnTextStyle.withStyle(unselectedLabelStyle), + tagSpacing: tagSpacing, + preLineTagCount: preLineTagCount, + tagHeight: tagHeight, + )); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .tabBarConfig .merge(this.themeData); } @@ -157,7 +158,7 @@ class BrnTabBar extends StatefulWidget { BrnTabBarState createState() => BrnTabBarState(closeController); } -/// BrnTabBarBadge的ta分配模式 +/// BrnTabBarBadge的tab分配模式 enum BrnTabBarBadgeMode { /// 原始的默认TabBar的分配模式 origin, @@ -168,33 +169,33 @@ enum BrnTabBarBadgeMode { class BrnTabBarState extends State { /// 小红点容器的样式 - BadgeShape _badgeShape; + late BadgeShape _badgeShape; /// 小红点文案 - String _badgeText; + late String _badgeText; /// 小红点容器内边距 - EdgeInsets _badgePadding; + late EdgeInsets _badgePadding; /// 小红点上偏移量 - double _paddingTop; + double _paddingTop = 0; /// 小红点右偏移量 - double _paddingRight; + double _paddingRight = 0; /// 小红点圆角 - BorderRadiusGeometry _borderRadius; + late BorderRadiusGeometry _borderRadius; /// 展开更多的按钮宽度 final double _moreSpacing = 50; /// BrnTabBarBadge展开更多数据处理控制器 - BrnTabbarController _brnTabbarController; + late BrnTabbarController _brnTabbarController; /// BrnTabBarBadge展开更多关闭处理控制器 - BrnCloseWindowController _closeWindowController; + BrnCloseWindowController? _closeWindowController; - BrnTabBarState(BrnCloseWindowController closeController) { + BrnTabBarState(BrnCloseWindowController? closeController) { this._closeWindowController = closeController; } @@ -203,11 +204,11 @@ class BrnTabBarState extends State { super.initState(); _brnTabbarController = BrnTabbarController(); // 监听更多弹框tab选中变化的时候 - _brnTabbarController?.addListener(() { + _brnTabbarController.addListener(() { _closeWindowController?.syncWindowState(_brnTabbarController.isShow); // 更新TabBar选中位置 if (widget.controller != null) { - widget.controller.animateTo(_brnTabbarController.selectIndex); + widget.controller!.animateTo(_brnTabbarController.selectIndex); } // 刷新选中TabBar小红点 refreshBadgeState(_brnTabbarController.selectIndex); @@ -215,10 +216,10 @@ class BrnTabBarState extends State { setState(() {}); }); - _closeWindowController?.getCloseController()?.stream?.listen((event) { - _brnTabbarController?.hide(); - _brnTabbarController?.entry?.remove(); - _brnTabbarController?.entry = null; + _closeWindowController?.getCloseController().stream.listen((event) { + _brnTabbarController.hide(); + _brnTabbarController.entry?.remove(); + _brnTabbarController.entry = null; }); widget.controller?.addListener(_handleTabIndexChangeTick); @@ -231,10 +232,10 @@ class BrnTabBarState extends State { } void _handleTabIndexChangeTick() { - if (widget.controller.index.toDouble() == - widget.controller.animation.value) { - _brnTabbarController?.selectIndex = widget.controller?.index ?? 0; - _brnTabbarController?.isShow = false; + if (widget.controller?.index.toDouble() == + widget.controller?.animation?.value) { + _brnTabbarController.selectIndex = widget.controller?.index ?? 0; + _brnTabbarController.isShow = false; } } @@ -242,18 +243,18 @@ class BrnTabBarState extends State { Widget build(BuildContext context) { return Container( padding: widget.padding, - constraints: BoxConstraints(minHeight: widget.themeData.tabHeight), - color: widget.themeData.backgroundColor, + constraints: BoxConstraints(minHeight: widget.themeData!.tabHeight), + color: widget.themeData!.backgroundColor, child: widget.showMore ? Row( - children: [ - Container( - width: MediaQuery.of(context).size.width - _moreSpacing, - child: _buildTabBar(), - ), - showMoreWidget(context) - ], - ) + children: [ + Container( + width: MediaQuery.of(context).size.width - _moreSpacing, + child: _buildTabBar(), + ), + showMoreWidget(context) + ], + ) : _buildTabBar(), ); } @@ -263,34 +264,34 @@ class BrnTabBarState extends State { return TabBar( tabs: fillWidgetByDataList(), controller: widget.controller, - isScrollable: widget.tabs.length > 4 || + isScrollable: widget.tabs!.length > 4 || widget.tabWidth != null || widget.isScroll, - labelColor: widget.labelColor ?? widget.themeData.labelStyle.color, + labelColor: widget.labelColor ?? widget.themeData!.labelStyle.color, labelStyle: widget.labelStyle ?? - widget.themeData.labelStyle.generateTextStyle(), + widget.themeData!.labelStyle.generateTextStyle(), labelPadding: widget.labelPadding, unselectedLabelColor: widget.unselectedLabelColor ?? - widget.themeData.unselectedLabelStyle.color, + widget.themeData!.unselectedLabelStyle.color, unselectedLabelStyle: widget.unselectedLabelStyle ?? - widget.themeData.unselectedLabelStyle.generateTextStyle(), + widget.themeData!.unselectedLabelStyle.generateTextStyle(), dragStartBehavior: widget.dragStartBehavior, onTap: (index) { if (widget.onTap != null) { - widget.onTap(this, index); - _brnTabbarController?.setSelectIndex(index); - _brnTabbarController?.isShow = false; - _brnTabbarController?.entry?.remove(); - _brnTabbarController?.entry = null; + widget.onTap!(this, index); + _brnTabbarController.setSelectIndex(index); + _brnTabbarController.isShow = false; + _brnTabbarController.entry?.remove(); + _brnTabbarController.entry = null; } }, indicator: CustomWidthUnderlineTabIndicator( insets: widget.indicatorPadding, borderSide: BorderSide( - width: widget.themeData.indicatorHeight, - color: widget.indicatorColor ?? widget.themeData.labelStyle.color, + width: widget.themeData!.indicatorHeight, + color: widget.indicatorColor ?? widget.themeData!.labelStyle.color!, ), - width: widget.themeData.indicatorWidth, + width: widget.themeData!.indicatorWidth, )); } @@ -301,11 +302,11 @@ class BrnTabBarState extends State { child: GestureDetector( onTap: () { if (!_brnTabbarController.isShow && - widget.controller.index.toDouble() == - widget.controller.animation.value) { - _brnTabbarController?.show(); + widget.controller!.index.toDouble() == + widget.controller!.animation!.value) { + _brnTabbarController.show(); if (widget.onMorePop != null) { - widget.onMorePop(); + widget.onMorePop!(); } showMoreWindow(context); setState(() {}); @@ -316,7 +317,7 @@ class BrnTabBarState extends State { }, child: Container( width: _moreSpacing, - height: widget.themeData.tabHeight, + height: widget.themeData!.tabHeight, decoration: BoxDecoration( color: Colors.white, boxShadow: [ @@ -327,9 +328,9 @@ class BrnTabBarState extends State { ], ), child: !_brnTabbarController.isShow - ? BrunoTools.getAssetImage(BrnAsset.ICON_TRIANGLE_DOWN) + ? BrunoTools.getAssetImage(BrnAsset.iconTriangleDown) : BrunoTools.getAssetImageWithBandColor( - BrnAsset.ICON_TRIANGLE_UP)), + BrnAsset.iconTriangleUp)), ), ); } @@ -337,7 +338,7 @@ class BrnTabBarState extends State { // 更新选中tab的小红点状态 void refreshBadgeState(int index) { setState(() { - BadgeTab badgeTab = widget.tabs[index]; + BadgeTab badgeTab = widget.tabs![index]; if (badgeTab != null && badgeTab.isAutoDismiss) { badgeTab.badgeNum = null; badgeTab.badgeText = null; @@ -347,10 +348,10 @@ class BrnTabBarState extends State { } List fillWidgetByDataList() { - List widgets = List(); - List tabList = widget.tabs; + List widgets = []; + List? tabList = widget.tabs; if (tabList != null && tabList.isNotEmpty) { - double minWidth; + double? minWidth; if (widget.tabWidth != null) { minWidth = widget.tabWidth; } else { @@ -397,11 +398,11 @@ class BrnTabBarState extends State { )), Badge( showBadge: (badgeTab.badgeNum != null - ? badgeTab.badgeNum > 0 - : false) || + ? badgeTab.badgeNum! > 0 + : false) || badgeTab.showRedBadge || (badgeTab.badgeText != null - ? badgeTab.badgeText.isNotEmpty + ? badgeTab.badgeText!.isNotEmpty : false), badgeContent: Text( _badgeText, @@ -415,8 +416,8 @@ class BrnTabBarState extends State { alignment: Alignment.topLeft, padding: _badgePadding, position: - BadgePosition.topEnd(top: _paddingTop, end: _paddingRight), - child: Text(badgeTab.text, + BadgePosition.topEnd(top: _paddingTop, end: _paddingRight), + child: Text(badgeTab.text!, maxLines: 1, softWrap: true, overflow: TextOverflow.ellipsis), @@ -438,7 +439,7 @@ class BrnTabBarState extends State { // 定制的等分tab样式 Widget _wrapAverageWidget( - BadgeTab badgeTab, double minWidth, bool lastElement) { + BadgeTab badgeTab, double? minWidth, bool lastElement) { caculateBadgeParams(badgeTab); return Container( width: minWidth, @@ -448,47 +449,47 @@ class BrnTabBarState extends State { children: [ Expanded( child: Container( - alignment: Alignment.center, - height: 47, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Visibility( - visible: widget.hasIndex && badgeTab.topText != null, - child: Text( - badgeTab.topText ?? "", - maxLines: 1, - overflow: TextOverflow.ellipsis, - )), - Badge( - showBadge: (badgeTab.badgeNum != null - ? badgeTab.badgeNum > 0 + alignment: Alignment.center, + height: 47, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Visibility( + visible: widget.hasIndex && badgeTab.topText != null, + child: Text( + badgeTab.topText ?? "", + maxLines: 1, + overflow: TextOverflow.ellipsis, + )), + Badge( + showBadge: (badgeTab.badgeNum != null + ? badgeTab.badgeNum! > 0 : false) || - badgeTab.showRedBadge || - (badgeTab.badgeText != null - ? badgeTab.badgeText.isNotEmpty - : false), - badgeContent: Text( - _badgeText, - style: TextStyle( - color: Color(0xFFFFFFFF), fontSize: 10, height: 1), - ), - shape: _badgeShape, - elevation: 0, - toAnimate: false, - borderRadius: _borderRadius, - alignment: Alignment.topLeft, - padding: _badgePadding, - position: BadgePosition.topEnd( - top: _paddingTop, end: _paddingRight), - child: Text(badgeTab.text, - maxLines: 1, - softWrap: true, - overflow: TextOverflow.ellipsis), - ) - ], - ), - )), + badgeTab.showRedBadge || + (badgeTab.badgeText != null + ? badgeTab.badgeText!.isNotEmpty + : false), + badgeContent: Text( + _badgeText, + style: TextStyle( + color: Color(0xFFFFFFFF), fontSize: 10, height: 1), + ), + shape: _badgeShape, + elevation: 0, + toAnimate: false, + borderRadius: _borderRadius, + alignment: Alignment.topLeft, + padding: _badgePadding, + position: BadgePosition.topEnd( + top: _paddingTop, end: _paddingRight), + child: Text(badgeTab.text!, + maxLines: 1, + softWrap: true, + overflow: TextOverflow.ellipsis), + ) + ], + ), + )), Visibility( visible: widget.hasDivider && !lastElement, child: Container( @@ -505,14 +506,14 @@ class BrnTabBarState extends State { // 计算小红点尺寸相关参数 void caculateBadgeParams(BadgeTab badgeTab) { if (badgeTab.badgeNum != null) { - if (badgeTab.badgeNum < 10) { + if (badgeTab.badgeNum! < 10) { _badgePadding = EdgeInsets.all(5); _badgeShape = BadgeShape.circle; _badgeText = badgeTab.badgeNum?.toString() ?? ""; _paddingTop = -8; _paddingRight = -18; _borderRadius = BorderRadius.all(Radius.circular(8.5)); - } else if (badgeTab.badgeNum > 99) { + } else if (badgeTab.badgeNum! > 99) { _badgePadding = EdgeInsets.fromLTRB(4, 3, 4, 2); _badgeShape = BadgeShape.square; _badgeText = "99+"; @@ -528,7 +529,7 @@ class BrnTabBarState extends State { _borderRadius = BorderRadius.all(Radius.circular(8.5)); } } else { - if (badgeTab.badgeText != null && badgeTab.badgeText.isNotEmpty) { + if (badgeTab.badgeText != null && badgeTab.badgeText!.isNotEmpty) { _badgePadding = EdgeInsets.fromLTRB(5, 3, 5, 2); _badgeShape = BadgeShape.square; _badgeText = badgeTab.badgeText?.toString() ?? ""; @@ -551,9 +552,10 @@ class BrnTabBarState extends State { // 展开更多 void showMoreWindow(BuildContext context) { - final RenderBox dropDownItemRenderBox = context.findRenderObject(); + final RenderBox dropDownItemRenderBox = + context.findRenderObject() as RenderBox; var position = - dropDownItemRenderBox.localToGlobal(Offset.zero, ancestor: null); + dropDownItemRenderBox.localToGlobal(Offset.zero, ancestor: null); var size = dropDownItemRenderBox.size; _brnTabbarController.top = size.height + position.dy; @@ -570,7 +572,7 @@ class BrnTabBarState extends State { }, child: Container( padding: EdgeInsets.only( - top: _brnTabbarController.top, + top: _brnTabbarController.top!, ), child: Stack( children: [ @@ -582,17 +584,17 @@ class BrnTabBarState extends State { child: Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height - - _brnTabbarController.top, + _brnTabbarController.top!, child: Padding( padding: EdgeInsets.all(0), child: _TabBarOverlayWidget( tabs: widget.tabs, moreWindowText: widget.moreWindowText, brnTabbarController: _brnTabbarController, - themeData: widget.themeData, - spacing: widget.themeData.tagSpacing, - preLineTagCount: widget.themeData.preLineTagCount, - tagHeight: widget.themeData.tagHeight, + themeData: widget.themeData!, + spacing: widget.themeData!.tagSpacing, + preLineTagCount: widget.themeData!.preLineTagCount, + tagHeight: widget.themeData!.tagHeight, ), ), ), @@ -608,17 +610,17 @@ class BrnTabBarState extends State { resetEntry(); } _brnTabbarController.entry = overlayEntry; - Overlay.of(context).insert(_brnTabbarController.entry); + Overlay.of(context)!.insert(_brnTabbarController.entry!); } void resetEntry() { - _brnTabbarController.entry.remove(); + _brnTabbarController.entry?.remove(); _brnTabbarController.entry = null; } void hideMoreWindow() { - if (_brnTabbarController?.isShow ?? false) { - _brnTabbarController?.hide(); + if (_brnTabbarController.isShow) { + _brnTabbarController.hide(); resetEntry(); } } @@ -627,11 +629,12 @@ class BrnTabBarState extends State { // 更多弹框样式 // ignore: must_be_immutable class _TabBarOverlayWidget extends StatefulWidget { - List tabs; - String moreWindowText; + List? tabs; - BrnTabbarController brnTabbarController; + String? moreWindowText; + + BrnTabbarController? brnTabbarController; BrnTabBarConfig themeData; @@ -642,15 +645,15 @@ class _TabBarOverlayWidget extends StatefulWidget { int preLineTagCount; /// tag高度 - double tagHeight; + double? tagHeight; _TabBarOverlayWidget( {this.tabs, this.moreWindowText, this.brnTabbarController, - this.themeData, - this.spacing, - this.preLineTagCount, + required this.themeData, + this.spacing: 12.0, + this.preLineTagCount: 4, this.tagHeight}); @override @@ -659,7 +662,7 @@ class _TabBarOverlayWidget extends StatefulWidget { class _TabBarOverlayWidgetState extends State<_TabBarOverlayWidget> { /// tag宽度 - double _tagWidth; + double _tagWidth = _tagDefaultSize; double _padding = 20; @@ -696,7 +699,7 @@ class _TabBarOverlayWidgetState extends State<_TabBarOverlayWidget> { children: [ Visibility( visible: widget.moreWindowText != null && - widget.moreWindowText.isNotEmpty, + widget.moreWindowText!.isNotEmpty, child: Padding( padding: EdgeInsets.only(bottom: 16), child: Text( @@ -723,13 +726,10 @@ class _TabBarOverlayWidgetState extends State<_TabBarOverlayWidget> { Widget _createMoreItems() { // 计算tag的宽度 - _tagWidth = (_parentWidth - - widget.spacing * (widget.preLineTagCount - 1) - - _padding * 2) / - widget.preLineTagCount; - - List widgets = List(); - List tabList = widget.tabs; + _tagWidth = (_parentWidth - widget.spacing * (widget.preLineTagCount - 1) - _padding * 2) / widget.preLineTagCount; + _tagWidth = _tagWidth <= _tagDefaultSize ? _tagDefaultSize : _tagWidth; + List widgets = []; + List? tabList = widget.tabs; if (tabList != null && tabList.isNotEmpty) { for (int i = 0; i < tabList.length; i++) { BadgeTab badgeTab = tabList[i]; @@ -746,14 +746,14 @@ class _TabBarOverlayWidgetState extends State<_TabBarOverlayWidget> { Widget _createMoreItemWidget(BadgeTab badgeTab, int index) { return GestureDetector( onTap: () { - if (widget.brnTabbarController.selectIndex == index) { + if (widget.brnTabbarController!.selectIndex == index) { widget.brnTabbarController?.setSelectIndex(index); widget.brnTabbarController?.isShow = false; widget.brnTabbarController?.entry?.remove(); widget.brnTabbarController?.entry = null; setState(() {}); } else { - widget.brnTabbarController.setSelectIndex(index); + widget.brnTabbarController!.setSelectIndex(index); widget.brnTabbarController?.isShow = false; widget.brnTabbarController?.entry?.remove(); widget.brnTabbarController?.entry = null; @@ -763,21 +763,21 @@ class _TabBarOverlayWidgetState extends State<_TabBarOverlayWidget> { child: Container( alignment: Alignment.center, decoration: BoxDecoration( - color: widget.brnTabbarController.selectIndex == index + color: widget.brnTabbarController!.selectIndex == index ? widget.themeData.tagSelectedBgColor : widget.themeData.tagNormalBgColor, borderRadius: BorderRadius.circular(widget.themeData.tagRadius)), height: widget.tagHeight, width: _tagWidth, child: Text( - badgeTab.text, + badgeTab.text ?? '', textAlign: TextAlign.center, maxLines: 1, softWrap: true, overflow: TextOverflow.ellipsis, - style: widget.brnTabbarController.selectIndex == index - ? widget.themeData.tagSelectedTextStyle?.generateTextStyle() - : widget.themeData.tagNormalTextStyle?.generateTextStyle(), + style: widget.brnTabbarController!.selectIndex == index + ? widget.themeData.tagSelectedTextStyle.generateTextStyle() + : widget.themeData.tagNormalTextStyle.generateTextStyle(), ), ), ); @@ -787,26 +787,26 @@ class _TabBarOverlayWidgetState extends State<_TabBarOverlayWidget> { class BadgeTab { BadgeTab( {this.key, - this.text, - this.badgeNum, - this.topText, - this.badgeText, - this.showRedBadge = false, - this.isAutoDismiss = true}); + this.text, + this.badgeNum, + this.topText, + this.badgeText, + this.showRedBadge = false, + this.isAutoDismiss = true}); - final Key key; + final Key? key; /// Tab文本 - final String text; + final String? text; /// 红点数字 - int badgeNum; + int? badgeNum; /// tab顶部文本信息 - String topText; + String? topText; /// 红点显示的文本 - String badgeText; + String? badgeText; /// 是否显示小红点,默认badgeNum没设置,不显示 bool showRedBadge; diff --git a/lib/src/components/tabbar/normal/brn_tabbar_controller.dart b/lib/src/components/tabbar/normal/brn_tabbar_controller.dart index e67c9153..b0337c54 100644 --- a/lib/src/components/tabbar/normal/brn_tabbar_controller.dart +++ b/lib/src/components/tabbar/normal/brn_tabbar_controller.dart @@ -1,3 +1,5 @@ + + import 'dart:async'; import 'package:flutter/material.dart'; @@ -6,7 +8,7 @@ class BrnTabbarController extends ChangeNotifier { /// /// 更多选项距离顶部距离 /// - double top; + double? top; /// /// 是否显示更多选项弹框 @@ -16,12 +18,12 @@ class BrnTabbarController extends ChangeNotifier { /// /// 屏幕高度 /// - double screenHeight; + double? screenHeight; /// /// 展开更多图层 /// - OverlayEntry entry; + OverlayEntry? entry; /// /// 选中的角标 @@ -45,7 +47,7 @@ class BrnTabbarController extends ChangeNotifier { } class CloseWindowEvent { - bool isShow = false; + bool? isShow = false; CloseWindowEvent({this.isShow}); } @@ -74,6 +76,6 @@ class BrnCloseWindowController { } void closeMoreWindow() { - _closeController?.add(CloseWindowEvent()); + _closeController.add(CloseWindowEvent()); } } diff --git a/lib/src/components/tag/brn_state_tag.dart b/lib/src/components/tag/brn_state_tag.dart index 6da94437..5b6f806b 100644 --- a/lib/src/components/tag/brn_state_tag.dart +++ b/lib/src/components/tag/brn_state_tag.dart @@ -15,17 +15,17 @@ import 'package:flutter/material.dart'; /// class BrnStateTag extends StatelessWidget { final String tagText; - final Color backgroundColor; - final Color textColor; final TagState tagState; + final Color? backgroundColor; + final Color? textColor; //默认为等待状态,黄色 const BrnStateTag( - {Key key, - this.tagText, + {Key? key, + required this.tagText, + this.tagState = TagState.waiting, this.backgroundColor, - this.textColor, - this.tagState = TagState.waiting}) + this.textColor,}) : super(key: key); @override diff --git a/lib/src/components/tag/brn_tag_custom.dart b/lib/src/components/tag/brn_tag_custom.dart index 1c7f04d0..6a8381db 100644 --- a/lib/src/components/tag/brn_tag_custom.dart +++ b/lib/src/components/tag/brn_tag_custom.dart @@ -20,10 +20,10 @@ class BrnTagCustom extends StatelessWidget { final String tagText; /// 标签的背景颜色 默认主题色 - final Color backgroundColor; + final Color? backgroundColor; /// 标签的文本颜色 默认F4的反白颜色 - final Color textColor; + final Color? textColor; /// 标签的圆角 默认为2 /// 如果同时设置了borderRadius、tagBorderRadius字段,优先使用tagBorderRadius字段设置圆角 @@ -42,15 +42,15 @@ class BrnTagCustom extends StatelessWidget { final double maxWidth; /// 标签边框 - final Border border; + final Border? border; BrnTagCustom({ - Key key, - this.tagText, + Key? key, + required this.tagText, this.textColor, this.backgroundColor, - this.tagBorderRadius, - this.textPadding, + this.tagBorderRadius = const BorderRadius.all(Radius.circular(2)), + this.textPadding = const EdgeInsets.only(bottom: 0.5, left: 3, right: 3, top: 0), this.border, this.fontSize = 11, this.fontWeight = FontWeight.normal, @@ -59,61 +59,46 @@ class BrnTagCustom extends StatelessWidget { ///快捷方式生成边框标签 BrnTagCustom.buildBorderTag({ - Key key, + Key? key, + required this.tagText, this.backgroundColor = Colors.transparent, - this.tagText = "", - this.textPadding = - const EdgeInsets.only(bottom: 3, left: 3, right: 3, top: 0), + this.textPadding = const EdgeInsets.only(bottom: 3, left: 3, right: 3, top: 0), this.fontSize = 11, this.fontWeight = FontWeight.normal, - this.tagBorderRadius, - Color textColor, - Color borderColor, + this.tagBorderRadius = const BorderRadius.all(Radius.circular(2)), + Color? textColor, + Color? borderColor, double borderWidth = 1, - double borderRadius = 3, }) : this.maxWidth = double.infinity, this.border = Border.all( - color: borderColor ?? - BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .brandPrimary, - width: borderWidth ?? 1, + color: borderColor ?? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + width: borderWidth, ), - this.textColor = textColor ?? - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, + this.textColor = + textColor ?? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, super(key: key); @override Widget build(BuildContext context) { - BorderRadius bRadius = - tagBorderRadius ?? BorderRadius.all(Radius.circular(2)); return Container( constraints: BoxConstraints( maxWidth: maxWidth, ), decoration: BoxDecoration( color: backgroundColor ?? - BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .brandPrimary, + BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, shape: BoxShape.rectangle, - borderRadius: bRadius, + borderRadius: tagBorderRadius, border: border), - padding: textPadding ?? - EdgeInsets.only(bottom: 0.5, left: 3, right: 3, top: 0), + padding: textPadding, child: Text( - tagText ?? "", + tagText, textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, style: TextStyle( - fontSize: fontSize ?? 11, + fontSize: fontSize, color: textColor ?? - BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .colorTextBaseInverse, + BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBaseInverse, fontWeight: fontWeight, ), )); diff --git a/lib/src/components/tag/tagview/brn_delete_tag.dart b/lib/src/components/tag/tagview/brn_delete_tag.dart index 4ea6cd9e..4e22b71e 100644 --- a/lib/src/components/tag/tagview/brn_delete_tag.dart +++ b/lib/src/components/tag/tagview/brn_delete_tag.dart @@ -12,34 +12,34 @@ import 'package:flutter/widgets.dart'; /// ignore: must_be_immutable class BrnDeleteTag extends StatefulWidget { /// 初始传入的标签,当传入controller的时候,应把初始标签放入controller的构造中 - final List tags; + final List? tags; /// 标签控制器,用于主动添加和删除标签,如果使用场景只需要删除标签并进行回调可以不传控制器 - final BrnDeleteTagController controller; + final BrnDeleteTagController? controller; /// 点击删除某个标签后的回调,参数包含 /// 剩余的标签集合 /// 被删除的标签内容 /// 被删除的标签索引 - final Function(List, String, int) onTagDelete; + final Function(List, String?, int)? onTagDelete; /// 垂直方向的间距 - final double verticalSpacing; + final double? verticalSpacing; /// 水平方向的间距 - final double horizontalSpacing; + final double? horizontalSpacing; /// 标签的字体颜色 - final TextStyle tagTextStyle; + final TextStyle? tagTextStyle; /// 标签的圆角 - final ShapeBorder shape; + final OutlinedBorder? shape; /// 标签背景色 - final Color backgroundColor; + final Color? backgroundColor; /// 删除图标的颜色 - final Color deleteIconColor; + final Color? deleteIconColor; /// true 流式展示,false 横向滑动展示,默认 true final bool softWrap; @@ -48,13 +48,13 @@ class BrnDeleteTag extends StatefulWidget { final EdgeInsets padding; /// 主题配置信息,包含标签背景色、文本颜色等字段,非必传 - BrnTagConfig themeData; + BrnTagConfig? themeData; /// delete Icon Size,不传默认使用 内置删除 icon 图片的的大小, - final Size deleteIconSize; + final Size? deleteIconSize; BrnDeleteTag( - {Key key, + {Key? key, this.tags, this.controller, this.onTagDelete, @@ -66,17 +66,17 @@ class BrnDeleteTag extends StatefulWidget { this.deleteIconColor, this.deleteIconSize, this.softWrap = true, - this.padding, + this.padding = const EdgeInsets.fromLTRB(20, 0, 20, 0), this.themeData}) : super(key: key) { themeData ??= BrnTagConfig(); - themeData = themeData.merge(BrnTagConfig( + themeData = themeData!.merge(BrnTagConfig( tagBackgroundColor: this.backgroundColor, tagTextStyle: BrnTextStyle.withStyle(tagTextStyle))); themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) + .getConfig(configId: themeData!.configId) .tagConfig - .merge(themeData); + .merge(this.themeData); } @override @@ -84,20 +84,19 @@ class BrnDeleteTag extends StatefulWidget { } class _BrnDeleteTagState extends State { - BrnDeleteTagController _controller; + late BrnDeleteTagController _controller; @override void initState() { super.initState(); - _controller = - widget.controller ?? BrnDeleteTagController(initTags: widget.tags); + _controller = widget.controller ?? BrnDeleteTagController(initTags: widget.tags); } @override Widget build(BuildContext context) { return Container( color: Colors.white, - child: ValueListenableBuilder( + child: ValueListenableBuilder>( valueListenable: _controller.notifier, builder: (context, value, _) { return _buildContent(value); @@ -107,8 +106,8 @@ class _BrnDeleteTagState extends State { /// 根据标签集合构建标签 UI Widget _buildContent(List tags) { - if (tags == null || tags.isEmpty) { - return Container(); + if (tags.isEmpty) { + return SizedBox.shrink(); } List itemList = []; @@ -118,28 +117,25 @@ class _BrnDeleteTagState extends State { tags[i], _deleteTag, deleteIconSize: widget.deleteIconSize, - style: widget.themeData.tagTextStyle?.generateTextStyle(), + style: widget.themeData!.tagTextStyle.generateTextStyle(), shape: widget.shape, - backgroundColor: widget.themeData?.tagBackgroundColor, + backgroundColor: widget.themeData!.tagBackgroundColor, deleteIconColor: widget.deleteIconColor, themeData: widget.themeData, )); } Widget result; - if (widget.softWrap ?? true) { + if (widget.softWrap) { result = Wrap( spacing: widget.horizontalSpacing ?? 10, - runSpacing: - widget.verticalSpacing != null ? widget.verticalSpacing - 16 : -6, + runSpacing: widget.verticalSpacing != null ? widget.verticalSpacing! - 16 : -6, alignment: WrapAlignment.start, children: itemList, ); } else { int tagIdx = 0; var finalTagList = itemList.map((tag) { - double rightPadding = (tagIdx == itemList.length - 1) - ? 0 - : widget.horizontalSpacing ?? 12; + double rightPadding = (tagIdx == itemList.length - 1) ? 0 : widget.horizontalSpacing ?? 12; var padding = Padding( child: tag, padding: EdgeInsets.only(right: rightPadding), @@ -158,7 +154,7 @@ class _BrnDeleteTagState extends State { return Container( color: Colors.white, - padding: widget.padding ?? EdgeInsets.fromLTRB(20, 0, 20, 0), + padding: widget.padding, alignment: Alignment.centerLeft, child: result, ); @@ -166,9 +162,9 @@ class _BrnDeleteTagState extends State { /// 删除指定 index 下标的标签,并且回调通知外部使用者 void _deleteTag(int index) { - String result = _controller.deleteForIndex(index); + String? result = _controller.deleteForIndex(index); if (widget.onTagDelete != null) { - widget.onTagDelete(_controller.tags, result, index); + widget.onTagDelete!(_controller.tags, result, index); } } } @@ -179,12 +175,12 @@ class DeleteTagItemWidget extends StatelessWidget { final int index; final String title; final Function(int) didDeleted; - final Size deleteIconSize; - final TextStyle style; - final ShapeBorder shape; - final Color backgroundColor; - final Color deleteIconColor; - BrnTagConfig themeData; + final Size? deleteIconSize; + final TextStyle? style; + final OutlinedBorder? shape; + final Color? backgroundColor; + final Color? deleteIconColor; + final BrnTagConfig? themeData; DeleteTagItemWidget(this.index, this.title, this.didDeleted, {this.deleteIconSize, @@ -199,20 +195,17 @@ class DeleteTagItemWidget extends StatelessWidget { return Chip( padding: EdgeInsets.fromLTRB(10, 0, -3, 0), labelPadding: EdgeInsets.fromLTRB(0, 0, -3, 0), - backgroundColor: themeData.tagBackgroundColor, + backgroundColor: themeData!.tagBackgroundColor, label: Text(this.title, - overflow: TextOverflow.ellipsis, - style: themeData?.tagTextStyle?.generateTextStyle()), + overflow: TextOverflow.ellipsis, style: themeData!.tagTextStyle.generateTextStyle()), shape: shape ?? - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(themeData?.tagRadius)), + RoundedRectangleBorder(borderRadius: BorderRadius.circular(themeData!.tagRadius)), //删除图标 deleteIcon: deleteIconSize != null ? BrunoTools.getAssetSizeImage( - BrnAsset.ICON_CLOSE, deleteIconSize.width, deleteIconSize.height, + BrnAsset.iconClose, deleteIconSize!.width, deleteIconSize!.height, color: deleteIconColor) - : BrunoTools.getAssetImageWithColor( - BrnAsset.ICON_CLOSE, deleteIconColor), + : BrunoTools.getAssetImageWithColor(BrnAsset.iconClose, deleteIconColor), onDeleted: () { debugPrint('$index'); didDeleted(index); @@ -223,15 +216,15 @@ class DeleteTagItemWidget extends StatelessWidget { /// 标签控制器,用于主动添加和删除标签 class BrnDeleteTagController { - ValueNotifier> notifier; + late ValueNotifier> notifier; /// 控制器中存储的标签数据 - List _tags = List(); + List _tags = []; List get tags => notifier.value; - BrnDeleteTagController({List initTags}) { - _tags = initTags; + BrnDeleteTagController({List? initTags}) { + _tags = initTags ?? []; notifier = ValueNotifier(_tags); } @@ -260,8 +253,8 @@ class BrnDeleteTagController { } /// 删除指定 index 的标签,并返回其内容 - String deleteForIndex(int index) { - if (_tags != null && _tags.length > index) { + String? deleteForIndex(int index) { + if (_tags.length > index) { String result = _tags.removeAt(index); _asyncData(); return result; @@ -271,17 +264,14 @@ class BrnDeleteTagController { /// 删除某个具体内容的标签,成功返回 true,失败返回 false bool deleteForTag(String tag) { - if (_tags != null) { - bool result = _tags.remove(tag); - _asyncData(); - return result; - } else - return false; + bool result = _tags.remove(tag); + _asyncData(); + return result; } void _asyncData() { // notifier 中的 value 引用是 _tags 所以直接赋值 _tags 不会触发回调 - List values = List(); + List values = []; _tags.forEach((e) => values.add(e)); notifier.value = values; } diff --git a/lib/src/components/tag/tagview/brn_select_tag.dart b/lib/src/components/tag/tagview/brn_select_tag.dart index cba62a0c..62f01fe4 100644 --- a/lib/src/components/tag/tagview/brn_select_tag.dart +++ b/lib/src/components/tag/tagview/brn_select_tag.dart @@ -13,11 +13,10 @@ import 'package:flutter/material.dart'; /// ignore: must_be_immutable class BrnSelectTag extends StatefulWidget { /// 展示的标签列表 - @required final List tags; /// 选择tag的回调,返回选中 tag 的位置 - final void Function(List) onSelect; + final void Function(List)? onSelect; /// 水平间距,默认 12 final double spacing; @@ -26,22 +25,22 @@ class BrnSelectTag extends StatefulWidget { final double verticalSpacing; /// 普通标签的样式 - final TextStyle tagTextStyle; + final TextStyle? tagTextStyle; /// 选中的标签样式 - final TextStyle selectedTagTextStyle; + final TextStyle? selectedTagTextStyle; /// 普通标签背景色,默认 F0Color - final Color tagBackgroundColor; + final Color? tagBackgroundColor; /// 选中的标签背景色,默认 B0Color - final Color selectedTagBackgroundColor; + final Color? selectedTagBackgroundColor; - /// 标签宽度。默认 75 - final double tagWidth; + /// 标签宽度。默认全局配置宽度 75 + final double? tagWidth; - /// 标签高度。默认 34 - final double tagHeight; + /// 标签高度。默认全局配置高度 34 + final double? tagHeight; /// true 流式展示,false 横向滑动展示,默认 true final bool softWrap; @@ -56,13 +55,13 @@ class BrnSelectTag extends StatefulWidget { final bool isSingleSelect; /// 多选时的初始状态数组 - final List initTagState; + final List? initTagState; - BrnTagConfig themeData; + BrnTagConfig? themeData; BrnSelectTag({ - Key key, - @required this.tags, + Key? key, + required this.tags, this.onSelect, this.spacing = 12, this.verticalSpacing = 10, @@ -78,13 +77,12 @@ class BrnSelectTag extends StatefulWidget { this.alignment = Alignment.centerLeft, this.fixWidthMode = true, this.themeData, - }) : assert(tags != null), - super(key: key) { + }) : super(key: key) { if (isSingleSelect == true) { - assert(initTagState == null || (initTagState.length <= 1)); + assert(initTagState == null || (initTagState!.length <= 1)); } this.themeData ??= BrnTagConfig(); - this.themeData = this.themeData.merge(BrnTagConfig( + this.themeData = this.themeData!.merge(BrnTagConfig( tagBackgroundColor: this.tagBackgroundColor, tagTextStyle: BrnTextStyle.withStyle(this.tagTextStyle), selectTagTextStyle: BrnTextStyle.withStyle(this.selectedTagTextStyle), @@ -92,7 +90,7 @@ class BrnSelectTag extends StatefulWidget { tagHeight: this.tagHeight, selectedTagBackgroundColor: this.selectedTagBackgroundColor)); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .tagConfig .merge(this.themeData); } @@ -102,17 +100,15 @@ class BrnSelectTag extends StatefulWidget { } class _BrnSelectTagState extends State { - List _tagState; + List _tagState = []; @override void initState() { super.initState(); _tagState = widget.tags.map((name) => false).toList(); if (widget.initTagState != null) { - for (int index = 0; - index < min(widget.initTagState.length, widget.tags.length); - index++) { - _tagState[index] = widget.initTagState[index]; + for (int index = 0; index < min(widget.initTagState!.length, widget.tags.length); index++) { + _tagState[index] = widget.initTagState![index]; } } } @@ -120,7 +116,7 @@ class _BrnSelectTagState extends State { @override Widget build(BuildContext context) { Widget content; - if (widget.softWrap ?? true) { + if (widget.softWrap) { content = Wrap( runSpacing: widget.verticalSpacing, spacing: widget.spacing, @@ -157,13 +153,13 @@ class _BrnSelectTagState extends State { } List _tagWidgetList(context) { - List list = List(); + List list = []; for (int nameIndex = 0; nameIndex < widget.tags.length; nameIndex++) { Widget tagWidget = _tagWidgetAtIndex(nameIndex); GestureDetector gdt = GestureDetector( child: tagWidget, onTap: () { - if (widget.isSingleSelect ?? true) { + if (widget.isSingleSelect) { bool selected = _tagState[nameIndex]; if (selected) { return; @@ -183,7 +179,7 @@ class _BrnSelectTagState extends State { for (int index = 0; index < _tagState.length; index++) { if (_tagState[index]) _selectedIndexes.add(index); } - widget.onSelect(_selectedIndexes); + widget.onSelect!(_selectedIndexes); } }); list.add(gdt); @@ -199,15 +195,14 @@ class _BrnSelectTagState extends State { overflow: TextOverflow.ellipsis, ); Container container = Container( - constraints: BoxConstraints(minWidth: widget.themeData.tagMinWidth), + constraints: BoxConstraints(minWidth: widget.themeData!.tagMinWidth), decoration: BoxDecoration( color: selected - ? (widget.themeData?.selectedTagBackgroundColor - ?.withOpacity(0.12)) - : (widget.themeData?.tagBackgroundColor), - borderRadius: BorderRadius.circular(widget.themeData?.tagRadius)), - width: widget.fixWidthMode ? widget.themeData?.tagWidth : null, - height: widget.themeData?.tagHeight, + ? (widget.themeData!.selectedTagBackgroundColor.withOpacity(0.12)) + : (widget.themeData!.tagBackgroundColor), + borderRadius: BorderRadius.circular(widget.themeData!.tagRadius)), + width: widget.fixWidthMode ? widget.themeData!.tagWidth : null, + height: widget.themeData!.tagHeight, padding: EdgeInsets.only(left: 8, right: 8), child: Center(widthFactor: 1, child: tx), ); @@ -215,28 +210,24 @@ class _BrnSelectTagState extends State { } TextStyle _tagTextStyle() { - return widget.themeData?.tagTextStyle?.generateTextStyle(); + return widget.themeData!.tagTextStyle.generateTextStyle(); } TextStyle _selectedTextStyle() { - return widget.themeData?.selectTagTextStyle?.generateTextStyle(); + return widget.themeData!.selectTagTextStyle.generateTextStyle(); } @override void didUpdateWidget(BrnSelectTag oldWidget) { super.didUpdateWidget(oldWidget); // 如果两个数组不相等,重置选中状态 - if (!sameList(oldWidget.tags, widget.tags)) - _tagState = List.filled(widget.tags.length, false); + if (!sameList(oldWidget.tags, widget.tags)) _tagState = List.filled(widget.tags.length, false); } /// 比较两个数组内容是否一致,如果一致,返回 true,否则 false bool sameList(List first, List second) { - if (first == null || second == null || first.length != second.length) - return false; + if (first.length != second.length) return false; int index = 0; - return first.firstWhere((item) => item != second[index++], - orElse: () => null) == - null; + return first.firstWhere((item) => item != second[index++], orElse: () => '') == ''; } } diff --git a/lib/src/components/text/brn_expandable_text.dart b/lib/src/components/text/brn_expandable_text.dart index 5bf52d7b..1f59e249 100644 --- a/lib/src/components/text/brn_expandable_text.dart +++ b/lib/src/components/text/brn_expandable_text.dart @@ -35,20 +35,20 @@ class BrnExpandableText extends StatefulWidget { final String text; ///显示的最多行数 - final int maxLines; + final int? maxLines; /// 文本的样式 - final TextStyle textStyle; + final TextStyle? textStyle; /// 展开或者收起的时候的回调 - final TextExpandedCallback onExpanded; + final TextExpandedCallback? onExpanded; /// 更多按钮渐变色的初始色 默认白色 - final Color color; + final Color? color; const BrnExpandableText( - {Key key, - @required this.text, + {Key? key, + required this.text, this.maxLines = 1000000, this.textStyle, this.onExpanded, @@ -59,13 +59,7 @@ class BrnExpandableText extends StatefulWidget { } class _BrnExpandableTextState extends State { - bool _expanded; - - @override - void initState() { - super.initState(); - _expanded = false; - } + bool _expanded = false; @override Widget build(BuildContext context) { @@ -139,7 +133,7 @@ class _BrnExpandableTextState extends State { setState(() { _expanded = true; if (null != widget.onExpanded) { - widget.onExpanded(_expanded); + widget.onExpanded!(_expanded); } }); }, @@ -182,7 +176,7 @@ class _BrnExpandableTextState extends State { setState(() { _expanded = false; if (null != widget.onExpanded) { - widget.onExpanded(_expanded); + widget.onExpanded!(_expanded); } }); }); diff --git a/lib/src/components/toast/brn_toast.dart b/lib/src/components/toast/brn_toast.dart index a37558fe..41d4e9eb 100644 --- a/lib/src/components/toast/brn_toast.dart +++ b/lib/src/components/toast/brn_toast.dart @@ -2,164 +2,254 @@ import 'dart:math'; import 'package:flutter/material.dart'; +/// 位置枚举 +enum BrnToastGravity { + /// 底部显示 + bottom, + + /// 居中显示 + center, + + /// 顶部显示 + top, +} + +/// toast 显示时长 +class BrnDuration { + BrnDuration._(); + + /// toast 显示较短时间(1s) + static const Duration short = Duration(seconds: 1); + + /// toast 显示较长时间(3s) + static const Duration long = Duration(seconds: 3); +} + /// 通用的Toast组件 class BrnToast { - static const LENGTH_SHORT = 1; - static const LENGTH_LONG = 2; - static const BOTTOM = 0; - static const CENTER = 1; - static const TOP = 2; + /// Toast 距离顶部默认间距 + static const int _defaultTopOffset = 50; + + /// Toast 距离底部默认间距 + static const int _defaultBottomOffset = 50; - static _ToastView preToastView; + /// _ToastView + static _ToastView? preToastView; /// 显示在中间。如不设置duration则会自动根据内容长度来计算(更友好,最长5秒) - static void showInCenter(String text, BuildContext context, {int duration}) { - show(text, context, duration: duration, gravity: CENTER); + static void showInCenter( + {required String text, + required BuildContext context, + Duration? duration}) { + show( + text, + context, + duration: duration, + gravity: BrnToastGravity.center, + ); } /// 显示Toast,如不设置duration则会自动根据内容长度来计算(更友好,最长5秒) - static void show(String text, BuildContext context, - {int duration, - int gravity = BOTTOM, - Color backgroundColor = const Color(0xFF222222), - textStyle = const TextStyle(fontSize: 16, color: Colors.white), - double backgroundRadius = 8, - Image preIcon, - double verticalOffset, - VoidCallback onDismiss}) { - OverlayState overlayState = Overlay.of(context); - if (text == null || context == null || overlayState == null) { - return; - } + static void show( + String text, + BuildContext context, { + Duration? duration, + Color? background, + TextStyle? textStyle, + double? radius, + Image? preIcon, + double? verticalOffset, + VoidCallback? onDismiss, + BrnToastGravity? gravity, + }) { + final OverlayState? overlayState = Overlay.of(context); + if (overlayState == null) return; + preToastView?._dismiss(); preToastView = null; - verticalOffset = getRealVerticalOffset(verticalOffset, gravity, context); - // 自动根据内容长度决定显示时长,更加人性化 - int aiDuration = duration ?? min(text.length * 0.06 + 0.8, 5.0).ceil(); - - _ToastView toastView = _ToastView(); - toastView.overlayState = overlayState; - OverlayEntry overlayEntry; - overlayEntry = OverlayEntry(builder: (context) { - return _buildToastLayout(context, backgroundColor, backgroundRadius, - preIcon, text, textStyle, gravity, - verticalOffset: verticalOffset); - }); - toastView._overlayEntry = overlayEntry; + final double finalVerticalOffset = getVerticalOffset( + context: context, + gravity: gravity, + verticalOffset: verticalOffset, + ); + + /// 自动根据内容长度决定显示时长,更加人性化 + final int autoDuration = min(text.length * 0.06 + 0.8, 5.0).ceil(); + final Duration finalDuration = + duration ?? Duration(seconds: autoDuration); + final OverlayEntry overlayEntry = OverlayEntry( + builder: (context) { + return _ToastWidget( + widget: ToastChild( + background: background, + radius: radius, + msg: text, + leading: preIcon, + textStyle: textStyle, + gravity: gravity, + verticalOffset: finalVerticalOffset, + ), + ); + }, + ); + final _ToastView toastView = + _ToastView(overlayState: overlayState, overlayEntry: overlayEntry); preToastView = toastView; - toastView._show(aiDuration, onDismiss: onDismiss); + toastView._show( + duration: finalDuration, + onDismiss: onDismiss, + ); } - static double getRealVerticalOffset( - double verticalOffset, int gravity, BuildContext context) { - if (gravity == BrnToast.TOP) { - verticalOffset = - (verticalOffset ?? 0) + MediaQuery.of(context).viewInsets.top + 50; - } else if (gravity == BrnToast.BOTTOM) { - verticalOffset = - (verticalOffset ?? 0) + MediaQuery.of(context).viewInsets.bottom + 50; - } else { - verticalOffset = 0; + /// 获取默认设置的垂直间距 + static double getVerticalOffset({ + required BuildContext context, + BrnToastGravity? gravity, + double? verticalOffset, + }) { + final double _verticalOffset = verticalOffset ?? 0; + final double defaultOffset; + switch (gravity) { + case BrnToastGravity.bottom: + final offset = verticalOffset ?? _defaultTopOffset; + defaultOffset = MediaQuery.of(context).viewInsets.bottom + offset; + break; + case BrnToastGravity.top: + final offset = verticalOffset ?? _defaultBottomOffset; + defaultOffset = MediaQuery.of(context).viewInsets.top + offset; + break; + case BrnToastGravity.center: + default: + defaultOffset = verticalOffset ?? 0; } - return verticalOffset; - } -} -_ToastWidget _buildToastLayout( - BuildContext context, - Color background, - double backgroundRadius, - Image preIcon, - String msg, - TextStyle textStyle, - int gravity, - {double verticalOffset}) { - Alignment alignment = Alignment.center; - EdgeInsets padding; - if (gravity == BrnToast.BOTTOM) { - alignment = Alignment.bottomCenter; - padding = EdgeInsets.only(bottom: verticalOffset); - } else if (gravity == BrnToast.TOP) { - alignment = Alignment.topCenter; - padding = EdgeInsets.only(top: verticalOffset); + return defaultOffset + _verticalOffset; } - - return _ToastWidget( - widget: Container( - width: MediaQuery.of(context).size.width, - child: Container( - padding: padding, - alignment: alignment, - width: MediaQuery.of(context).size.width, - child: Container( - decoration: BoxDecoration( - color: background, - borderRadius: BorderRadius.circular(backgroundRadius), - ), - margin: EdgeInsets.symmetric(horizontal: 20), - padding: EdgeInsets.fromLTRB(18, 10, 18, 10), - child: RichText( - text: TextSpan(children: [ - preIcon != null - ? WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Padding( - padding: EdgeInsets.only(right: 6), - child: preIcon, - )) - : TextSpan(text: ""), - TextSpan(text: msg, style: textStyle), - ]), - ), - )), - ), - gravity: gravity); } class _ToastView { OverlayState overlayState; - OverlayEntry _overlayEntry; + OverlayEntry overlayEntry; bool _isVisible = false; - _show(int duration, {VoidCallback onDismiss}) async { + _ToastView({ + required this.overlayState, + required this.overlayEntry, + }); + + void _show({required Duration duration, VoidCallback? onDismiss}) async { _isVisible = true; - overlayState.insert(_overlayEntry); - await Future.delayed( - Duration(seconds: duration == null ? BrnToast.LENGTH_SHORT : duration)); - _dismiss(); - if (onDismiss != null) { - onDismiss(); - } + overlayState.insert(overlayEntry); + Future.delayed(duration, () { + _dismiss(); + onDismiss?.call(); + }); } - _dismiss() async { + void _dismiss() async { if (!_isVisible) { return; } _isVisible = false; - _overlayEntry?.remove(); + overlayEntry.remove(); } } -class _ToastWidget extends StatelessWidget { - final Widget widget; - final int gravity; +class ToastChild extends StatelessWidget { + const ToastChild({ + Key? key, + required this.msg, + required this.verticalOffset, + this.background, + this.radius, + this.leading, + this.gravity, + this.textStyle, + }) : super(key: key); + + Alignment get alignment { + switch (gravity) { + case BrnToastGravity.bottom: + return Alignment.bottomCenter; + case BrnToastGravity.top: + return Alignment.topCenter; + case BrnToastGravity.center: + default: + return Alignment.center; + } + } + + EdgeInsets get padding { + switch (gravity) { + case BrnToastGravity.bottom: + return EdgeInsets.only(bottom: verticalOffset); + case BrnToastGravity.top: + return EdgeInsets.only(top: verticalOffset); + case BrnToastGravity.center: + default: + return EdgeInsets.only(top: verticalOffset); + } + } + + final String msg; + final double verticalOffset; + final Color? background; + final double? radius; + final Image? leading; + final BrnToastGravity? gravity; + final TextStyle? textStyle; + + InlineSpan get leadingSpan { + if (leading == null) { + return const TextSpan(text: ""); + } + return WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Padding(padding: const EdgeInsets.only(right: 6), child: leading!), + ); + } - _ToastWidget({ - Key key, - @required this.widget, - @required this.gravity, + @override + Widget build(BuildContext context) { + return SizedBox( + width: MediaQuery.of(context).size.width, + child: Container( + padding: padding, + alignment: alignment, + width: MediaQuery.of(context).size.width, + child: Container( + decoration: BoxDecoration( + color: background ?? const Color(0xFF222222), + borderRadius: BorderRadius.circular(radius ?? 8), + ), + margin: const EdgeInsets.symmetric(horizontal: 20), + padding: const EdgeInsets.fromLTRB(18, 10, 18, 10), + child: RichText( + text: TextSpan(children: [ + leadingSpan, + TextSpan(text: msg, style: textStyle), + ]), + ), + ), + ), + ); + } +} + +class _ToastWidget extends StatelessWidget { + const _ToastWidget({ + Key? key, + required this.widget, }) : super(key: key); - // 使用IgnorePointer,方便手势透传过去 + final Widget widget; + + /// 使用IgnorePointer,方便手势透传过去 @override Widget build(BuildContext context) { return IgnorePointer( - child: Material( - color: Colors.transparent, - child: widget, - ), + child: Material(color: Colors.transparent, child: widget), ); } } diff --git a/lib/src/constants/brn_asset_constants.dart b/lib/src/constants/brn_asset_constants.dart index f2850b54..abb01801 100644 --- a/lib/src/constants/brn_asset_constants.dart +++ b/lib/src/constants/brn_asset_constants.dart @@ -1,4 +1,6 @@ class BrnAsset { + const BrnAsset._(); + static const String emptyState = "images/empty_state.png"; static const String stepTitle = 'images/img_step_title.png'; @@ -19,165 +21,164 @@ class BrnAsset { static const String iconBottomPickerRightTopBg = "images/icon_bottom_picker_right_top_bg.png"; - static const String ICON_ARROWUP_SELECT = "images/icon_arrow_up_selected.png"; - static const String ICON_REFRESH = "assets/images/icon_refresh.png"; - static const String ICON_ARROWDOWN_SELECT = + static const String iconArrowUpSelect = "images/icon_arrow_up_selected.png"; + static const String iconRefresh = "assets/images/icon_refresh.png"; + static const String iconArrowDownSelect = "images/icon_arrow_down_selected.png"; - static const String ICON_ARROWDOWN_UNSELECT = + static const String iconArrowDownUnSelect = "images/icon_arrow_down_unselected.png"; - static const String ICON_ARROW_RIGHT_1 = "icons/icon_right_arrow_1.png"; - static const String SELECT_CHECKED_STATUS = + static const String iconArrowRight = "icons/icon_right_arrow_1.png"; + static const String selectCheckedStatus = "images/select_checked_status.png"; - static const String SELECT_NORMAL_STATUS = "icons/normol_border.png"; - static const String ICON_SELECTED_UP_TRIANGLE = + static const String selectNormalStatus = "icons/normol_border.png"; + static const String iconSelectedUpTriangle = "icons/icon_selcted_triangle.png"; - static const String ICON_UNSELECT_DOWN_TRIANGLE = + static const String iconUnSelectDownTriangle = "icons/icon_unselected_triangle.png"; - static const String ICON_REQUIRE_RED = 'icons/icon_require_red.png'; - static const String ICON_RIGHT_ARROW = 'icons/icon_right_arrow.png'; - static const String ICON_BACK_WHITE = 'assets/icons/icon_back_white.png'; - static const String ICON_BACK_BLACK = 'assets/icons/icon_back_black.png'; - static const String ICON_STEP_2 = 'icons/icon_step_2.png'; - static const String ICON_STEP_3 = 'icons/icon_step_3.png'; - static const String ICON_STEP_4 = 'icons/icon_step_4.png'; - static const String ICON_STEP_5 = 'icons/icon_step_5.png'; - static const String ICON_STEP_DOING = 'icons/icon_step_doing.png'; - static const String ICON_STEP_COMPLETED = 'icons/icon_step_completed.png'; - - static const String ICON_DELETE_TEXT = 'icons/ic_delete_grey.png'; - static const String ICON_SEARCH = 'icons/ic_search.png'; - - static const String ICON_POPUP_CLOSE = 'icons/icon_popup_close.png'; - static const String ICON_CLOSE = 'icons/icon_close.png'; - static const String ICON_CALENDAR_PRE_MONTH = + static const String iconRequireRed = 'icons/icon_require_red.png'; + static const String iconRightArrow = 'icons/icon_right_arrow.png'; + static const String iconBackWhite = 'assets/icons/icon_back_white.png'; + static const String iconBackBlack = 'assets/icons/icon_back_black.png'; + static const String iconStep2 = 'icons/icon_step_2.png'; + static const String iconStep3 = 'icons/icon_step_3.png'; + static const String iconStep4 = 'icons/icon_step_4.png'; + static const String iconStep5 = 'icons/icon_step_5.png'; + static const String iconStepDoing = 'icons/icon_step_doing.png'; + static const String iconStepCompleted = 'icons/icon_step_completed.png'; + + static const String iconDeleteText = 'icons/ic_delete_grey.png'; + static const String iconSearch = 'icons/ic_search.png'; + + static const String iconPopupClose = 'icons/icon_popup_close.png'; + static const String iconClose = 'icons/icon_close.png'; + static const String iconCalendarPreMonth = 'icons/icon_calendar_pre_month.png'; - static const String ICON_CALENDAR_NEXT_MONTH = + static const String iconCalendarNextMonth = 'icons/icon_calendar_next_month.png'; - static const String ICON_UP_ARROW = 'icons/icon_up_arrow.png'; - static const String ICON_DOWN_ARROW = 'icons/icon_down_arrow.png'; - static const String ICON_TRASH_BIN = 'icons/icon_trash.png'; - static const String ICON_STAR_UNSELECT = 'icons/icon_star_unselect.png'; - static const String ICON_STAR_SELECT = 'icons/icon_star_select.png'; - static const String ICON_ADD_FORM_ITEM = 'icons/icon_add_form_item.png'; - static const String ICON_REMOVE_FORM_ITEM = 'icons/icon_remove_form_item.png'; + static const String iconUpArrow = 'icons/icon_up_arrow.png'; + static const String iconDownArrow = 'icons/icon_down_arrow.png'; + static const String iconTrashBin = 'icons/icon_trash.png'; + static const String iconStarUnSelect = 'icons/icon_star_unselect.png'; + static const String iconStarSelect = 'icons/icon_star_select.png'; + static const String iconAddFormItem = 'icons/icon_add_form_item.png'; + static const String iconRemoveFormItem = 'icons/icon_remove_form_item.png'; - static const String ICON_TRIANGLE_DOWN = 'icons/icon_triangle_down.png'; - static const String ICON_TRIANGLE_UP = 'icons/icon_triangle_up.png'; + static const String iconTriangleDown = 'icons/icon_triangle_down.png'; + static const String iconTriangleUp = 'icons/icon_triangle_up.png'; - static const String ICON_PAIR_INFO_QUESTION = + static const String iconPairInfoQuestion = 'icons/icon_pait_info_question.png'; - static const String ICON_PICKER_CLOSE = 'images/icon_guanbi.png'; + static const String iconPickerClose = 'images/icon_guanbi.png'; - static const String ICON_NOTICE = 'icons/icon_notice.png'; - static const String ICON_NOTICE_ARROW_BLUE = + static const String iconNotice = 'icons/icon_notice.png'; + static const String iconNoticeArrowBlue = 'icons/icon_notice_arrow_blue.png'; - static const String ICON_NOTICE_ARROW_GREEN = + static const String iconNoticeArrowGreen = 'icons/icon_notice_arrow_green.png'; - static const String ICON_NOTICE_ARROW_ORANGE = + static const String iconNoticeArrowOrange = 'icons/icon_notice_arrow_orange.png'; - static const String ICON_NOTICE_ARROW_RED = 'icons/icon_notice_arrow_red.png'; - static const String ICON_NOTICE_CLOSE_BLUE = + static const String iconNoticeArrowRed = 'icons/icon_notice_arrow_red.png'; + static const String iconNoticeCloseBlue = 'icons/icon_notice_close_blue.png'; - static const String ICON_NOTICE_CLOSE_GREEN = + static const String iconNoticeCloseGreen = 'icons/icon_notice_close_green.png'; - static const String ICON_NOTICE_CLOSE_ORANGE = + static const String iconNoticeCloseOrange = 'icons/icon_notice_close_orange.png'; - static const String ICON_NOTICE_CLOSE_RED = 'icons/icon_notice_close_red.png'; - static const String ICON_NOTICE_FAIL = 'icons/icon_notice_fail.png'; - static const String ICON_NOTICE_RUNNING = 'icons/icon_notice_running.png'; - static const String ICON_NOTICE_SUCCEED = 'icons/icon_notice_succeed.png'; - static const String ICON_NOTICE_WARNING = 'icons/icon_notice_warning.png'; + static const String iconNoticeCloseRed = 'icons/icon_notice_close_red.png'; + static const String iconNoticeFail = 'icons/icon_notice_fail.png'; + static const String iconNoticeRunning = 'icons/icon_notice_running.png'; + static const String iconNoticeSucceed = 'icons/icon_notice_succeed.png'; + static const String iconNoticeWarning = 'icons/icon_notice_warning.png'; - static const String ICON_OPERATION_OTHER_RIGHT = + static const String iconOperationOtherRight = 'icons/icon_operation_line_right.png'; - static const String ICON_OPERATION_OTHER_LEFT = + static const String iconOperationOtherLeft = 'icons/icon_operation_line_left.png'; - static const String ICON_RESULT_SUCCESS = 'icons/icon_result_success.png'; - static const String ICON_RESULT_ERROR = 'icons/icon_result_error.png'; - static const String ICON_STAR = 'icons/icon_star.png'; - static const String ICON_STAR_HALF = 'icons/icon_star_half.png'; - static const String ICON_UPARROW = 'icons/icon_uparrow.png'; - static const String ICOS_QRCODE_BG = 'assets/images/icon_qrcode_bg.png'; - static const String ICONS_QRCODE_FAILED = + static const String iconResultSuccess = 'icons/icon_result_success.png'; + static const String iconResultError = 'icons/icon_result_error.png'; + static const String iconStar = 'icons/icon_star.png'; + static const String iconStarHalf = 'icons/icon_star_half.png'; + static const String iconQrCodeBg = 'assets/images/icon_qrcode_bg.png'; + static const String iconsQrCodeFailed = '/assets/images/icon_qrcode_failed.png'; - static const String ICONS_REFRESH_WHITE = + static const String iconsRefreshWhite = 'assets/images/icon_refresh_white.png'; - static const String ICONS_AVATAR_NEW = '/assets/icons/img_avatar_new.png'; + static const String iconsAvatarNew = '/assets/icons/img_avatar_new.png'; - static const String ICON_AUDIOPALYER_PLAY = 'icons/icon_audioplayer_play.png'; - static const String ICON_AUDIOPALYER_PAUSE = + static const String iconAudioPlayer = 'icons/icon_audioplayer_play.png'; + static const String iconAudioPlayerPause = 'icons/icon_audioplayer_pause.png'; - static const String ICON_GREY_PLACE_HOLDER = 'icons/grey_place_holder.png'; + static const String iconGreyPlaceHolder = 'icons/grey_place_holder.png'; - static const String ICON_QUOTATION_MARK = 'icons/ic_quotation_mark.png'; + static const String iconQuotationMark = 'icons/ic_quotation_mark.png'; - static const String IMG_BACKGROUND_CARD = 'images/img_bg_card.png'; + static const String imgBackgroundCard = 'images/img_bg_card.png'; - static const String IMG_BG_BLUR = 'images/img_bg_blur.png'; + static const String imgBgBlur = 'images/img_bg_blur.png'; /// 用于图片右上角删除icon 的展示 - static const String ICON_DELETE = 'icons/icon_delete.png'; + static const String iconDelete = 'icons/icon_delete.png'; - static const String ICON_IM = 'images/icon_im_blue.png'; - static const String ICON_CALL = 'images/icon_call.png'; - static const String ICON_CALL_DISABLE = 'images/icon_call_disable.png'; - static const String PERSON_PLACE_HOLDER = + static const String iconIm = 'images/icon_im_blue.png'; + static const String iconCall = 'images/icon_call.png'; + static const String iconCallDisable = 'images/icon_call_disable.png'; + static const String personPlaceHolder = 'packages/bruno/assets/icons/img_avatar_new.png'; /// radio组件,用于单选和多选 - static const String ICON_RADIO_MULTI_SELECTED = + static const String iconRadioMultiSelected = 'icons/radio/multiple_selected.png'; - static const String ICON_RADIO_UNSELECTED = 'icons/radio/unselected.png'; - static const String ICON_RADIO_DISABLE_MULTI_SELECTED = + static const String iconRadioUnSelected = 'icons/radio/unselected.png'; + static const String iconRadioDisableMultiSelected = 'icons/radio/disable_multi_selected.png'; - static const String ICON_RADIO_DISABLE_UNSELECTED = + static const String iconRadioDisableUnselected = 'icons/radio/disable_unselected.png'; - static const String ICON_RADIO_SINGLE_SELECTED = + static const String iconRadioSingleSelected = 'icons/radio/single_selected.png'; - static const String ICON_RADIO_DISABLE_SINGLE_SELECTED = + static const String iconRadioDisableSingleSelected = 'icons/radio/disable_single_selected.png'; /// 评价组件--表情 - static const String ICON_APPRAISE_BAD_UNSELECTED = + static const String iconAppraiseBadUnselected = 'assets/images/icon_appraise_bad_unselected.png'; - static const String ICON_APPRAISE_NOT_GOOD_UNSELECTED = + static const String iconAppraiseNotGoodUnselected = 'assets/images/icon_appraise_not_good_unselected.png'; - static const String ICON_APPRAISE_OK_UNSELECTED = + static const String iconAppraiseOkUnselected = 'assets/images/icon_appraise_ok_unselected.png'; - static const String ICON_APPRAISE_GOOD_UNSELECTED = + static const String iconAppraiseGoodUnselected = 'assets/images/icon_appraise_good_unselected.png'; - static const String ICON_APPRAISE_SURPRISE_UNSELECTED = + static const String iconAppraiseSurpriseUnselected = 'assets/images/icon_appraise_surprise_unselected.png'; - static const String ICON_APPRAISE_BAD_DEFAULT = + static const String iconAppraiseBadDefault = 'assets/images/icon_appraise_bad_default.png'; - static const String ICON_APPRAISE_NOT_GOOD_DEFAULT = + static const String iconAppraiseNotGoodDefault = 'assets/images/icon_appraise_not_good_default.png'; - static const String ICON_APPRAISE_OK_DEFAULT = + static const String iconAppraiseOkDefault = 'assets/images/icon_appraise_ok_default.png'; - static const String ICON_APPRAISE_GOOD_DEFAULT = + static const String iconAppraiseGoodDefault = 'assets/images/icon_appraise_good_default.png'; - static const String ICON_APPRAISE_SURPRISE_DEFAULT = + static const String iconAppraiseSurpriseDefault = 'assets/images/icon_appraise_surprise_default.png'; - static const String ICON_APPRAISE_BAD_SELECTED = + static const String iconAppraiseBadSelected = 'assets/images/icon_appraise_bad_selected.png'; - static const String ICON_APPRAISE_NOT_GOOD_SELECTED = + static const String iconAppraiseNotGoodSelected = 'assets/images/icon_appraise_not_good_selected.png'; - static const String ICON_APPRAISE_OK_SELECTED = + static const String iconAppraiseOkSelected = 'assets/images/icon_appraise_ok_selected.png'; - static const String ICON_APPRAISE_GOOD_SELECTED = + static const String iconAppraiseGoodSelected = 'assets/images/icon_appraise_good_selected.png'; - static const String ICON_APPRAISE_SURPRISE_SELECTED = + static const String iconAppraiseSurpriseSelected = 'assets/images/icon_appraise_surprise_selected.png'; - static const String ICON_QUESTION = "icons/icon_question.png"; + static const String iconQuestion = "icons/icon_question.png"; /// 录入项icon - static const String ICON_ADD_DISABLE = "icons/icon_add_disable.png"; - static const String ICON_ADD_ENABLE = "icons/icon_add_enable.png"; + static const String iconAddDisable = "icons/icon_add_disable.png"; + static const String iconAddEnable = "icons/icon_add_enable.png"; - static const String ICON_MINUS_DISABLE = "icons/icon_minus_disable.png"; - static const String ICON_MINUS_ENABLE = "icons/icon_minus_enable.png"; + static const String iconMinusDisable = "icons/icon_minus_disable.png"; + static const String iconMinusEnable = "icons/icon_minus_enable.png"; } diff --git a/lib/src/constants/brn_constants.dart b/lib/src/constants/brn_constants.dart index 88b37bbe..f08bee66 100644 --- a/lib/src/constants/brn_constants.dart +++ b/lib/src/constants/brn_constants.dart @@ -1,6 +1,6 @@ class BrnShareItemConstants { /// 分享渠道名称列表 - static const List shareItemTitleList = [ + static const List shareItemTitleList = [ "微信", "朋友圈", "QQ", @@ -14,7 +14,7 @@ class BrnShareItemConstants { ]; /// 分享渠道图片地址列表 - static const List shareItemImagePathList = [ + static const List shareItemImagePathList = [ "images/icon_share_weChat.png", "images/icon_share_moments.png", "images/icon_share_qq.png", @@ -28,7 +28,7 @@ class BrnShareItemConstants { ]; /// 不可点击的分享渠道图片地址列表 - static const List disableShareItemImagePathList = [ + static const List disableShareItemImagePathList = [ "images/icon_share_weChat_disable.png", "images/icon_share_moments_disable.png", "images/icon_share_qq_disble.png", @@ -42,39 +42,47 @@ class BrnShareItemConstants { ]; /// 微信 - static const int SHARE_WEIXIN = 0; + static const int shareWeiXin = 0; /// 朋友圈 - static const int SHARE_FRIEND = 1; + static const int shareFriend = 1; /// qq - static const int SHARE_QQ = 2; + static const int shareQQ = 2; /// qq空间 - static const int SHARE_QZONE = 3; + static const int shareQZone = 3; /// 微博 - static const int SHARE_WEIBO = 4; + static const int shareWeiBo = 4; /// 链接 - static const int SHARE_LINK = 5; + static const int shareLink = 5; /// 短信 - static const int SHARE_SMS = 6; + static const int shareSms = 6; /// 剪贴板 - static const int SHARE_COPY_LINK = 7; + static const int shareCopyLink = 7; /// 浏览器 - static const int SHARE_BROWSER = 8; + static const int shareBrowser = 8; /// 相册 - static const int SHARE_SAVE_IMAGE = 9; + static const int shareSaveImage = 9; /// 自定义 - static const int SHARE_CUSTOM = 100; + static const int shareCustom = 100; } class BrnSelectionConstant { - static const int MAX_SELECT_COUNT = 65535; + static const int maxSelectCount = 65535; } + +class BrnButtonConstant { + /// 默认水平间距 + static const double horizontalPadding = 6; + + /// 默认垂直间距 + static const double verticalPadding = 8; +} \ No newline at end of file diff --git a/lib/src/constants/brn_fonts_constants.dart b/lib/src/constants/brn_fonts_constants.dart new file mode 100644 index 00000000..a6ecea8c --- /dev/null +++ b/lib/src/constants/brn_fonts_constants.dart @@ -0,0 +1,10 @@ +class BrnFonts { + const BrnFonts._(); + + static const double f12 = 12; + static const double f14 = 14; + static const double f16 = 16; + static const double f18 = 18; + static const double f20 = 20; + static const double f22 = 22; +} diff --git a/lib/src/constants/brn_strings_constants.dart b/lib/src/constants/brn_strings_constants.dart index 9dab7f23..5928c255 100644 --- a/lib/src/constants/brn_strings_constants.dart +++ b/lib/src/constants/brn_strings_constants.dart @@ -1,5 +1,7 @@ class BrnStrings { - //加载获取assets资源需要 + const BrnStrings._(); + + /// 加载获取 assets 资源需要 static const String flutterPackageName = "bruno"; static const String getDateFailed = "获取数据失败,请重试"; @@ -7,4 +9,5 @@ class BrnStrings { static const String noData = "暂无数据"; static const String noSearchData = "暂无搜索结果"; static const String clickPageRetry = "请点击页面重试"; + static const String loadingContent = '加载中...'; } diff --git a/lib/src/theme/base/brn_base_config.dart b/lib/src/theme/base/brn_base_config.dart index 860c0005..ccb9ad60 100644 --- a/lib/src/theme/base/brn_base_config.dart +++ b/lib/src/theme/base/brn_base_config.dart @@ -3,39 +3,50 @@ import 'package:bruno/src/theme/configs/brn_common_config.dart'; /// 组件配置基类 abstract class BrnBaseConfig { - String configId; - - BrnCommonConfig _currentLevelCommonConfig; - - BrnBaseConfig( - {this.configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID, - bool autoFlatConfig = false}) { + BrnBaseConfig({ + String configId = GLOBAL_CONFIG_ID, + bool autoFlatConfig = false, + }) : _configId = configId { if (autoFlatConfig) { initThemeConfig(configId); } } + String get configId => _configId; + String _configId; + BrnCommonConfig? _currentLevelCommonConfig; + /// 部分代码示意如下: - /// cardTitleConfig.detailTextStyle.merge(BrnTextStyle( - /// color: commonConfig.colorTextBase, - /// fontSize: commonConfig.fontSizeBase, - /// ).merge(detailTextStyle)); - /// 第一步 以commonConfig字段为基础merge detailTextStyle detailTextStyle 字段优先级高 - /// 当detailTextStyle中字段(如:color)为null时会使用commonConfig.colorTextBase - /// 第二步 以默认上一级配置为基础merge 第一步结果,当第一步中字段(如:color)为空时 , - /// 使用上一层级配置的color(cardTitleConfig.detailTextStyle.color) - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { + /// + /// ```dart + /// cardTitleConfig.detailTextStyle.merge( + /// BrnTextStyle( + /// color: commonConfig.colorTextBase, + /// fontSize: commonConfig.fontSizeBase, + /// ).merge(detailTextStyle), + /// ); + /// + /// - 以 `commonConfig` 字段为基础 merge `detailTextStyle`。 + /// `detailTextStyle` 字段优先级高,当detailTextStyle中字段(如 color)为 null 时 + /// 会使用 `commonConfig.colorTextBase`。 + /// - 以默认上一级配置为基础 merge 第一步的结果,当第一步中字段(如 color)为空时, + /// 使用上一层级配置的 color (`cardTitleConfig.detailTextStyle.color`)。 + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { _currentLevelCommonConfig = currentLevelCommonConfig; } /// 当自定义组件的配置时调用 - /// 根据自定义时传入的configId对配置字段打平 + /// 根据自定义时传入的 [configId] 对配置字段打平 void initThemeConfigPersonal() { initThemeConfig(configId); } BrnCommonConfig get commonConfig => _currentLevelCommonConfig ?? - BrnThemeConfigurator.instance.getConfig(configId: configId).commonConfig; + BrnThemeConfigurator.instance + .getConfig(configId: configId) + .commonConfig; } diff --git a/lib/src/theme/base/brn_default_config_utils.dart b/lib/src/theme/base/brn_default_config_utils.dart index e781d0be..26b02abf 100644 --- a/lib/src/theme/base/brn_default_config_utils.dart +++ b/lib/src/theme/base/brn_default_config_utils.dart @@ -1,15 +1,18 @@ -import 'package:bruno/bruno.dart'; import 'package:bruno/src/components/navbar/brn_appbar_theme.dart'; import 'package:bruno/src/components/picker/base/brn_picker_constants.dart'; +import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/constants/brn_strings_constants.dart'; -import 'package:bruno/src/theme/brn_theme.dart'; -import 'package:bruno/src/theme/brn_theme_configurator.dart'; +import 'package:bruno/src/theme/base/brn_text_style.dart'; +import 'package:bruno/src/theme/brn_theme_configurator.dart' + show BRUNO_CONFIG_ID; import 'package:bruno/src/theme/configs/brn_abnormal_state_config.dart'; import 'package:bruno/src/theme/configs/brn_action_sheet_config.dart'; +import 'package:bruno/src/theme/configs/brn_all_config.dart'; import 'package:bruno/src/theme/configs/brn_appbar_config.dart'; import 'package:bruno/src/theme/configs/brn_button_config.dart'; import 'package:bruno/src/theme/configs/brn_card_title_config.dart'; import 'package:bruno/src/theme/configs/brn_common_config.dart'; +import 'package:bruno/src/theme/configs/brn_dialog_config.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:bruno/src/theme/configs/brn_gallery_detail_config.dart'; import 'package:bruno/src/theme/configs/brn_enhance_number_card_config.dart'; @@ -23,24 +26,30 @@ import 'package:flutter/services.dart'; /// Bruno默认配置 class BrnDefaultConfigUtils { - /// 默认全局配置 + const BrnDefaultConfigUtils._(); + + /// 默认全局配置 static BrnAllThemeConfig defaultAllConfig = BrnAllThemeConfig( - commonConfig: defaultCommonConfig, - formItemConfig: defaultFormItemConfig, - dialogConfig: defaultDialogConfig, - cardTitleConfig: defaultCardTitleConfig, - abnormalStateConfig: defaultAbnormalStateConfig, - tagConfig: defaultTagConfig, - appBarConfig: defaultAppBarConfig, - pairInfoTableConfig: defaultPairInfoTableConfig, - pairRichInfoGridConfig: defaultPairRichInfoGridConfig, - buttonConfig: defaultButtonConfig, - actionSheetConfig: defaultActionSheetConfig, - pickerConfig: defaultPickerConfig, - enhanceNumberCardConfig: defaultNumberInfoConfig, - tabBarConfig: defaultTabBarConfig, - selectionConfig: defaultSelectionConfig, - galleryDetailConfig: defaultGalleryDetailConfig); + commonConfig: defaultCommonConfig, + formItemConfig: defaultFormItemConfig, + dialogConfig: defaultDialogConfig, + cardTitleConfig: defaultCardTitleConfig, + abnormalStateConfig: defaultAbnormalStateConfig, + tagConfig: defaultTagConfig, + appBarConfig: defaultAppBarConfig, + pairInfoTableConfig: defaultPairInfoTableConfig, + pairRichInfoGridConfig: defaultPairRichInfoGridConfig, + buttonConfig: defaultButtonConfig, + actionSheetConfig: defaultActionSheetConfig, + pickerConfig: defaultPickerConfig, + enhanceNumberCardConfig: defaultEnhanceNumberInfoConfig, + tabBarConfig: defaultTabBarConfig, + selectionConfig: defaultSelectionConfig, + galleryDetailConfig: defaultGalleryDetailConfig, + ); + + + /// 全局默认配置 static BrnCommonConfig defaultCommonConfig = BrnCommonConfig( @@ -113,29 +122,29 @@ class BrnDefaultConfigUtils { /// 文本字号 /// /// 特殊数据展示,Bebas 数字字体,用于强吸引 - fontSizeBebas: 28, + fontSizeBebas: 28.0, /// 标题字体 /// 名称/页面大标题 - fontSizeHeadLg: 22, + fontSizeHeadLg: 22.0, /// 标题字体 /// 内容模块标题/一级标题 - fontSizeHead: 18, + fontSizeHead: 18.0, /// 子标题字体 /// 标题/录入文字/大按钮文字/二级标题 - fontSizeSubHead: 16, + fontSizeSubHead: 16.0, /// 基础字体 /// 内容副文本/普通说明文字 - fontSizeBase: 14, + fontSizeBase: 14.0, /// 辅助字体-普通 - fontSizeCaption: 12, + fontSizeCaption: 12.0, ///辅助字体-小 - fontSizeCaptionSm: 11, + fontSizeCaptionSm: 11.0, /// 圆角尺寸 radiusXs: 2.0, @@ -145,31 +154,31 @@ class BrnDefaultConfigUtils { /// 边框尺寸 borderWidthSm: 0.5, - borderWidthMd: 1, - borderWidthLg: 2, + borderWidthMd: 1.0, + borderWidthLg: 2.0, /// 水平间距 - hSpacingXs: 8, - hSpacingSm: 12, - hSpacingMd: 16, - hSpacingLg: 20, - hSpacingXl: 24, - hSpacingXxl: 42, + hSpacingXs: 8.0, + hSpacingSm: 12.0, + hSpacingMd: 16.0, + hSpacingLg: 20.0, + hSpacingXl: 24.0, + hSpacingXxl: 42.0, /// 垂直间距 - vSpacingXs: 4, - vSpacingSm: 8, - vSpacingMd: 12, - vSpacingLg: 14, - vSpacingXl: 16, - vSpacingXxl: 28, + vSpacingXs: 4.0, + vSpacingSm: 8.0, + vSpacingMd: 12.0, + vSpacingLg: 14.0, + vSpacingXl: 16.0, + vSpacingXxl: 28.0, /// 图标大小 - iconSizeXxs: 8, - iconSizeXs: 12, - iconSizeSm: 14, - iconSizeMd: 16, - iconSizeLg: 32, + iconSizeXxs: 8.0, + iconSizeXs: 12.0, + iconSizeSm: 14.0, + iconSizeMd: 16.0, + iconSizeLg: 32.0, ); ///******** 以下是子配置项 ********/// @@ -177,140 +186,167 @@ class BrnDefaultConfigUtils { /// 表单项默认配置 static BrnFormItemConfig defaultFormItemConfig = BrnFormItemConfig( headTitleTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeHead), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeHead, + ), titleTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeSubHead), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead, + ), subTitleTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextSecondary, - fontSize: defaultCommonConfig.fontSizeCaption), + color: defaultCommonConfig.colorTextSecondary, + fontSize: defaultCommonConfig.fontSizeCaption, + ), errorTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandError, - fontSize: defaultCommonConfig.fontSizeCaption), + color: defaultCommonConfig.brandError, + fontSize: defaultCommonConfig.fontSizeCaption, + ), hintTextStyle: BrnTextStyle( color: defaultCommonConfig.colorTextHint, fontSize: defaultCommonConfig.fontSizeSubHead, ), contentTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeSubHead), - optionsMiddlePadding: EdgeInsets.only(left: defaultCommonConfig.hSpacingMd), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead, + ), + optionsMiddlePadding: EdgeInsets.only( + left: defaultCommonConfig.hSpacingMd, + ), optionTextStyle: BrnTextStyle( - height: 1.3, - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeSubHead), + height: 1.3, + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead, + ), optionSelectedTextStyle: BrnTextStyle( - height: 1.3, - color: defaultCommonConfig.brandPrimary, - fontSize: defaultCommonConfig.fontSizeSubHead), + height: 1.3, + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeSubHead, + ), formPadding: EdgeInsets.only( - left: 0, - top: defaultCommonConfig.vSpacingLg, - right: defaultCommonConfig.hSpacingLg, - bottom: defaultCommonConfig.vSpacingLg), + left: 0.0, + top: defaultCommonConfig.vSpacingLg , + right: defaultCommonConfig.hSpacingLg , + bottom: defaultCommonConfig.vSpacingLg, + ), titlePaddingSm: EdgeInsets.only(left: 10), titlePaddingLg: EdgeInsets.only(left: defaultCommonConfig.hSpacingLg), subTitlePadding: EdgeInsets.only( - left: defaultCommonConfig.hSpacingLg, - top: defaultCommonConfig.vSpacingXs), + left: defaultCommonConfig.hSpacingLg, + top: defaultCommonConfig.vSpacingXs, + ), errorPadding: EdgeInsets.only( - left: defaultCommonConfig.hSpacingLg, - top: defaultCommonConfig.vSpacingXs), + left: defaultCommonConfig.hSpacingLg, + top: defaultCommonConfig.vSpacingXs, + ), disableTextStyle: BrnTextStyle( color: defaultCommonConfig.colorTextDisabled, fontSize: defaultCommonConfig.fontSizeSubHead, ), tipsTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextSecondary, - fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextSecondary, + fontSize: defaultCommonConfig.fontSizeBase, + ), ); /// Dialog默认配置 static BrnDialogConfig defaultDialogConfig = BrnDialogConfig( - dialogWidth: 300, - radius: defaultCommonConfig.radiusLg, - iconPadding: EdgeInsets.only(top: defaultCommonConfig.vSpacingXxl), - titlePaddingSm: EdgeInsets.only( - top: 12, - left: defaultCommonConfig.hSpacingXxl, - right: defaultCommonConfig.hSpacingXxl), - titlePaddingLg: EdgeInsets.only( - top: 28, - left: defaultCommonConfig.hSpacingXxl, - right: defaultCommonConfig.hSpacingXxl), - titleTextStyle: BrnTextStyle( - fontWeight: FontWeight.w600, - fontSize: defaultCommonConfig.fontSizeHead, - color: defaultCommonConfig.colorTextBase), - titleTextAlign: TextAlign.center, - contentPaddingSm: EdgeInsets.only( - top: 8, - left: defaultCommonConfig.hSpacingXl, - right: defaultCommonConfig.hSpacingXl), - contentPaddingLg: EdgeInsets.only( - top: 28, - left: defaultCommonConfig.hSpacingXl, - right: defaultCommonConfig.hSpacingXl), - contentTextStyle: BrnTextStyle( - fontSize: defaultCommonConfig.fontSizeBase, - color: defaultCommonConfig.colorTextImportant, - decoration: TextDecoration.none, - ), - contentTextAlign: TextAlign.center, - warningPaddingSm: EdgeInsets.only( - top: 6, - left: defaultCommonConfig.hSpacingXl, - right: defaultCommonConfig.hSpacingXl), - warningPaddingLg: EdgeInsets.only( - top: 28, - left: defaultCommonConfig.hSpacingXl, - right: defaultCommonConfig.hSpacingXl), - warningTextAlign: TextAlign.center, - warningTextStyle: BrnTextStyle( - fontSize: defaultCommonConfig.fontSizeBase, - color: defaultCommonConfig.brandError, - decoration: TextDecoration.none, - ), - dividerPadding: EdgeInsets.only(top: 28), - mainActionTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, - fontWeight: FontWeight.w600, - fontSize: defaultCommonConfig.fontSizeSubHead), - assistActionsTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontWeight: FontWeight.w600, - fontSize: defaultCommonConfig.fontSizeSubHead), - mainActionBackgroundColor: defaultCommonConfig.fillBase, - assistActionsBackgroundColor: defaultCommonConfig.fillBase, - bottomHeight: 44.0, - backgroundColor: defaultCommonConfig.fillBase); + dialogWidth: 300.0, + radius: defaultCommonConfig.radiusLg, + iconPadding: EdgeInsets.only(top: defaultCommonConfig.vSpacingXxl), + titlePaddingSm: EdgeInsets.only( + top: 12.0, + left: defaultCommonConfig.hSpacingXxl, + right: defaultCommonConfig.hSpacingXxl, + ), + titlePaddingLg: EdgeInsets.only( + top: 28.0, + left: defaultCommonConfig.hSpacingXxl, + right: defaultCommonConfig.hSpacingXxl, + ), + titleTextStyle: BrnTextStyle( + fontWeight: FontWeight.w600, + fontSize: defaultCommonConfig.fontSizeHead, + color: defaultCommonConfig.colorTextBase, + ), + titleTextAlign: TextAlign.center, + contentPaddingSm: EdgeInsets.only( + top: 8.0, + left: defaultCommonConfig.hSpacingXl, + right: defaultCommonConfig.hSpacingXl, + ), + contentPaddingLg: EdgeInsets.only( + top: 28.0, + left: defaultCommonConfig.hSpacingXl, + right: defaultCommonConfig.hSpacingXl, + ), + contentTextStyle: BrnTextStyle( + fontSize: defaultCommonConfig.fontSizeBase, + color: defaultCommonConfig.colorTextImportant, + decoration: TextDecoration.none, + ), + contentTextAlign: TextAlign.center, + warningPaddingSm: EdgeInsets.only( + top: 6.0, + left: defaultCommonConfig.hSpacingXl, + right: defaultCommonConfig.hSpacingXl, + ), + warningPaddingLg: EdgeInsets.only( + top: 28.0, + left: defaultCommonConfig.hSpacingXl, + right: defaultCommonConfig.hSpacingXl, + ), + warningTextAlign: TextAlign.center, + warningTextStyle: BrnTextStyle( + fontSize: defaultCommonConfig.fontSizeBase, + color: defaultCommonConfig.brandError, + decoration: TextDecoration.none, + ), + dividerPadding: EdgeInsets.only(top: 28.0), + mainActionTextStyle: BrnTextStyle( + color: defaultCommonConfig.brandPrimary, + fontWeight: FontWeight.w600, + fontSize: defaultCommonConfig.fontSizeSubHead, + ), + assistActionsTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBase, + fontWeight: FontWeight.w600, + fontSize: defaultCommonConfig.fontSizeSubHead, + ), + mainActionBackgroundColor: defaultCommonConfig.fillBase, + assistActionsBackgroundColor: defaultCommonConfig.fillBase, + bottomHeight: 44.0, + backgroundColor: defaultCommonConfig.fillBase, + ); /// 卡片标题配置 static BrnCardTitleConfig defaultCardTitleConfig = BrnCardTitleConfig( titleWithHeightTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeHead, - height: 25 / 18, - fontWeight: FontWeight.w600), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeHead, + height: 25.0 / 18.0, + fontWeight: FontWeight.w600, + ), titleTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeHead, - fontWeight: FontWeight.w600), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeHead, + fontWeight: FontWeight.w600, + ), subtitleTextStyle: BrnTextStyle( color: defaultCommonConfig.colorTextSecondary, fontSize: defaultCommonConfig.fontSizeBase, ), detailTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeBase, + ), accessoryTextStyle: BrnTextStyle( color: defaultCommonConfig.colorTextSecondary, fontSize: defaultCommonConfig.fontSizeBase, ), cardTitlePadding: EdgeInsets.only( - top: defaultCommonConfig.vSpacingXl, - bottom: defaultCommonConfig.vSpacingMd), + top: defaultCommonConfig.vSpacingXl, + bottom: defaultCommonConfig.vSpacingMd, + ), alignment: PlaceholderAlignment.middle, cardBackgroundColor: defaultCommonConfig.fillBase, ); @@ -318,69 +354,81 @@ class BrnDefaultConfigUtils { /// 空页面配置 static BrnAbnormalStateConfig defaultAbnormalStateConfig = BrnAbnormalStateConfig( - titleTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeSubHead, - fontWeight: FontWeight.w600), - contentTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextHint, - fontSize: defaultCommonConfig.fontSizeBase), - operateTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, - fontSize: defaultCommonConfig.fontSizeBase), - btnRadius: 4, - doubleBrnTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, - fontSize: defaultCommonConfig.fontSizeSubHead), - singleBrnTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBaseInverse, - fontSize: defaultCommonConfig.fontSizeSubHead, - ), - singleMinWidth: 160, - doubleMinWidth: 120); + titleTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead, + fontWeight: FontWeight.w600, + ), + contentTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextHint, + fontSize: defaultCommonConfig.fontSizeBase, + ), + operateTextStyle: BrnTextStyle( + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeBase, + ), + btnRadius: 4, + doubleTextStyle: BrnTextStyle( + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeSubHead, + ), + singleTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBaseInverse, + fontSize: defaultCommonConfig.fontSizeSubHead, + ), + singleMinWidth: 160.0, + doubleMinWidth: 120.0, + ); /// 标签配置 static BrnTagConfig defaultTagConfig = BrnTagConfig( - tagTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeCaption), - selectTagTextStyle: BrnTextStyle( - fontWeight: FontWeight.w600, - color: defaultCommonConfig.brandPrimary, - fontSize: defaultCommonConfig.fontSizeCaption), - tagBackgroundColor: defaultCommonConfig.fillBody, - selectedTagBackgroundColor: defaultCommonConfig.brandPrimary, - tagRadius: defaultCommonConfig.radiusXs, - tagHeight: 34, - tagWidth: 75, - tagMinWidth: 75); + tagTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeCaption, + ), + selectTagTextStyle: BrnTextStyle( + fontWeight: FontWeight.w600, + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeCaption, + ), + tagBackgroundColor: defaultCommonConfig.fillBody, + selectedTagBackgroundColor: defaultCommonConfig.brandPrimary, + tagRadius: defaultCommonConfig.radiusXs, + tagHeight: 34.0, + tagWidth: 75.0, + tagMinWidth: 75.0, + ); + /// 导航栏配置 static BrnAppBarConfig defaultAppBarConfig = BrnAppBarConfig( - backgroundColor: Colors.white, - appBarHeight: BrnAppBarTheme.appBarHeight, - leadIconBuilder: () => Image.asset( - BrnAsset.ICON_BACK_BLACK, - package: BrnStrings.flutterPackageName, - width: BrnAppBarTheme.iconSize, - height: BrnAppBarTheme.iconSize, - fit: BoxFit.fitHeight, - ), - titleStyle: BrnTextStyle( - fontSize: BrnAppBarTheme.titleFontSize, - fontWeight: FontWeight.w600, - color: BrnAppBarTheme.lightTextColor), - actionsStyle: BrnTextStyle( - color: BrnAppBarTheme.lightTextColor, - fontSize: BrnAppBarTheme.actionFontSize, - fontWeight: FontWeight.w600), - titleMaxLength: BrnAppBarTheme.maxLength, - leftAndRightPadding: 20, - itemSpacing: BrnAppBarTheme.iconMargin, - titlePadding: EdgeInsets.zero, - iconSize: BrnAppBarTheme.iconSize, - configId: BrnThemeConfigurator.BRUNO_CONFIG_ID, - systemUiOverlayStyle: SystemUiOverlayStyle.dark); + backgroundColor: Colors.white, + appBarHeight: BrnAppBarTheme.appBarHeight, + leadIconBuilder: () => Image.asset( + BrnAsset.iconBackBlack, + package: BrnStrings.flutterPackageName, + width: BrnAppBarTheme.iconSize, + height: BrnAppBarTheme.iconSize, + fit: BoxFit.fitHeight, + ), + titleStyle: BrnTextStyle( + fontSize: BrnAppBarTheme.titleFontSize, + fontWeight: FontWeight.w600, + color: BrnAppBarTheme.lightTextColor, + ), + actionsStyle: BrnTextStyle( + color: BrnAppBarTheme.lightTextColor, + fontSize: BrnAppBarTheme.actionFontSize, + fontWeight: FontWeight.w600, + ), + titleMaxLength: BrnAppBarTheme.maxLength, + leftAndRightPadding: 20.0, + itemSpacing: BrnAppBarTheme.iconMargin, + titlePadding: EdgeInsets.zero, + iconSize: BrnAppBarTheme.iconSize, + configId: BRUNO_CONFIG_ID, + systemUiOverlayStyle: SystemUiOverlayStyle.dark, + ); /// 内容信息(两列)配置 static BrnPairInfoTableConfig defaultPairInfoTableConfig = @@ -388,63 +436,71 @@ class BrnDefaultConfigUtils { rowSpacing: 4, itemSpacing: 2, keyTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextSecondary, - fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextSecondary, + fontSize: defaultCommonConfig.fontSizeBase, + ), valueTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeBase, + ), linkTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, - fontSize: defaultCommonConfig.fontSizeBase), - configId: BrnThemeConfigurator.BRUNO_CONFIG_ID, + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeBase, + ), + configId: BRUNO_CONFIG_ID, ); /// 内容信息(一列)配置 static BrnPairRichInfoGridConfig defaultPairRichInfoGridConfig = BrnPairRichInfoGridConfig( - rowSpacing: 4, - itemSpacing: 2, - itemHeight: 20, + rowSpacing: 4.0, + itemSpacing: 2.0, + itemHeight: 20.0, keyTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextSecondary, - fontSize: defaultCommonConfig.fontSizeBase, - textBaseline: TextBaseline.ideographic), + color: defaultCommonConfig.colorTextSecondary, + fontSize: defaultCommonConfig.fontSizeBase, + textBaseline: TextBaseline.ideographic, + ), valueTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeBase, - textBaseline: TextBaseline.ideographic), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeBase, + textBaseline: TextBaseline.ideographic, + ), linkTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, - fontSize: defaultCommonConfig.fontSizeBase, - textBaseline: TextBaseline.ideographic), - configId: BrnThemeConfigurator.BRUNO_CONFIG_ID, + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeBase, + textBaseline: TextBaseline.ideographic, + ), + configId: BRUNO_CONFIG_ID, ); /// 按钮配置 static BrnButtonConfig defaultButtonConfig = BrnButtonConfig( - bigButtonRadius: 6, - bigButtonHeight: 48, - bigButtonFontSize: 16, - smallButtonRadius: 4, - smallButtonHeight: 32, - smallButtonFontSize: 14, - configId: BrnThemeConfigurator.BRUNO_CONFIG_ID, + bigButtonRadius: 6.0, + bigButtonHeight: 48.0, + bigButtonFontSize: 16.0, + smallButtonRadius: 4.0, + smallButtonHeight: 32.0, + smallButtonFontSize: 14.0, + configId: BRUNO_CONFIG_ID, ); static BrnActionSheetConfig defaultActionSheetConfig = BrnActionSheetConfig( topRadius: defaultCommonConfig.radiusLg, titleStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextSecondary, - fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextSecondary, + fontSize: defaultCommonConfig.fontSizeBase, + ), itemTitleStyle: BrnTextStyle( color: defaultCommonConfig.colorTextBase, fontSize: defaultCommonConfig.fontSizeSubHead, fontWeight: FontWeight.w600, ), itemTitleStyleLink: BrnTextStyle( - fontSize: defaultCommonConfig.fontSizeSubHead, - fontWeight: FontWeight.w600, - color: defaultCommonConfig.colorLink), + fontSize: defaultCommonConfig.fontSizeSubHead, + fontWeight: FontWeight.w600, + color: defaultCommonConfig.colorLink, + ), itemTitleStyleAlert: BrnTextStyle( color: defaultCommonConfig.brandError, fontSize: defaultCommonConfig.fontSizeSubHead, @@ -470,30 +526,34 @@ class BrnDefaultConfigUtils { fontSize: defaultCommonConfig.fontSizeSubHead, fontWeight: FontWeight.w600, ), - titlePadding: EdgeInsets.only(top: 16, bottom: 16, left: 60, right: 60), - contentPadding: EdgeInsets.only(top: 12, bottom: 12, left: 60, right: 60), + titlePadding: EdgeInsets.symmetric(horizontal: 60.0, vertical: 16.0), + contentPadding: EdgeInsets.symmetric(horizontal: 60.0, vertical: 12.0), ); static BrnPickerConfig defaultPickerConfig = BrnPickerConfig( - backgroundColor: PICKER_BACKGROUND_COLOR, + backgroundColor: pickerBackgroundColor, cancelTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeSubHead), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead, + ), confirmTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, - fontSize: defaultCommonConfig.fontSizeSubHead), + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeSubHead, + ), titleTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeSubHead, - fontWeight: FontWeight.w600, - decoration: TextDecoration.none), - pickerHeight: PICKER_HEIGHT, - titleHeight: PICKER_TITLE_HEIGHT, - itemHeight: PICKER_ITEM_HEIGHT, + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead, + fontWeight: FontWeight.w600, + decoration: TextDecoration.none, + ), + pickerHeight: pickerHeight, + titleHeight: pickerTitleHeight, + itemHeight: pickerItemHeight, dividerColor: Color(0xFFF0F0F0), itemTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeHead), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeHead, + ), itemTextSelectedStyle: BrnTextStyle( color: defaultCommonConfig.brandPrimary, fontSize: defaultCommonConfig.fontSizeHead, @@ -503,119 +563,139 @@ class BrnDefaultConfigUtils { ); /// 数字增强信息配置 - static BrnEnhanceNumberCardConfig defaultNumberInfoConfig = + static BrnEnhanceNumberCardConfig defaultEnhanceNumberInfoConfig = BrnEnhanceNumberCardConfig( - runningSpace: 16, - itemRunningSpace: 8, - titleTextStyle: BrnTextStyle(fontSize: 28, fontWeight: FontWeight.w500), + runningSpace: 16.0, + itemRunningSpace: 8.0, + titleTextStyle: BrnTextStyle(fontSize: 28.0, fontWeight: FontWeight.w500), descTextStyle: BrnTextStyle( - fontSize: 12, color: defaultCommonConfig.colorTextSecondary), + fontSize: 12.0, + color: defaultCommonConfig.colorTextSecondary, + ), dividerWidth: 0.5, ); /// TabBar配置 static BrnTabBarConfig defaultTabBarConfig = BrnTabBarConfig( - tabHeight: 50, - indicatorHeight: 2, - indicatorWidth: 24, + backgroundColor: Colors.white, + tabHeight: 50.0, + indicatorHeight: 2.0, + indicatorWidth: 24.0, labelStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, - fontSize: defaultCommonConfig.fontSizeSubHead, - fontWeight: FontWeight.w600), + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeSubHead, + fontWeight: FontWeight.w600, + ), unselectedLabelStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeSubHead, - fontWeight: FontWeight.normal), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead, + fontWeight: FontWeight.normal, + ), tagRadius: defaultCommonConfig.radiusSm, tagNormalTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeCaption), - tagNormalBgColor: defaultCommonConfig.brandPrimary.withAlpha(0x14), + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeCaption, + ), + tagNormalBgColor: defaultCommonConfig.fillBody, tagSelectedTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, - fontSize: defaultCommonConfig.fontSizeCaption), - tagSelectedBgColor: defaultCommonConfig.fillBody, - tagSpacing: 12, + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeCaption, + ), + tagSelectedBgColor: defaultCommonConfig.brandPrimary.withAlpha(0x14), + tagSpacing: 12.0, preLineTagCount: 4, - tagHeight: 32, + tagHeight: 32.0, ); /// 筛选项配置 static BrnSelectionConfig defaultSelectionConfig = BrnSelectionConfig( - menuNormalTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeBase), - menuSelectedTextStyle: BrnTextStyle( - fontWeight: FontWeight.w600, - fontSize: defaultCommonConfig.fontSizeBase, - color: defaultCommonConfig.brandPrimary), - tagNormalTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeCaption), - tagSelectedTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, - fontSize: defaultCommonConfig.fontSizeCaption, - fontWeight: FontWeight.w600, - ), - tagRadius: defaultCommonConfig.radiusSm, - tagNormalBackgroundColor: defaultCommonConfig.fillBody, - tagSelectedBackgroundColor: - defaultCommonConfig.brandPrimary.withOpacity(0.12), - rangeTitleTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeSubHead, - fontWeight: FontWeight.w600), - hintTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextHint, - fontSize: defaultCommonConfig.fontSizeBase), - inputTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeBase), - itemNormalTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeBase), - itemSelectedTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, - fontSize: defaultCommonConfig.fontSizeBase, - fontWeight: FontWeight.w600, - ), - itemBoldTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeBase, - fontWeight: FontWeight.w600, - ), - lightSelectBgColor: Colors.white, - lightNormalBgColor: Colors.white, - middleSelectBgColor: Colors.white, - middleNormalBgColor: Color(0xFFF8F8F8), - deepSelectBgColor: Color(0xFFF8F8F8), - deepNormalBgColor: Color(0xFFF0F0F0), - resetTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextImportant, - fontSize: defaultCommonConfig.fontSizeCaption), - titleForMoreTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeBase, - fontWeight: FontWeight.w600, - ), - optionTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, - fontSize: defaultCommonConfig.fontSizeBase), - moreTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextSecondary, - fontSize: defaultCommonConfig.fontSizeCaption, - ), - flayNormalTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeSubHead), - flatSelectedTextStyle: BrnTextStyle( - color: defaultCommonConfig.brandPrimary, - fontSize: defaultCommonConfig.fontSizeSubHead, - fontWeight: FontWeight.w600), - flatBoldTextStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBase, - fontSize: defaultCommonConfig.fontSizeSubHead, - fontWeight: FontWeight.w600)); + menuNormalTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeBase, + ), + menuSelectedTextStyle: BrnTextStyle( + fontWeight: FontWeight.w600, + fontSize: defaultCommonConfig.fontSizeBase, + color: defaultCommonConfig.brandPrimary, + ), + tagNormalTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeCaption, + ), + tagSelectedTextStyle: BrnTextStyle( + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeCaption, + fontWeight: FontWeight.w600, + ), + tagRadius: defaultCommonConfig.radiusSm, + tagNormalBackgroundColor: defaultCommonConfig.fillBody, + tagSelectedBackgroundColor: + defaultCommonConfig.brandPrimary.withOpacity(0.12), + rangeTitleTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead, + fontWeight: FontWeight.w600, + ), + hintTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextHint, + fontSize: defaultCommonConfig.fontSizeBase, + ), + inputTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeBase, + ), + itemNormalTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeBase, + ), + itemSelectedTextStyle: BrnTextStyle( + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeBase, + fontWeight: FontWeight.w600, + ), + itemBoldTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeBase, + fontWeight: FontWeight.w600, + ), + lightSelectBgColor: Colors.white, + lightNormalBgColor: Colors.white, + middleSelectBgColor: Colors.white, + middleNormalBgColor: Color(0xFFF8F8F8), + deepSelectBgColor: Color(0xFFF8F8F8), + deepNormalBgColor: Color(0xFFF0F0F0), + resetTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextImportant, + fontSize: defaultCommonConfig.fontSizeCaption, + ), + titleForMoreTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeBase, + fontWeight: FontWeight.w600, + ), + optionTextStyle: BrnTextStyle( + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeBase, + ), + moreTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextSecondary, + fontSize: defaultCommonConfig.fontSizeCaption, + ), + flayerNormalTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead, + ), + flayerSelectedTextStyle: BrnTextStyle( + color: defaultCommonConfig.brandPrimary, + fontSize: defaultCommonConfig.fontSizeSubHead, + fontWeight: FontWeight.w600, + ), + flayerBoldTextStyle: BrnTextStyle( + color: defaultCommonConfig.colorTextBase, + fontSize: defaultCommonConfig.fontSizeSubHead, + fontWeight: FontWeight.w600, + ), + ); /// 查看图片配置 static BrnGalleryDetailConfig defaultGalleryDetailConfig = @@ -626,29 +706,37 @@ class BrnDefaultConfigUtils { fontWeight: FontWeight.w600, ), appbarActionStyle: BrnTextStyle( - color: BrnAppBarTheme.lightTextColor, - fontSize: BrnAppBarTheme.actionFontSize, - fontWeight: FontWeight.w600), + color: BrnAppBarTheme.lightTextColor, + fontSize: BrnAppBarTheme.actionFontSize, + fontWeight: FontWeight.w600, + ), appbarBackgroundColor: Colors.black, appbarBrightness: Brightness.dark, - tabBarUnSelectedLabelStyle: - BrnTextStyle(fontSize: 16, color: Color(0XFFCCCCCC)), + tabBarUnSelectedLabelStyle: BrnTextStyle( + fontSize: 16.0, + color: Color(0XFFCCCCCC), + ), tabBarLabelStyle: BrnTextStyle( - fontSize: defaultCommonConfig.fontSizeSubHead, - fontWeight: FontWeight.w600, - color: defaultCommonConfig.colorTextBaseInverse), + fontSize: defaultCommonConfig.fontSizeSubHead, + fontWeight: FontWeight.w600, + color: defaultCommonConfig.colorTextBaseInverse, + ), tabBarBackgroundColor: Colors.black, pageBackgroundColor: Colors.black, bottomBackgroundColor: Color(0X88000000), titleStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBaseInverse, - fontSize: defaultCommonConfig.fontSizeHead, - fontWeight: FontWeight.w600), + color: defaultCommonConfig.colorTextBaseInverse, + fontSize: defaultCommonConfig.fontSizeHead, + fontWeight: FontWeight.w600, + ), contentStyle: BrnTextStyle( - color: Color(0xFFCCCCCC), fontSize: defaultCommonConfig.fontSizeBase), + color: Color(0xFFCCCCCC), + fontSize: defaultCommonConfig.fontSizeBase, + ), actionStyle: BrnTextStyle( - color: defaultCommonConfig.colorTextBaseInverse, - fontSize: defaultCommonConfig.fontSizeBase), + color: defaultCommonConfig.colorTextBaseInverse, + fontSize: defaultCommonConfig.fontSizeBase, + ), iconColor: Colors.white, ); } diff --git a/lib/src/theme/base/brn_text_style.dart b/lib/src/theme/base/brn_text_style.dart index 967027eb..dad190b7 100644 --- a/lib/src/theme/base/brn_text_style.dart +++ b/lib/src/theme/base/brn_text_style.dart @@ -2,14 +2,6 @@ import 'package:flutter/material.dart'; /// TextStyle处理类 用来将内部属性重新赋值进行copyWith 和 merge操作 class BrnTextStyle { - @required - Color color; - double fontSize; - FontWeight fontWeight; - TextDecoration decoration; - double height; - TextBaseline textBaseline; - BrnTextStyle({ this.color, this.fontSize, @@ -19,28 +11,23 @@ class BrnTextStyle { this.height, }); - BrnTextStyle.withStyle(TextStyle style) { + Color? color; + double? fontSize; + FontWeight? fontWeight; + TextDecoration? decoration; + double? height; + TextBaseline? textBaseline; + + BrnTextStyle.withStyle(TextStyle? style) { if (style == null) { return; } - if (style.color != null) { - this.color = style.color; - } - if (style.fontSize != null) { - this.fontSize = style.fontSize; - } - if (style?.fontWeight != null) { - this.fontWeight = style.fontWeight; - } - if (style?.decoration != null) { - this.decoration = style.decoration; - } - if (style?.height != null) { - this.height = style.height; - } - if (style?.textBaseline != null) { - this.textBaseline = style.textBaseline; - } + color = style.color ?? color; + fontSize = style.fontSize ?? fontSize; + fontWeight = style.fontWeight ?? fontWeight; + decoration = style.decoration ?? decoration; + height = style.height ?? height; + textBaseline = style.textBaseline ?? textBaseline; } TextStyle generateTextStyle() { @@ -54,37 +41,26 @@ class BrnTextStyle { ); } - void flatTextStyle(BrnTextStyle defaultTextStyle) { + void flatTextStyle(BrnTextStyle? defaultTextStyle) { if (defaultTextStyle == null) { return; } - if (defaultTextStyle.color != null) { - this.color ??= defaultTextStyle.color; - } - if (defaultTextStyle.fontSize != null) { - this.fontSize ??= defaultTextStyle.fontSize; - } - if (defaultTextStyle.fontWeight != null) { - this.fontWeight ??= defaultTextStyle.fontWeight; - } - if (defaultTextStyle.decoration != null) { - this.decoration ??= defaultTextStyle.decoration; - } - if (defaultTextStyle.height != null) { - this.height ??= defaultTextStyle.height; - } - if (defaultTextStyle.textBaseline != null) { - this.textBaseline ??= defaultTextStyle.textBaseline; - } + color ??= defaultTextStyle.color; + fontSize ??= defaultTextStyle.fontSize; + fontWeight ??= defaultTextStyle.fontWeight; + decoration ??= defaultTextStyle.decoration; + height ??= defaultTextStyle.height; + textBaseline ??= defaultTextStyle.textBaseline; } - BrnTextStyle copyWith( - {Color color, - double fontSize, - FontWeight fontWeight, - TextDecoration decoration, - double height, - TextBaseline textBaseline}) { + BrnTextStyle copyWith({ + Color? color, + double? fontSize, + FontWeight? fontWeight, + TextDecoration? decoration, + double? height, + TextBaseline? textBaseline, + }) { return BrnTextStyle( color: color ?? this.color, fontSize: fontSize ?? this.fontSize, @@ -95,7 +71,7 @@ class BrnTextStyle { ); } - BrnTextStyle merge(BrnTextStyle other) { + BrnTextStyle merge(BrnTextStyle? other) { if (other == null) return this; return copyWith( color: other.color, diff --git a/lib/src/theme/brn_initializer.dart b/lib/src/theme/brn_initializer.dart index a8f19d88..b90c0b5b 100644 --- a/lib/src/theme/brn_initializer.dart +++ b/lib/src/theme/brn_initializer.dart @@ -1,20 +1,13 @@ import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_all_config.dart'; -import 'package:bruno/src/theme/img/brn_theme_default_utils.dart'; -import 'package:bruno/src/theme/img/brn_theme_img_utils.dart'; - -///bruno初始化 +/// Bruno 初始化 class BrnInitializer { /// 手动注册时,默认注册渠道是 GLOBAL_CONFIG_ID - static register( - {BrnAllThemeConfig allThemeConfig, - String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID, - BrnThemeImgUtils brunoImgUtils}) { - /// 配置图片 - if (brunoImgUtils != null) { - BrnThemeImg.register(brunoImgUtils: brunoImgUtils); - } + static register({ + BrnAllThemeConfig? allThemeConfig, + String configId = GLOBAL_CONFIG_ID, + }) { /// 配置主题定制 BrnThemeConfigurator.instance.register(allThemeConfig, configId: configId); diff --git a/lib/src/theme/brn_theme.dart b/lib/src/theme/brn_theme.dart index ddabdd35..6300080e 100644 --- a/lib/src/theme/brn_theme.dart +++ b/lib/src/theme/brn_theme.dart @@ -1,4 +1,5 @@ /// theme export + library bruno_theme; export 'base/brn_base_config.dart'; @@ -22,5 +23,5 @@ export 'configs/brn_picker_config.dart'; export 'configs/brn_selection_config.dart'; export 'configs/brn_tabbar_config.dart'; export 'configs/brn_tag_config.dart'; -export 'img/brn_theme_default_utils.dart'; export 'brn_initializer.dart'; +export 'brn_theme_configurator.dart'; diff --git a/lib/src/theme/brn_theme_configurator.dart b/lib/src/theme/brn_theme_configurator.dart index 90fa0e4e..2449d465 100644 --- a/lib/src/theme/brn_theme_configurator.dart +++ b/lib/src/theme/brn_theme_configurator.dart @@ -1,33 +1,33 @@ -import 'package:bruno/src/theme/brn_theme.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; import 'package:bruno/src/theme/configs/brn_all_config.dart'; +const String BRUNO_CONFIG_ID = 'BRUNO_CONFIG_ID'; +const String GLOBAL_CONFIG_ID = 'GLOBAL_CONFIG_ID'; + class BrnThemeConfigurator { - static const String BRUNO_CONFIG_ID = 'BRUNO_CONFIG_ID'; - static const String GLOBAL_CONFIG_ID = 'GLOBAL_CONFIG_ID'; - static final BrnThemeConfigurator _instance = BrnThemeConfigurator._(); - Map globalConfig = Map(); + BrnThemeConfigurator._(){ + _checkAndInitBrunoConfig(); + } - BrnThemeConfigurator._(); + static final BrnThemeConfigurator _instance = BrnThemeConfigurator._(); static BrnThemeConfigurator get instance { return _instance; } - /// 手动注册时,默认注册渠道是 GLOBAL_CONFIG_ID - void register(BrnAllThemeConfig allThemeConfig, - {String configId = GLOBAL_CONFIG_ID}) { - assert(configId != null); - - /// 先赋值默认配置 - checkAndInitBrunoConfig(); + Map globalConfig = {}; - /// 打平内部字段 - allThemeConfig?.initThemeConfig(configId); - - /// 赋值传入配置 + /// 手动注册时,默认注册渠道是 GLOBAL_CONFIG_ID + void register( + BrnAllThemeConfig? allThemeConfig, { + String configId = GLOBAL_CONFIG_ID, + }) { + // 打平内部字段 if (allThemeConfig != null) { - instance.globalConfig[configId] = allThemeConfig; + // 赋值传入配置 + globalConfig[configId] = allThemeConfig + ..initThemeConfig(configId); } } @@ -36,26 +36,19 @@ class BrnThemeConfigurator { /// 2、若获取的为 null,则使用默认的全局配置。 /// 3、若没有配置 GLOBAL_CONFIG_ID ,则使用 BRUNO 的配置。 BrnAllThemeConfig getConfig({String configId = GLOBAL_CONFIG_ID}) { - assert(configId != null); - checkAndInitBrunoConfig(); - BrnAllThemeConfig allThemeConfig = globalConfig[configId]; - if (allThemeConfig == null) { - allThemeConfig = globalConfig[GLOBAL_CONFIG_ID]; - } - if (allThemeConfig == null) { - allThemeConfig = globalConfig[BRUNO_CONFIG_ID]; - } - return allThemeConfig; + BrnAllThemeConfig? allThemeConfig = globalConfig[configId] ?? + globalConfig[GLOBAL_CONFIG_ID] ?? + globalConfig[BRUNO_CONFIG_ID]; + assert(allThemeConfig != null, 'No suitable config found.'); + return allThemeConfig!; } /// 检查是否有默认配置 - bool isBrunoConfig() { - return globalConfig[BRUNO_CONFIG_ID] != null; - } + bool isBrunoConfig() => globalConfig[BRUNO_CONFIG_ID] != null; /// 没有默认配置 配置默认配置 - void checkAndInitBrunoConfig() { + void _checkAndInitBrunoConfig() { if (!isBrunoConfig()) { globalConfig[BRUNO_CONFIG_ID] = BrnDefaultConfigUtils.defaultAllConfig; } diff --git a/lib/src/theme/configs/brn_abnormal_state_config.dart b/lib/src/theme/configs/brn_abnormal_state_config.dart index 48265af7..67b829ff 100644 --- a/lib/src/theme/configs/brn_abnormal_state_config.dart +++ b/lib/src/theme/configs/brn_abnormal_state_config.dart @@ -1,139 +1,198 @@ import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; import 'package:bruno/src/theme/base/brn_text_style.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_common_config.dart'; /// 描述: 空页面配置类 class BrnAbnormalStateConfig extends BrnBaseConfig { + BrnAbnormalStateConfig({ + BrnTextStyle? titleTextStyle, + BrnTextStyle? contentTextStyle, + BrnTextStyle? operateTextStyle, + double? btnRadius, + BrnTextStyle? singleTextStyle, + BrnTextStyle? doubleTextStyle, + double? singleMinWidth, + double? doubleMinWidth, + String configId = GLOBAL_CONFIG_ID, + }) : _titleTextStyle = titleTextStyle, + _contentTextStyle = contentTextStyle, + _operateTextStyle = operateTextStyle, + _btnRadius = btnRadius, + _singleTextStyle = singleTextStyle, + _doubleTextStyle = doubleTextStyle, + _singleMinWidth = singleMinWidth, + _doubleMinWidth = doubleMinWidth, + super(configId: configId); + /// 文案区域标题 - /// TextStyle(fontWeight: FontWeight.w600,color: [BrnCommonConfig.colorTextBase], fontSize: [BrnCommonConfig.fontSizeSubHead]) - BrnTextStyle titleTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _titleTextStyle; /// 文案区域内容 - /// TextStyle(color: [BrnCommonConfig.colorTextHint], fontSize: [BrnCommonConfig.fontSizeBase]) - BrnTextStyle contentTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextHint], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _contentTextStyle; /// 操作区域文本样式 - /// TextStyle(color: [BrnCommonConfig.brandPrimary], fontSize: [BrnCommonConfig.fontSizeBase]) - BrnTextStyle operateTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _operateTextStyle; /// 圆角 /// default value is [BrnCommonConfig.radiusSm] - double btnRadius; + double? _btnRadius; /// 单按钮文本样式 - /// default value is TextStyle(color: [BrnCommonConfig.colorTextBaseInverse], fontSize: [BrnCommonConfig.fontSizeSubHead] - BrnTextStyle singleBrnTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBaseInverse], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// ) + BrnTextStyle? _singleTextStyle; /// 双按钮文本样式 - /// default value is TextStyle(color: [BrnCommonConfig.brandPrimary], fontSize: [BrnCommonConfig.fontSizeSubHead]) - BrnTextStyle doubleBrnTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// ) + BrnTextStyle? _doubleTextStyle; /// 单按钮的按钮最小宽度 - /// default value is 160 - double singleMinWidth; + /// 默认值为 160 + double? _singleMinWidth; /// 多按钮的按钮最小宽度 - /// default value is 120 - double doubleMinWidth; - - BrnAbnormalStateConfig( - {this.titleTextStyle, - this.contentTextStyle, - this.operateTextStyle, - this.btnRadius, - this.doubleBrnTextStyle, - this.singleBrnTextStyle, - this.singleMinWidth, - this.doubleMinWidth, - String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID}) - : super(configId: configId); + /// 默认值为 120 + double? _doubleMinWidth; - @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + BrnTextStyle get titleTextStyle => + _titleTextStyle ?? + BrnDefaultConfigUtils.defaultAbnormalStateConfig.titleTextStyle; - /// 用户全局组件配置 - BrnAbnormalStateConfig abnormalStateConfig = BrnThemeConfigurator.instance - .getConfig(configId: configId) - .abnormalStateConfig; + BrnTextStyle get contentTextStyle => + _contentTextStyle ?? + BrnDefaultConfigUtils.defaultAbnormalStateConfig.contentTextStyle; - this.singleBrnTextStyle = abnormalStateConfig.singleBrnTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBaseInverse, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.singleBrnTextStyle)); + BrnTextStyle get operateTextStyle => + _operateTextStyle ?? + BrnDefaultConfigUtils.defaultAbnormalStateConfig.operateTextStyle; - this.titleTextStyle = abnormalStateConfig.titleTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.titleTextStyle)); + double get btnRadius => + _btnRadius ?? BrnDefaultConfigUtils.defaultAbnormalStateConfig.btnRadius; - this.contentTextStyle = abnormalStateConfig.contentTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextHint, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.contentTextStyle)); + BrnTextStyle get singleTextStyle => + _singleTextStyle ?? + BrnDefaultConfigUtils.defaultAbnormalStateConfig.singleTextStyle; - this.operateTextStyle = abnormalStateConfig.operateTextStyle.merge( - BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeBase) - .merge(this.operateTextStyle)); + BrnTextStyle get doubleTextStyle => + _doubleTextStyle ?? + BrnDefaultConfigUtils.defaultAbnormalStateConfig.doubleTextStyle; - this.doubleBrnTextStyle = abnormalStateConfig.doubleBrnTextStyle.merge( - BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.doubleBrnTextStyle)); + double get singleMinWidth => + _singleMinWidth ?? + BrnDefaultConfigUtils.defaultAbnormalStateConfig.singleMinWidth; - this.btnRadius ??= abnormalStateConfig.btnRadius; + double get doubleMinWidth => + _doubleMinWidth ?? + BrnDefaultConfigUtils.defaultAbnormalStateConfig.doubleMinWidth; - this.singleMinWidth ??= abnormalStateConfig.singleMinWidth; + @override + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); - this.doubleMinWidth ??= abnormalStateConfig.doubleMinWidth; + /// 用户全局组件配置 + BrnAbnormalStateConfig abnormalStateConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .abnormalStateConfig; + + _titleTextStyle = abnormalStateConfig.titleTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_titleTextStyle), + ); + _contentTextStyle = abnormalStateConfig.contentTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextHint, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_contentTextStyle), + ); + _operateTextStyle = abnormalStateConfig.operateTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeBase, + ).merge(_operateTextStyle), + ); + _singleTextStyle = abnormalStateConfig.singleTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBaseInverse, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_singleTextStyle), + ); + _doubleTextStyle = abnormalStateConfig.doubleTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_doubleTextStyle), + ); + _btnRadius ??= abnormalStateConfig._btnRadius; + _singleMinWidth ??= abnormalStateConfig._singleMinWidth; + _doubleMinWidth ??= abnormalStateConfig._doubleMinWidth; } BrnAbnormalStateConfig copyWith({ - BrnTextStyle titleTextStyle, - BrnTextStyle contentTextStyle, - BrnTextStyle operateTextStyle, - double btnRadius, - BrnTextStyle singleBrnTextStyle, - BrnTextStyle doubleBrnTextStyle, - double singleMinWidth, - double doubleMinWidth, + BrnTextStyle? titleTextStyle, + BrnTextStyle? contentTextStyle, + BrnTextStyle? operateTextStyle, + double? btnRadius, + BrnTextStyle? singleTextStyle, + BrnTextStyle? doubleTextStyle, + double? singleMinWidth, + double? doubleMinWidth, }) { return BrnAbnormalStateConfig( - titleTextStyle: titleTextStyle ?? this.titleTextStyle, - contentTextStyle: contentTextStyle ?? this.contentTextStyle, - operateTextStyle: operateTextStyle ?? this.operateTextStyle, - btnRadius: btnRadius ?? this.btnRadius, - doubleBrnTextStyle: doubleBrnTextStyle ?? this.doubleBrnTextStyle, - singleBrnTextStyle: singleBrnTextStyle ?? this.singleBrnTextStyle, - singleMinWidth: singleMinWidth ?? this.singleMinWidth, - doubleMinWidth: doubleMinWidth ?? this.doubleMinWidth, + titleTextStyle: titleTextStyle ?? _titleTextStyle, + contentTextStyle: contentTextStyle ?? _contentTextStyle, + operateTextStyle: operateTextStyle ?? _operateTextStyle, + btnRadius: btnRadius ?? _btnRadius, + singleTextStyle: singleTextStyle ?? _singleTextStyle, + doubleTextStyle: doubleTextStyle ?? _doubleTextStyle, + singleMinWidth: singleMinWidth ?? _singleMinWidth, + doubleMinWidth: doubleMinWidth ?? _doubleMinWidth, ); } - BrnAbnormalStateConfig merge(BrnAbnormalStateConfig other) { + BrnAbnormalStateConfig merge(BrnAbnormalStateConfig? other) { if (other == null) return this; return copyWith( - titleTextStyle: - titleTextStyle?.merge(other.titleTextStyle) ?? other.titleTextStyle, - contentTextStyle: contentTextStyle?.merge(other.contentTextStyle) ?? - other.contentTextStyle, - operateTextStyle: operateTextStyle?.merge(other.operateTextStyle) ?? - other.operateTextStyle, - btnRadius: other.btnRadius, - doubleBrnTextStyle: doubleBrnTextStyle?.merge(other.doubleBrnTextStyle) ?? - other.doubleBrnTextStyle, - singleBrnTextStyle: singleBrnTextStyle?.merge(other.singleBrnTextStyle) ?? - other.singleBrnTextStyle, - singleMinWidth: other.singleMinWidth, - doubleMinWidth: other.doubleMinWidth, + titleTextStyle: titleTextStyle.merge(other._titleTextStyle), + contentTextStyle: contentTextStyle.merge(other._contentTextStyle), + operateTextStyle: operateTextStyle.merge(other._operateTextStyle), + btnRadius: other._btnRadius, + singleTextStyle: singleTextStyle.merge(other._singleTextStyle), + doubleTextStyle: doubleTextStyle.merge(other._doubleTextStyle), + singleMinWidth: other._singleMinWidth, + doubleMinWidth: other._doubleMinWidth, ); } } diff --git a/lib/src/theme/configs/brn_action_sheet_config.dart b/lib/src/theme/configs/brn_action_sheet_config.dart index 788b1ddb..b383cf94 100644 --- a/lib/src/theme/configs/brn_action_sheet_config.dart +++ b/lib/src/theme/configs/brn_action_sheet_config.dart @@ -1,4 +1,5 @@ import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; import 'package:bruno/src/theme/base/brn_text_style.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_common_config.dart'; @@ -6,197 +7,270 @@ import 'package:flutter/material.dart'; /// BrnActionSheet 主题配置 class BrnActionSheetConfig extends BrnBaseConfig { - /// 遵循外部主题配置,Bruno默认配置[BrnDefaultConfigUtils.defaultActionSheetConfig] - BrnActionSheetConfig( - {this.titleStyle, - this.itemTitleStyle, - this.itemTitleStyleLink, - this.itemTitleStyleAlert, - this.itemDescStyle, - this.itemDescStyleLink, - this.itemDescStyleAlert, - this.cancelStyle, - this.topRadius, - this.contentPadding, - this.titlePadding, - String configId: BrnThemeConfigurator.GLOBAL_CONFIG_ID}) - : super(configId: configId); + /// 遵循外部主题配置 + /// 默认为 [BrnDefaultConfigUtils.defaultActionSheetConfig] + BrnActionSheetConfig({ + BrnTextStyle? titleStyle, + BrnTextStyle? itemTitleStyle, + BrnTextStyle? itemTitleStyleLink, + BrnTextStyle? itemTitleStyleAlert, + BrnTextStyle? itemDescStyle, + BrnTextStyle? itemDescStyleLink, + BrnTextStyle? itemDescStyleAlert, + BrnTextStyle? cancelStyle, + double? topRadius, + EdgeInsets? contentPadding, + EdgeInsets? titlePadding, + String configId = GLOBAL_CONFIG_ID, + }) : _titleStyle = titleStyle, + _itemTitleStyle = itemTitleStyle, + _itemTitleStyleLink = itemTitleStyleLink, + _itemTitleStyleAlert = itemTitleStyleAlert, + _itemDescStyle = itemDescStyle, + _itemDescStyleLink = itemDescStyleLink, + _itemDescStyleAlert = itemDescStyleAlert, + _cancelStyle = cancelStyle, + _topRadius = topRadius, + _contentPadding = contentPadding, + _titlePadding = titlePadding, + super(configId: configId); /// ActionSheet 的顶部圆角 - /// default value is [BrnCommonConfig.radiusLg] - double topRadius; + /// 默认值为 [BrnCommonConfig.radiusLg] + double? _topRadius; /// 标题样式 - /// default value is TextStyle(color:[BrnCommonConfig.colorTextSecondary],fontSize:[BrnCommonConfig.fontSizeBase]) - BrnTextStyle titleStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextSecondary], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _titleStyle; /// 元素标题默认样式 - /// default value is TextStyle(color:[BrnCommonConfig.colorTextBase],fontSize:[BrnCommonConfig.fontSizeSubHead]) - BrnTextStyle itemTitleStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize:[BrnCommonConfig.fontSizeSubHead], + /// ) + BrnTextStyle? _itemTitleStyle; /// 元素标题链接样式 - /// default value is TextStyle(color:[BrnCommonConfig.colorLink],fontSize:[BrnCommonConfig.fontSizeSubHead],fontWeight: FontWeight.w600) - BrnTextStyle itemTitleStyleLink; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorLink], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _itemTitleStyleLink; /// 元素警示项标题样式 - /// default value is TextStyle(color:[BrnCommonConfig.brandError],fontSize:[BrnCommonConfig.fontSizeBase],fontWeight: FontWeight.w600) - BrnTextStyle itemTitleStyleAlert; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandError], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _itemTitleStyleAlert; /// 元素描述默认样式 - /// default value is TextStyle(color:[BrnCommonConfig.colorTextBase],fontSize:[BrnCommonConfig.fontSizeCaption],fontWeight: FontWeight.w600) - BrnTextStyle itemDescStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeCaption], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _itemDescStyle; /// 元素标题描述链接样式 - /// default value is TextStyle(color:[BrnCommonConfig.colorLink],fontSize:[BrnCommonConfig.fontSizeCaption],fontWeight: FontWeight.w600) - BrnTextStyle itemDescStyleLink; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorLink], + /// fontSize: [BrnCommonConfig.fontSizeCaption], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _itemDescStyleLink; /// 元素警示项标题描述样式 - /// default value is TextStyle(color:[BrnCommonConfig.brandError],fontSize:[BrnCommonConfig.fontSizeCaption],fontWeight: FontWeight.w600) - BrnTextStyle itemDescStyleAlert; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandError], + /// fontSize: [BrnCommonConfig.fontSizeCaption], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _itemDescStyleAlert; /// 取消按钮样式 - /// default value is TextStyle(color:[BrnCommonConfig.colorTextBase],fontSize:[BrnCommonConfig.fontSizeSubHead],fontWeight: FontWeight.w600) - BrnTextStyle cancelStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _cancelStyle; /// 内容左右间距 - /// default value is EdgeInsets.only(top: 12, bottom: 12, left: 60, right: 60) - EdgeInsets contentPadding; + /// + /// EdgeInsets.symmetric(horizontal: 60, vertical: 12) + EdgeInsets? _contentPadding; - /// title 左右间距 - ///default value is EdgeInsets.only(top: 16, bottom: 16, left: 60, right: 60) - EdgeInsets titlePadding; + /// 标题左右间距 + /// + /// EdgeInsets.symmetric(horizontal: 60, vertical: 16) + EdgeInsets? _titlePadding; - @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + double get topRadius => + _topRadius ?? BrnDefaultConfigUtils.defaultActionSheetConfig.topRadius; - /// 用户全局组件配置 - BrnActionSheetConfig actionSheetConfig = BrnThemeConfigurator.instance - .getConfig(configId: configId) - .actionSheetConfig; + BrnTextStyle get titleStyle => + _titleStyle ?? BrnDefaultConfigUtils.defaultActionSheetConfig.titleStyle; - this.titlePadding ??= actionSheetConfig.titlePadding; - - this.contentPadding ??= actionSheetConfig.contentPadding; - - this.titleStyle = actionSheetConfig.titleStyle.merge(BrnTextStyle( - color: commonConfig.colorTextSecondary, - fontSize: commonConfig.fontSizeBase) - .merge(this.titleStyle)); - - this.itemTitleStyle = actionSheetConfig.itemTitleStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.itemTitleStyle)); - - this.itemTitleStyleLink = actionSheetConfig.itemTitleStyleLink.merge( - BrnTextStyle( - color: commonConfig.colorLink, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.itemTitleStyleLink)); - - this.itemTitleStyleAlert = actionSheetConfig.itemTitleStyleAlert.merge( - BrnTextStyle( - color: commonConfig.brandError, - fontSize: commonConfig.fontSizeBase) - .merge(this.itemTitleStyleAlert)); - - this.itemDescStyle = actionSheetConfig.itemDescStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeCaption) - .merge(this.itemDescStyle)); - - this.itemDescStyleLink = actionSheetConfig.itemDescStyleLink.merge( - BrnTextStyle( - color: commonConfig.colorLink, - fontSize: commonConfig.fontSizeCaption) - .merge(this.itemDescStyleLink)); - - this.itemDescStyleAlert = actionSheetConfig.itemDescStyleAlert.merge( - BrnTextStyle( - color: commonConfig.brandError, - fontSize: commonConfig.fontSizeCaption) - .merge(this.itemDescStyleAlert)); - - this.cancelStyle = actionSheetConfig.cancelStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.cancelStyle)); - - this.topRadius ??= commonConfig.radiusLg; - } + BrnTextStyle get itemTitleStyle => + _itemTitleStyle ?? + BrnDefaultConfigUtils.defaultActionSheetConfig.itemTitleStyle; - BrnActionSheetConfig copyWith({ - /// ActionSheet 的顶部圆角 - double topRadius, + BrnTextStyle get itemTitleStyleLink => + _itemTitleStyleLink ?? + BrnDefaultConfigUtils.defaultActionSheetConfig.itemTitleStyleLink; - /// 标题样式 - BrnTextStyle titleStyle, + BrnTextStyle get itemTitleStyleAlert => + _itemTitleStyleAlert ?? + BrnDefaultConfigUtils.defaultActionSheetConfig.itemTitleStyleAlert; - /// 元素标题默认样式 - BrnTextStyle itemTitleStyle, + BrnTextStyle get itemDescStyle => + _itemDescStyle ?? + BrnDefaultConfigUtils.defaultActionSheetConfig.itemDescStyle; - /// 元素标题链接样式 - BrnTextStyle itemTitleStyleLink, + BrnTextStyle get itemDescStyleLink => + _itemDescStyleLink ?? + BrnDefaultConfigUtils.defaultActionSheetConfig.itemDescStyleLink; - /// 元素警示项标题样式 - BrnTextStyle itemTitleStyleAlert, + BrnTextStyle get itemDescStyleAlert => + _itemDescStyleAlert ?? + BrnDefaultConfigUtils.defaultActionSheetConfig.itemDescStyleAlert; - /// 元素描述默认样式 - BrnTextStyle itemDescStyle, + BrnTextStyle get cancelStyle => + _cancelStyle ?? + BrnDefaultConfigUtils.defaultActionSheetConfig.cancelStyle; - /// 元素标题描述链接样式 - BrnTextStyle itemDescStyleLink, + EdgeInsets get contentPadding => + _contentPadding ?? + BrnDefaultConfigUtils.defaultActionSheetConfig.contentPadding; + + EdgeInsets get titlePadding => + _titlePadding ?? + BrnDefaultConfigUtils.defaultActionSheetConfig.titlePadding; + + @override + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); + + /// 用户全局组件配置 + BrnActionSheetConfig actionSheetConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .actionSheetConfig; - /// 元素警示项标题描述样式 - BrnTextStyle itemDescStyleAlert, + _titlePadding ??= actionSheetConfig.titlePadding; + _contentPadding ??= actionSheetConfig.contentPadding; + _titleStyle = actionSheetConfig.titleStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextSecondary, + fontSize: commonConfig.fontSizeBase, + ).merge(_titleStyle), + ); + _itemTitleStyle = actionSheetConfig.itemTitleStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_itemTitleStyle), + ); + _itemTitleStyleLink = actionSheetConfig.itemTitleStyleLink.merge( + BrnTextStyle( + color: commonConfig.colorLink, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_itemTitleStyleLink), + ); + _itemTitleStyleAlert = actionSheetConfig.itemTitleStyleAlert.merge( + BrnTextStyle( + color: commonConfig.brandError, + fontSize: commonConfig.fontSizeBase, + ).merge(_itemTitleStyleAlert), + ); + _itemDescStyle = actionSheetConfig.itemDescStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeCaption, + ).merge(_itemDescStyle), + ); + _itemDescStyleLink = actionSheetConfig.itemDescStyleLink.merge( + BrnTextStyle( + color: commonConfig.colorLink, + fontSize: commonConfig.fontSizeCaption, + ).merge(_itemDescStyleLink), + ); + _itemDescStyleAlert = actionSheetConfig.itemDescStyleAlert.merge( + BrnTextStyle( + color: commonConfig.brandError, + fontSize: commonConfig.fontSizeCaption, + ).merge(_itemDescStyleAlert), + ); + _cancelStyle = actionSheetConfig.cancelStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_cancelStyle), + ); + _topRadius ??= commonConfig.radiusLg; + } - /// 取消按钮样式 - BrnTextStyle cancelStyle, - EdgeInsets contentPadding, - EdgeInsets titlePadding, + BrnActionSheetConfig copyWith({ + double? topRadius, + BrnTextStyle? titleStyle, + BrnTextStyle? itemTitleStyle, + BrnTextStyle? itemTitleStyleLink, + BrnTextStyle? itemTitleStyleAlert, + BrnTextStyle? itemDescStyle, + BrnTextStyle? itemDescStyleLink, + BrnTextStyle? itemDescStyleAlert, + BrnTextStyle? cancelStyle, + EdgeInsets? contentPadding, + EdgeInsets? titlePadding, }) { return BrnActionSheetConfig( - titleStyle: titleStyle ?? this.titleStyle, - itemTitleStyle: itemTitleStyle ?? this.itemTitleStyle, - itemTitleStyleLink: itemTitleStyleLink ?? this.itemTitleStyleLink, - itemTitleStyleAlert: itemTitleStyleAlert ?? this.itemTitleStyleAlert, - itemDescStyle: itemDescStyle ?? this.itemDescStyle, - itemDescStyleLink: itemDescStyleLink ?? this.itemDescStyleLink, - itemDescStyleAlert: itemDescStyleAlert ?? this.itemDescStyleAlert, - cancelStyle: cancelStyle ?? this.cancelStyle, - topRadius: topRadius ?? this.topRadius, - contentPadding: contentPadding ?? this.contentPadding, - titlePadding: titlePadding ?? this.titlePadding); + titleStyle: titleStyle ?? _titleStyle, + itemTitleStyle: itemTitleStyle ?? _itemTitleStyle, + itemTitleStyleLink: itemTitleStyleLink ?? _itemTitleStyleLink, + itemTitleStyleAlert: itemTitleStyleAlert ?? _itemTitleStyleAlert, + itemDescStyle: itemDescStyle ?? _itemDescStyle, + itemDescStyleLink: itemDescStyleLink ?? _itemDescStyleLink, + itemDescStyleAlert: itemDescStyleAlert ?? _itemDescStyleAlert, + cancelStyle: cancelStyle ?? _cancelStyle, + topRadius: topRadius ?? _topRadius, + contentPadding: contentPadding ?? _contentPadding, + titlePadding: titlePadding ?? _titlePadding, + ); } - BrnActionSheetConfig merge(BrnActionSheetConfig other) { + BrnActionSheetConfig merge(BrnActionSheetConfig? other) { if (other == null) return this; return copyWith( - titleStyle: this.titleStyle?.merge(other.titleStyle) ?? other.titleStyle, - itemTitleStyle: this.itemTitleStyle?.merge(other.itemTitleStyle) ?? - other.itemTitleStyle, - itemTitleStyleLink: - this.itemTitleStyleLink?.merge(other.itemTitleStyleLink) ?? - other.itemTitleStyleLink, - itemTitleStyleAlert: - this.itemTitleStyleAlert?.merge(other.itemTitleStyleAlert) ?? - other.itemTitleStyleAlert, - itemDescStyle: - this.itemDescStyle?.merge(other.itemDescStyle) ?? other.itemDescStyle, - itemDescStyleLink: - this.itemDescStyleLink?.merge(other.itemDescStyleLink) ?? - other.itemDescStyleLink, - itemDescStyleAlert: - this.itemDescStyleAlert?.merge(other.itemDescStyleAlert) ?? - other.itemDescStyleAlert, - cancelStyle: - this.cancelStyle?.merge(other.cancelStyle) ?? other.cancelStyle, - topRadius: other.topRadius, - contentPadding: other.contentPadding, - titlePadding: other.titlePadding, + titleStyle: titleStyle.merge(other._titleStyle), + itemTitleStyle: itemTitleStyle.merge(other._itemTitleStyle), + itemTitleStyleLink: itemTitleStyleLink.merge(other._itemTitleStyleLink), + itemTitleStyleAlert: itemTitleStyleAlert.merge(other._itemTitleStyleAlert), + itemDescStyle: itemDescStyle.merge(other._itemDescStyle), + itemDescStyleLink: itemDescStyleLink.merge(other._itemDescStyleLink), + itemDescStyleAlert: itemDescStyleAlert.merge(other._itemDescStyleAlert), + cancelStyle: cancelStyle.merge(other._cancelStyle), + topRadius: other._topRadius, + contentPadding: other._contentPadding, + titlePadding: other._titlePadding, ); } } diff --git a/lib/src/theme/configs/brn_all_config.dart b/lib/src/theme/configs/brn_all_config.dart index d3292b26..fe244f36 100644 --- a/lib/src/theme/configs/brn_all_config.dart +++ b/lib/src/theme/configs/brn_all_config.dart @@ -1,100 +1,225 @@ -import 'package:bruno/src/theme/brn_theme.dart'; +import 'package:bruno/bruno.dart'; +import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_abnormal_state_config.dart'; +import 'package:bruno/src/theme/configs/brn_action_sheet_config.dart'; +import 'package:bruno/src/theme/configs/brn_appbar_config.dart'; +import 'package:bruno/src/theme/configs/brn_button_config.dart'; +import 'package:bruno/src/theme/configs/brn_card_title_config.dart'; +import 'package:bruno/src/theme/configs/brn_common_config.dart'; +import 'package:bruno/src/theme/configs/brn_dialog_config.dart'; +import 'package:bruno/src/theme/configs/brn_enhance_number_card_config.dart'; +import 'package:bruno/src/theme/configs/brn_form_config.dart'; +import 'package:bruno/src/theme/configs/brn_gallery_detail_config.dart'; +import 'package:bruno/src/theme/configs/brn_pair_info_config.dart'; +import 'package:bruno/src/theme/configs/brn_picker_config.dart'; +import 'package:bruno/src/theme/configs/brn_selection_config.dart'; +import 'package:bruno/src/theme/configs/brn_tabbar_config.dart'; +import 'package:bruno/src/theme/configs/brn_tag_config.dart'; /// 描述: 全局配置 /// /// 当用户使用时对单个组件自定义配置,优先走单个组件特定配置(作用范围档次使用) -/// 当用户配置组件通用配置时如[BrnDialogConfig]优先使用该配置 -/// 若没有配置组件通用配置,走[BrnCommonConfig]全局配置 -/// 如果以上都没有配置走Bruno默认配置即[BrnDefaultConfigUtils]中配置 +/// 当用户配置组件通用配置时如 [BrnDialogConfig] 优先使用该配置 +/// 若没有配置组件通用配置,走 [BrnCommonConfig] 全局配置 +/// 如果以上都没有配置走 Bruno 默认配置,即 [BrnDefaultConfigUtils] 中的配置 /// 当没有配置组件的特定属性时使用上一级特定配置 -/// class BrnAllThemeConfig { - BrnCommonConfig commonConfig; - BrnAppBarConfig appBarConfig; - BrnButtonConfig buttonConfig; - BrnDialogConfig dialogConfig; - BrnCardTitleConfig cardTitleConfig; - BrnAbnormalStateConfig abnormalStateConfig; - BrnTagConfig tagConfig; - BrnPairInfoTableConfig pairInfoTableConfig; - BrnPairRichInfoGridConfig pairRichInfoGridConfig; - BrnActionSheetConfig actionSheetConfig; - BrnPickerConfig pickerConfig; - BrnEnhanceNumberCardConfig enhanceNumberCardConfig; - BrnTabBarConfig tabBarConfig; - BrnFormItemConfig formItemConfig; - BrnSelectionConfig selectionConfig; - BrnGalleryDetailConfig galleryDetailConfig; - - BrnAllThemeConfig( - {this.commonConfig, - this.appBarConfig, - this.buttonConfig, - this.dialogConfig, - this.formItemConfig, - this.cardTitleConfig, - this.abnormalStateConfig, - this.tagConfig, - this.pairInfoTableConfig, - this.pairRichInfoGridConfig, - this.actionSheetConfig, - this.pickerConfig, - this.enhanceNumberCardConfig, - this.tabBarConfig, - this.selectionConfig, - this.galleryDetailConfig, - String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID}); + BrnAllThemeConfig({ + BrnCommonConfig? commonConfig, + BrnAppBarConfig? appBarConfig, + BrnButtonConfig? buttonConfig, + BrnDialogConfig? dialogConfig, + BrnFormItemConfig? formItemConfig, + BrnCardTitleConfig? cardTitleConfig, + BrnAbnormalStateConfig? abnormalStateConfig, + BrnTagConfig? tagConfig, + BrnPairInfoTableConfig? pairInfoTableConfig, + BrnPairRichInfoGridConfig? pairRichInfoGridConfig, + BrnActionSheetConfig? actionSheetConfig, + BrnPickerConfig? pickerConfig, + BrnEnhanceNumberCardConfig? enhanceNumberCardConfig, + BrnTabBarConfig? tabBarConfig, + BrnSelectionConfig? selectionConfig, + BrnGalleryDetailConfig? galleryDetailConfig, + String configId = GLOBAL_CONFIG_ID, + }) : _commonConfig = commonConfig, + _appBarConfig = appBarConfig, + _buttonConfig = buttonConfig, + _dialogConfig = dialogConfig, + _formItemConfig = formItemConfig, + _cardTitleConfig = cardTitleConfig, + _abnormalStateConfig = abnormalStateConfig, + _tagConfig = tagConfig, + _pairInfoTableConfig = pairInfoTableConfig, + _pairRichInfoGridConfig = pairRichInfoGridConfig, + _actionSheetConfig = actionSheetConfig, + _pickerConfig = pickerConfig, + _enhanceNumberCardConfig = enhanceNumberCardConfig, + _tabBarConfig = tabBarConfig, + _selectionConfig = selectionConfig, + _galleryDetailConfig = galleryDetailConfig; + + BrnCommonConfig? _commonConfig; + + BrnCommonConfig get commonConfig => + _commonConfig ?? BrnDefaultConfigUtils.defaultCommonConfig; + + BrnAppBarConfig? _appBarConfig; + + BrnAppBarConfig get appBarConfig => + _appBarConfig ?? BrnDefaultConfigUtils.defaultAppBarConfig; + + BrnButtonConfig? _buttonConfig; + + BrnButtonConfig get buttonConfig => + _buttonConfig ?? BrnDefaultConfigUtils.defaultButtonConfig; + + BrnDialogConfig? _dialogConfig; + + BrnDialogConfig get dialogConfig => + _dialogConfig ?? BrnDefaultConfigUtils.defaultDialogConfig; + + BrnCardTitleConfig? _cardTitleConfig; + + BrnCardTitleConfig get cardTitleConfig => + _cardTitleConfig ?? BrnDefaultConfigUtils.defaultCardTitleConfig; + + BrnAbnormalStateConfig? _abnormalStateConfig; + + BrnAbnormalStateConfig get abnormalStateConfig => + _abnormalStateConfig ?? BrnDefaultConfigUtils.defaultAbnormalStateConfig; + + BrnTagConfig? _tagConfig; + + BrnTagConfig get tagConfig => + _tagConfig ?? BrnDefaultConfigUtils.defaultTagConfig; + + BrnPairInfoTableConfig? _pairInfoTableConfig; + + BrnPairInfoTableConfig get pairInfoTableConfig => + _pairInfoTableConfig ?? BrnDefaultConfigUtils.defaultPairInfoTableConfig; + + BrnPairRichInfoGridConfig? _pairRichInfoGridConfig; + + BrnPairRichInfoGridConfig get pairRichInfoGridConfig => + _pairRichInfoGridConfig ?? + BrnDefaultConfigUtils.defaultPairRichInfoGridConfig; + + BrnActionSheetConfig? _actionSheetConfig; + + BrnActionSheetConfig get actionSheetConfig => + _actionSheetConfig ?? BrnDefaultConfigUtils.defaultActionSheetConfig; + + BrnPickerConfig? _pickerConfig; + + BrnPickerConfig get pickerConfig => + _pickerConfig ?? BrnDefaultConfigUtils.defaultPickerConfig; + + BrnEnhanceNumberCardConfig? _enhanceNumberCardConfig; + + BrnEnhanceNumberCardConfig get enhanceNumberCardConfig => + _enhanceNumberCardConfig ?? + BrnDefaultConfigUtils.defaultEnhanceNumberInfoConfig; + + BrnTabBarConfig? _tabBarConfig; + + BrnTabBarConfig get tabBarConfig => + _tabBarConfig ?? BrnDefaultConfigUtils.defaultTabBarConfig; + + BrnFormItemConfig? _formItemConfig; + + BrnFormItemConfig get formItemConfig => + _formItemConfig ?? BrnDefaultConfigUtils.defaultFormItemConfig; + + BrnSelectionConfig? _selectionConfig; + + BrnSelectionConfig get selectionConfig => + _selectionConfig ?? BrnDefaultConfigUtils.defaultSelectionConfig; + + BrnGalleryDetailConfig? _galleryDetailConfig; + + BrnGalleryDetailConfig get galleryDetailConfig => + _galleryDetailConfig ?? BrnDefaultConfigUtils.defaultGalleryDetailConfig; void initThemeConfig(String configId) { - this.commonConfig ??= BrnCommonConfig(); - this.appBarConfig ??= BrnAppBarConfig(); - this.buttonConfig ??= BrnButtonConfig(); - this.dialogConfig ??= BrnDialogConfig(); - this.formItemConfig ??= BrnFormItemConfig(); - this.cardTitleConfig ??= BrnCardTitleConfig(); - this.abnormalStateConfig ??= BrnAbnormalStateConfig(); - this.tagConfig ??= BrnTagConfig(); - this.appBarConfig ??= BrnAppBarConfig(); - this.pairInfoTableConfig ??= BrnPairInfoTableConfig(); - this.pairRichInfoGridConfig ??= BrnPairRichInfoGridConfig(); - this.actionSheetConfig ??= BrnActionSheetConfig(); - this.pickerConfig ??= BrnPickerConfig(); - this.enhanceNumberCardConfig ??= BrnEnhanceNumberCardConfig(); - this.tabBarConfig ??= BrnTabBarConfig(); - this.selectionConfig ??= BrnSelectionConfig(); - this.galleryDetailConfig ??= BrnGalleryDetailConfig(); - - commonConfig?.initThemeConfig(configId); - appBarConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); - buttonConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); - dialogConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); - formItemConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); - cardTitleConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); - abnormalStateConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); - tagConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); - pairInfoTableConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); - pairRichInfoGridConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); - selectionConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); - actionSheetConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); - pickerConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); - enhanceNumberCardConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); - tabBarConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); - galleryDetailConfig?.initThemeConfig(configId, - currentLevelCommonConfig: commonConfig); + this._commonConfig ??= BrnCommonConfig(); + this._appBarConfig ??= BrnAppBarConfig(); + this._buttonConfig ??= BrnButtonConfig(); + this._dialogConfig ??= BrnDialogConfig(); + this._formItemConfig ??= BrnFormItemConfig(); + this._cardTitleConfig ??= BrnCardTitleConfig(); + this._abnormalStateConfig ??= BrnAbnormalStateConfig(); + this._tagConfig ??= BrnTagConfig(); + this._appBarConfig ??= BrnAppBarConfig(); + this._pairInfoTableConfig ??= BrnPairInfoTableConfig(); + this._pairRichInfoGridConfig ??= BrnPairRichInfoGridConfig(); + this._actionSheetConfig ??= BrnActionSheetConfig(); + this._pickerConfig ??= BrnPickerConfig(); + this._enhanceNumberCardConfig ??= BrnEnhanceNumberCardConfig(); + this._tabBarConfig ??= BrnTabBarConfig(); + this._selectionConfig ??= BrnSelectionConfig(); + this._galleryDetailConfig ??= BrnGalleryDetailConfig(); + + commonConfig.initThemeConfig(configId); + appBarConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); + buttonConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); + dialogConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); + formItemConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); + cardTitleConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); + abnormalStateConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); + tagConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); + pairInfoTableConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); + pairRichInfoGridConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); + selectionConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); + actionSheetConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); + pickerConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); + enhanceNumberCardConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); + tabBarConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); + galleryDetailConfig.initThemeConfig( + configId, + currentLevelCommonConfig: commonConfig, + ); } } diff --git a/lib/src/theme/configs/brn_appbar_config.dart b/lib/src/theme/configs/brn_appbar_config.dart index 4633f6c6..bc2323b4 100644 --- a/lib/src/theme/configs/brn_appbar_config.dart +++ b/lib/src/theme/configs/brn_appbar_config.dart @@ -1,7 +1,11 @@ -import 'package:bruno/bruno.dart'; import 'package:bruno/src/components/navbar/brn_appbar_theme.dart'; +import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/constants/brn_strings_constants.dart'; -import 'package:bruno/src/theme/brn_theme.dart'; +import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; +import 'package:bruno/src/theme/base/brn_text_style.dart'; +import 'package:bruno/src/theme/brn_theme_configurator.dart'; +import 'package:bruno/src/theme/configs/brn_common_config.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -9,201 +13,259 @@ typedef BrnWidgetBuilder = Widget Function(); /// Appbar主题配置 class BrnAppBarConfig extends BrnBaseConfig { - /// BrnAppBar 主题配置,遵循外部主题配置,Bruno默认配置[BrnDefaultConfigUtils.defaultAppBarConfig] - BrnAppBarConfig( - {this.backgroundColor, - this.appBarHeight, - this.leadIconBuilder, - this.titleStyle, - this.actionsStyle, - this.titleMaxLength, - this.leftAndRightPadding, - this.itemSpacing, - this.titlePadding, - this.iconSize, - this.flexibleSpace, - this.systemUiOverlayStyle, - String configId: BrnThemeConfigurator.GLOBAL_CONFIG_ID}) - : super(configId: configId); - - BrnAppBarConfig.dark( - {this.backgroundColor, - this.appBarHeight, - this.leadIconBuilder, - this.titleStyle, - this.actionsStyle, - this.titleMaxLength, - this.leftAndRightPadding, - this.itemSpacing, - this.titlePadding, - this.iconSize, - this.flexibleSpace, - this.systemUiOverlayStyle, - String configId: BrnThemeConfigurator.GLOBAL_CONFIG_ID}) - : super(configId: configId) { - this.systemUiOverlayStyle = SystemUiOverlayStyle.light; - this.backgroundColor = Color(0xff2E313B); - this.leadIconBuilder = () => Image.asset( - BrnAsset.ICON_BACK_WHITE, - package: BrnStrings.flutterPackageName, - width: BrnAppBarTheme.iconSize, - height: BrnAppBarTheme.iconSize, - fit: BoxFit.fitHeight, - ); - this.titleStyle = BrnTextStyle( - fontSize: BrnAppBarTheme.titleFontSize, - fontWeight: FontWeight.w600, - color: BrnAppBarTheme.darkTextColor); - this.actionsStyle = BrnTextStyle( - color: BrnAppBarTheme.darkTextColor, - fontSize: BrnAppBarTheme.actionFontSize, - fontWeight: FontWeight.w600); + /// BrnAppBar 主题配置,遵循外部主题配置 + /// 默认为 [BrnDefaultConfigUtils.defaultAppBarConfig] + BrnAppBarConfig({ + Color? backgroundColor, + double? appBarHeight, + BrnWidgetBuilder? leadIconBuilder, + BrnTextStyle? titleStyle, + BrnTextStyle? actionsStyle, + int? titleMaxLength, + double? leftAndRightPadding, + double? itemSpacing, + EdgeInsets? titlePadding, + double? iconSize, + SystemUiOverlayStyle? systemUiOverlayStyle, + String configId = GLOBAL_CONFIG_ID, + }) : _backgroundColor = backgroundColor, + _appBarHeight = appBarHeight, + _leadIconBuilder = leadIconBuilder, + _titleStyle = titleStyle, + _actionsStyle = actionsStyle, + _titleMaxLength = titleMaxLength, + _leftAndRightPadding = leftAndRightPadding, + _itemSpacing = itemSpacing, + _titlePadding = titlePadding, + _iconSize = iconSize, + _systemUiOverlayStyle = systemUiOverlayStyle, + super(configId: configId); + + BrnAppBarConfig.dark({ + double? appBarHeight, + int? titleMaxLength, + double? leftAndRightPadding, + double? itemSpacing, + EdgeInsets? titlePadding, + double? iconSize, + String configId = GLOBAL_CONFIG_ID, + }) : _appBarHeight = appBarHeight, + _titleMaxLength = titleMaxLength, + _leftAndRightPadding = leftAndRightPadding, + _itemSpacing = itemSpacing, + _titlePadding = titlePadding, + _iconSize = iconSize, + super(configId: configId) { + _backgroundColor = Color(0xff2E313B); + _leadIconBuilder = () => Image.asset( + BrnAsset.iconBackWhite, + package: BrnStrings.flutterPackageName, + width: BrnAppBarTheme.iconSize, + height: BrnAppBarTheme.iconSize, + fit: BoxFit.fitHeight, + ); + _titleStyle = BrnTextStyle( + fontSize: BrnAppBarTheme.titleFontSize, + fontWeight: FontWeight.w600, + color: BrnAppBarTheme.darkTextColor, + ); + _actionsStyle = BrnTextStyle( + color: BrnAppBarTheme.darkTextColor, + fontSize: BrnAppBarTheme.actionFontSize, + fontWeight: FontWeight.w600, + ); + _systemUiOverlayStyle = SystemUiOverlayStyle.light; } - BrnAppBarConfig.light( - {this.backgroundColor, - this.appBarHeight, - this.leadIconBuilder, - this.titleStyle, - this.actionsStyle, - this.titleMaxLength, - this.leftAndRightPadding, - this.itemSpacing, - this.titlePadding, - this.iconSize, - this.flexibleSpace, - this.systemUiOverlayStyle, - String configId: BrnThemeConfigurator.GLOBAL_CONFIG_ID}) - : super(configId: configId) { - this.systemUiOverlayStyle = SystemUiOverlayStyle.dark; - this.backgroundColor = Colors.white; - this.leadIconBuilder = () => Image.asset( - BrnAsset.ICON_BACK_BLACK, - package: BrnStrings.flutterPackageName, - width: BrnAppBarTheme.iconSize, - height: BrnAppBarTheme.iconSize, - fit: BoxFit.fitHeight, - ); - this.titleStyle = BrnTextStyle( - fontSize: BrnAppBarTheme.titleFontSize, - fontWeight: FontWeight.w600, - color: BrnAppBarTheme.lightTextColor); - this.actionsStyle = BrnTextStyle( - color: BrnAppBarTheme.lightTextColor, - fontSize: BrnAppBarTheme.actionFontSize, - fontWeight: FontWeight.w600); + BrnAppBarConfig.light({ + double? appBarHeight, + int? titleMaxLength, + double? leftAndRightPadding, + double? itemSpacing, + EdgeInsets? titlePadding, + double? iconSize, + String configId = GLOBAL_CONFIG_ID, + }) : _appBarHeight = appBarHeight, + _titleMaxLength = titleMaxLength, + _leftAndRightPadding = leftAndRightPadding, + _itemSpacing = itemSpacing, + _titlePadding = titlePadding, + _iconSize = iconSize, + super(configId: configId) { + _backgroundColor = Colors.white; + _leadIconBuilder = () => Image.asset( + BrnAsset.iconBackBlack, + package: BrnStrings.flutterPackageName, + width: BrnAppBarTheme.iconSize, + height: BrnAppBarTheme.iconSize, + fit: BoxFit.fitHeight, + ); + _titleStyle = BrnTextStyle( + fontSize: BrnAppBarTheme.titleFontSize, + fontWeight: FontWeight.w600, + color: BrnAppBarTheme.lightTextColor, + ); + _actionsStyle = BrnTextStyle( + color: BrnAppBarTheme.lightTextColor, + fontSize: BrnAppBarTheme.actionFontSize, + fontWeight: FontWeight.w600, + ); + _systemUiOverlayStyle = SystemUiOverlayStyle.dark; } - /// AppBar的背景色 - Color backgroundColor; + /// AppBar 的背景色 + Color? _backgroundColor; + + Color get backgroundColor => + _backgroundColor ?? + BrnDefaultConfigUtils.defaultAppBarConfig.backgroundColor; + + /// AppBar 的高度 + double? _appBarHeight; - /// AppBar的高度 - double appBarHeight; + double get appBarHeight => + _appBarHeight ?? BrnDefaultConfigUtils.defaultAppBarConfig.appBarHeight; /// 返回按钮的child widget,一般为Image - BrnWidgetBuilder leadIconBuilder; + BrnWidgetBuilder? _leadIconBuilder; + + BrnWidgetBuilder get leadIconBuilder => + _leadIconBuilder ?? + BrnDefaultConfigUtils.defaultAppBarConfig.leadIconBuilder; + + /// 标题样式,仅当直接 title 设置为 String 生效 + /// + /// **注意**:`fontSize` 必须传大小,否则报错 + BrnTextStyle? _titleStyle; + + BrnTextStyle get titleStyle => + _titleStyle ?? BrnDefaultConfigUtils.defaultAppBarConfig.titleStyle; - /// 标题样式,仅当直接title设置为String生效,[注意]:`fontSize`必须传大小,否则报错 - BrnTextStyle titleStyle; + /// 右侧文字按钮样式,仅当直接actions里面元素为BrnTextAction类型生效 + /// + /// **注意**:`fontSize` 必须传大小,否则报错 + /// + /// BrnTextStyle( + /// color: AppBarBrightness(brightness).textColor, + /// fontSize: BrnAppBarTheme.actionFontSize, + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _actionsStyle; - /// 右侧文字按钮样式,仅当直接actions里面元素为BrnTextAction类型生效[注意]:`fontSize`必须传大小,否则报错 - /// default value is TextStyle(color: AppBarBrightness(brightness).textColor,fontSize: BrnAppBarTheme.actionFontSize,fontWeight: FontWeight.w600) - BrnTextStyle actionsStyle; + BrnTextStyle get actionsStyle => + _actionsStyle ?? BrnDefaultConfigUtils.defaultAppBarConfig.actionsStyle; - /// AppBar title的最大字符数 8 - int titleMaxLength; + /// AppBar title 的最大字符数 8 + int? _titleMaxLength; + + int get titleMaxLength => + _titleMaxLength ?? + BrnDefaultConfigUtils.defaultAppBarConfig.titleMaxLength; /// 左右边距 - double leftAndRightPadding; + double? _leftAndRightPadding; + + double get leftAndRightPadding => + _leftAndRightPadding ?? + BrnDefaultConfigUtils.defaultAppBarConfig.leftAndRightPadding; /// 元素间间距 - double itemSpacing; + double? _itemSpacing; + + double get itemSpacing => + _itemSpacing ?? BrnDefaultConfigUtils.defaultAppBarConfig.itemSpacing; /// title的padding - EdgeInsets titlePadding; + EdgeInsets? _titlePadding; + + EdgeInsets get titlePadding => + _titlePadding ?? BrnDefaultConfigUtils.defaultAppBarConfig.titlePadding; /// leadIcon 宽高,需要相同 - /// default value is 20 - double iconSize; + /// 默认为 20 + double? _iconSize; - ///[AppBar]中flexibleSpace - Widget flexibleSpace; + double get iconSize => + _iconSize ?? BrnDefaultConfigUtils.defaultAppBarConfig.iconSize; /// statusBar 样式 - /// default value is SystemUiOverlayStyle.dark - SystemUiOverlayStyle systemUiOverlayStyle; + /// 默认为 [SystemUiOverlayStyle.dark] + SystemUiOverlayStyle? _systemUiOverlayStyle; + + SystemUiOverlayStyle get systemUiOverlayStyle => + _systemUiOverlayStyle ?? + BrnDefaultConfigUtils.defaultAppBarConfig.systemUiOverlayStyle; @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); /// 用户全局组件配置 BrnAppBarConfig appbarConfig = BrnThemeConfigurator.instance .getConfig(configId: configId) .appBarConfig; - this.backgroundColor ??= appbarConfig?.backgroundColor; - this.appBarHeight ??= appbarConfig?.appBarHeight; - this.leadIconBuilder ??= appbarConfig?.leadIconBuilder; - this.titleStyle = appbarConfig.titleStyle.merge(titleStyle); - this.actionsStyle = appbarConfig.actionsStyle.merge(actionsStyle); - this.titleMaxLength ??= appbarConfig?.titleMaxLength; - this.leftAndRightPadding ??= appbarConfig?.leftAndRightPadding; - this.itemSpacing ??= appbarConfig?.itemSpacing; - this.titlePadding ??= appbarConfig?.titlePadding; - this.iconSize ??= appbarConfig?.iconSize; - this.flexibleSpace ??= appbarConfig?.flexibleSpace; - this.systemUiOverlayStyle ??= appbarConfig?.systemUiOverlayStyle; + _backgroundColor ??= appbarConfig._backgroundColor; + _appBarHeight ??= appbarConfig._appBarHeight; + _leadIconBuilder ??= appbarConfig._leadIconBuilder; + _titleStyle = appbarConfig.titleStyle.merge(_titleStyle); + _actionsStyle = appbarConfig.actionsStyle.merge(_actionsStyle); + _titleMaxLength ??= appbarConfig._titleMaxLength; + _leftAndRightPadding ??= appbarConfig._leftAndRightPadding; + _itemSpacing ??= appbarConfig._itemSpacing; + _titlePadding ??= appbarConfig._titlePadding; + _iconSize ??= appbarConfig._iconSize; + _systemUiOverlayStyle ??= appbarConfig._systemUiOverlayStyle; } BrnAppBarConfig copyWith({ - Color backgroundColor, - double appBarHeight, - BrnWidgetBuilder leadIconBuilder, - BrnTextStyle titleStyle, - BrnTextStyle actionsStyle, - int titleMaxLength, - double leftAndRightPadding, - double itemSpacing, - EdgeInsets titlePading, - double iconSize, - Widget flexibleSpace, - SystemUiOverlayStyle systemUiOverlayStyle, + Color? backgroundColor, + double? appBarHeight, + BrnWidgetBuilder? leadIconBuilder, + BrnTextStyle? titleStyle, + BrnTextStyle? actionsStyle, + int? titleMaxLength, + double? leftAndRightPadding, + double? itemSpacing, + EdgeInsets? titlePadding, + double? iconSize, + SystemUiOverlayStyle? systemUiOverlayStyle, }) { return BrnAppBarConfig( - backgroundColor: backgroundColor ?? this.backgroundColor, - appBarHeight: appBarHeight ?? this.appBarHeight, - leadIconBuilder: leadIconBuilder ?? this.leadIconBuilder, - titleStyle: titleStyle ?? this.titleStyle, - actionsStyle: actionsStyle ?? this.actionsStyle, - titleMaxLength: titleMaxLength ?? this.titleMaxLength, - leftAndRightPadding: leftAndRightPadding ?? this.leftAndRightPadding, - itemSpacing: itemSpacing ?? this.itemSpacing, - titlePadding: titlePading ?? this.titlePadding, - iconSize: iconSize ?? this.iconSize, - flexibleSpace: flexibleSpace ?? this.flexibleSpace, - systemUiOverlayStyle: - systemUiOverlayStyle ?? this.systemUiOverlayStyle); + backgroundColor: backgroundColor ?? _backgroundColor, + appBarHeight: appBarHeight ?? _appBarHeight, + leadIconBuilder: leadIconBuilder ?? _leadIconBuilder, + titleStyle: titleStyle ?? _titleStyle, + actionsStyle: actionsStyle ?? _actionsStyle, + titleMaxLength: titleMaxLength ?? _titleMaxLength, + leftAndRightPadding: leftAndRightPadding ?? _leftAndRightPadding, + itemSpacing: itemSpacing ?? _itemSpacing, + titlePadding: titlePadding ?? _titlePadding, + iconSize: iconSize ?? _iconSize, + systemUiOverlayStyle: systemUiOverlayStyle ?? _systemUiOverlayStyle, + ); } - BrnAppBarConfig merge(BrnAppBarConfig other) { + BrnAppBarConfig merge(BrnAppBarConfig? other) { if (other == null) return this; return copyWith( - backgroundColor: other.backgroundColor, - appBarHeight: other.appBarHeight, - leadIconBuilder: other.leadIconBuilder, - titleStyle: - this.titleStyle?.merge(other.titleStyle) ?? other.titleStyle, - actionsStyle: - this.actionsStyle?.merge(other.actionsStyle) ?? other.actionsStyle, - titleMaxLength: other.titleMaxLength, - leftAndRightPadding: other.leftAndRightPadding, - itemSpacing: other.itemSpacing, - titlePading: other.titlePadding, - iconSize: other.iconSize, - flexibleSpace: other.flexibleSpace, - systemUiOverlayStyle: other.systemUiOverlayStyle); + backgroundColor: other._backgroundColor, + appBarHeight: other._appBarHeight, + leadIconBuilder: other._leadIconBuilder, + titleStyle: titleStyle.merge(other._titleStyle), + actionsStyle: actionsStyle.merge(other._actionsStyle), + titleMaxLength: other._titleMaxLength, + leftAndRightPadding: other._leftAndRightPadding, + itemSpacing: other._itemSpacing, + titlePadding: other._titlePadding, + iconSize: other._iconSize, + systemUiOverlayStyle: other._systemUiOverlayStyle, + ); } } diff --git a/lib/src/theme/configs/brn_button_config.dart b/lib/src/theme/configs/brn_button_config.dart index b57dc912..d6e29919 100644 --- a/lib/src/theme/configs/brn_button_config.dart +++ b/lib/src/theme/configs/brn_button_config.dart @@ -1,79 +1,119 @@ -import 'package:bruno/src/theme/brn_theme.dart'; +import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; +import 'package:bruno/src/theme/brn_theme_configurator.dart'; +import 'package:bruno/src/theme/configs/brn_common_config.dart'; /// 按钮基础配置 class BrnButtonConfig extends BrnBaseConfig { - ///遵循外部主题配置,Bruno默认配置[BrnDefaultConfigUtils.defaultButtonConfig] + /// 遵循外部主题配置 + /// 默认为 [BrnDefaultConfigUtils.defaultButtonConfig] BrnButtonConfig({ - this.bigButtonRadius, - this.bigButtonHeight, - this.bigButtonFontSize, - this.smallButtonRadius, - this.smallButtonHeight, - this.smallButtonFontSize, - String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID, - }) : super(configId: configId); + double? bigButtonRadius, + double? bigButtonHeight, + double? bigButtonFontSize, + double? smallButtonRadius, + double? smallButtonHeight, + double? smallButtonFontSize, + String configId = GLOBAL_CONFIG_ID, + }) : _bigButtonRadius = bigButtonRadius, + _bigButtonHeight = bigButtonHeight, + _bigButtonFontSize = bigButtonFontSize, + _smallButtonRadius = smallButtonRadius, + _smallButtonHeight = smallButtonHeight, + _smallButtonFontSize = smallButtonFontSize, + super(configId: configId); - /// default value is 6 - double bigButtonRadius; + /// 默认为 6 + double? _bigButtonRadius; - /// default value is 48 - double bigButtonHeight; + double get bigButtonRadius => + _bigButtonRadius ?? + BrnDefaultConfigUtils.defaultButtonConfig.bigButtonRadius; - /// default value is 16 - double bigButtonFontSize; + /// 默认为 48 + double? _bigButtonHeight; - /// default value is 4 - double smallButtonRadius; + double get bigButtonHeight => + _bigButtonHeight ?? + BrnDefaultConfigUtils.defaultButtonConfig.bigButtonHeight; - /// default value is 32 - double smallButtonHeight; + /// 默认为 16 + double? _bigButtonFontSize; - /// default value is 14 - double smallButtonFontSize; + double get bigButtonFontSize => + _bigButtonFontSize ?? + BrnDefaultConfigUtils.defaultButtonConfig.bigButtonFontSize; + + /// 默认为 4 + double? _smallButtonRadius; + + double get smallButtonRadius => + _smallButtonRadius ?? + BrnDefaultConfigUtils.defaultButtonConfig.smallButtonRadius; + + /// 默认为 32 + double? _smallButtonHeight; + + double get smallButtonHeight => + _smallButtonHeight ?? + BrnDefaultConfigUtils.defaultButtonConfig.smallButtonHeight; + + /// 默认为 14 + double? _smallButtonFontSize; + + double get smallButtonFontSize => + _smallButtonFontSize ?? + BrnDefaultConfigUtils.defaultButtonConfig.smallButtonFontSize; @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); BrnButtonConfig userConfig = BrnThemeConfigurator.instance .getConfig(configId: configId) .buttonConfig; - this.bigButtonRadius ??= userConfig?.bigButtonRadius; - this.bigButtonHeight ??= userConfig?.bigButtonHeight; - this.bigButtonFontSize ??= userConfig?.bigButtonFontSize; - this.smallButtonRadius ??= userConfig?.smallButtonRadius; - this.smallButtonHeight ??= userConfig?.smallButtonHeight; - this.smallButtonFontSize ??= userConfig?.smallButtonFontSize; + _bigButtonRadius ??= userConfig._bigButtonRadius; + _bigButtonHeight ??= userConfig._bigButtonHeight; + _bigButtonFontSize ??= userConfig._bigButtonFontSize; + _smallButtonRadius ??= userConfig._smallButtonRadius; + _smallButtonHeight ??= userConfig._smallButtonHeight; + _smallButtonFontSize ??= userConfig._smallButtonFontSize; } - BrnButtonConfig copyWith( - {double bigButtonRadius, - double bigButtonHeight, - double bigButtonFontSize, - double smallButtonRadius, - double smallButtonHeight, - double smallButtonFontSize}) { + BrnButtonConfig copyWith({ + double? bigButtonRadius, + double? bigButtonHeight, + double? bigButtonFontSize, + double? smallButtonRadius, + double? smallButtonHeight, + double? smallButtonFontSize, + }) { return BrnButtonConfig( - bigButtonRadius: bigButtonRadius ?? this.bigButtonRadius, - bigButtonHeight: bigButtonHeight ?? this.bigButtonHeight, - bigButtonFontSize: bigButtonFontSize ?? this.bigButtonFontSize, - smallButtonRadius: smallButtonRadius ?? this.smallButtonRadius, - smallButtonHeight: smallButtonHeight ?? this.smallButtonHeight, - smallButtonFontSize: smallButtonFontSize ?? this.smallButtonFontSize, + bigButtonRadius: bigButtonRadius ?? _bigButtonRadius, + bigButtonHeight: bigButtonHeight ?? _bigButtonHeight, + bigButtonFontSize: bigButtonFontSize ?? _bigButtonFontSize, + smallButtonRadius: smallButtonRadius ?? _smallButtonRadius, + smallButtonHeight: smallButtonHeight ?? _smallButtonHeight, + smallButtonFontSize: smallButtonFontSize ?? _smallButtonFontSize, ); } - BrnButtonConfig merge(BrnButtonConfig other) { + BrnButtonConfig merge(BrnButtonConfig? other) { if (other == null) return this; return copyWith( - bigButtonRadius: other.bigButtonRadius, - bigButtonHeight: other.bigButtonHeight, - bigButtonFontSize: other.bigButtonFontSize, - smallButtonRadius: other.smallButtonRadius, - smallButtonHeight: other.smallButtonHeight, - smallButtonFontSize: other.smallButtonFontSize); + bigButtonRadius: other._bigButtonRadius, + bigButtonHeight: other._bigButtonHeight, + bigButtonFontSize: other._bigButtonFontSize, + smallButtonRadius: other._smallButtonRadius, + smallButtonHeight: other._smallButtonHeight, + smallButtonFontSize: other._smallButtonFontSize, + ); } } diff --git a/lib/src/theme/configs/brn_card_title_config.dart b/lib/src/theme/configs/brn_card_title_config.dart index 84a32fd7..95ea6a70 100644 --- a/lib/src/theme/configs/brn_card_title_config.dart +++ b/lib/src/theme/configs/brn_card_title_config.dart @@ -1,3 +1,4 @@ +import 'package:bruno/bruno.dart'; import 'package:bruno/src/theme/base/brn_base_config.dart'; import 'package:bruno/src/theme/base/brn_text_style.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; @@ -6,143 +7,206 @@ import 'package:flutter/material.dart'; /// 卡片标题 配置类 class BrnCardTitleConfig extends BrnBaseConfig { + BrnCardTitleConfig({ + BrnTextStyle? titleWithHeightTextStyle, + BrnTextStyle? detailTextStyle, + BrnTextStyle? accessoryTextStyle, + EdgeInsets? cardTitlePadding, + BrnTextStyle? titleTextStyle, + BrnTextStyle? subtitleTextStyle, + PlaceholderAlignment? alignment, + Color? cardBackgroundColor, + String configId = GLOBAL_CONFIG_ID, + }) : _titleWithHeightTextStyle = titleWithHeightTextStyle, + _detailTextStyle = detailTextStyle, + _accessoryTextStyle = accessoryTextStyle, + _cardTitlePadding = cardTitlePadding, + _titleTextStyle = titleTextStyle, + _subtitleTextStyle = subtitleTextStyle, + _alignment = alignment, + _cardBackgroundColor = cardBackgroundColor, + super(configId: configId); + /// 标题外边距间距 - /// EdgeInsets.only(top: [BrnCommonConfig.vSpacingXl],bottom: [BrnCommonConfig.vSpacingMd]) - EdgeInsets cardTitlePadding; + /// + /// EdgeInsets.only( + /// top: [BrnCommonConfig.vSpacingXl], + /// bottom: [BrnCommonConfig.vSpacingMd], + /// ) + EdgeInsets? _cardTitlePadding; + + EdgeInsets get cardTitlePadding => + _cardTitlePadding ?? + BrnDefaultConfigUtils.defaultCardTitleConfig.cardTitlePadding; /// 标题文本样式 - /// BrnTextStyle(fontSize: [BrnCommonConfig.fontSizeHead],height: 25 / 18,fontWeight: FontWeight.w600,color: [BrnCommonConfig.colorTextBase]) - BrnTextStyle titleWithHeightTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeHead], + /// fontWeight: FontWeight.w600, + /// height: 25 / 18, + /// ) + BrnTextStyle? _titleWithHeightTextStyle; + + BrnTextStyle get titleWithHeightTextStyle => + _titleWithHeightTextStyle ?? + BrnDefaultConfigUtils.defaultCardTitleConfig.titleWithHeightTextStyle; /// 标题文本样式 - /// BrnTextStyle(fontSize: [BrnCommonConfig.fontSizeHead],fontWeight: FontWeight.w600,color: [BrnCommonConfig.colorTextBase]) - BrnTextStyle titleTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeHead], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _titleTextStyle; + + BrnTextStyle get titleTextStyle => + _titleTextStyle ?? + BrnDefaultConfigUtils.defaultCardTitleConfig.titleTextStyle; /// 标题右边的副标题文本样式 - /// TextStyle(fontSize: [BrnCommonConfig.fontSizeBase],color: [BrnCommonConfig.colorTextSecondary]) - BrnTextStyle subtitleTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextSecondary], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _subtitleTextStyle; + + BrnTextStyle get subtitleTextStyle => + _subtitleTextStyle ?? + BrnDefaultConfigUtils.defaultCardTitleConfig.subtitleTextStyle; /// 详情文本样式 - /// TextStyle(fontSize: [BrnCommonConfig.fontSizeBase], color: [BrnCommonConfig.colorTextBase]) - BrnTextStyle detailTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _detailTextStyle; + + BrnTextStyle get detailTextStyle => + _detailTextStyle ?? + BrnDefaultConfigUtils.defaultCardTitleConfig.detailTextStyle; /// 辅助文本样式 - /// TextStyle(fontSize: [BrnCommonConfig.fontSizeBase],color: [BrnCommonConfig.colorTextSecondary],) - BrnTextStyle accessoryTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextSecondary], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _accessoryTextStyle; + + BrnTextStyle get accessoryTextStyle => + _accessoryTextStyle ?? + BrnDefaultConfigUtils.defaultCardTitleConfig.accessoryTextStyle; /// 对齐方式 - /// PlaceholderAlignment.middle - PlaceholderAlignment alignment; + /// 默认为 [PlaceholderAlignment.middle] + PlaceholderAlignment? _alignment; + + PlaceholderAlignment get alignment => + _alignment ?? BrnDefaultConfigUtils.defaultCardTitleConfig.alignment; /// 卡片背景 - /// [BrnCommonConfig.fillBase] - Color cardBackgroundColor; - - BrnCardTitleConfig( - {this.titleWithHeightTextStyle, - this.detailTextStyle, - this.accessoryTextStyle, - this.cardTitlePadding, - this.titleTextStyle, - this.subtitleTextStyle, - this.alignment, - this.cardBackgroundColor, - String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID}) - : super(configId: configId); + /// 默认为 [BrnCommonConfig.fillBase] + Color? _cardBackgroundColor; + + Color get cardBackgroundColor => + _cardBackgroundColor ?? + BrnDefaultConfigUtils.defaultCardTitleConfig.cardBackgroundColor; /// cardTitleConfig 获取逻辑详见 [BrnThemeConfigurator.getConfig] 方法 @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); BrnCardTitleConfig cardTitleConfig = BrnThemeConfigurator.instance .getConfig(configId: configId) .cardTitleConfig; - this.cardBackgroundColor ??= commonConfig.fillBase; - - if (this.cardTitlePadding == null) { - this.cardTitlePadding = EdgeInsets.only( - left: cardTitleConfig.cardTitlePadding.left, - top: commonConfig.vSpacingXl, - right: cardTitleConfig.cardTitlePadding.right, - bottom: commonConfig.vSpacingMd); - } - - this.titleWithHeightTextStyle = cardTitleConfig.titleWithHeightTextStyle - .merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeHead) - .merge(this.titleWithHeightTextStyle)); - - this.titleTextStyle = cardTitleConfig.titleTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeHead, - ).merge(this.titleTextStyle)); - - this.subtitleTextStyle = - cardTitleConfig.subtitleTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeBase, - ).merge(this.subtitleTextStyle)); - - this.accessoryTextStyle = - cardTitleConfig.accessoryTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextSecondary, - fontSize: commonConfig.fontSizeHead, - ).merge(this.accessoryTextStyle)); - - this.detailTextStyle = cardTitleConfig.detailTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeBase, - ).merge(this.detailTextStyle)); - - this.alignment ??= cardTitleConfig.alignment; + _cardBackgroundColor ??= commonConfig.fillBase; + _cardTitlePadding ??= EdgeInsets.only( + left: cardTitleConfig.cardTitlePadding.left, + top: commonConfig.vSpacingXl, + right: cardTitleConfig.cardTitlePadding.right, + bottom: commonConfig.vSpacingMd, + ); + _titleWithHeightTextStyle = cardTitleConfig.titleWithHeightTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeHead, + ).merge(_titleWithHeightTextStyle), + ); + _titleTextStyle = cardTitleConfig.titleTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeHead, + ).merge(_titleTextStyle), + ); + _subtitleTextStyle = cardTitleConfig.subtitleTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase, + ).merge(_subtitleTextStyle), + ); + _accessoryTextStyle = cardTitleConfig.accessoryTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextSecondary, + fontSize: commonConfig.fontSizeHead, + ).merge(_accessoryTextStyle), + ); + _detailTextStyle = cardTitleConfig.detailTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase, + ).merge(_detailTextStyle), + ); + _alignment ??= cardTitleConfig._alignment; } - BrnCardTitleConfig copyWith( - {EdgeInsets cardTitlePadding, - BrnTextStyle titleWithHeightTextStyle, - BrnTextStyle titleTextStyle, - BrnTextStyle subtitleTextStyle, - BrnTextStyle detailTextStyle, - BrnTextStyle accessoryTextStyle, - PlaceholderAlignment alignment, - Color cardBackgroundColor}) { + BrnCardTitleConfig copyWith({ + EdgeInsets? cardTitlePadding, + BrnTextStyle? titleWithHeightTextStyle, + BrnTextStyle? titleTextStyle, + BrnTextStyle? subtitleTextStyle, + BrnTextStyle? detailTextStyle, + BrnTextStyle? accessoryTextStyle, + PlaceholderAlignment? alignment, + Color? cardBackgroundColor, + }) { return BrnCardTitleConfig( - cardTitlePadding: cardTitlePadding ?? this.cardTitlePadding, - titleWithHeightTextStyle: - titleWithHeightTextStyle ?? this.titleWithHeightTextStyle, - titleTextStyle: titleTextStyle ?? this.titleTextStyle, - subtitleTextStyle: subtitleTextStyle ?? this.subtitleTextStyle, - detailTextStyle: detailTextStyle ?? this.detailTextStyle, - accessoryTextStyle: accessoryTextStyle ?? this.accessoryTextStyle, - alignment: alignment ?? this.alignment, - cardBackgroundColor: cardBackgroundColor ?? this.cardBackgroundColor); + cardTitlePadding: cardTitlePadding ?? _cardTitlePadding, + titleWithHeightTextStyle: + titleWithHeightTextStyle ?? _titleWithHeightTextStyle, + titleTextStyle: titleTextStyle ?? _titleTextStyle, + subtitleTextStyle: subtitleTextStyle ?? _subtitleTextStyle, + detailTextStyle: detailTextStyle ?? _detailTextStyle, + accessoryTextStyle: accessoryTextStyle ?? _accessoryTextStyle, + alignment: alignment ?? _alignment, + cardBackgroundColor: cardBackgroundColor ?? _cardBackgroundColor, + ); } - BrnCardTitleConfig merge(BrnCardTitleConfig other) { + BrnCardTitleConfig merge(BrnCardTitleConfig? other) { if (other == null) return this; return copyWith( - cardTitlePadding: other.cardTitlePadding, - titleWithHeightTextStyle: this - .titleWithHeightTextStyle - ?.merge(other.titleWithHeightTextStyle) ?? - other.titleWithHeightTextStyle, - titleTextStyle: this.titleTextStyle?.merge(other.titleTextStyle) ?? - other.titleTextStyle, - subtitleTextStyle: - this.subtitleTextStyle?.merge(other.subtitleTextStyle) ?? - other.subtitleTextStyle, - detailTextStyle: this.detailTextStyle?.merge(other.detailTextStyle) ?? - other.detailTextStyle, - accessoryTextStyle: - this.accessoryTextStyle?.merge(other.accessoryTextStyle) ?? - other.accessoryTextStyle, - alignment: other.alignment, - cardBackgroundColor: other.cardBackgroundColor, + cardTitlePadding: other._cardTitlePadding, + titleWithHeightTextStyle: + titleWithHeightTextStyle.merge(other._titleWithHeightTextStyle), + titleTextStyle: titleTextStyle.merge(other._titleTextStyle), + subtitleTextStyle: subtitleTextStyle.merge(other._subtitleTextStyle), + detailTextStyle: detailTextStyle.merge(other._detailTextStyle), + accessoryTextStyle: accessoryTextStyle.merge(other._accessoryTextStyle), + alignment: other._alignment, + cardBackgroundColor: other._cardBackgroundColor, ); } } diff --git a/lib/src/theme/configs/brn_common_config.dart b/lib/src/theme/configs/brn_common_config.dart index 5464eac7..fa652fff 100644 --- a/lib/src/theme/configs/brn_common_config.dart +++ b/lib/src/theme/configs/brn_common_config.dart @@ -1,381 +1,660 @@ -import 'dart:ui'; - import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; +import 'package:flutter/painting.dart'; -/// 描述: 全局配置 -/// 配置属性 色值、字体大小、间距、圆角 - +/// 描述: 全局配置 +/// 配置属性:色值、字体大小、间距、圆角 class BrnCommonConfig extends BrnBaseConfig { - static const double hd = 1; // 基本单位 + BrnCommonConfig({ + Color? brandPrimary, + Color? brandPrimaryTap, + Color? brandSuccess, + Color? brandWarning, + Color? brandError, + Color? brandImportant, + Color? brandImportantValue, + Color? brandAuxiliary, + Color? colorTextBase, + Color? colorTextImportant, + Color? colorTextBaseInverse, + Color? colorTextSecondary, + Color? colorTextDisabled, + Color? colorTextHint, + Color? colorLink, + Color? fillBase, + Color? fillBody, + Color? fillMask, + Color? borderColorBase, + Color? dividerColorBase, + double? fontSizeBebas, + double? fontSizeHeadLg, + double? fontSizeBase, + double? fontSizeHead, + double? fontSizeSubHead, + double? fontSizeCaption, + double? fontSizeCaptionSm, + double? radiusXs, + double? radiusSm, + double? radiusMd, + double? radiusLg, + double? borderWidthSm, + double? borderWidthMd, + double? borderWidthLg, + double? hSpacingXs, + double? hSpacingSm, + double? hSpacingMd, + double? hSpacingLg, + double? hSpacingXl, + double? hSpacingXxl, + double? vSpacingXs, + double? vSpacingSm, + double? vSpacingMd, + double? vSpacingLg, + double? vSpacingXl, + double? vSpacingXxl, + double? iconSizeXxs, + double? iconSizeXs, + double? iconSizeSm, + double? iconSizeMd, + double? iconSizeLg, + String configId = GLOBAL_CONFIG_ID, + }) : _brandPrimary = brandPrimary, + _brandPrimaryTap = brandPrimaryTap, + _brandSuccess = brandSuccess, + _brandWarning = brandWarning, + _brandError = brandError, + _brandImportant = brandImportant, + _brandImportantValue = brandImportantValue, + _brandAuxiliary = brandAuxiliary, + _colorTextBase = colorTextBase, + _colorTextImportant = colorTextImportant, + _colorTextBaseInverse = colorTextBaseInverse, + _colorTextSecondary = colorTextSecondary, + _colorTextDisabled = colorTextDisabled, + _colorTextHint = colorTextHint, + _colorLink = colorLink, + _fillBase = fillBase, + _fillBody = fillBody, + _fillMask = fillMask, + _borderColorBase = borderColorBase, + _dividerColorBase = dividerColorBase, + _fontSizeBebas = fontSizeBebas, + _fontSizeHeadLg = fontSizeHeadLg, + _fontSizeBase = fontSizeBase, + _fontSizeHead = fontSizeHead, + _fontSizeSubHead = fontSizeSubHead, + _fontSizeCaption = fontSizeCaption, + _fontSizeCaptionSm = fontSizeCaptionSm, + _radiusXs = radiusXs, + _radiusSm = radiusSm, + _radiusMd = radiusMd, + _radiusLg = radiusLg, + _borderWidthSm = borderWidthSm, + _borderWidthMd = borderWidthMd, + _borderWidthLg = borderWidthLg, + _hSpacingXs = hSpacingXs, + _hSpacingSm = hSpacingSm, + _hSpacingMd = hSpacingMd, + _hSpacingLg = hSpacingLg, + _hSpacingXl = hSpacingXl, + _hSpacingXxl = hSpacingXxl, + _vSpacingXs = vSpacingXs, + _vSpacingSm = vSpacingSm, + _vSpacingMd = vSpacingMd, + _vSpacingLg = vSpacingLg, + _vSpacingXl = vSpacingXl, + _vSpacingXxl = vSpacingXxl, + _iconSizeXxs = iconSizeXxs, + _iconSizeXs = iconSizeXs, + _iconSizeSm = iconSizeSm, + _iconSizeMd = iconSizeMd, + _iconSizeLg = iconSizeLg, + super(configId: configId); - ///*******************色彩********************* + BrnCommonConfig.autoFlatConfig({ + Color? brandPrimary, + Color? brandPrimaryTap, + Color? brandSuccess, + Color? brandWarning, + Color? brandError, + Color? brandImportant, + Color? brandImportantValue, + Color? brandAuxiliary, + Color? colorTextBase, + Color? colorTextImportant, + Color? colorTextBaseInverse, + Color? colorTextSecondary, + Color? colorTextDisabled, + Color? colorTextHint, + Color? colorLink, + Color? fillBase, + Color? fillBody, + Color? fillMask, + Color? borderColorBase, + Color? dividerColorBase, + double? fontSizeBebas, + double? fontSizeHeadLg, + double? fontSizeBase, + double? fontSizeHead, + double? fontSizeSubHead, + double? fontSizeCaption, + double? fontSizeCaptionSm, + double? radiusXs, + double? radiusSm, + double? radiusMd, + double? radiusLg, + double? borderWidthSm, + double? borderWidthMd, + double? borderWidthLg, + double? hSpacingXs, + double? hSpacingSm, + double? hSpacingMd, + double? hSpacingLg, + double? hSpacingXl, + double? hSpacingXxl, + double? vSpacingXs, + double? vSpacingSm, + double? vSpacingMd, + double? vSpacingLg, + double? vSpacingXl, + double? vSpacingXxl, + double? iconSizeXxs, + double? iconSizeXs, + double? iconSizeSm, + double? iconSizeMd, + double? iconSizeLg, + String configId = GLOBAL_CONFIG_ID, + }) : _brandPrimary = brandPrimary, + _brandPrimaryTap = brandPrimaryTap, + _brandSuccess = brandSuccess, + _brandWarning = brandWarning, + _brandError = brandError, + _brandImportant = brandImportant, + _brandImportantValue = brandImportantValue, + _brandAuxiliary = brandAuxiliary, + _colorTextBase = colorTextBase, + _colorTextImportant = colorTextImportant, + _colorTextBaseInverse = colorTextBaseInverse, + _colorTextSecondary = colorTextSecondary, + _colorTextDisabled = colorTextDisabled, + _colorTextHint = colorTextHint, + _colorLink = colorLink, + _fillBase = fillBase, + _fillBody = fillBody, + _fillMask = fillMask, + _borderColorBase = borderColorBase, + _dividerColorBase = dividerColorBase, + _fontSizeBebas = fontSizeBebas, + _fontSizeHeadLg = fontSizeHeadLg, + _fontSizeBase = fontSizeBase, + _fontSizeHead = fontSizeHead, + _fontSizeSubHead = fontSizeSubHead, + _fontSizeCaption = fontSizeCaption, + _fontSizeCaptionSm = fontSizeCaptionSm, + _radiusXs = radiusXs, + _radiusSm = radiusSm, + _radiusMd = radiusMd, + _radiusLg = radiusLg, + _borderWidthSm = borderWidthSm, + _borderWidthMd = borderWidthMd, + _borderWidthLg = borderWidthLg, + _hSpacingXs = hSpacingXs, + _hSpacingSm = hSpacingSm, + _hSpacingMd = hSpacingMd, + _hSpacingLg = hSpacingLg, + _hSpacingXl = hSpacingXl, + _hSpacingXxl = hSpacingXxl, + _vSpacingXs = vSpacingXs, + _vSpacingSm = vSpacingSm, + _vSpacingMd = vSpacingMd, + _vSpacingLg = vSpacingLg, + _vSpacingXl = vSpacingXl, + _vSpacingXxl = vSpacingXxl, + _iconSizeXxs = iconSizeXxs, + _iconSizeXs = iconSizeXs, + _iconSizeSm = iconSizeSm, + _iconSizeMd = iconSizeMd, + _iconSizeLg = iconSizeLg, + super(configId: configId, autoFlatConfig: true); + + /// 基本单位 + static const double hd = 1; + +/////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////// 色彩 ///////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////// 品牌色 ///////////////////////////////////// - /// 品牌色相关 - /// /// 品牌色 - /// default value is Color(0xFF0984F9) - Color brandPrimary; + /// 默认为 Color(0xFF0984F9) + Color? _brandPrimary; /// 主题色按下效果 - /// default value is Color(0x190984F9) - Color brandPrimaryTap; + /// 默认为 Color(0x190984F9) + Color? _brandPrimaryTap; /// 成功色 - /// default value is Color(0xFF00AE66) - Color brandSuccess; + /// 默认为 Color(0xFF00AE66) + Color? _brandSuccess; /// 警告色 - /// default value is Color(0xFFFAAD14) - Color brandWarning; + /// 默认为 Color(0xFFFAAD14) + Color? _brandWarning; /// 失败色 - /// default value is Color(0xFFFA3F3F) - Color brandError; + /// 默认为 Color(0xFFFA3F3F) + Color? _brandError; /// 重要-多用于红点色 - /// default value is Color(0xFFFA3F3F) - Color brandImportant; + /// 默认为 Color(0xFFFA3F3F) + Color? _brandImportant; /// 重要数值色 - /// default value is Color(0xFFFF5722) - Color brandImportantValue; + /// 默认为 Color(0xFFFF5722) + Color? _brandImportantValue; /// 辅助色 - /// default value is Color(0xFF44C2FF) - Color brandAuxiliary; + /// 默认为 Color(0xFF44C2FF) + Color? _brandAuxiliary; /// 文本色相关 /// /// 基础文字纯黑色 - /// default value is Color(0xFF222222) - Color colorTextBase; + /// 默认为 Color(0xFF222222) + Color? _colorTextBase; /// 基础文字重要色 - /// default value is Color(0xFF666666) - Color colorTextImportant; + /// 默认为 Color(0xFF666666) + Color? _colorTextImportant; /// 基础文字-反色 - /// default value is Color(0xFFFFFFFF) - Color colorTextBaseInverse; + /// 默认为 Color(0xFFFFFFFF) + Color? _colorTextBaseInverse; /// 辅助文字色 - /// default value is Color(0xFF999999) - Color colorTextSecondary; + /// 默认为 Color(0xFF999999) + Color? _colorTextSecondary; /// 失效或不可更改文字色 - /// default value is Color(0xFF999999) - Color colorTextDisabled; + /// 默认为 Color(0xFF999999) + Color? _colorTextDisabled; /// 文本框提示暗文文字色 - /// default value is Color(0xFFCCCCCC) - Color colorTextHint; + /// 默认为 Color(0xFFCCCCCC) + Color? _colorTextHint; /// 跟随主题色[brandPrimary] - Color colorLink; + Color? _colorLink; /// 背景色相关 /// /// 组件背景色 - /// default value is Color(0xFFFFFFFF) - Color fillBase; + /// 默认为 Color(0xFFFFFFFF) + Color? _fillBase; /// 页面背景色 - /// default value is Color(0xFFF8F8F8) - Color fillBody; + /// 默认为 Color(0xFFF8F8F8) + Color? _fillBody; /// 遮罩背景 - /// default value is Color(0x99000000) - Color fillMask; + /// 默认为 Color(0x99000000) + Color? _fillMask; /// 边框色 - /// default value is Color(0xFFF0F0F0) - Color borderColorBase; + /// 默认为 Color(0xFFF0F0F0) + Color? _borderColorBase; /// 分割线色 - /// default value is Color(0xFFF0F0F0) - Color dividerColorBase; + /// 默认为 Color(0xFFF0F0F0) + Color? _dividerColorBase; + +/////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////// 尺寸 ///////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// /// 文本字号 /// /// 特殊数据展示,Bebas 数字字体,用于强吸引 /// default value is 28 - double fontSizeBebas; + double? _fontSizeBebas; /// 标题字体 /// 名称/页面大标题 - /// default value is 22 - double fontSizeHeadLg; + /// 默认为 22 + double? _fontSizeHeadLg; /// 标题字体 /// 内容模块标题/一级标题 - /// default value is 18 - double fontSizeHead; + /// 默认为 18 + double? _fontSizeHead; /// 子标题字体 /// 标题/录入文字/大按钮文字/二级标题 - /// default value is 16 - double fontSizeSubHead; + /// 默认为 16 + double? _fontSizeSubHead; /// 基础字体 /// 内容副文本/普通说明文字 - /// default value is 14 - double fontSizeBase; + /// 默认为 14 + double? _fontSizeBase; /// 辅助字体-普通 - /// default value is 12 - double fontSizeCaption; + /// 默认为 12 + double? _fontSizeCaption; ///辅助字体-小 - /// default value is 11 - double fontSizeCaptionSm; + /// 默认为 11 + double? _fontSizeCaptionSm; /// 圆角尺寸 - /// default value is 2.0 - double radiusXs; + /// 默认为 2.0 + double? _radiusXs; - /// default value is 4.0 - double radiusSm; + /// 默认为 4.0 + double? _radiusSm; - /// default value is 6.0 - double radiusMd; + /// 默认为 6.0 + double? _radiusMd; - /// default value is 8.0 - double radiusLg; + /// 默认为 8.0 + double? _radiusLg; /// 边框尺寸 /// - /// default 0.5 - double borderWidthSm; + /// 默认为 0.5 + double? _borderWidthSm; - /// default 1 - double borderWidthMd; + /// 默认为 1 + double? _borderWidthMd; - /// default 2 - double borderWidthLg; + /// 默认为 2 + double? _borderWidthLg; /// 水平间距 - /// - /// default 8 - double hSpacingXs; + /// 默认为 8 + double? _hSpacingXs; - /// default 12 - double hSpacingSm; + /// 默认为 12 + double? _hSpacingSm; - /// default 16 - double hSpacingMd; + /// 默认为 16 + double? _hSpacingMd; - /// default 20 - double hSpacingLg; + /// 默认为 20 + double? _hSpacingLg; - /// default 24 - double hSpacingXl; + /// 默认为 24 + double? _hSpacingXl; - /// default 42 - double hSpacingXxl; + /// 默认为 42 + double? _hSpacingXxl; /// 垂直间距 - /// - /// default 4 - double vSpacingXs; + /// 默认为 4 + double? _vSpacingXs; - /// default 8 - double vSpacingSm; + /// 默认为 8 + double? _vSpacingSm; - /// default 12 - double vSpacingMd; + /// 默认为 12 + double? _vSpacingMd; - /// default 14 - double vSpacingLg; + /// 默认为 14 + double? _vSpacingLg; - /// default 16 - double vSpacingXl; + /// 默认为 16 + double? _vSpacingXl; - /// default 28 - double vSpacingXxl; + /// 默认为 28 + double? _vSpacingXxl; /// 图标尺寸 + /// 默认为 8 + double? _iconSizeXxs; - /// default 8 - double iconSizeXxs; + /// 默认为 12 + double? _iconSizeXs; - /// default 12 - double iconSizeXs; + /// 默认为 14 + double? _iconSizeSm; - /// default 14 - double iconSizeSm; + /// 默认为 16 + double? _iconSizeMd; - /// default 16 - double iconSizeMd; + /// 默认为 32 + double? _iconSizeLg; - /// default 32 - double iconSizeLg; + Color get brandPrimary => + _brandPrimary ?? BrnDefaultConfigUtils.defaultCommonConfig.brandPrimary; - BrnCommonConfig({ - this.brandPrimary, - this.brandPrimaryTap, - this.brandSuccess, - this.brandWarning, - this.brandError, - this.brandImportant, - this.brandImportantValue, - this.brandAuxiliary, - this.colorTextBase, - this.colorTextImportant, - this.colorTextBaseInverse, - this.colorTextSecondary, - this.colorTextDisabled, - this.colorTextHint, - this.colorLink, - this.fillBase, - this.fillBody, - this.fillMask, - this.borderColorBase, - this.dividerColorBase, - this.fontSizeBebas, - this.fontSizeHeadLg, - this.fontSizeBase, - this.fontSizeHead, - this.fontSizeSubHead, - this.fontSizeCaption, - this.fontSizeCaptionSm, - this.radiusXs, - this.radiusSm, - this.radiusMd, - this.radiusLg, - this.borderWidthSm, - this.borderWidthMd, - this.borderWidthLg, - this.hSpacingXs, - this.hSpacingSm, - this.hSpacingMd, - this.hSpacingLg, - this.hSpacingXl, - this.hSpacingXxl, - this.vSpacingXs, - this.vSpacingSm, - this.vSpacingMd, - this.vSpacingLg, - this.vSpacingXl, - this.vSpacingXxl, - this.iconSizeXxs, - this.iconSizeXs, - this.iconSizeSm, - this.iconSizeMd, - this.iconSizeLg, - String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID, - }) : super(configId: configId); + Color get brandPrimaryTap => + _brandPrimaryTap ?? + BrnDefaultConfigUtils.defaultCommonConfig.brandPrimaryTap; - BrnCommonConfig.autoFlatConfig({ - this.brandPrimary, - this.brandPrimaryTap, - this.brandSuccess, - this.brandWarning, - this.brandError, - this.brandImportant, - this.brandImportantValue, - this.brandAuxiliary, - this.colorTextBase, - this.colorTextImportant, - this.colorTextBaseInverse, - this.colorTextSecondary, - this.colorTextDisabled, - this.colorTextHint, - this.colorLink, - this.fillBase, - this.fillBody, - this.fillMask, - this.borderColorBase, - this.dividerColorBase, - this.fontSizeBebas, - this.fontSizeHeadLg, - this.fontSizeBase, - this.fontSizeHead, - this.fontSizeSubHead, - this.fontSizeCaption, - this.fontSizeCaptionSm, - this.radiusXs, - this.radiusSm, - this.radiusMd, - this.radiusLg, - this.borderWidthSm, - this.borderWidthMd, - this.borderWidthLg, - this.hSpacingXs, - this.hSpacingSm, - this.hSpacingMd, - this.hSpacingLg, - this.hSpacingXl, - this.hSpacingXxl, - this.vSpacingXs, - this.vSpacingSm, - this.vSpacingMd, - this.vSpacingLg, - this.vSpacingXl, - this.vSpacingXxl, - this.iconSizeXxs, - this.iconSizeXs, - this.iconSizeSm, - this.iconSizeMd, - this.iconSizeLg, - String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID, - }) : super(configId: configId, autoFlatConfig: true); - - /// 优先级 [GLOBAL_CONFIG_ID] 获取配置 > [BRUNO_CONFIG_ID] 获取配置 + Color get brandSuccess => + _brandSuccess ?? BrnDefaultConfigUtils.defaultCommonConfig.brandSuccess; + + Color get brandWarning => + _brandWarning ?? BrnDefaultConfigUtils.defaultCommonConfig.brandWarning; + + Color get brandError => + _brandError ?? BrnDefaultConfigUtils.defaultCommonConfig.brandError; + + Color get brandImportant => + _brandImportant ?? + BrnDefaultConfigUtils.defaultCommonConfig.brandImportant; + + Color get brandImportantValue => + _brandImportantValue ?? + BrnDefaultConfigUtils.defaultCommonConfig.brandImportantValue; + + Color get brandAuxiliary => + _brandAuxiliary ?? + BrnDefaultConfigUtils.defaultCommonConfig.brandAuxiliary; + + Color get colorTextBase => + _colorTextBase ?? BrnDefaultConfigUtils.defaultCommonConfig.colorTextBase; + + Color get colorTextImportant => + _colorTextImportant ?? + BrnDefaultConfigUtils.defaultCommonConfig.colorTextImportant; + + Color get colorTextBaseInverse => + _colorTextBaseInverse ?? + BrnDefaultConfigUtils.defaultCommonConfig.colorTextBaseInverse; + + Color get colorTextSecondary => + _colorTextSecondary ?? + BrnDefaultConfigUtils.defaultCommonConfig.colorTextSecondary; + + Color get colorTextDisabled => + _colorTextDisabled ?? + BrnDefaultConfigUtils.defaultCommonConfig.colorTextDisabled; + + Color get colorTextHint => + _colorTextHint ?? BrnDefaultConfigUtils.defaultCommonConfig.colorTextHint; + + Color get colorLink => + _colorLink ?? BrnDefaultConfigUtils.defaultCommonConfig.colorLink; + + Color get fillBase => + _fillBase ?? BrnDefaultConfigUtils.defaultCommonConfig.fillBase; + + Color get fillBody => + _fillBody ?? BrnDefaultConfigUtils.defaultCommonConfig.fillBody; + + Color get fillMask => + _fillMask ?? BrnDefaultConfigUtils.defaultCommonConfig.fillMask; + + Color get borderColorBase => + _borderColorBase ?? + BrnDefaultConfigUtils.defaultCommonConfig.borderColorBase; + + Color get dividerColorBase => + _dividerColorBase ?? + BrnDefaultConfigUtils.defaultCommonConfig.dividerColorBase; + + double get fontSizeBebas => + _fontSizeBebas ?? BrnDefaultConfigUtils.defaultCommonConfig.fontSizeBebas; + + double get fontSizeHeadLg => + _fontSizeHeadLg ?? + BrnDefaultConfigUtils.defaultCommonConfig.fontSizeHeadLg; + + double get fontSizeHead => + _fontSizeHead ?? BrnDefaultConfigUtils.defaultCommonConfig.fontSizeHead; + + double get fontSizeSubHead => + _fontSizeSubHead ?? + BrnDefaultConfigUtils.defaultCommonConfig.fontSizeSubHead; + + double get fontSizeBase => + _fontSizeBase ?? BrnDefaultConfigUtils.defaultCommonConfig.fontSizeBase; + + double get fontSizeCaption => + _fontSizeCaption ?? + BrnDefaultConfigUtils.defaultCommonConfig.fontSizeCaption; + + double get fontSizeCaptionSm => + _fontSizeCaptionSm ?? + BrnDefaultConfigUtils.defaultCommonConfig.fontSizeCaptionSm; + + double get radiusXs => + _radiusXs ?? BrnDefaultConfigUtils.defaultCommonConfig.radiusXs; + + double get radiusSm => + _radiusSm ?? BrnDefaultConfigUtils.defaultCommonConfig.radiusSm; + + double get radiusMd => + _radiusMd ?? BrnDefaultConfigUtils.defaultCommonConfig.radiusMd; + + double get radiusLg => + _radiusLg ?? BrnDefaultConfigUtils.defaultCommonConfig.radiusLg; + + double get borderWidthSm => + _borderWidthSm ?? BrnDefaultConfigUtils.defaultCommonConfig.borderWidthSm; + + double get borderWidthMd => + _borderWidthMd ?? BrnDefaultConfigUtils.defaultCommonConfig.borderWidthMd; + + double get borderWidthLg => + _borderWidthLg ?? BrnDefaultConfigUtils.defaultCommonConfig.borderWidthLg; + + double get hSpacingXs => + _hSpacingXs ?? BrnDefaultConfigUtils.defaultCommonConfig.hSpacingXs; + + double get hSpacingSm => + _hSpacingSm ?? BrnDefaultConfigUtils.defaultCommonConfig.hSpacingSm; + + double get hSpacingMd => + _hSpacingMd ?? BrnDefaultConfigUtils.defaultCommonConfig.hSpacingMd; + + double get hSpacingLg => + _hSpacingLg ?? BrnDefaultConfigUtils.defaultCommonConfig.hSpacingLg; + + double get hSpacingXl => + _hSpacingXl ?? BrnDefaultConfigUtils.defaultCommonConfig.hSpacingXl; + + double get hSpacingXxl => + _hSpacingXxl ?? BrnDefaultConfigUtils.defaultCommonConfig.hSpacingXxl; + + double get vSpacingXs => + _vSpacingXs ?? BrnDefaultConfigUtils.defaultCommonConfig.vSpacingXs; + + double get vSpacingSm => + _vSpacingSm ?? BrnDefaultConfigUtils.defaultCommonConfig.vSpacingSm; + + double get vSpacingMd => + _vSpacingMd ?? BrnDefaultConfigUtils.defaultCommonConfig.vSpacingMd; + + double get vSpacingLg => + _vSpacingLg ?? BrnDefaultConfigUtils.defaultCommonConfig.vSpacingLg; + + double get vSpacingXl => + _vSpacingXl ?? BrnDefaultConfigUtils.defaultCommonConfig.vSpacingXl; + + double get vSpacingXxl => + _vSpacingXxl ?? BrnDefaultConfigUtils.defaultCommonConfig.vSpacingXxl; + + double get iconSizeXxs => + _iconSizeXxs ?? BrnDefaultConfigUtils.defaultCommonConfig.iconSizeXxs; + + double get iconSizeXs => + _iconSizeXs ?? BrnDefaultConfigUtils.defaultCommonConfig.iconSizeXs; + + double get iconSizeSm => + _iconSizeSm ?? BrnDefaultConfigUtils.defaultCommonConfig.iconSizeSm; + + double get iconSizeMd => + _iconSizeMd ?? BrnDefaultConfigUtils.defaultCommonConfig.iconSizeMd; + + double get iconSizeLg => + _iconSizeLg ?? BrnDefaultConfigUtils.defaultCommonConfig.iconSizeLg; + + /// 优先级 [GLOBAL_CONFIG_ID] 获取配置 > [BRUNO_CONFIG_ID] 获取配置 @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); + /// 获取合适的 完整配置(BrnAllConfig) - this.colorTextBase ??= commonConfig.colorTextBase; - this.colorTextImportant ??= commonConfig.colorTextImportant; - this.colorTextBaseInverse ??= commonConfig.colorTextBaseInverse; - this.colorTextSecondary ??= commonConfig.colorTextSecondary; - this.colorTextHint ??= commonConfig.colorTextHint; - this.colorTextDisabled ??= commonConfig.colorTextDisabled; - this.brandAuxiliary ??= commonConfig.brandAuxiliary; - this.colorLink ??= commonConfig.colorLink; - this.fillBase ??= commonConfig.fillBase; - this.fillBody ??= commonConfig.fillBody; - this.fillMask ??= commonConfig.fillMask; - this.brandPrimary ??= commonConfig.brandPrimary; - this.brandPrimaryTap ??= commonConfig.brandPrimaryTap; - this.brandSuccess ??= commonConfig.brandSuccess; - this.brandWarning ??= commonConfig.brandWarning; - this.brandError ??= commonConfig.brandError; - this.brandImportant ??= commonConfig.brandImportant; - this.brandImportantValue ??= commonConfig.brandImportantValue; - this.borderColorBase ??= commonConfig.borderColorBase; - this.dividerColorBase ??= commonConfig.dividerColorBase; - this.fontSizeBebas ??= commonConfig.fontSizeBebas; - this.fontSizeHeadLg ??= commonConfig.fontSizeHeadLg; - this.fontSizeBase ??= commonConfig.fontSizeBase; - this.fontSizeHead ??= commonConfig.fontSizeHead; - this.fontSizeSubHead ??= commonConfig.fontSizeSubHead; - this.fontSizeCaption ??= commonConfig.fontSizeCaption; - this.fontSizeCaptionSm ??= commonConfig.fontSizeCaptionSm; - this.radiusXs ??= commonConfig.radiusXs; - this.radiusSm ??= commonConfig.radiusSm; - this.radiusMd ??= commonConfig.radiusMd; - this.radiusLg ??= commonConfig.radiusLg; - this.borderWidthSm ??= commonConfig.borderWidthSm; - this.borderWidthMd ??= commonConfig.borderWidthMd; - this.borderWidthLg ??= commonConfig.borderWidthLg; - this.hSpacingXs ??= commonConfig.hSpacingXs; - this.hSpacingSm ??= commonConfig.hSpacingSm; - this.hSpacingMd ??= commonConfig.hSpacingMd; - this.hSpacingLg ??= commonConfig.hSpacingLg; - this.hSpacingXl ??= commonConfig.hSpacingXl; - this.hSpacingXxl ??= commonConfig.hSpacingXxl; - this.vSpacingXs ??= commonConfig.vSpacingXs; - this.vSpacingSm ??= commonConfig.vSpacingSm; - this.vSpacingMd ??= commonConfig.vSpacingMd; - this.vSpacingLg ??= commonConfig.vSpacingLg; - this.vSpacingXl ??= commonConfig.vSpacingXl; - this.vSpacingXxl ??= commonConfig.vSpacingXxl; - this.iconSizeXxs ??= commonConfig.iconSizeXxs; - this.iconSizeXs ??= commonConfig.iconSizeXs; - this.iconSizeSm ??= commonConfig.iconSizeSm; - this.iconSizeMd ??= commonConfig.iconSizeMd; - this.iconSizeLg ??= commonConfig.iconSizeLg; + _colorTextBase ??= commonConfig._colorTextBase; + _colorTextImportant ??= commonConfig._colorTextImportant; + _colorTextBaseInverse ??= commonConfig._colorTextBaseInverse; + _colorTextSecondary ??= commonConfig._colorTextSecondary; + _colorTextHint ??= commonConfig._colorTextHint; + _colorTextDisabled ??= commonConfig._colorTextDisabled; + _brandAuxiliary ??= commonConfig._brandAuxiliary; + _colorLink ??= commonConfig._colorLink; + _fillBase ??= commonConfig._fillBase; + _fillBody ??= commonConfig._fillBody; + _fillMask ??= commonConfig._fillMask; + _brandPrimary ??= commonConfig._brandPrimary; + _brandPrimaryTap ??= commonConfig._brandPrimaryTap; + _brandSuccess ??= commonConfig._brandSuccess; + _brandWarning ??= commonConfig._brandWarning; + _brandError ??= commonConfig._brandError; + _brandImportant ??= commonConfig._brandImportant; + _brandImportantValue ??= commonConfig._brandImportantValue; + _borderColorBase ??= commonConfig._borderColorBase; + _dividerColorBase ??= commonConfig._dividerColorBase; + _fontSizeBebas ??= commonConfig._fontSizeBebas; + _fontSizeHeadLg ??= commonConfig._fontSizeHeadLg; + _fontSizeBase ??= commonConfig._fontSizeBase; + _fontSizeHead ??= commonConfig._fontSizeHead; + _fontSizeSubHead ??= commonConfig._fontSizeSubHead; + _fontSizeCaption ??= commonConfig._fontSizeCaption; + _fontSizeCaptionSm ??= commonConfig._fontSizeCaptionSm; + _radiusXs ??= commonConfig._radiusXs; + _radiusSm ??= commonConfig._radiusSm; + _radiusMd ??= commonConfig._radiusMd; + _radiusLg ??= commonConfig._radiusLg; + _borderWidthSm ??= commonConfig._borderWidthSm; + _borderWidthMd ??= commonConfig._borderWidthMd; + _borderWidthLg ??= commonConfig._borderWidthLg; + _hSpacingXs ??= commonConfig._hSpacingXs; + _hSpacingSm ??= commonConfig._hSpacingSm; + _hSpacingMd ??= commonConfig._hSpacingMd; + _hSpacingLg ??= commonConfig._hSpacingLg; + _hSpacingXl ??= commonConfig._hSpacingXl; + _hSpacingXxl ??= commonConfig._hSpacingXxl; + _vSpacingXs ??= commonConfig._vSpacingXs; + _vSpacingSm ??= commonConfig._vSpacingSm; + _vSpacingMd ??= commonConfig._vSpacingMd; + _vSpacingLg ??= commonConfig._vSpacingLg; + _vSpacingXl ??= commonConfig._vSpacingXl; + _vSpacingXxl ??= commonConfig._vSpacingXxl; + _iconSizeXxs ??= commonConfig._iconSizeXxs; + _iconSizeXs ??= commonConfig._iconSizeXs; + _iconSizeSm ??= commonConfig._iconSizeSm; + _iconSizeMd ??= commonConfig._iconSizeMd; + _iconSizeLg ??= commonConfig._iconSizeLg; } } diff --git a/lib/src/theme/configs/brn_dialog_config.dart b/lib/src/theme/configs/brn_dialog_config.dart index 3529ec86..cab28d71 100644 --- a/lib/src/theme/configs/brn_dialog_config.dart +++ b/lib/src/theme/configs/brn_dialog_config.dart @@ -1,125 +1,285 @@ import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; import 'package:bruno/src/theme/base/brn_text_style.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_common_config.dart'; import 'package:flutter/material.dart'; -/// 描述: Dialog 弹框主配置类 - +/// 描述: Dialog 弹框主配置类 class BrnDialogConfig extends BrnBaseConfig { + BrnDialogConfig({ + double? dialogWidth, + double? radius, + EdgeInsets? iconPadding, + EdgeInsets? titlePaddingSm, + EdgeInsets? titlePaddingLg, + BrnTextStyle? titleTextStyle, + TextAlign? titleTextAlign, + EdgeInsets? contentPaddingSm, + EdgeInsets? contentPaddingLg, + BrnTextStyle? contentTextStyle, + TextAlign? contentTextAlign, + EdgeInsets? warningPaddingSm, + EdgeInsets? warningPaddingLg, + BrnTextStyle? warningTextStyle, + TextAlign? warningTextAlign, + EdgeInsets? dividerPadding, + BrnTextStyle? mainActionTextStyle, + BrnTextStyle? assistActionsTextStyle, + Color? mainActionBackgroundColor, + Color? assistActionsBackgroundColor, + double? bottomHeight, + Color? backgroundColor, + String configId = GLOBAL_CONFIG_ID, + }) : _dialogWidth = dialogWidth, + _radius = radius, + _iconPadding = iconPadding, + _titlePaddingSm = titlePaddingSm, + _titlePaddingLg = titlePaddingLg, + _titleTextStyle = titleTextStyle, + _titleTextAlign = titleTextAlign, + _contentPaddingSm = contentPaddingSm, + _contentPaddingLg = contentPaddingLg, + _contentTextStyle = contentTextStyle, + _contentTextAlign = contentTextAlign, + _warningPaddingSm = warningPaddingSm, + _warningPaddingLg = warningPaddingLg, + _warningTextStyle = warningTextStyle, + _warningTextAlign = warningTextAlign, + _dividerPadding = dividerPadding, + _mainActionTextStyle = mainActionTextStyle, + _assistActionsTextStyle = assistActionsTextStyle, + _mainActionBackgroundColor = mainActionBackgroundColor, + _assistActionsBackgroundColor = assistActionsBackgroundColor, + _bottomHeight = bottomHeight, + _backgroundColor = backgroundColor, + super(configId: configId); + /// Dialog 宽度 - /// default 300 - double dialogWidth; + /// 默认为 300 + double? _dialogWidth; + + double get dialogWidth => + _dialogWidth ?? BrnDefaultConfigUtils.defaultDialogConfig.dialogWidth; /// Dialog 四周圆角 - /// default 8.0 use [BrnCommonConfig.radiusLg] - double radius; + /// 默认为 [BrnCommonConfig.radiusLg] + double? _radius; + + double get radius => + _radius ?? BrnDefaultConfigUtils.defaultDialogConfig.radius; - /// Dialog icon 距离顶部的边距 仅有顶部间距 - /// default EdgeInsets.only(top: [BrnCommonConfig.vSpacingXxl]) - EdgeInsets iconPadding; + /// Dialog icon 距离顶部的边距 + /// + /// EdgeInsets.only(top: [BrnCommonConfig.vSpacingXxl]) + EdgeInsets? _iconPadding; + + EdgeInsets get iconPadding => + _iconPadding ?? BrnDefaultConfigUtils.defaultDialogConfig.iconPadding; - /// title 当顶部 有 icon时四周间距,无底部间距 - /// default EdgeInsets.only(top: 12, left: [BrnCommonConfig.hSpacingXxl], right: [BrnCommonConfig.hSpacingXxl]) - EdgeInsets titlePaddingSm; + /// title 在顶部有 icon 时的边距 + /// + /// EdgeInsets.only( + /// top: 12, + /// left: [BrnCommonConfig.hSpacingXxl], + /// right: [BrnCommonConfig.hSpacingXxl], + /// ) + EdgeInsets? _titlePaddingSm; + + EdgeInsets get titlePaddingSm => + _titlePaddingSm ?? + BrnDefaultConfigUtils.defaultDialogConfig.titlePaddingSm; + + /// title 当顶部无 icon 时的边距 + /// + /// EdgeInsets.only( + /// top: 28, + /// left: [BrnCommonConfig.hSpacingXxl], + /// right: [BrnCommonConfig.hSpacingXxl], + /// ) + EdgeInsets? _titlePaddingLg; - /// title 当顶部 无 icon时四周间距,无底部间距 - /// default EdgeInsets.only(top: 28, left: [BrnCommonConfig.hSpacingXxl], right: [BrnCommonConfig.hSpacingXxl]) - EdgeInsets titlePaddingLg; + EdgeInsets get titlePaddingLg => + _titlePaddingLg ?? + BrnDefaultConfigUtils.defaultDialogConfig.titlePaddingLg; /// title 标题样式 - /// default BrnTextStyle(fontWeight: FontWeight.w600, fontSize: [ BrnCommonConfig.fontSizeHead], color: [BrnCommonConfig.colorTextBase]) - BrnTextStyle titleTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeHead], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _titleTextStyle; + + BrnTextStyle get titleTextStyle => + _titleTextStyle ?? + BrnDefaultConfigUtils.defaultDialogConfig.titleTextStyle; /// 标题的文字对齐 - /// default TextAlign.center - TextAlign titleTextAlign; + /// 默认为 [TextAlign.center] + TextAlign? _titleTextAlign; - /// content 当顶部 有 title或者icon时四周间距,无底部间距 - /// default EdgeInsets.only(top: 8, lecontentPaddingSmft: [BrnCommonConfig.hSpacingXl], right: [BrnCommonConfig.hSpacingXl]) - EdgeInsets contentPaddingSm; + TextAlign get titleTextAlign => + _titleTextAlign ?? + BrnDefaultConfigUtils.defaultDialogConfig.titleTextAlign; - /// content 当顶部 无 title或者icon时四周间距,无底部间距 - /// default EdgeInsets.only(top: 28, left: [BrnCommonConfig.hSpacingXl], right: [BrnCommonConfig.hSpacingXl]) - EdgeInsets contentPaddingLg; + /// content 当顶部有 title 或者 icon 时的边距 + /// + /// EdgeInsets.only( + /// top: 8, + /// left: [BrnCommonConfig.hSpacingXl], + /// right: [BrnCommonConfig.hSpacingXl], + /// ) + EdgeInsets? _contentPaddingSm; + + EdgeInsets get contentPaddingSm => + _contentPaddingSm ?? + BrnDefaultConfigUtils.defaultDialogConfig.contentPaddingSm; + + /// content 当顶部无 title 或者 icon 时的边距 + /// + /// EdgeInsets.only( + /// top: 28, + /// left: [BrnCommonConfig.hSpacingXl], + /// right: [BrnCommonConfig.hSpacingXl], + /// ) + EdgeInsets? _contentPaddingLg; + + EdgeInsets get contentPaddingLg => + _contentPaddingLg ?? + BrnDefaultConfigUtils.defaultDialogConfig.contentPaddingLg; /// message 内容样式 - /// default BrnTextStyle(fontSize: [BrnCommonConfig.fontSizeBase], color: [BrnCommonConfig.colorTextImportant]) - BrnTextStyle contentTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextImportant], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _contentTextStyle; + + BrnTextStyle get contentTextStyle => + _contentTextStyle ?? + BrnDefaultConfigUtils.defaultDialogConfig.contentTextStyle; /// 内容文字的对齐 - /// default TextAlign.center - TextAlign contentTextAlign; + /// 默认为 [TextAlign.center] + TextAlign? _contentTextAlign; - /// warning 当顶部 有 title/icon/content时四周边距,无底部间距 - /// default EdgeInsets.only(top: 6, left: [BrnCommonConfig.hSpacingXl], right: [BrnCommonConfig.hSpacingXl]) - EdgeInsets warningPaddingSm; + TextAlign get contentTextAlign => + _contentTextAlign ?? + BrnDefaultConfigUtils.defaultDialogConfig.contentTextAlign; - /// warning 当顶部 无 title/icon/content时四周边距,无底部间距 - /// default EdgeInsets.only(top: 28, left: [BrnCommonConfig.hSpacingXl], right: [BrnCommonConfig.hSpacingXl]) - EdgeInsets warningPaddingLg; + /// warning 当顶部有 title/icon/content 时的边距 + /// + /// EdgeInsets.only( + /// top: 6, + /// left: [BrnCommonConfig.hSpacingXl], + /// right: [BrnCommonConfig.hSpacingXl], + /// ) + EdgeInsets? _warningPaddingSm; + + EdgeInsets get warningPaddingSm => + _warningPaddingSm ?? + BrnDefaultConfigUtils.defaultDialogConfig.warningPaddingSm; + + /// warning 当顶部无 title/icon/content 时的边距 + /// + /// EdgeInsets.only( + /// top: 28, + /// left: [BrnCommonConfig.hSpacingXl], + /// right: [BrnCommonConfig.hSpacingXl], + /// ) + EdgeInsets? _warningPaddingLg; + + EdgeInsets get warningPaddingLg => + _warningPaddingLg ?? + BrnDefaultConfigUtils.defaultDialogConfig.warningPaddingLg; /// 警告样式 - /// default BrnTextStyle(fontSize: [BrnCommonConfig.fontSizeBase], color: [BrnCommonConfig.brandError]) - BrnTextStyle warningTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandError], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _warningTextStyle; + + BrnTextStyle get warningTextStyle => + _warningTextStyle ?? + BrnDefaultConfigUtils.defaultDialogConfig.warningTextStyle; /// 警示文案文字的对齐 - /// default TextAlign.center - TextAlign warningTextAlign; + /// 默认为 [TextAlign.center] + TextAlign? _warningTextAlign; + + TextAlign get warningTextAlign => + _warningTextAlign ?? + BrnDefaultConfigUtils.defaultDialogConfig.warningTextAlign; /// action 顶部 divider 的上方边距 - /// default EdgeInsets.only(top: 28) - EdgeInsets dividerPadding; + /// + /// EdgeInsets.only(top: 28) + EdgeInsets? _dividerPadding; + + EdgeInsets get dividerPadding => + _dividerPadding ?? + BrnDefaultConfigUtils.defaultDialogConfig.dividerPadding; /// 主色调按钮样式 - /// default BrnTextStyle(color: [BrnCommonConfig.brandPrimary], fontWeight: FontWeight.w600, fontSize: [BrnCommonConfig.fontSizeSubHead]) - BrnTextStyle mainActionTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _mainActionTextStyle; + + BrnTextStyle get mainActionTextStyle => + _mainActionTextStyle ?? + BrnDefaultConfigUtils.defaultDialogConfig.mainActionTextStyle; /// 主色调按钮的背景 - /// default [BrnCommonConfig.fillBase] - Color mainActionBackgroundColor; + /// 默认为 [BrnCommonConfig.fillBase] + Color? _mainActionBackgroundColor; + + Color get mainActionBackgroundColor => + _mainActionBackgroundColor ?? + BrnDefaultConfigUtils.defaultDialogConfig.mainActionBackgroundColor; /// 其他按钮的样式(超2个时按钮样式) - /// BrnTextStyle(color: [BrnCommonConfig.colorTextBase], fontWeight: FontWeight.w600,fontSize: [BrnCommonConfig.fontSizeSubHead]) - BrnTextStyle assistActionsTextStyle; + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _assistActionsTextStyle; + + BrnTextStyle get assistActionsTextStyle => + _assistActionsTextStyle ?? + BrnDefaultConfigUtils.defaultDialogConfig.assistActionsTextStyle; /// 其他按钮的背景 - /// default [BrnCommonConfig.fillBase] - Color assistActionsBackgroundColor; + /// 默认为 [BrnCommonConfig.fillBase] + Color? _assistActionsBackgroundColor; + + Color get assistActionsBackgroundColor => + _assistActionsBackgroundColor ?? + BrnDefaultConfigUtils.defaultDialogConfig.assistActionsBackgroundColor; /// 底部按钮高度 - /// default 44.0 - double bottomHeight; + /// 默认为 44.0 + double? _bottomHeight; + + double get bottomHeight => + _bottomHeight ?? BrnDefaultConfigUtils.defaultDialogConfig.bottomHeight; /// Dialog背景 - /// default [BrnCommonConfig.fillBase] - Color backgroundColor; - - BrnDialogConfig( - {this.dialogWidth, - this.radius, - this.iconPadding, - this.titlePaddingSm, - this.titlePaddingLg, - this.titleTextStyle, - this.titleTextAlign, - this.contentPaddingSm, - this.contentPaddingLg, - this.contentTextStyle, - this.contentTextAlign, - this.warningPaddingSm, - this.warningPaddingLg, - this.warningTextStyle, - this.warningTextAlign, - this.dividerPadding, - this.mainActionTextStyle, - this.assistActionsTextStyle, - this.mainActionBackgroundColor, - this.assistActionsBackgroundColor, - this.bottomHeight, - this.backgroundColor, - String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID}) - : super(configId: configId); + /// 默认为 [BrnCommonConfig.fillBase] + Color? _backgroundColor; + + Color get backgroundColor => + _backgroundColor ?? + BrnDefaultConfigUtils.defaultDialogConfig.backgroundColor; /// 按优先级,打平 【Bruno 内置配置】 < 【用户全局的默认配置】 < 【用户特殊配置】 < 【临时组件配置】 /// @@ -129,201 +289,183 @@ class BrnDialogConfig extends BrnBaseConfig { /// ③ 如果全局配置中的配置同样为 null 则根据 [configId] 取出全局配置。 /// ④ 如果没有配置 [configId] 的全局配置,则使用 Bruno 默认的配置 @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); /// 用户全局组件配置 BrnDialogConfig dialogConfig = BrnThemeConfigurator.instance .getConfig(configId: configId) .dialogConfig; - this.dialogWidth ??= dialogConfig?.dialogWidth; - - this.radius ??= commonConfig.radiusLg; - - if (this.titlePaddingSm == null) { - this.titlePaddingSm = EdgeInsets.only( - left: commonConfig.hSpacingXxl, - right: commonConfig.hSpacingXxl, - top: dialogConfig.titlePaddingSm.top, - bottom: dialogConfig.titlePaddingSm.bottom); - } - - if (this.titlePaddingLg == null) { - this.titlePaddingLg = EdgeInsets.only( - left: commonConfig.hSpacingXxl, - right: commonConfig.hSpacingXxl, - top: dialogConfig.titlePaddingLg.top, - bottom: dialogConfig.titlePaddingLg.bottom); - } - - if (this.iconPadding == null) { - this.iconPadding = EdgeInsets.only( - left: dialogConfig.iconPadding.left, - top: commonConfig.vSpacingXxl, - right: dialogConfig.iconPadding.right, - bottom: dialogConfig.iconPadding.bottom); - } - - this.titleTextStyle = dialogConfig.titleTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeHead) - .merge(this.titleTextStyle)); - - this.contentTextStyle = dialogConfig.contentTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextImportant, - fontSize: commonConfig.fontSizeBase) - .merge(this.contentTextStyle)); - - this.warningTextStyle = dialogConfig.warningTextStyle.merge(BrnTextStyle( - color: commonConfig.brandError, fontSize: commonConfig.fontSizeBase) - .merge(this.warningTextStyle)); - - this.mainActionTextStyle = dialogConfig.mainActionTextStyle.merge( - BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.mainActionTextStyle)); - - this.assistActionsTextStyle = dialogConfig.assistActionsTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.assistActionsTextStyle)); - - if (this.contentPaddingSm == null) { - this.contentPaddingSm = EdgeInsets.only( - left: commonConfig.hSpacingXl, - right: commonConfig.hSpacingXl, - top: dialogConfig.contentPaddingSm.top, - bottom: dialogConfig.contentPaddingSm.bottom); - } - - if (this.contentPaddingLg == null) { - this.contentPaddingLg = EdgeInsets.only( - left: commonConfig.hSpacingXl, - right: commonConfig.hSpacingXl, - top: dialogConfig.contentPaddingLg.top, - bottom: dialogConfig.contentPaddingLg.bottom); - } - - if (this.warningPaddingSm == null) { - this.warningPaddingSm = EdgeInsets.only( - left: commonConfig.hSpacingXl, - right: commonConfig.hSpacingXl, - top: dialogConfig.warningPaddingSm.top, - bottom: dialogConfig.warningPaddingSm.bottom); - } - - if (this.warningPaddingLg == null) { - this.warningPaddingLg = EdgeInsets.only( - left: commonConfig.hSpacingXl, - right: commonConfig.hSpacingXl, - top: dialogConfig.warningPaddingLg.top, - bottom: dialogConfig.warningPaddingLg.bottom); - } - - this.titleTextAlign ??= dialogConfig?.titleTextAlign; - - this.contentTextAlign ??= dialogConfig?.contentTextAlign; - - this.warningTextAlign ??= dialogConfig?.warningTextAlign; - - this.mainActionBackgroundColor ??= commonConfig.fillBase; - - this.assistActionsBackgroundColor ??= commonConfig.fillBase; - - this.bottomHeight ??= dialogConfig?.bottomHeight; - - this.dividerPadding ??= dialogConfig?.dividerPadding; - - this.backgroundColor ??= commonConfig.fillBase; + _dialogWidth ??= dialogConfig.dialogWidth; + _radius ??= commonConfig.radiusLg; + _titlePaddingSm ??= EdgeInsets.only( + left: commonConfig.hSpacingXxl, + right: commonConfig.hSpacingXxl, + top: dialogConfig.titlePaddingSm.top, + bottom: dialogConfig.titlePaddingSm.bottom, + ); + _titlePaddingLg ??= EdgeInsets.only( + left: commonConfig.hSpacingXxl, + right: commonConfig.hSpacingXxl, + top: dialogConfig.titlePaddingLg.top, + bottom: dialogConfig.titlePaddingLg.bottom, + ); + _iconPadding ??= EdgeInsets.only( + left: dialogConfig.iconPadding.left, + top: commonConfig.vSpacingXxl, + right: dialogConfig.iconPadding.right, + bottom: dialogConfig.iconPadding.bottom, + ); + _titleTextStyle = dialogConfig.titleTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeHead, + ).merge(_titleTextStyle), + ); + _contentTextStyle = dialogConfig.contentTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextImportant, + fontSize: commonConfig.fontSizeBase, + ).merge(_contentTextStyle), + ); + _warningTextStyle = dialogConfig.warningTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandError, + fontSize: commonConfig.fontSizeBase, + ).merge(_warningTextStyle), + ); + _mainActionTextStyle = dialogConfig.mainActionTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_mainActionTextStyle), + ); + _assistActionsTextStyle = dialogConfig.assistActionsTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_assistActionsTextStyle), + ); + _contentPaddingSm ??= EdgeInsets.only( + left: commonConfig.hSpacingXl, + right: commonConfig.hSpacingXl, + top: dialogConfig.contentPaddingSm.top, + bottom: dialogConfig.contentPaddingSm.bottom, + ); + _contentPaddingSm ??= EdgeInsets.only( + left: commonConfig.hSpacingXl, + right: commonConfig.hSpacingXl, + top: dialogConfig.contentPaddingLg.top, + bottom: dialogConfig.contentPaddingLg.bottom, + ); + _warningPaddingSm ??= EdgeInsets.only( + left: commonConfig.hSpacingXl, + right: commonConfig.hSpacingXl, + top: dialogConfig.warningPaddingSm.top, + bottom: dialogConfig.warningPaddingSm.bottom, + ); + _warningPaddingLg ??= EdgeInsets.only( + left: commonConfig.hSpacingXl, + right: commonConfig.hSpacingXl, + top: dialogConfig.warningPaddingLg.top, + bottom: dialogConfig.warningPaddingLg.bottom, + ); + _titleTextAlign ??= dialogConfig.titleTextAlign; + _contentTextAlign ??= dialogConfig.contentTextAlign; + _warningTextAlign ??= dialogConfig.warningTextAlign; + _mainActionBackgroundColor ??= commonConfig.fillBase; + _assistActionsBackgroundColor ??= commonConfig.fillBase; + _bottomHeight ??= dialogConfig.bottomHeight; + _dividerPadding ??= dialogConfig.dividerPadding; + _backgroundColor ??= commonConfig.fillBase; } - BrnDialogConfig copyWith( - {double dialogWidth, - double radius, - EdgeInsets iconPadding, - EdgeInsets titlePaddingSm, - EdgeInsets titlePaddingLg, - BrnTextStyle titleTextStyle, - TextAlign titleTextAlign, - EdgeInsets contentPaddingSm, - EdgeInsets contentPaddingLg, - BrnTextStyle contentTextStyle, - TextAlign contentTextAlign, - EdgeInsets warningPaddingSm, - EdgeInsets warningPaddingLg, - BrnTextStyle warningTextStyle, - TextAlign warningTextAlign, - EdgeInsets dividerPadding, - BrnTextStyle mainActionTextStyle, - BrnTextStyle assistActionsTextStyle, - Color mainActionBackgroundColor, - Color assistActionsBackgroundColor, - double bottomHeight, - Color backgroundColor}) { + BrnDialogConfig copyWith({ + double? dialogWidth, + double? radius, + EdgeInsets? iconPadding, + EdgeInsets? titlePaddingSm, + EdgeInsets? titlePaddingLg, + BrnTextStyle? titleTextStyle, + TextAlign? titleTextAlign, + EdgeInsets? contentPaddingSm, + EdgeInsets? contentPaddingLg, + BrnTextStyle? contentTextStyle, + TextAlign? contentTextAlign, + EdgeInsets? warningPaddingSm, + EdgeInsets? warningPaddingLg, + BrnTextStyle? warningTextStyle, + TextAlign? warningTextAlign, + EdgeInsets? dividerPadding, + BrnTextStyle? mainActionTextStyle, + BrnTextStyle? assistActionsTextStyle, + Color? mainActionBackgroundColor, + Color? assistActionsBackgroundColor, + double? bottomHeight, + Color? backgroundColor, + }) { return BrnDialogConfig( - dialogWidth: dialogWidth ?? this.dialogWidth, - radius: radius ?? this.radius, - iconPadding: iconPadding ?? this.iconPadding, - titlePaddingSm: titlePaddingSm ?? this.titlePaddingSm, - titlePaddingLg: titlePaddingLg ?? this.titlePaddingLg, - titleTextStyle: titleTextStyle ?? this.titleTextStyle, - titleTextAlign: titleTextAlign ?? this.titleTextAlign, - contentPaddingSm: contentPaddingSm ?? this.contentPaddingSm, - contentPaddingLg: contentPaddingLg ?? this.contentPaddingLg, - contentTextStyle: contentTextStyle ?? this.contentTextStyle, - contentTextAlign: contentTextAlign ?? this.contentTextAlign, - warningPaddingSm: warningPaddingSm ?? this.warningPaddingSm, - warningPaddingLg: warningPaddingLg ?? this.warningPaddingLg, - warningTextStyle: warningTextStyle ?? this.warningTextStyle, - warningTextAlign: warningTextAlign ?? this.warningTextAlign, - dividerPadding: dividerPadding ?? this.dividerPadding, - mainActionTextStyle: mainActionTextStyle ?? this.mainActionTextStyle, - assistActionsTextStyle: - assistActionsTextStyle ?? this.assistActionsTextStyle, - mainActionBackgroundColor: - mainActionBackgroundColor ?? this.mainActionBackgroundColor, - assistActionsBackgroundColor: - assistActionsBackgroundColor ?? this.assistActionsBackgroundColor, - bottomHeight: bottomHeight ?? this.bottomHeight, - backgroundColor: backgroundColor ?? this.backgroundColor); + dialogWidth: dialogWidth ?? _dialogWidth, + radius: radius ?? _radius, + iconPadding: iconPadding ?? _iconPadding, + titlePaddingSm: titlePaddingSm ?? _titlePaddingSm, + titlePaddingLg: titlePaddingLg ?? _titlePaddingLg, + titleTextStyle: titleTextStyle ?? _titleTextStyle, + titleTextAlign: titleTextAlign ?? _titleTextAlign, + contentPaddingSm: contentPaddingSm ?? _contentPaddingSm, + contentPaddingLg: contentPaddingLg ?? _contentPaddingLg, + contentTextStyle: contentTextStyle ?? _contentTextStyle, + contentTextAlign: contentTextAlign ?? _contentTextAlign, + warningPaddingSm: warningPaddingSm ?? _warningPaddingSm, + warningPaddingLg: warningPaddingLg ?? _warningPaddingLg, + warningTextStyle: warningTextStyle ?? _warningTextStyle, + warningTextAlign: warningTextAlign ?? _warningTextAlign, + dividerPadding: dividerPadding ?? _dividerPadding, + mainActionTextStyle: mainActionTextStyle ?? _mainActionTextStyle, + assistActionsTextStyle: assistActionsTextStyle ?? _assistActionsTextStyle, + mainActionBackgroundColor: + mainActionBackgroundColor ?? _mainActionBackgroundColor, + assistActionsBackgroundColor: + assistActionsBackgroundColor ?? _assistActionsBackgroundColor, + bottomHeight: bottomHeight ?? _bottomHeight, + backgroundColor: backgroundColor ?? _backgroundColor, + ); } - BrnDialogConfig merge(BrnDialogConfig other) { + BrnDialogConfig merge(BrnDialogConfig? other) { if (other == null) return this; return copyWith( - dialogWidth: other.dialogWidth, - radius: other.radius, - iconPadding: other.iconPadding, - titlePaddingSm: other.titlePaddingSm, - titlePaddingLg: other.titlePaddingLg, - titleTextStyle: - titleTextStyle?.merge(other.titleTextStyle) ?? other.titleTextStyle, - titleTextAlign: other.titleTextAlign, - contentPaddingSm: other.contentPaddingSm, - contentPaddingLg: other.contentPaddingLg, - contentTextStyle: contentTextStyle?.merge(other.contentTextStyle) ?? - other.contentTextStyle, - contentTextAlign: other.contentTextAlign, - warningPaddingSm: other.warningPaddingSm, - warningPaddingLg: other.warningPaddingLg, - warningTextStyle: warningTextStyle?.merge(other.warningTextStyle) ?? - other.warningTextStyle, - warningTextAlign: other.warningTextAlign, - dividerPadding: other.dividerPadding, - mainActionTextStyle: - mainActionTextStyle?.merge(other.mainActionTextStyle) ?? - other.mainActionTextStyle, - assistActionsTextStyle: - assistActionsTextStyle?.merge(other.assistActionsTextStyle) ?? - other.assistActionsTextStyle, - mainActionBackgroundColor: other.mainActionBackgroundColor, - assistActionsBackgroundColor: other.assistActionsBackgroundColor, - bottomHeight: other.bottomHeight, - backgroundColor: other.backgroundColor); + dialogWidth: other._dialogWidth, + radius: other._radius, + iconPadding: other._iconPadding, + titlePaddingSm: other._titlePaddingSm, + titlePaddingLg: other._titlePaddingLg, + titleTextStyle: titleTextStyle.merge(other._titleTextStyle), + titleTextAlign: other._titleTextAlign, + contentPaddingSm: other._contentPaddingSm, + contentPaddingLg: other._contentPaddingLg, + contentTextStyle: contentTextStyle.merge(other._contentTextStyle), + contentTextAlign: other._contentTextAlign, + warningPaddingSm: other._warningPaddingSm, + warningPaddingLg: other._warningPaddingLg, + warningTextStyle: warningTextStyle.merge(other._warningTextStyle), + warningTextAlign: other._warningTextAlign, + dividerPadding: other._dividerPadding, + mainActionTextStyle: + mainActionTextStyle.merge(other._mainActionTextStyle), + assistActionsTextStyle: + assistActionsTextStyle.merge(other._assistActionsTextStyle), + mainActionBackgroundColor: other._mainActionBackgroundColor, + assistActionsBackgroundColor: other._assistActionsBackgroundColor, + bottomHeight: other._bottomHeight, + backgroundColor: other._backgroundColor, + ); } } diff --git a/lib/src/theme/configs/brn_enhance_number_card_config.dart b/lib/src/theme/configs/brn_enhance_number_card_config.dart index 231d8faa..12c261aa 100644 --- a/lib/src/theme/configs/brn_enhance_number_card_config.dart +++ b/lib/src/theme/configs/brn_enhance_number_card_config.dart @@ -1,78 +1,106 @@ -import 'package:bruno/src/theme/brn_theme.dart'; +import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; +import 'package:bruno/src/theme/base/brn_text_style.dart'; +import 'package:bruno/src/theme/brn_theme_configurator.dart'; +import 'package:bruno/src/theme/configs/brn_common_config.dart'; /// 强化数字展示组件配置 class BrnEnhanceNumberCardConfig extends BrnBaseConfig { - ///遵循外部主题配置,Bruno默认配置[BrnDefaultConfigUtils.defaultNumberInfoConfig] + /// 遵循外部主题配置 + /// 默认为 [BrnDefaultConfigUtils.defaultEnhanceNumberInfoConfig] BrnEnhanceNumberCardConfig({ - this.runningSpace, - this.itemRunningSpace, - this.titleTextStyle, - this.descTextStyle, - this.dividerWidth, - String configId: BrnThemeConfigurator.GLOBAL_CONFIG_ID, - }) : super(configId: configId); + double? runningSpace, + double? itemRunningSpace, + BrnTextStyle? titleTextStyle, + BrnTextStyle? descTextStyle, + double? dividerWidth, + String configId: GLOBAL_CONFIG_ID, + }) : _runningSpace = runningSpace, + _itemRunningSpace = itemRunningSpace, + _titleTextStyle = titleTextStyle, + _descTextStyle = descTextStyle, + _dividerWidth = dividerWidth, + super(configId: configId); - ///如果超过一行,行间距 - double runningSpace; + /// 如果超过一行,行间距 + double? _runningSpace; - ///Item的上半部分和下半部分的间距 - double itemRunningSpace; + double get runningSpace => + _runningSpace ?? + BrnDefaultConfigUtils.defaultEnhanceNumberInfoConfig.runningSpace; - double dividerWidth; + /// Item的上半部分和下半部分的间距 + double? _itemRunningSpace; - BrnTextStyle titleTextStyle; + double get itemRunningSpace => + _itemRunningSpace ?? + BrnDefaultConfigUtils.defaultEnhanceNumberInfoConfig.itemRunningSpace; - BrnTextStyle descTextStyle; + double? _dividerWidth; + + double get dividerWidth => + _dividerWidth ?? + BrnDefaultConfigUtils.defaultEnhanceNumberInfoConfig.dividerWidth; + BrnTextStyle? _titleTextStyle; + + BrnTextStyle get titleTextStyle => + _titleTextStyle ?? + BrnDefaultConfigUtils.defaultEnhanceNumberInfoConfig.titleTextStyle; + BrnTextStyle? _descTextStyle; + + BrnTextStyle get descTextStyle => + _descTextStyle ?? + BrnDefaultConfigUtils.defaultEnhanceNumberInfoConfig.descTextStyle; @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); BrnEnhanceNumberCardConfig userConfig = BrnThemeConfigurator.instance .getConfig(configId: configId) .enhanceNumberCardConfig; - this.runningSpace ??= userConfig.runningSpace; - this.itemRunningSpace ??= userConfig.itemRunningSpace; - this.dividerWidth ??= userConfig.dividerWidth; - - this.titleTextStyle = userConfig.titleTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextBase) - .merge(this.titleTextStyle)); - - this.descTextStyle = userConfig.descTextStyle.merge( - BrnTextStyle(color: commonConfig.colorTextSecondary) - .merge(this.descTextStyle)); + _runningSpace ??= userConfig._runningSpace; + _itemRunningSpace ??= userConfig._itemRunningSpace; + _dividerWidth ??= userConfig._dividerWidth; + _titleTextStyle = userConfig.titleTextStyle.merge( + BrnTextStyle(color: commonConfig.colorTextBase).merge(_titleTextStyle), + ); + _descTextStyle = userConfig.descTextStyle.merge( + BrnTextStyle(color: commonConfig.colorTextSecondary).merge(_descTextStyle), + ); } BrnEnhanceNumberCardConfig copyWith({ - double runningSpace, - double itemRunningSpace, - double dividerWidth, - BrnTextStyle titleTextStyle, - BrnTextStyle descTextStyle, + double? runningSpace, + double? itemRunningSpace, + double? dividerWidth, + BrnTextStyle? titleTextStyle, + BrnTextStyle? descTextStyle, }) { return BrnEnhanceNumberCardConfig( - runningSpace: runningSpace ?? this.runningSpace, - itemRunningSpace: itemRunningSpace ?? this.itemRunningSpace, - dividerWidth: dividerWidth ?? this.dividerWidth, - titleTextStyle: titleTextStyle ?? this.titleTextStyle, - descTextStyle: descTextStyle ?? this.descTextStyle, + runningSpace: runningSpace ?? _runningSpace, + itemRunningSpace: itemRunningSpace ?? _itemRunningSpace, + dividerWidth: dividerWidth ?? _dividerWidth, + titleTextStyle: titleTextStyle ?? _titleTextStyle, + descTextStyle: descTextStyle ?? _descTextStyle, ); } - BrnEnhanceNumberCardConfig merge(BrnEnhanceNumberCardConfig other) { + BrnEnhanceNumberCardConfig merge(BrnEnhanceNumberCardConfig? other) { if (other == null) return this; return copyWith( - runningSpace: other.runningSpace, - itemRunningSpace: other.itemRunningSpace, - dividerWidth: other.dividerWidth, - titleTextStyle: - titleTextStyle?.merge(other.titleTextStyle) ?? other.titleTextStyle, - descTextStyle: - descTextStyle?.merge(other.descTextStyle) ?? other.descTextStyle, + runningSpace: other._runningSpace, + itemRunningSpace: other._itemRunningSpace, + dividerWidth: other._dividerWidth, + titleTextStyle: titleTextStyle.merge(other._titleTextStyle), + descTextStyle: descTextStyle.merge(other._descTextStyle), ); } } diff --git a/lib/src/theme/configs/brn_form_config.dart b/lib/src/theme/configs/brn_form_config.dart index 93cbd523..0a932215 100644 --- a/lib/src/theme/configs/brn_form_config.dart +++ b/lib/src/theme/configs/brn_form_config.dart @@ -1,99 +1,238 @@ import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; import 'package:bruno/src/theme/base/brn_text_style.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_common_config.dart'; import 'package:flutter/material.dart'; /// 描述: form 表单项主配置类 - class BrnFormItemConfig extends BrnBaseConfig { + /// 遵循全局配置 + /// 默认为 [BrnDefaultConfigUtils.defaultFormItemConfig] + BrnFormItemConfig({ + BrnTextStyle? titleTextStyle, + BrnTextStyle? subTitleTextStyle, + BrnTextStyle? errorTextStyle, + BrnTextStyle? hintTextStyle, + BrnTextStyle? contentTextStyle, + EdgeInsets? formPadding, + EdgeInsets? titlePaddingSm, + EdgeInsets? titlePaddingLg, + EdgeInsets? optionsMiddlePadding, + EdgeInsets? subTitlePadding, + EdgeInsets? errorPadding, + BrnTextStyle? disableTextStyle, + BrnTextStyle? tipsTextStyle, + BrnTextStyle? headTitleTextStyle, + BrnTextStyle? optionTextStyle, + BrnTextStyle? optionSelectedTextStyle, + String configId = GLOBAL_CONFIG_ID, + }) : _titleTextStyle = titleTextStyle, + _subTitleTextStyle = subTitleTextStyle, + _errorTextStyle = errorTextStyle, + _hintTextStyle = hintTextStyle, + _contentTextStyle = contentTextStyle, + _formPadding = formPadding, + _titlePaddingSm = titlePaddingSm, + _titlePaddingLg = titlePaddingLg, + _optionsMiddlePadding = optionsMiddlePadding, + _subTitlePadding = subTitlePadding, + _errorPadding = errorPadding, + _disableTextStyle = disableTextStyle, + _tipsTextStyle = tipsTextStyle, + _headTitleTextStyle = headTitleTextStyle, + _optionTextStyle = optionTextStyle, + _optionSelectedTextStyle = optionSelectedTextStyle, + super(configId: configId); + + BrnFormItemConfig.generatorFromConfigId(String configId) { + initThemeConfig(configId); + } + /// 左侧标题文本样式 - /// default BrnTextStyle(color: [BrnCommonConfig.colorTextBase],fontSize: [BrnCommonConfig.fontSizeHead]) - BrnTextStyle headTitleTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeHead], + /// ) + BrnTextStyle? _headTitleTextStyle; /// 左侧标题文本样式 - /// default BrnTextStyle(color: [BrnCommonConfig.colorTextBase],fontSize: [BrnCommonConfig.fontSizeSubHead]) - BrnTextStyle titleTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// ) + BrnTextStyle? _titleTextStyle; /// 左侧辅助文本样式 - /// default BrnTextStyle(color: [BrnCommonConfig.colorTextSecondary], fontSize: [BrnCommonConfig.fontSizeCaption]) - BrnTextStyle subTitleTextStyle; - - /// 左侧Error文本样式 - /// default BrnTextStyle(color: [BrnCommonConfig.brandError], fontSize: [BrnCommonConfig.fontSizeCaption]) - BrnTextStyle errorTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextSecondary], + /// fontSize: [BrnCommonConfig.fontSizeCaption], + /// ) + BrnTextStyle? _subTitleTextStyle; + + /// 左侧 Error 文本样式 + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandError], + /// fontSize: [BrnCommonConfig.fontSizeCaption], + /// ) + BrnTextStyle? _errorTextStyle; /// 右侧 输入、选择提示文本样式 - /// default BrnTextStyle(color: [BrnCommonConfig.colorTextHint], fontSize: [BrnCommonConfig.fontSizeSubHead]) - BrnTextStyle hintTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextHint], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// ) + BrnTextStyle? _hintTextStyle; /// 右侧 主要内容样式 - /// default BrnTextStyle([BrnCommonConfig.colorTextBase]), fontSize: [BrnCommonConfig.fontSizeSubHead]) - BrnTextStyle contentTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// ) + BrnTextStyle? _contentTextStyle; /// 表单项 当有星号标识 上下右边距 - /// default EdgeInsets.only(left: 0, top: [BrnCommonConfig.vSpacingLg], right: [BrnCommonConfig.hSpacingLg], bottom: [BrnCommonConfig.vSpacingLg]) - EdgeInsets formPadding; + /// + /// EdgeInsets.only( + /// left: 0, + /// top: [BrnCommonConfig.vSpacingLg], + /// right: [BrnCommonConfig.hSpacingLg], + /// bottom: [BrnCommonConfig.vSpacingLg], + /// ) + EdgeInsets? _formPadding; /// 表单项 当有星号标识 左边距 - /// default EdgeInsets.only(left: 10) - EdgeInsets titlePaddingSm; + /// + /// EdgeInsets.only(left: 10) + EdgeInsets? _titlePaddingSm; /// 表单项 当无星号标识 左右边距 - /// default EdgeInsets.only(left: [BrnCommonConfig.hSpacingLg]) - EdgeInsets titlePaddingLg; + /// + /// EdgeInsets.only(left: [BrnCommonConfig.hSpacingLg]) + EdgeInsets? _titlePaddingLg; /// 选项之间间距 单选 or 多选 - /// default EdgeInsets.only(left: [BrnCommonConfig.hSpacingMd]) - EdgeInsets optionsMiddlePadding; + /// + /// EdgeInsets.only(left: [BrnCommonConfig.hSpacingMd]) + EdgeInsets? _optionsMiddlePadding; /// 选项普通文本样式 - /// TextStyle(color: [BrnCommonConfig.colorTextBase], height: 1.3, fontSize: [BrnCommonConfig.fontSizeSubHead],) - BrnTextStyle optionTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// height: 1.3, + /// ) + BrnTextStyle? _optionTextStyle; /// 选项选中文本样式 - /// TextStyle(color: [BrnCommonConfig.brandPrimary], height: 1.3, fontSize: [BrnCommonConfig.fontSizeSubHead],) - BrnTextStyle optionSelectedTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// height: 1.3, + /// ) + BrnTextStyle? _optionSelectedTextStyle; /// 子标题 左上间距 - /// default EdgeInsets.only(left: [BrnCommonConfig.hSpacingLg], top: [BrnCommonConfig.vSpacingXs]) - EdgeInsets subTitlePadding; + /// + /// EdgeInsets.only( + /// left: [BrnCommonConfig.hSpacingLg], + /// top: [BrnCommonConfig.vSpacingXs], + /// ) + EdgeInsets? _subTitlePadding; /// error提示 左上间距 - /// EdgeInsets.only(left: [BrnCommonConfig.hSpacingLg], top: [BrnCommonConfig.vSpacingXs]) - EdgeInsets errorPadding; + /// + /// EdgeInsets.only( + /// left: [BrnCommonConfig.hSpacingLg], + /// top: [BrnCommonConfig.vSpacingXs], + /// ) + EdgeInsets? _errorPadding; /// 不可修改内容展示 - /// BrnTextStyle(color: [BrnCommonConfig.colorTextDisabled],fontSize: [BrnCommonConfig.fontSizeSubHead]) - BrnTextStyle disableTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextDisabled], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// ) + BrnTextStyle? _disableTextStyle; /// 提示文本样式 - /// BrnTextStyle(color: [BrnCommonConfig.colorTextSecondary], fontSize: [BrnCommonConfig.fontSizeBase]) - BrnTextStyle tipsTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextSecondary], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _tipsTextStyle; - BrnFormItemConfig.generatorFromConfigId(String configId) { - initThemeConfig(configId); - } + BrnTextStyle get headTitleTextStyle => + _headTitleTextStyle ?? + BrnDefaultConfigUtils.defaultFormItemConfig.headTitleTextStyle; + + BrnTextStyle get titleTextStyle => + _titleTextStyle ?? + BrnDefaultConfigUtils.defaultFormItemConfig.titleTextStyle; + + BrnTextStyle get subTitleTextStyle => + _subTitleTextStyle ?? + BrnDefaultConfigUtils.defaultFormItemConfig.subTitleTextStyle; + + BrnTextStyle get errorTextStyle => + _errorTextStyle ?? + BrnDefaultConfigUtils.defaultFormItemConfig.errorTextStyle; + + BrnTextStyle get hintTextStyle => + _hintTextStyle ?? + BrnDefaultConfigUtils.defaultFormItemConfig.hintTextStyle; + + BrnTextStyle get contentTextStyle => + _contentTextStyle ?? + BrnDefaultConfigUtils.defaultFormItemConfig.contentTextStyle; + + EdgeInsets get formPadding => + _formPadding ?? BrnDefaultConfigUtils.defaultFormItemConfig.formPadding; + + EdgeInsets get titlePaddingSm => + _titlePaddingSm ?? + BrnDefaultConfigUtils.defaultFormItemConfig.titlePaddingSm; + + EdgeInsets get titlePaddingLg => + _titlePaddingLg ?? + BrnDefaultConfigUtils.defaultFormItemConfig.titlePaddingLg; + + EdgeInsets get optionsMiddlePadding => + _optionsMiddlePadding ?? + BrnDefaultConfigUtils.defaultFormItemConfig.optionsMiddlePadding; + + BrnTextStyle get optionTextStyle => + _optionTextStyle ?? + BrnDefaultConfigUtils.defaultFormItemConfig.optionTextStyle; + + BrnTextStyle get optionSelectedTextStyle => + _optionSelectedTextStyle ?? + BrnDefaultConfigUtils.defaultFormItemConfig.optionSelectedTextStyle; - BrnFormItemConfig( - {this.titleTextStyle, - this.subTitleTextStyle, - this.errorTextStyle, - this.hintTextStyle, - this.contentTextStyle, - this.formPadding, - this.titlePaddingSm, - this.titlePaddingLg, - this.optionsMiddlePadding, - this.subTitlePadding, - this.errorPadding, - this.disableTextStyle, - this.tipsTextStyle, - this.headTitleTextStyle, - this.optionTextStyle, - this.optionSelectedTextStyle, - String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID}) - : super(configId: configId); + EdgeInsets get subTitlePadding => + _subTitlePadding ?? + BrnDefaultConfigUtils.defaultFormItemConfig.subTitlePadding; + + EdgeInsets get errorPadding => + _errorPadding ?? BrnDefaultConfigUtils.defaultFormItemConfig.errorPadding; + + BrnTextStyle get disableTextStyle => + _disableTextStyle ?? + BrnDefaultConfigUtils.defaultFormItemConfig.disableTextStyle; + + BrnTextStyle get tipsTextStyle => + _tipsTextStyle ?? + BrnDefaultConfigUtils.defaultFormItemConfig.tipsTextStyle; /// 举例: /// ① 尝试获取最近的配置 [topRadius] 若配不为 null,直接使用该配置. @@ -101,173 +240,162 @@ class BrnFormItemConfig extends BrnBaseConfig { /// ③ 如果全局配置中的配置同样为 null 则根据 [configId] 取出全局配置。 /// ④ 如果没有配置 [configId] 的全局配置,则使用 Bruno 默认的配置 @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); /// 用户全局form组件配置 BrnFormItemConfig formItemThemeData = BrnThemeConfigurator.instance .getConfig(configId: configId) .formItemConfig; - this.titlePaddingSm ??= formItemThemeData.titlePaddingSm; - - this.titlePaddingLg ??= formItemThemeData.titlePaddingLg; - - this.optionSelectedTextStyle = - formItemThemeData.optionSelectedTextStyle.merge(BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeSubHead, - ).merge(this.optionSelectedTextStyle)); - - this.optionTextStyle = formItemThemeData.optionTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.optionTextStyle)); - - this.headTitleTextStyle = formItemThemeData.headTitleTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeHead) - .merge(this.headTitleTextStyle)); - - if (this.errorPadding == null) { - this.errorPadding = EdgeInsets.only( - left: commonConfig.hSpacingLg, - right: formItemThemeData.errorPadding.right, - top: commonConfig.vSpacingXs, - bottom: formItemThemeData.errorPadding.bottom, - ); - } - - if (this.subTitlePadding == null) { - this.subTitlePadding = EdgeInsets.only( - left: commonConfig.hSpacingLg, - right: formItemThemeData.subTitlePadding.right, - top: commonConfig.vSpacingXs, - bottom: formItemThemeData.subTitlePadding.bottom, - ); - } - - if (this.formPadding == null) { - this.formPadding = EdgeInsets.only( - left: formItemThemeData.formPadding.left, - right: commonConfig.hSpacingLg, - top: commonConfig.vSpacingLg, - bottom: commonConfig.vSpacingLg); - } - - this.tipsTextStyle = formItemThemeData.tipsTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextSecondary, - fontSize: commonConfig.fontSizeBase) - .merge(this.tipsTextStyle)); - - this.disableTextStyle = formItemThemeData.disableTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextDisabled, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.disableTextStyle)); - - this.contentTextStyle = formItemThemeData.contentTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.contentTextStyle)); - - this.hintTextStyle = formItemThemeData.hintTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextHint, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.hintTextStyle)); - - this.titleTextStyle = formItemThemeData.titleTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.titleTextStyle)); - - this.subTitleTextStyle = formItemThemeData.subTitleTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextSecondary, - fontSize: commonConfig.fontSizeCaption) - .merge(this.subTitleTextStyle)); - - this.errorTextStyle = formItemThemeData.errorTextStyle.merge(BrnTextStyle( - color: commonConfig.brandError, - fontSize: commonConfig.fontSizeCaption) - .merge(this.errorTextStyle)); - - this.optionsMiddlePadding ??= formItemThemeData?.optionsMiddlePadding; + _titlePaddingSm ??= formItemThemeData.titlePaddingSm; + _titlePaddingLg ??= formItemThemeData.titlePaddingLg; + _optionSelectedTextStyle = formItemThemeData.optionSelectedTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_optionSelectedTextStyle), + ); + _optionTextStyle = formItemThemeData.optionTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_optionTextStyle), + ); + _headTitleTextStyle = formItemThemeData.headTitleTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeHead, + ).merge(_headTitleTextStyle), + ); + _errorPadding ??= EdgeInsets.only( + left: commonConfig.hSpacingLg, + right: formItemThemeData.errorPadding.right, + top: commonConfig.vSpacingXs, + bottom: formItemThemeData.errorPadding.bottom, + ); + _subTitlePadding ??= EdgeInsets.only( + left: commonConfig.hSpacingLg, + right: formItemThemeData.subTitlePadding.right, + top: commonConfig.vSpacingXs, + bottom: formItemThemeData.subTitlePadding.bottom, + ); + _formPadding ??= EdgeInsets.only( + left: formItemThemeData.formPadding.left, + right: commonConfig.hSpacingLg, + top: commonConfig.vSpacingLg, + bottom: commonConfig.vSpacingLg, + ); + _tipsTextStyle = formItemThemeData.tipsTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextSecondary, + fontSize: commonConfig.fontSizeBase, + ).merge(_tipsTextStyle), + ); + _disableTextStyle = formItemThemeData.disableTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextDisabled, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_disableTextStyle), + ); + _contentTextStyle = formItemThemeData.contentTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_contentTextStyle), + ); + _hintTextStyle = formItemThemeData.hintTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextHint, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_hintTextStyle), + ); + _titleTextStyle = formItemThemeData.titleTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_titleTextStyle), + ); + _subTitleTextStyle = formItemThemeData.subTitleTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextSecondary, + fontSize: commonConfig.fontSizeCaption, + ).merge(_subTitleTextStyle), + ); + _errorTextStyle = formItemThemeData.errorTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandError, + fontSize: commonConfig.fontSizeCaption, + ).merge(_errorTextStyle), + ); + _optionsMiddlePadding ??= formItemThemeData.optionsMiddlePadding; } BrnFormItemConfig copyWith({ - BrnTextStyle titleTextStyle, - BrnTextStyle subTitleTextStyle, - BrnTextStyle errorTextStyle, - BrnTextStyle hintTextStyle, - BrnTextStyle contentTextStyle, - EdgeInsets formPadding, - EdgeInsets titlePaddingSm, - EdgeInsets titlePaddingLg, - EdgeInsets optionsMiddlePadding, - EdgeInsets subTitlePadding, - EdgeInsets errorPadding, - BrnTextStyle disableTextStyle, - BrnTextStyle tipsTextStyle, - BrnTextStyle headTitleTextStyle, - BrnTextStyle optionTextStyle, - BrnTextStyle optionSelectedTextStyle, + BrnTextStyle? titleTextStyle, + BrnTextStyle? subTitleTextStyle, + BrnTextStyle? errorTextStyle, + BrnTextStyle? hintTextStyle, + BrnTextStyle? contentTextStyle, + EdgeInsets? formPadding, + EdgeInsets? titlePaddingSm, + EdgeInsets? titlePaddingLg, + EdgeInsets? optionsMiddlePadding, + EdgeInsets? subTitlePadding, + EdgeInsets? errorPadding, + BrnTextStyle? disableTextStyle, + BrnTextStyle? tipsTextStyle, + BrnTextStyle? headTitleTextStyle, + BrnTextStyle? optionTextStyle, + BrnTextStyle? optionSelectedTextStyle, }) { return BrnFormItemConfig( - titleTextStyle: titleTextStyle ?? this.titleTextStyle, - subTitleTextStyle: subTitleTextStyle ?? this.subTitleTextStyle, - errorTextStyle: errorTextStyle ?? this.errorTextStyle, - hintTextStyle: hintTextStyle ?? this.hintTextStyle, - contentTextStyle: contentTextStyle ?? this.contentTextStyle, - formPadding: formPadding ?? this.formPadding, - titlePaddingSm: titlePaddingSm ?? this.titlePaddingSm, - titlePaddingLg: titlePaddingLg ?? this.titlePaddingLg, - optionsMiddlePadding: optionsMiddlePadding ?? this.optionsMiddlePadding, - subTitlePadding: subTitlePadding ?? this.subTitlePadding, - errorPadding: errorPadding ?? this.errorPadding, - disableTextStyle: disableTextStyle ?? this.disableTextStyle, - tipsTextStyle: tipsTextStyle ?? this.tipsTextStyle, - headTitleTextStyle: headTitleTextStyle ?? this.headTitleTextStyle, - optionTextStyle: optionTextStyle ?? this.optionTextStyle, + titleTextStyle: titleTextStyle ?? _titleTextStyle, + subTitleTextStyle: subTitleTextStyle ?? _subTitleTextStyle, + errorTextStyle: errorTextStyle ?? _errorTextStyle, + hintTextStyle: hintTextStyle ?? _hintTextStyle, + contentTextStyle: contentTextStyle ?? _contentTextStyle, + formPadding: formPadding ?? _formPadding, + titlePaddingSm: titlePaddingSm ?? _titlePaddingSm, + titlePaddingLg: titlePaddingLg ?? _titlePaddingLg, + optionsMiddlePadding: optionsMiddlePadding ?? _optionsMiddlePadding, + subTitlePadding: subTitlePadding ?? _subTitlePadding, + errorPadding: errorPadding ?? _errorPadding, + disableTextStyle: disableTextStyle ?? _disableTextStyle, + tipsTextStyle: tipsTextStyle ?? _tipsTextStyle, + headTitleTextStyle: headTitleTextStyle ?? _headTitleTextStyle, + optionTextStyle: optionTextStyle ?? _optionTextStyle, optionSelectedTextStyle: - optionSelectedTextStyle ?? this.optionSelectedTextStyle, + optionSelectedTextStyle ?? _optionSelectedTextStyle, ); } - BrnFormItemConfig merge(BrnFormItemConfig other) { + BrnFormItemConfig merge(BrnFormItemConfig? other) { if (other == null) return this; return copyWith( - titleTextStyle: - titleTextStyle?.merge(other.titleTextStyle) ?? other.titleTextStyle, - subTitleTextStyle: subTitleTextStyle?.merge(other.subTitleTextStyle) ?? - other.subTitleTextStyle, - errorTextStyle: - errorTextStyle?.merge(other.errorTextStyle) ?? other.errorTextStyle, - hintTextStyle: - hintTextStyle?.merge(other.hintTextStyle) ?? other.hintTextStyle, - contentTextStyle: contentTextStyle?.merge(other.contentTextStyle) ?? - other.contentTextStyle, - formPadding: other.formPadding, - titlePaddingSm: other.titlePaddingSm, - titlePaddingLg: other.titlePaddingLg, - optionsMiddlePadding: other.optionsMiddlePadding, - subTitlePadding: other.subTitlePadding, - errorPadding: other.errorPadding, - disableTextStyle: disableTextStyle?.merge(other.disableTextStyle) ?? - other.disableTextStyle, - tipsTextStyle: - tipsTextStyle?.merge(other.tipsTextStyle) ?? other.tipsTextStyle, - headTitleTextStyle: - headTitleTextStyle?.merge(other.headTitleTextStyle) ?? - other.headTitleTextStyle, - optionTextStyle: optionTextStyle?.merge(other.optionTextStyle) ?? - other.optionTextStyle, - optionSelectedTextStyle: - optionSelectedTextStyle?.merge(other.optionSelectedTextStyle) ?? - other.optionSelectedTextStyle); + titleTextStyle: titleTextStyle.merge(other._titleTextStyle), + subTitleTextStyle: subTitleTextStyle.merge(other._subTitleTextStyle), + errorTextStyle: errorTextStyle.merge(other._errorTextStyle), + hintTextStyle: hintTextStyle.merge(other._hintTextStyle), + contentTextStyle: contentTextStyle.merge(other._contentTextStyle), + formPadding: other._formPadding, + titlePaddingSm: other._titlePaddingSm, + titlePaddingLg: other._titlePaddingLg, + optionsMiddlePadding: other._optionsMiddlePadding, + subTitlePadding: other._subTitlePadding, + errorPadding: other._errorPadding, + disableTextStyle: disableTextStyle.merge(other._disableTextStyle), + tipsTextStyle: tipsTextStyle.merge(other._tipsTextStyle), + headTitleTextStyle: headTitleTextStyle.merge(other._headTitleTextStyle), + optionTextStyle: optionTextStyle.merge(other._optionTextStyle), + optionSelectedTextStyle: + optionSelectedTextStyle.merge(other._optionSelectedTextStyle), + ); } } diff --git a/lib/src/theme/configs/brn_gallery_detail_config.dart b/lib/src/theme/configs/brn_gallery_detail_config.dart index daa027a9..b7155350 100644 --- a/lib/src/theme/configs/brn_gallery_detail_config.dart +++ b/lib/src/theme/configs/brn_gallery_detail_config.dart @@ -1,7 +1,6 @@ -import 'dart:ui'; - import 'package:bruno/src/components/navbar/brn_appbar_theme.dart'; import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; import 'package:bruno/src/theme/base/brn_text_style.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_common_config.dart'; @@ -9,265 +8,331 @@ import 'package:flutter/material.dart'; /// 查看大图配置 class BrnGalleryDetailConfig extends BrnBaseConfig { + /// 遵循全局配置 + /// 默认为 [BrnDefaultConfigUtils.defaultGalleryDetailConfig] + BrnGalleryDetailConfig({ + BrnTextStyle? appbarTitleStyle, + BrnTextStyle? appbarActionStyle, + Color? appbarBackgroundColor, + Brightness? appbarBrightness, + BrnTextStyle? tabBarUnSelectedLabelStyle, + BrnTextStyle? tabBarLabelStyle, + Color? tabBarBackgroundColor, + Color? pageBackgroundColor, + Color? bottomBackgroundColor, + BrnTextStyle? titleStyle, + BrnTextStyle? contentStyle, + BrnTextStyle? actionStyle, + Color? iconColor, + String configId = GLOBAL_CONFIG_ID, + }) : _appbarTitleStyle = appbarTitleStyle, + _appbarActionStyle = appbarActionStyle, + _appbarBackgroundColor = appbarBackgroundColor, + _appbarBrightness = appbarBrightness, + _tabBarUnSelectedLabelStyle = tabBarUnSelectedLabelStyle, + _tabBarLabelStyle = tabBarLabelStyle, + _tabBarBackgroundColor = tabBarBackgroundColor, + _pageBackgroundColor = pageBackgroundColor, + _bottomBackgroundColor = bottomBackgroundColor, + _titleStyle = titleStyle, + _contentStyle = contentStyle, + _actionStyle = actionStyle, + _iconColor = iconColor, + super(configId: configId); + + /// 黑色主题 + BrnGalleryDetailConfig.dark({ + String configId = GLOBAL_CONFIG_ID, + }) : super(configId: configId) { + _appbarTitleStyle = BrnTextStyle(color: commonConfig.colorTextBaseInverse); + _appbarActionStyle = BrnTextStyle(color: BrnAppBarTheme.lightTextColor); + _appbarBackgroundColor = Colors.black; + _appbarBrightness = Brightness.dark; + _tabBarUnSelectedLabelStyle = BrnTextStyle(color: Color(0XFFCCCCCC)); + _tabBarLabelStyle = BrnTextStyle(color: commonConfig.colorTextBaseInverse); + _tabBarBackgroundColor = Colors.black; + _pageBackgroundColor = Colors.black; + _bottomBackgroundColor = Color(0X88000000); + _titleStyle = BrnTextStyle(color: commonConfig.colorTextBaseInverse); + _contentStyle = BrnTextStyle(color: Color(0xFFCCCCCC)); + _actionStyle = BrnTextStyle(color: commonConfig.colorTextBaseInverse); + _iconColor = Colors.white; + } + + /// 白色主题 + BrnGalleryDetailConfig.light({ + String configId = GLOBAL_CONFIG_ID, + }) : super(configId: configId) { + _appbarTitleStyle = BrnTextStyle(color: commonConfig.colorTextBase); + _appbarActionStyle = BrnTextStyle(color: commonConfig.colorTextBase); + _appbarBackgroundColor = commonConfig.fillBody; + _appbarBrightness = Brightness.light; + _tabBarUnSelectedLabelStyle = BrnTextStyle( + color: commonConfig.colorTextBase, + ); + _tabBarLabelStyle = BrnTextStyle(color: commonConfig.brandPrimary); + _tabBarBackgroundColor = commonConfig.fillBody; + _pageBackgroundColor = commonConfig.fillBody; + _bottomBackgroundColor = commonConfig.fillBody.withOpacity(.85); + _titleStyle = BrnTextStyle(color: commonConfig.colorTextBase); + _contentStyle = BrnTextStyle(color: commonConfig.colorTextBase); + _actionStyle = BrnTextStyle(color: commonConfig.colorTextSecondary); + _iconColor = commonConfig.colorTextSecondary; + } + /// appbar brightness待定 /// appbar 标题样式 - /// default value is TextStyle(color: [BrnCommonConfig.colorTextBaseInverse],fontSize: [BrnCommonConfig.fontSizeHead],fontWeight: FontWeight.w600) - BrnTextStyle appbarTitleStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBaseInverse], + /// fontSize: [BrnCommonConfig.fontSizeHead], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _appbarTitleStyle; /// 右侧操作区域文案样式 - /// default value is TextStyle(color: AppBarBrightness(brightness).textColor,fontSize: BrnAppBarTheme.actionFontSize,fontWeight: FontWeight.w600) - BrnTextStyle appbarActionStyle; + /// + /// BrnTextStyle( + /// color: AppBarBrightness(brightness).textColor, + /// fontSize: BrnAppBarTheme.actionFontSize, + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _appbarActionStyle; /// appBar 背景色 - /// default value is Colors.black - Color appbarBackgroundColor; + /// 默认为 Colors.black + Color? _appbarBackgroundColor; /// appbar brightness - /// default value is [Brightness.dark] - Brightness appbarBrightness; + /// 默认为 [Brightness.dark] + Brightness? _appbarBrightness; /// tabBar 标题普通样式 - /// default value is TextStyle(fontSize: [BrnCommonConfig.fontSizeSubHead], color: Colors.red) - BrnTextStyle tabBarUnSelectedLabelStyle; + /// + /// BrnTextStyle( + /// color: Colors.red, + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// ) + BrnTextStyle? _tabBarUnSelectedLabelStyle; /// tabBar 标题选中样式 - /// default value is TextStyle(fontSize: [BrnCommonConfig.fontSizeSubHead],fontWeight: FontWeight.w600,color: [BrnCommonConfig.colorTextBaseInverse]) - BrnTextStyle tabBarLabelStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBaseInverse], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _tabBarLabelStyle; /// tabBar 背景色 - /// default value is Colors.black - Color tabBarBackgroundColor; + /// 默认为 Colors.black + Color? _tabBarBackgroundColor; /// 页面 背景色 - /// default value is Colors.black - Color pageBackgroundColor; + /// 默认为 Colors.black + Color? _pageBackgroundColor; /// 底部内容区域的背景色 - /// default value is Color(0X88000000) - Color bottomBackgroundColor; - - /// 标题文案样式 TextStyle(color: [BrnCommonConfig.colorTextBaseInverse],fontSize: [BrnCommonConfig.fontSizeHead],fontWeight: FontWeight.w600) - /// default value is - BrnTextStyle titleStyle; + /// 默认为 Color(0x88000000) + Color? _bottomBackgroundColor; + + /// 标题文案样式 + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBaseInverse], + /// fontSize: [BrnCommonConfig.fontSizeHead], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _titleStyle; /// 内容文案样式 - /// default value is TextStyle(color: Color(0xFFCCCCCC), fontSize: [BrnCommonConfig.fontSizeBase]) - BrnTextStyle contentStyle; + /// + /// BrnTextStyle( + /// color: Color(0xFFCCCCCC), + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _contentStyle; /// 右侧展开收起样式 - /// default value is TextStyle(color: [BrnCommonConfig.colorTextBaseInverse],fontSize: [BrnCommonConfig.fontSizeBase],) - BrnTextStyle actionStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBaseInverse], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _actionStyle; /// icon 颜色 - /// default value is Colors.white - Color iconColor; - - BrnGalleryDetailConfig( - {this.appbarTitleStyle, - this.appbarActionStyle, - this.appbarBackgroundColor, - this.appbarBrightness, - this.tabBarUnSelectedLabelStyle, - this.tabBarLabelStyle, - this.tabBarBackgroundColor, - this.pageBackgroundColor, - this.bottomBackgroundColor, - this.titleStyle, - this.contentStyle, - this.actionStyle, - this.iconColor, - String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID}) - : super(configId: configId); + /// 默认为 Colors.white + Color? _iconColor; - /// 黑色主题 - BrnGalleryDetailConfig.dark( - {this.appbarTitleStyle, - this.appbarActionStyle, - this.appbarBackgroundColor, - this.appbarBrightness, - this.tabBarUnSelectedLabelStyle, - this.tabBarLabelStyle, - this.tabBarBackgroundColor, - this.pageBackgroundColor, - this.bottomBackgroundColor, - this.titleStyle, - this.contentStyle, - this.actionStyle, - this.iconColor, - String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID}) - : super(configId: configId) { - this.appbarTitleStyle = - BrnTextStyle(color: commonConfig.colorTextBaseInverse); - this.appbarActionStyle = BrnTextStyle(color: BrnAppBarTheme.lightTextColor); - this.appbarBackgroundColor = Colors.black; - this.appbarBrightness = Brightness.dark; - this.tabBarUnSelectedLabelStyle = BrnTextStyle(color: Color(0XFFCCCCCC)); - this.tabBarLabelStyle = - BrnTextStyle(color: commonConfig.colorTextBaseInverse); - this.tabBarBackgroundColor = Colors.black; - this.pageBackgroundColor = Colors.black; - this.bottomBackgroundColor = Color(0X88000000); - this.titleStyle = BrnTextStyle(color: commonConfig.colorTextBaseInverse); - this.contentStyle = BrnTextStyle(color: Color(0xFFCCCCCC)); - this.actionStyle = BrnTextStyle(color: commonConfig.colorTextBaseInverse); - this.iconColor = Colors.white; - } + BrnTextStyle get appbarTitleStyle => + _appbarTitleStyle ?? + BrnDefaultConfigUtils.defaultGalleryDetailConfig.appbarTitleStyle; - /// 白色主题 - BrnGalleryDetailConfig.light( - {this.appbarTitleStyle, - this.appbarActionStyle, - this.appbarBackgroundColor, - this.appbarBrightness, - this.tabBarUnSelectedLabelStyle, - this.tabBarLabelStyle, - this.tabBarBackgroundColor, - this.pageBackgroundColor, - this.bottomBackgroundColor, - this.titleStyle, - this.contentStyle, - this.actionStyle, - this.iconColor, - String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID}) - : super(configId: configId) { - this.appbarTitleStyle = BrnTextStyle(color: commonConfig.colorTextBase); - this.appbarActionStyle = BrnTextStyle(color: commonConfig.colorTextBase); - this.appbarBackgroundColor = commonConfig.fillBody; - this.appbarBrightness = Brightness.light; - this.tabBarUnSelectedLabelStyle = - BrnTextStyle(color: commonConfig.colorTextBase); - this.tabBarLabelStyle = BrnTextStyle(color: commonConfig.brandPrimary); - this.tabBarBackgroundColor = commonConfig.fillBody; - this.pageBackgroundColor = commonConfig.fillBody; - this.bottomBackgroundColor = commonConfig.fillBody.withOpacity(0.85); - this.titleStyle = BrnTextStyle(color: commonConfig.colorTextBase); - this.contentStyle = BrnTextStyle(color: commonConfig.colorTextBase); - this.actionStyle = BrnTextStyle(color: commonConfig.colorTextSecondary); - this.iconColor = commonConfig.colorTextSecondary; - } + BrnTextStyle get appbarActionStyle => + _appbarActionStyle ?? + BrnDefaultConfigUtils.defaultGalleryDetailConfig.appbarActionStyle; - @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + Color get appbarBackgroundColor => + _appbarBackgroundColor ?? + BrnDefaultConfigUtils.defaultGalleryDetailConfig.appbarBackgroundColor; - /// 用户全局组件配置 - BrnGalleryDetailConfig galleryDetailConfig = BrnThemeConfigurator.instance - .getConfig(configId: configId) - .galleryDetailConfig; + Brightness get appbarBrightness => + _appbarBrightness ?? + BrnDefaultConfigUtils.defaultGalleryDetailConfig.appbarBrightness; - this.appbarTitleStyle = galleryDetailConfig.appbarTitleStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBaseInverse, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.appbarTitleStyle)); + BrnTextStyle get tabBarUnSelectedLabelStyle => + _tabBarUnSelectedLabelStyle ?? + BrnDefaultConfigUtils + .defaultGalleryDetailConfig.tabBarUnSelectedLabelStyle; - this.appbarActionStyle = - galleryDetailConfig.appbarActionStyle.merge(this.appbarActionStyle); + BrnTextStyle get tabBarLabelStyle => + _tabBarLabelStyle ?? + BrnDefaultConfigUtils.defaultGalleryDetailConfig.tabBarLabelStyle; - this.appbarBrightness ??= galleryDetailConfig.appbarBrightness; + Color get tabBarBackgroundColor => + _tabBarBackgroundColor ?? + BrnDefaultConfigUtils.defaultGalleryDetailConfig.tabBarBackgroundColor; - this.appbarBackgroundColor ??= galleryDetailConfig.appbarBackgroundColor; + Color get pageBackgroundColor => + _pageBackgroundColor ?? + BrnDefaultConfigUtils.defaultGalleryDetailConfig.pageBackgroundColor; - this.tabBarUnSelectedLabelStyle = galleryDetailConfig - .tabBarUnSelectedLabelStyle - .merge(BrnTextStyle(fontSize: commonConfig.fontSizeSubHead)) - .merge(this.tabBarUnSelectedLabelStyle); + Color get bottomBackgroundColor => + _bottomBackgroundColor ?? + BrnDefaultConfigUtils.defaultGalleryDetailConfig.bottomBackgroundColor; - this.tabBarLabelStyle = galleryDetailConfig.tabBarLabelStyle - .merge(BrnTextStyle( - color: commonConfig.colorTextBaseInverse, - fontSize: commonConfig.fontSizeSubHead)) - .merge(this.tabBarLabelStyle); + BrnTextStyle get titleStyle => + _titleStyle ?? + BrnDefaultConfigUtils.defaultGalleryDetailConfig.titleStyle; - this.tabBarBackgroundColor ??= galleryDetailConfig.tabBarBackgroundColor; + BrnTextStyle get contentStyle => + _contentStyle ?? + BrnDefaultConfigUtils.defaultGalleryDetailConfig.contentStyle; - this.pageBackgroundColor ??= galleryDetailConfig.pageBackgroundColor; + BrnTextStyle get actionStyle => + _actionStyle ?? + BrnDefaultConfigUtils.defaultGalleryDetailConfig.actionStyle; - this.bottomBackgroundColor ??= galleryDetailConfig.bottomBackgroundColor; + Color get iconColor => + _iconColor ?? BrnDefaultConfigUtils.defaultGalleryDetailConfig.iconColor; - this.titleStyle = galleryDetailConfig.titleStyle - .merge(BrnTextStyle( - color: commonConfig.colorTextBaseInverse, - fontSize: commonConfig.fontSizeHead)) - .merge(this.titleStyle); + @override + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); - this.contentStyle = galleryDetailConfig.contentStyle - .merge(BrnTextStyle(fontSize: commonConfig.fontSizeBase)) - .merge(this.contentStyle); + /// 用户全局组件配置 + BrnGalleryDetailConfig galleryDetailConfig = BrnThemeConfigurator.instance + .getConfig(configId: configId) + .galleryDetailConfig; - this.actionStyle = galleryDetailConfig.actionStyle - .merge(BrnTextStyle( + _appbarTitleStyle = galleryDetailConfig.appbarTitleStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBaseInverse, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_appbarTitleStyle), + ); + _appbarActionStyle = galleryDetailConfig.appbarActionStyle.merge( + _appbarActionStyle, + ); + _appbarBrightness ??= galleryDetailConfig.appbarBrightness; + _appbarBackgroundColor ??= galleryDetailConfig.appbarBackgroundColor; + _tabBarUnSelectedLabelStyle = galleryDetailConfig.tabBarUnSelectedLabelStyle + .merge(BrnTextStyle(fontSize: commonConfig.fontSizeSubHead)) + .merge(_tabBarUnSelectedLabelStyle); + _tabBarLabelStyle = galleryDetailConfig.tabBarLabelStyle + .merge( + BrnTextStyle( color: commonConfig.colorTextBaseInverse, - fontSize: commonConfig.fontSizeBase)) - .merge(this.actionStyle); - - this.iconColor ??= galleryDetailConfig.iconColor; + fontSize: commonConfig.fontSizeSubHead, + ), + ) + .merge(_tabBarLabelStyle); + _tabBarBackgroundColor ??= galleryDetailConfig._tabBarBackgroundColor; + _pageBackgroundColor ??= galleryDetailConfig._pageBackgroundColor; + _bottomBackgroundColor ??= galleryDetailConfig._bottomBackgroundColor; + _titleStyle = galleryDetailConfig.titleStyle + .merge( + BrnTextStyle( + color: commonConfig.colorTextBaseInverse, + fontSize: commonConfig.fontSizeHead, + ), + ) + .merge(_titleStyle); + _contentStyle = galleryDetailConfig.contentStyle + .merge(BrnTextStyle(fontSize: commonConfig.fontSizeBase)) + .merge(_contentStyle); + _actionStyle = galleryDetailConfig.actionStyle + .merge( + BrnTextStyle( + color: commonConfig.colorTextBaseInverse, + fontSize: commonConfig.fontSizeBase, + ), + ) + .merge(_actionStyle); + _iconColor ??= galleryDetailConfig._iconColor; } BrnGalleryDetailConfig copyWith({ - BrnTextStyle appbarTitleStyle, - BrnTextStyle appbarActionStyle, - Color appbarBackgroundColor, - Brightness appbarBrightness, - BrnTextStyle tabBarUnSelectedLabelStyle, - Color tabBarUnselectedLabelColor, - BrnTextStyle tabBarLabelStyle, - Color tabBarLabelColor, - Color tabBarBackgroundColor, - Color indicatorColor, - Color pageBackgroundColor, - Color bottomBackgroundColor, - BrnTextStyle titleStyle, - BrnTextStyle contentStyle, - BrnTextStyle actionStyle, - Color iconColor, + BrnTextStyle? appbarTitleStyle, + BrnTextStyle? appbarActionStyle, + Color? appbarBackgroundColor, + Brightness? appbarBrightness, + BrnTextStyle? tabBarUnSelectedLabelStyle, + Color? tabBarUnselectedLabelColor, + BrnTextStyle? tabBarLabelStyle, + Color? tabBarLabelColor, + Color? tabBarBackgroundColor, + Color? indicatorColor, + Color? pageBackgroundColor, + Color? bottomBackgroundColor, + BrnTextStyle? titleStyle, + BrnTextStyle? contentStyle, + BrnTextStyle? actionStyle, + Color? iconColor, }) { return BrnGalleryDetailConfig( - appbarTitleStyle: appbarTitleStyle ?? this.appbarTitleStyle, - appbarActionStyle: appbarActionStyle ?? this.appbarActionStyle, - appbarBackgroundColor: - appbarBackgroundColor ?? this.appbarBackgroundColor, - appbarBrightness: appbarBrightness ?? this.appbarBrightness, + appbarTitleStyle: appbarTitleStyle ?? _appbarTitleStyle, + appbarActionStyle: appbarActionStyle ?? _appbarActionStyle, + appbarBackgroundColor: appbarBackgroundColor ?? _appbarBackgroundColor, + appbarBrightness: appbarBrightness ?? _appbarBrightness, tabBarUnSelectedLabelStyle: - tabBarUnSelectedLabelStyle ?? this.tabBarUnSelectedLabelStyle, - tabBarLabelStyle: tabBarLabelStyle ?? this.tabBarLabelStyle, - tabBarBackgroundColor: - tabBarBackgroundColor ?? this.tabBarBackgroundColor, - pageBackgroundColor: pageBackgroundColor ?? this.pageBackgroundColor, - bottomBackgroundColor: - bottomBackgroundColor ?? this.bottomBackgroundColor, - titleStyle: titleStyle ?? this.titleStyle, - contentStyle: contentStyle ?? this.contentStyle, - actionStyle: actionStyle ?? this.actionStyle, - iconColor: iconColor ?? this.iconColor, + tabBarUnSelectedLabelStyle ?? _tabBarUnSelectedLabelStyle, + tabBarLabelStyle: tabBarLabelStyle ?? _tabBarLabelStyle, + tabBarBackgroundColor: tabBarBackgroundColor ?? _tabBarBackgroundColor, + pageBackgroundColor: pageBackgroundColor ?? _pageBackgroundColor, + bottomBackgroundColor: bottomBackgroundColor ?? _bottomBackgroundColor, + titleStyle: titleStyle ?? _titleStyle, + contentStyle: contentStyle ?? _contentStyle, + actionStyle: actionStyle ?? _actionStyle, + iconColor: iconColor ?? _iconColor, ); } - BrnGalleryDetailConfig merge(BrnGalleryDetailConfig other) { + BrnGalleryDetailConfig merge(BrnGalleryDetailConfig? other) { if (other == null) return this; return copyWith( - appbarTitleStyle: appbarTitleStyle?.merge(other.appbarTitleStyle) ?? - other.appbarTitleStyle, - appbarActionStyle: appbarActionStyle?.merge(other.appbarActionStyle) ?? - other.appbarActionStyle, - appbarBackgroundColor: other.appbarBackgroundColor, - appbarBrightness: other.appbarBrightness, + appbarTitleStyle: appbarTitleStyle.merge(other._appbarTitleStyle), + appbarActionStyle: appbarActionStyle.merge(other._appbarActionStyle), + appbarBackgroundColor: other._appbarBackgroundColor, + appbarBrightness: other._appbarBrightness, tabBarUnSelectedLabelStyle: - tabBarUnSelectedLabelStyle?.merge(other.tabBarUnSelectedLabelStyle) ?? - other.tabBarUnSelectedLabelStyle, - tabBarLabelStyle: tabBarLabelStyle?.merge(other.tabBarLabelStyle) ?? - other.tabBarLabelStyle, - tabBarBackgroundColor: other.tabBarBackgroundColor, - pageBackgroundColor: other.pageBackgroundColor, - bottomBackgroundColor: other.bottomBackgroundColor, - titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle, - contentStyle: - contentStyle?.merge(other.contentStyle) ?? other.contentStyle, - actionStyle: actionStyle?.merge(other.actionStyle) ?? other.actionStyle, - iconColor: other.iconColor, + tabBarUnSelectedLabelStyle.merge(other._tabBarUnSelectedLabelStyle), + tabBarLabelStyle: tabBarLabelStyle.merge(other._tabBarLabelStyle), + tabBarBackgroundColor: other._tabBarBackgroundColor, + pageBackgroundColor: other._pageBackgroundColor, + bottomBackgroundColor: other._bottomBackgroundColor, + titleStyle: titleStyle.merge(other._titleStyle), + contentStyle: contentStyle.merge(other._contentStyle), + actionStyle: actionStyle.merge(other._actionStyle), + iconColor: other._iconColor, ); } } diff --git a/lib/src/theme/configs/brn_pair_info_config.dart b/lib/src/theme/configs/brn_pair_info_config.dart index cb55dfb5..987dfb67 100644 --- a/lib/src/theme/configs/brn_pair_info_config.dart +++ b/lib/src/theme/configs/brn_pair_info_config.dart @@ -1,134 +1,233 @@ -import 'package:bruno/src/theme/brn_theme.dart'; +import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; +import 'package:bruno/src/theme/base/brn_text_style.dart'; +import 'package:bruno/src/theme/brn_theme_configurator.dart'; +import 'package:bruno/src/theme/configs/brn_common_config.dart'; -///BrnPairInfoTable的配置文件 全局配置 +/// BrnPairInfoTable 的配置文件 全局配置 class BrnPairInfoTableConfig extends BrnBaseConfig { - ///遵循外部主题配置,Bruno默认配置[BrnDefaultConfigUtils.defaultPairInfoTableConfig] + /// 遵循外部主题配置 + /// 默认为 [BrnDefaultConfigUtils.defaultPairInfoTableConfig] BrnPairInfoTableConfig({ - this.rowSpacing, - this.itemSpacing, - this.keyTextStyle, - this.valueTextStyle, - this.linkTextStyle, - String configId: BrnThemeConfigurator.GLOBAL_CONFIG_ID, - }) : super(configId: configId); + double? rowSpacing, + double? itemSpacing, + BrnTextStyle? keyTextStyle, + BrnTextStyle? valueTextStyle, + BrnTextStyle? linkTextStyle, + String configId: GLOBAL_CONFIG_ID, + }) : _rowSpacing = rowSpacing, + _itemSpacing = itemSpacing, + _keyTextStyle = keyTextStyle, + _valueTextStyle = valueTextStyle, + _linkTextStyle = linkTextStyle, + super(configId: configId); /// 行间距 纵向 - double rowSpacing; + double? _rowSpacing; /// BrnInfoModal 属性配置 行间距 - double itemSpacing; + double? _itemSpacing; /// BrnInfoModal key文字样式 - /// TextStyle(fontWeight: FontWeight.w400,color: [BrnCommonConfig.colorTextSecondary], fontSize: [BrnCommonConfig.fontSizeBase]) - BrnTextStyle keyTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextSecondary], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// fontWeight: FontWeight.w400, + /// ) + BrnTextStyle? _keyTextStyle; /// BrnInfoModal value文字样式 - /// TextStyle(fontWeight: FontWeight.w400,color: [BrnCommonConfig.colorTextBase], fontSize: [BrnCommonConfig.fontSizeBase]) - BrnTextStyle valueTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// fontWeight: FontWeight.w400, + /// ) + BrnTextStyle? _valueTextStyle; /// BrnInfoModal 链接文字样式 - /// TextStyle(fontWeight: FontWeight.w400,color: [BrnCommonConfig.brandPrimary], fontSize: [BrnCommonConfig.fontSizeBase]) - BrnTextStyle linkTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandPrimary], + /// fontWeight: FontWeight.w400, + /// fontSize: [BrnCommonConfig.fontSizeBase] + /// ) + BrnTextStyle? _linkTextStyle; + + double get rowSpacing => + _rowSpacing ?? + BrnDefaultConfigUtils.defaultPairInfoTableConfig.rowSpacing; + + double get itemSpacing => + _itemSpacing ?? + BrnDefaultConfigUtils.defaultPairInfoTableConfig.itemSpacing; + + BrnTextStyle get keyTextStyle => + _keyTextStyle ?? + BrnDefaultConfigUtils.defaultPairInfoTableConfig.keyTextStyle; + + BrnTextStyle get valueTextStyle => + _valueTextStyle ?? + BrnDefaultConfigUtils.defaultPairInfoTableConfig.valueTextStyle; + + BrnTextStyle get linkTextStyle => + _linkTextStyle ?? + BrnDefaultConfigUtils.defaultPairInfoTableConfig.linkTextStyle; @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); /// 用户全局组件配置 BrnPairInfoTableConfig pairInfoTableConfig = BrnThemeConfigurator.instance .getConfig(configId: configId) .pairInfoTableConfig; - this.rowSpacing ??= pairInfoTableConfig?.rowSpacing; - - this.keyTextStyle = pairInfoTableConfig.keyTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextSecondary, - fontSize: commonConfig.fontSizeBase) - .merge(this.keyTextStyle)); - - this.valueTextStyle = pairInfoTableConfig.valueTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeBase) - .merge(this.valueTextStyle)); - - this.linkTextStyle = pairInfoTableConfig.linkTextStyle.merge(BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeBase) - .merge(this.linkTextStyle)); - - this.itemSpacing ??= pairInfoTableConfig?.itemSpacing; + _rowSpacing ??= pairInfoTableConfig._rowSpacing; + _keyTextStyle = pairInfoTableConfig.keyTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextSecondary, + fontSize: commonConfig.fontSizeBase, + ).merge(_keyTextStyle), + ); + _valueTextStyle = pairInfoTableConfig.valueTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase, + ).merge(_valueTextStyle), + ); + _linkTextStyle = pairInfoTableConfig.linkTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeBase, + ).merge(_linkTextStyle), + ); + _itemSpacing ??= pairInfoTableConfig._itemSpacing; } - BrnPairInfoTableConfig copyWith( - {double rowSpacing, - double itemSpacing, - BrnTextStyle keyTextStyle, - BrnTextStyle valueTextStyle, - BrnTextStyle linkTextStyle}) { + BrnPairInfoTableConfig copyWith({ + double? rowSpacing, + double? itemSpacing, + BrnTextStyle? keyTextStyle, + BrnTextStyle? valueTextStyle, + BrnTextStyle? linkTextStyle, + }) { return BrnPairInfoTableConfig( - rowSpacing: rowSpacing ?? this.rowSpacing, - itemSpacing: itemSpacing ?? this.itemSpacing, - keyTextStyle: keyTextStyle ?? this.keyTextStyle, - valueTextStyle: valueTextStyle ?? this.valueTextStyle, - linkTextStyle: linkTextStyle ?? this.linkTextStyle, + rowSpacing: rowSpacing ?? _rowSpacing, + itemSpacing: itemSpacing ?? _itemSpacing, + keyTextStyle: keyTextStyle ?? _keyTextStyle, + valueTextStyle: valueTextStyle ?? _valueTextStyle, + linkTextStyle: linkTextStyle ?? _linkTextStyle, ); } - BrnPairInfoTableConfig merge(BrnPairInfoTableConfig other) { + BrnPairInfoTableConfig merge(BrnPairInfoTableConfig? other) { if (other == null) return this; return copyWith( - rowSpacing: other.rowSpacing, - itemSpacing: other.itemSpacing, - keyTextStyle: - keyTextStyle?.merge(other.keyTextStyle) ?? other.keyTextStyle, - valueTextStyle: - valueTextStyle?.merge(other.valueTextStyle) ?? other.valueTextStyle, - linkTextStyle: - linkTextStyle?.merge(other.linkTextStyle) ?? other.linkTextStyle, + rowSpacing: other._rowSpacing, + itemSpacing: other._itemSpacing, + keyTextStyle: keyTextStyle.merge(other._keyTextStyle), + valueTextStyle: valueTextStyle.merge(other._valueTextStyle), + linkTextStyle: linkTextStyle.merge(other._linkTextStyle), ); } } class BrnPairRichInfoGridConfig extends BrnBaseConfig { - ///遵循外部主题配置,Bruno默认配置[BrnDefaultConfigUtils.defaultPairRichInfoGridConfig] + /// 遵循外部主题配置 + /// 默认为 [BrnDefaultConfigUtils.defaultPairRichInfoGridConfig] BrnPairRichInfoGridConfig({ - this.rowSpacing, - this.itemSpacing, - this.itemHeight, - this.keyTextStyle, - this.valueTextStyle, - this.linkTextStyle, - String configId: BrnThemeConfigurator.GLOBAL_CONFIG_ID, - }) : super(configId: configId); + double? rowSpacing, + double? itemSpacing, + double? itemHeight, + BrnTextStyle? keyTextStyle, + BrnTextStyle? valueTextStyle, + BrnTextStyle? linkTextStyle, + String configId: GLOBAL_CONFIG_ID, + }) : _rowSpacing = rowSpacing, + _itemSpacing = itemSpacing, + _itemHeight = itemHeight, + _keyTextStyle = keyTextStyle, + _valueTextStyle = valueTextStyle, + _linkTextStyle = linkTextStyle, + super(configId: configId); /// 行间距 纵向 - double rowSpacing; + double? _rowSpacing; /// 元素间距 横向 - double itemSpacing; + double? _itemSpacing; /// 元素高度 - double itemHeight; + double? _itemHeight; /// key文字样式 - /// TextStyle(fontWeight: FontWeight.w400,color: [BrnCommonConfig.colorTextSecondary], fontSize: [BrnCommonConfig.fontSizeBase]) - BrnTextStyle keyTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextSecondary], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// fontWeight: FontWeight.w400, + /// ) + BrnTextStyle? _keyTextStyle; /// value文字样式 - /// TextStyle(fontWeight: FontWeight.w400,color: [BrnCommonConfig.colorTextBase], fontSize: [BrnCommonConfig.fontSizeBase]) - BrnTextStyle valueTextStyle; + /// + /// BrnTextStyle( + /// fontWeight: FontWeight.w400, + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _valueTextStyle; /// 链接文字样式 - /// TextStyle(fontWeight: FontWeight.w400,color: [BrnCommonConfig.brandPrimary], fontSize: [BrnCommonConfig.fontSizeBase]) - BrnTextStyle linkTextStyle; + /// + /// BrnTextStyle( + /// fontWeight: FontWeight.w400, + /// color: [BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _linkTextStyle; + + double get rowSpacing => + _rowSpacing ?? + BrnDefaultConfigUtils.defaultPairRichInfoGridConfig.rowSpacing; + + double get itemSpacing => + _itemSpacing ?? + BrnDefaultConfigUtils.defaultPairRichInfoGridConfig.itemSpacing; + + double get itemHeight => + _itemHeight ?? + BrnDefaultConfigUtils.defaultPairRichInfoGridConfig.itemHeight; + + BrnTextStyle get keyTextStyle => + _keyTextStyle ?? + BrnDefaultConfigUtils.defaultPairRichInfoGridConfig.keyTextStyle; + + BrnTextStyle get valueTextStyle => + _valueTextStyle ?? + BrnDefaultConfigUtils.defaultPairRichInfoGridConfig.valueTextStyle; + + BrnTextStyle get linkTextStyle => + _linkTextStyle ?? + BrnDefaultConfigUtils.defaultPairRichInfoGridConfig.linkTextStyle; @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); /// 用户全局组件配置 BrnPairRichInfoGridConfig pairRichInfoGridConfig = BrnThemeConfigurator @@ -136,58 +235,57 @@ class BrnPairRichInfoGridConfig extends BrnBaseConfig { .getConfig(configId: configId) .pairRichInfoGridConfig; - this.rowSpacing ??= pairRichInfoGridConfig?.rowSpacing; - this.itemSpacing ??= pairRichInfoGridConfig?.itemSpacing; - this.itemHeight ??= pairRichInfoGridConfig?.itemHeight; - - this.keyTextStyle = pairRichInfoGridConfig.keyTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextSecondary, - fontSize: commonConfig.fontSizeBase, - ).merge(this.keyTextStyle)); - - this.valueTextStyle = pairRichInfoGridConfig.valueTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeBase) - .merge(this.valueTextStyle)); - - this.linkTextStyle = pairRichInfoGridConfig.linkTextStyle.merge( - BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeBase) - .merge(this.linkTextStyle)); + _rowSpacing ??= pairRichInfoGridConfig._rowSpacing; + _itemSpacing ??= pairRichInfoGridConfig._itemSpacing; + _itemHeight ??= pairRichInfoGridConfig._itemHeight; + _keyTextStyle = pairRichInfoGridConfig.keyTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextSecondary, + fontSize: commonConfig.fontSizeBase, + ).merge(_keyTextStyle), + ); + _valueTextStyle = pairRichInfoGridConfig.valueTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase, + ).merge(_valueTextStyle), + ); + _linkTextStyle = pairRichInfoGridConfig.linkTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeBase, + ).merge(_linkTextStyle), + ); } - BrnPairRichInfoGridConfig copyWith( - {double rowSpacing, - double itemSpacing, - double itemHeight, - BrnTextStyle keyTextStyle, - BrnTextStyle valueTextStyle, - BrnTextStyle linkTextStyle, - BrnTextStyle titleTextsStyle}) { + BrnPairRichInfoGridConfig copyWith({ + double? rowSpacing, + double? itemSpacing, + double? itemHeight, + BrnTextStyle? keyTextStyle, + BrnTextStyle? valueTextStyle, + BrnTextStyle? linkTextStyle, + BrnTextStyle? titleTextsStyle, + }) { return BrnPairRichInfoGridConfig( - rowSpacing: rowSpacing ?? this.rowSpacing, - itemSpacing: itemSpacing ?? this.itemSpacing, - itemHeight: itemHeight ?? this.itemHeight, - keyTextStyle: keyTextStyle ?? this.keyTextStyle, - valueTextStyle: valueTextStyle ?? this.valueTextStyle, - linkTextStyle: linkTextStyle ?? this.linkTextStyle, + rowSpacing: rowSpacing ?? _rowSpacing, + itemSpacing: itemSpacing ?? _itemSpacing, + itemHeight: itemHeight ?? _itemHeight, + keyTextStyle: keyTextStyle ?? _keyTextStyle, + valueTextStyle: valueTextStyle ?? _valueTextStyle, + linkTextStyle: linkTextStyle ?? _linkTextStyle, ); } - BrnPairRichInfoGridConfig merge(BrnPairRichInfoGridConfig other) { - if (BrnPairRichInfoGridConfig == null) return this; + BrnPairRichInfoGridConfig merge(BrnPairRichInfoGridConfig? other) { + if (other == null) return this; return copyWith( - rowSpacing: other.rowSpacing, - itemSpacing: other.itemSpacing, - itemHeight: other.itemHeight, - keyTextStyle: - keyTextStyle?.merge(other.keyTextStyle) ?? other.keyTextStyle, - valueTextStyle: - valueTextStyle?.merge(other.valueTextStyle) ?? other.valueTextStyle, - linkTextStyle: - linkTextStyle?.merge(other.linkTextStyle) ?? other.linkTextStyle, + rowSpacing: other._rowSpacing, + itemSpacing: other._itemSpacing, + itemHeight: other._itemHeight, + keyTextStyle: keyTextStyle.merge(other._keyTextStyle), + valueTextStyle: valueTextStyle.merge(other._valueTextStyle), + linkTextStyle: linkTextStyle.merge(other._linkTextStyle), ); } } diff --git a/lib/src/theme/configs/brn_picker_config.dart b/lib/src/theme/configs/brn_picker_config.dart index a15bf8e1..92b903ba 100644 --- a/lib/src/theme/configs/brn_picker_config.dart +++ b/lib/src/theme/configs/brn_picker_config.dart @@ -1,4 +1,5 @@ import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; import 'package:bruno/src/theme/base/brn_text_style.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_common_config.dart'; @@ -6,154 +7,231 @@ import 'package:flutter/material.dart'; /// 选择器配置 class BrnPickerConfig extends BrnBaseConfig { - ///遵循外部主题配置,Bruno默认配置[BrnDefaultConfigUtils.defaultPickerConfig] - BrnPickerConfig( - {this.backgroundColor, - this.cancelTextStyle, - this.confirmTextStyle, - this.titleTextStyle, - this.pickerHeight, - this.titleHeight, - this.itemHeight, - this.itemTextStyle, - this.itemTextSelectedStyle, - this.dividerColor, - this.cornerRadius, - String configId: BrnThemeConfigurator.GLOBAL_CONFIG_ID}) - : super(configId: configId); - - /// DatePicker's background color. value is [PICKER_BACKGROUND_COLOR] - Color backgroundColor; - - /// cancel text style - /// Default style is TextStyle(color:[BrnCommonConfig.colorTextBase],fontSize:[BrnCommonConfig.fontSizeSubHead]). - BrnTextStyle cancelTextStyle; - - /// confirm text style - /// Default style is TextStyle(color:[BrnCommonConfig.brandPrimary],fontSize:[BrnCommonConfig.fontSizeSubHead]). - BrnTextStyle confirmTextStyle; - - /// title style - /// Default style is TextStyle(color:[BrnCommonConfig.colorTextBase],fontSize:[BrnCommonConfig.fontSizeSubHead],fontWidget:FontWeight.w600). - BrnTextStyle titleTextStyle; - - /// The value of DatePicker's height. - /// default value is [PICKER_HEIGHT] - double pickerHeight; - - /// The value of DatePicker's title height. - /// default value is [PICKER_TITLE_HEIGHT] - double titleHeight; - - /// The value of DatePicker's column height. - /// default value is [PICKER_ITEM_HEIGHT] - double itemHeight; - - /// The value of DatePicker's column [TextStyle]. - /// Default style is TextStyle(color:[BrnCommonConfig.colorTextBase],fontSize:[BrnCommonConfig.fontSizeHead]). - BrnTextStyle itemTextStyle; - - /// The value of DatePicker's column selected [TextStyle]. - /// Default style is TextStyle(color:[BrnCommonConfig.brandPrimary],fontSize:[BrnCommonConfig.fontSizeHead],fontWidget:FontWeight.w600). - BrnTextStyle itemTextSelectedStyle; - - Color dividerColor; - double cornerRadius; + /// 遵循外部主题配置 + /// 默认为 [BrnDefaultConfigUtils.defaultPickerConfig] + BrnPickerConfig({ + Color? backgroundColor, + BrnTextStyle? cancelTextStyle, + BrnTextStyle? confirmTextStyle, + BrnTextStyle? titleTextStyle, + double? pickerHeight, + double? titleHeight, + double? itemHeight, + BrnTextStyle? itemTextStyle, + BrnTextStyle? itemTextSelectedStyle, + Color? dividerColor, + double? cornerRadius, + String configId = GLOBAL_CONFIG_ID, + }) : _backgroundColor = backgroundColor, + _cancelTextStyle = cancelTextStyle, + _confirmTextStyle = confirmTextStyle, + _titleTextStyle = titleTextStyle, + _pickerHeight = pickerHeight, + _titleHeight = titleHeight, + _itemHeight = itemHeight, + _itemTextStyle = itemTextStyle, + _itemTextSelectedStyle = itemTextSelectedStyle, + _dividerColor = dividerColor, + _cornerRadius = cornerRadius, + super(configId: configId); + + /// 日期选择器的背景色 + /// 默认为 [PICKER_BACKGROUND_COLOR] + Color? _backgroundColor; + + /// 取消文字的样式 + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// ) + BrnTextStyle? _cancelTextStyle; + + /// 确认文字的样式 + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// ) + BrnTextStyle? _confirmTextStyle; + + /// 标题文字的样式 + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// fontWidget:FontWeight.w600, + /// ) + BrnTextStyle? _titleTextStyle; + + /// 日期选择器的高度 + /// 默认为 [PICKER_HEIGHT] + double? _pickerHeight; + + /// 日期选择器标题的高度 + /// 默认为 [PICKER_TITLE_HEIGHT] + double? _titleHeight; + + /// 日期选择器列表的高度 + /// 默认为 [PICKER_ITEM_HEIGHT] + double? _itemHeight; + + /// 日期选择器列表的文字样式 + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeHead], + /// ) + BrnTextStyle? _itemTextStyle; + + /// 日期选择器列表选中的文字样式 + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeHead], + /// fontWidget: FontWeight.w600, + /// ) + BrnTextStyle? _itemTextSelectedStyle; + + Color? _dividerColor; + double? _cornerRadius; + + Color get backgroundColor => + _backgroundColor ?? + BrnDefaultConfigUtils.defaultPickerConfig.backgroundColor; + + BrnTextStyle get cancelTextStyle => + _cancelTextStyle ?? + BrnDefaultConfigUtils.defaultPickerConfig.cancelTextStyle; + + BrnTextStyle get confirmTextStyle => + _confirmTextStyle ?? + BrnDefaultConfigUtils.defaultPickerConfig.confirmTextStyle; + + BrnTextStyle get titleTextStyle => + _titleTextStyle ?? + BrnDefaultConfigUtils.defaultPickerConfig.titleTextStyle; + + double get pickerHeight => + _pickerHeight ?? BrnDefaultConfigUtils.defaultPickerConfig.pickerHeight; + + double get titleHeight => + _titleHeight ?? BrnDefaultConfigUtils.defaultPickerConfig.titleHeight; + + double get itemHeight => + _itemHeight ?? BrnDefaultConfigUtils.defaultPickerConfig.itemHeight; + + BrnTextStyle get itemTextStyle => + _itemTextStyle ?? BrnDefaultConfigUtils.defaultPickerConfig.itemTextStyle; + + BrnTextStyle get itemTextSelectedStyle => + _itemTextSelectedStyle ?? + BrnDefaultConfigUtils.defaultPickerConfig.itemTextSelectedStyle; + + Color get dividerColor => + _dividerColor ?? BrnDefaultConfigUtils.defaultPickerConfig.dividerColor; + + double get cornerRadius => + _cornerRadius ?? BrnDefaultConfigUtils.defaultPickerConfig.cornerRadius; @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); /// 用户全局组件配置 BrnPickerConfig pickerConfig = BrnThemeConfigurator.instance .getConfig(configId: configId) .pickerConfig; - this.backgroundColor ??= pickerConfig.backgroundColor; - this.pickerHeight ??= pickerConfig.pickerHeight; - this.titleHeight ??= pickerConfig.titleHeight; - this.itemHeight ??= pickerConfig.itemHeight; - this.dividerColor ??= pickerConfig.dividerColor; - this.cornerRadius ??= pickerConfig.cornerRadius; - - this.titleTextStyle = pickerConfig.titleTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.titleTextStyle)); - - this.cancelTextStyle = pickerConfig.cancelTextStyle - .merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeSubHead)) - .merge(this.cancelTextStyle); - - this.confirmTextStyle = pickerConfig.confirmTextStyle.merge(BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.confirmTextStyle)); - - this.itemTextStyle = pickerConfig.itemTextStyle.merge(BrnTextStyle( + _backgroundColor ??= pickerConfig.backgroundColor; + _pickerHeight ??= pickerConfig.pickerHeight; + _titleHeight ??= pickerConfig.titleHeight; + _itemHeight ??= pickerConfig.itemHeight; + _dividerColor ??= pickerConfig.dividerColor; + _cornerRadius ??= pickerConfig.cornerRadius; + _titleTextStyle = pickerConfig.titleTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_titleTextStyle), + ); + _cancelTextStyle = pickerConfig.cancelTextStyle + .merge( + BrnTextStyle( color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeHead) - .merge(this.itemTextStyle)); - - this.itemTextSelectedStyle = pickerConfig.itemTextSelectedStyle.merge( - BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeHead) - .merge(this.itemTextSelectedStyle)); + fontSize: commonConfig.fontSizeSubHead, + ), + ) + .merge(_cancelTextStyle); + _confirmTextStyle = pickerConfig.confirmTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_confirmTextStyle), + ); + _itemTextStyle = pickerConfig.itemTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeHead, + ).merge(_itemTextStyle), + ); + _itemTextSelectedStyle = pickerConfig.itemTextSelectedStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeHead, + ).merge(_itemTextSelectedStyle), + ); } - BrnPickerConfig copyWith( - {Color backgroundColor, - BrnTextStyle cancelTextStyle, - BrnTextStyle confirmTextStyle, - BrnTextStyle titleTextStyle, - double pickerHeight, - double titleHeight, - double itemHeight, - BrnTextStyle itemTextStyle, - BrnTextStyle itemTextSelectedStyle, - Color dividerColor, - double cornerRadius}) { + BrnPickerConfig copyWith({ + Color? backgroundColor, + BrnTextStyle? cancelTextStyle, + BrnTextStyle? confirmTextStyle, + BrnTextStyle? titleTextStyle, + double? pickerHeight, + double? titleHeight, + double? itemHeight, + BrnTextStyle? itemTextStyle, + BrnTextStyle? itemTextSelectedStyle, + Color? dividerColor, + double? cornerRadius, + }) { return BrnPickerConfig( - backgroundColor: backgroundColor ?? this.backgroundColor, - cancelTextStyle: cancelTextStyle ?? this.cancelTextStyle, - confirmTextStyle: confirmTextStyle ?? this.confirmTextStyle, - titleTextStyle: titleTextStyle ?? this.titleTextStyle, - pickerHeight: pickerHeight ?? this.pickerHeight, - titleHeight: titleHeight ?? this.titleHeight, - itemHeight: itemHeight ?? this.itemHeight, - itemTextStyle: itemTextStyle ?? this.itemTextStyle, - itemTextSelectedStyle: - itemTextSelectedStyle ?? this.itemTextSelectedStyle, - dividerColor: dividerColor ?? this.dividerColor, - cornerRadius: cornerRadius ?? this.cornerRadius, + backgroundColor: backgroundColor ?? _backgroundColor, + cancelTextStyle: cancelTextStyle ?? _cancelTextStyle, + confirmTextStyle: confirmTextStyle ?? _confirmTextStyle, + titleTextStyle: titleTextStyle ?? _titleTextStyle, + pickerHeight: pickerHeight ?? _pickerHeight, + titleHeight: titleHeight ?? _titleHeight, + itemHeight: itemHeight ?? _itemHeight, + itemTextStyle: itemTextStyle ?? _itemTextStyle, + itemTextSelectedStyle: itemTextSelectedStyle ?? _itemTextSelectedStyle, + dividerColor: dividerColor ?? _dividerColor, + cornerRadius: cornerRadius ?? _cornerRadius, ); } - BrnPickerConfig merge(BrnPickerConfig other) { + BrnPickerConfig merge(BrnPickerConfig? other) { if (other == null) return this; return copyWith( - backgroundColor: other.backgroundColor, - cancelTextStyle: this.cancelTextStyle?.merge(other.cancelTextStyle) ?? - other.cancelTextStyle, - confirmTextStyle: - this.confirmTextStyle?.merge(other.confirmTextStyle) ?? - other.confirmTextStyle, - titleTextStyle: this.titleTextStyle?.merge(other.titleTextStyle) ?? - other.titleTextStyle, - pickerHeight: other.pickerHeight, - titleHeight: other.titleHeight, - itemHeight: other.itemHeight, - itemTextStyle: this.itemTextStyle?.merge(other.itemTextStyle) ?? - other.itemTextStyle, - itemTextSelectedStyle: - this.itemTextSelectedStyle?.merge(other.itemTextSelectedStyle) ?? - other.itemTextSelectedStyle, - dividerColor: other.dividerColor, - cornerRadius: other.cornerRadius); + backgroundColor: other._backgroundColor, + cancelTextStyle: cancelTextStyle.merge(other._cancelTextStyle), + confirmTextStyle: confirmTextStyle.merge(other._confirmTextStyle), + titleTextStyle: titleTextStyle.merge(other._titleTextStyle), + pickerHeight: other._pickerHeight, + titleHeight: other._titleHeight, + itemHeight: other._itemHeight, + itemTextStyle: itemTextStyle.merge(other._itemTextStyle), + itemTextSelectedStyle: + itemTextSelectedStyle.merge(other._itemTextSelectedStyle), + dividerColor: other._dividerColor, + cornerRadius: other._cornerRadius, + ); } } diff --git a/lib/src/theme/configs/brn_selection_config.dart b/lib/src/theme/configs/brn_selection_config.dart index 190f3266..1dc0019b 100644 --- a/lib/src/theme/configs/brn_selection_config.dart +++ b/lib/src/theme/configs/brn_selection_config.dart @@ -1,378 +1,577 @@ -import 'dart:ui'; - import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; import 'package:bruno/src/theme/base/brn_text_style.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_common_config.dart'; +import 'package:flutter/painting.dart'; /// 筛选项 配置类 - class BrnSelectionConfig extends BrnBaseConfig { + /// 遵循外部主题配置 + /// 默认为 [BrnDefaultConfigUtils.defaultSelectionConfig] + BrnSelectionConfig({ + BrnTextStyle? menuNormalTextStyle, + BrnTextStyle? menuSelectedTextStyle, + BrnTextStyle? tagNormalTextStyle, + BrnTextStyle? tagSelectedTextStyle, + double? tagRadius, + Color? tagNormalBackgroundColor, + Color? tagSelectedBackgroundColor, + BrnTextStyle? hintTextStyle, + BrnTextStyle? rangeTitleTextStyle, + BrnTextStyle? inputTextStyle, + BrnTextStyle? itemNormalTextStyle, + BrnTextStyle? itemSelectedTextStyle, + BrnTextStyle? itemBoldTextStyle, + Color? deepNormalBgColor, + Color? deepSelectBgColor, + Color? middleNormalBgColor, + Color? middleSelectBgColor, + Color? lightNormalBgColor, + Color? lightSelectBgColor, + BrnTextStyle? resetTextStyle, + BrnTextStyle? titleForMoreTextStyle, + BrnTextStyle? optionTextStyle, + BrnTextStyle? moreTextStyle, + BrnTextStyle? flayerNormalTextStyle, + BrnTextStyle? flayerSelectedTextStyle, + BrnTextStyle? flayerBoldTextStyle, + String configId = GLOBAL_CONFIG_ID, + }) : _menuNormalTextStyle = menuNormalTextStyle, + _menuSelectedTextStyle = menuSelectedTextStyle, + _tagNormalTextStyle = tagNormalTextStyle, + _tagSelectedTextStyle = tagSelectedTextStyle, + _tagRadius = tagRadius, + _tagNormalBackgroundColor = tagNormalBackgroundColor, + _tagSelectedBackgroundColor = tagSelectedBackgroundColor, + _hintTextStyle = hintTextStyle, + _rangeTitleTextStyle = rangeTitleTextStyle, + _inputTextStyle = inputTextStyle, + _itemNormalTextStyle = itemNormalTextStyle, + _itemSelectedTextStyle = itemSelectedTextStyle, + _itemBoldTextStyle = itemBoldTextStyle, + _deepNormalBgColor = deepNormalBgColor, + _deepSelectBgColor = deepSelectBgColor, + _middleNormalBgColor = middleNormalBgColor, + _middleSelectBgColor = middleSelectBgColor, + _lightNormalBgColor = lightNormalBgColor, + _lightSelectBgColor = lightSelectBgColor, + _resetTextStyle = resetTextStyle, + _titleForMoreTextStyle = titleForMoreTextStyle, + _optionTextStyle = optionTextStyle, + _moreTextStyle = moreTextStyle, + _flayerNormalTextStyle = flayerNormalTextStyle, + _flayerSelectedTextStyle = flayerSelectedTextStyle, + _flayerBoldTextStyle = flayerBoldTextStyle, + super(configId: configId); + /// menu 正常文本样式 - /// TextStyle(fontWeight: FontWeight.normal ,fontSize: [BrnCommonConfig.fontSizeBase],color: [BrnCommonConfig.colorTextBase]) - BrnTextStyle menuNormalTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// fontWeight: FontWeight.normal, + /// ) + BrnTextStyle? _menuNormalTextStyle; /// menu 选中文本样式 - /// TextStyle(fontWeight: FontWeight.w600,fontSize: [BrnCommonConfig.fontSizeBase],color: [BrnCommonConfig.brandPrimary]) - BrnTextStyle menuSelectedTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _menuSelectedTextStyle; /// tag 正常文本样式 - /// TextStyle(fontWeight: FontWeight.w400,fontSize: [BrnCommonConfig.fontSizeCaption],color: [BrnCommonConfig.colorTextBase]) - BrnTextStyle tagNormalTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeCaption], + /// fontWeight: FontWeight.w400, + /// ) + BrnTextStyle? _tagNormalTextStyle; /// tag 选中文本样式 - /// TextStyle(fontWeight: FontWeight.w600,fontSize: [BrnCommonConfig.fontSizeCaption],color: [BrnCommonConfig.brandPrimary]) - BrnTextStyle tagSelectedTextStyle; - - /// tag圆角 - /// default value is [BrnCommonConfig.radiusSm] - double tagRadius; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeCaption], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _tagSelectedTextStyle; + + /// tag 圆角 + /// 默认为 [BrnCommonConfig.radiusSm] + double? _tagRadius; /// tag 正常背景色 - /// default value is [BrnCommonConfig.fillBody] - Color tagNormalBackgroundColor; + /// 默认为 [BrnCommonConfig.fillBody] + Color? _tagNormalBackgroundColor; /// tag 选中背景色 - /// [BrnCommonConfig.brandPrimary].withOpacity(0.12) - Color tagSelectedBackgroundColor; + /// 默认为 [BrnCommonConfig.brandPrimary].withOpacity(0.12) + Color? _tagSelectedBackgroundColor; /// 输入选项标题文本样式 - /// TextStyle(fontWeight : FontWeight.w600,fontSize: [BrnCommonConfig.fontSizeSubHead], color: [BrnCommonConfig.colorTextBase]) - BrnTextStyle rangeTitleTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _rangeTitleTextStyle; /// 输入提示文本样式 - /// TextStyle(fontSize: [BrnCommonConfig.fontSizeBase], color: [BrnCommonConfig.colorTextHint]) - BrnTextStyle hintTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextHint], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _hintTextStyle; /// 输入框默认文本样式 - /// TextStyle(fontSize: [BrnCommonConfig.fontSizeBase], color: [BrnCommonConfig.colorTextBase]) - BrnTextStyle inputTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _inputTextStyle; /// item 正常字体样式 - /// TextStyle(fontSize: [BrnCommonConfig.fontSizeBase],color: [BrnCommonConfig.colorTextBase]) - BrnTextStyle itemNormalTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _itemNormalTextStyle; /// item 选中文本样式 - /// TextStyle(fontSize: [BrnCommonConfig.fontSizeBase],fontWeight: FontWeight.w600,color: [BrnCommonConfig.brandPrimary]) - BrnTextStyle itemSelectedTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _itemSelectedTextStyle; /// item 仅加粗样式 - /// TextStyle(fontSize: [BrnCommonConfig.fontSizeBase],fontWeight: FontWeight.w600,color: [BrnCommonConfig.colorTextBase]) - BrnTextStyle itemBoldTextStyle; - - /// 三级item 背景色 - /// Color(0xFFF0F0F0) - Color deepNormalBgColor; - - /// 三级item 选中背景色 - /// Color(0xFFF8F8F8) - Color deepSelectBgColor; - - /// 二级item 背景色 - /// Color(0xFFF8F8F8) - Color middleNormalBgColor; - - /// 二级item 选中背景色 - /// Colors.white - Color middleSelectBgColor; - - /// 一级item 背景色 - /// Colors.white - Color lightNormalBgColor; - - /// 一级item 选中背景色 - /// Colors.white - Color lightSelectBgColor; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _itemBoldTextStyle; + + /// 三级 item 背景色 + /// 默认为 Color(0xFFF0F0F0) + Color? _deepNormalBgColor; + + /// 三级 item 选中背景色 + /// 默认为 Color(0xFFF8F8F8) + Color? _deepSelectBgColor; + + /// 二级 item 背景色 + /// 默认为 Color(0xFFF8F8F8) + Color? _middleNormalBgColor; + + /// 二级 item 选中背景色 + /// 默认为 Colors.white + Color? _middleSelectBgColor; + + /// 一级 item 背景色 + /// 默认为 Colors.white + Color? _lightNormalBgColor; + + /// 一级 item 选中背景色 + /// 默认为 Colors.white + Color? _lightSelectBgColor; /// 重置按钮颜色 - /// TextStyle(color: [BrnCommonConfig.colorTextImportant],fontSize: [BrnCommonConfig.fontSizeCaption]) - BrnTextStyle resetTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextImportant], + /// fontSize: [BrnCommonConfig.fontSizeCaption] + /// ) + BrnTextStyle? _resetTextStyle; /// 更多筛选-标题文本样式 - /// TextStyle(color: [BrnCommonConfig.colorTextBase],fontSize: [BrnCommonConfig.fontSizeBase],fontWeight: FontWeight.w600) - BrnTextStyle titleForMoreTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _titleForMoreTextStyle; /// 选项-显示文本 - /// TextStyle(color: [BrnCommonConfig.brandPrimary],fontSize: [BrnCommonConfig.fontSizeBase]) - BrnTextStyle optionTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeBase], + /// ) + BrnTextStyle? _optionTextStyle; /// 更多文本样式 - /// TextStyle(color: [BrnCommonConfig.colorTextSecondary],fontSize: [BrnCommonConfig.fontSizeCaption]) - BrnTextStyle moreTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextSecondary], + /// fontSize: [BrnCommonConfig.fontSizeCaption], + /// ) + BrnTextStyle? _moreTextStyle; /// 跳转二级页-正常文本样式 - /// TextStyle(color: [BrnCommonConfig.colorTextBase],fontSize: [BrnCommonConfig.fontSizeSubHead],fontWeight: FontWeight.normal) - BrnTextStyle flayNormalTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// fontWeight: FontWeight.normal, + /// ) + BrnTextStyle? _flayerNormalTextStyle; /// 跳转二级页-选中文本样式 - /// TextStyle(color: [BrnCommonConfig.brandPrimary],fontSize: [BrnCommonConfig.fontSizeSubHead],fontWeight: FontWeight.w600) - BrnTextStyle flatSelectedTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _flayerSelectedTextStyle; /// 跳转二级页-加粗文本样式 - /// TextStyle(color: [BrnCommonConfig.colorTextBase],fontSize: [BrnCommonConfig.fontSizeSubHead],fontWeight: FontWeight.w600) - BrnTextStyle flatBoldTextStyle; - - BrnSelectionConfig( - {this.menuNormalTextStyle, - this.menuSelectedTextStyle, - this.tagNormalTextStyle, - this.tagSelectedTextStyle, - this.tagRadius, - this.tagNormalBackgroundColor, - this.tagSelectedBackgroundColor, - this.hintTextStyle, - this.rangeTitleTextStyle, - this.inputTextStyle, - this.itemNormalTextStyle, - this.itemSelectedTextStyle, - this.itemBoldTextStyle, - this.deepNormalBgColor, - this.deepSelectBgColor, - this.middleNormalBgColor, - this.middleSelectBgColor, - this.lightNormalBgColor, - this.lightSelectBgColor, - this.resetTextStyle, - this.titleForMoreTextStyle, - this.optionTextStyle, - this.moreTextStyle, - this.flayNormalTextStyle, - this.flatSelectedTextStyle, - this.flatBoldTextStyle, - String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID}) - : super(configId: configId); + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// fontWeight: FontWeight.w600 + /// ) + BrnTextStyle? _flayerBoldTextStyle; + + BrnTextStyle get menuNormalTextStyle => + _menuNormalTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.menuNormalTextStyle; + + BrnTextStyle get menuSelectedTextStyle => + _menuSelectedTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.menuSelectedTextStyle; + + BrnTextStyle get tagNormalTextStyle => + _tagNormalTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.tagNormalTextStyle; + + BrnTextStyle get tagSelectedTextStyle => + _tagSelectedTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.tagSelectedTextStyle; + + double get tagRadius => + _tagRadius ?? BrnDefaultConfigUtils.defaultSelectionConfig.tagRadius; + + Color get tagNormalBackgroundColor => + _tagNormalBackgroundColor ?? + BrnDefaultConfigUtils.defaultSelectionConfig.tagNormalBackgroundColor; + + Color get tagSelectedBackgroundColor => + _tagSelectedBackgroundColor ?? + BrnDefaultConfigUtils.defaultSelectionConfig.tagSelectedBackgroundColor; + + BrnTextStyle get rangeTitleTextStyle => + _rangeTitleTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.rangeTitleTextStyle; + + BrnTextStyle get hintTextStyle => + _hintTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.hintTextStyle; + + BrnTextStyle get inputTextStyle => + _inputTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.inputTextStyle; + + BrnTextStyle get itemNormalTextStyle => + _itemNormalTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.itemNormalTextStyle; + + BrnTextStyle get itemSelectedTextStyle => + _itemSelectedTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.itemSelectedTextStyle; + + BrnTextStyle get itemBoldTextStyle => + _itemBoldTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.itemBoldTextStyle; + + Color get deepNormalBgColor => + _deepNormalBgColor ?? + BrnDefaultConfigUtils.defaultSelectionConfig.deepNormalBgColor; + + Color get deepSelectBgColor => + _deepSelectBgColor ?? + BrnDefaultConfigUtils.defaultSelectionConfig.deepSelectBgColor; + + Color get middleNormalBgColor => + _middleNormalBgColor ?? + BrnDefaultConfigUtils.defaultSelectionConfig.middleNormalBgColor; + + Color get middleSelectBgColor => + _middleSelectBgColor ?? + BrnDefaultConfigUtils.defaultSelectionConfig.middleSelectBgColor; + + Color get lightNormalBgColor => + _lightNormalBgColor ?? + BrnDefaultConfigUtils.defaultSelectionConfig.lightNormalBgColor; + + Color get lightSelectBgColor => + _lightSelectBgColor ?? + BrnDefaultConfigUtils.defaultSelectionConfig.lightSelectBgColor; + + BrnTextStyle get resetTextStyle => + _resetTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.resetTextStyle; + + BrnTextStyle get titleForMoreTextStyle => + _titleForMoreTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.titleForMoreTextStyle; + + BrnTextStyle get optionTextStyle => + _optionTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.optionTextStyle; + + BrnTextStyle get moreTextStyle => + _moreTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.moreTextStyle; + + BrnTextStyle get flayerNormalTextStyle => + _flayerNormalTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.flayerNormalTextStyle; + + BrnTextStyle get flayerSelectedTextStyle => + _flayerSelectedTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.flayerSelectedTextStyle; + + BrnTextStyle get flayerBoldTextStyle => + _flayerBoldTextStyle ?? + BrnDefaultConfigUtils.defaultSelectionConfig.flayerBoldTextStyle; @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); /// 用户全局筛选配置 BrnSelectionConfig selectionConfig = BrnThemeConfigurator.instance .getConfig(configId: configId) .selectionConfig; - lightSelectBgColor ??= selectionConfig.lightSelectBgColor; - - lightNormalBgColor ??= selectionConfig.lightNormalBgColor; - - middleSelectBgColor ??= selectionConfig.middleSelectBgColor; - - middleNormalBgColor ??= selectionConfig.middleNormalBgColor; - - deepSelectBgColor ??= selectionConfig.deepSelectBgColor; - - deepNormalBgColor ??= selectionConfig.deepNormalBgColor; - - tagSelectedBackgroundColor ??= commonConfig.brandPrimary.withOpacity(0.12); - - tagNormalBackgroundColor ??= commonConfig.fillBody; - - tagRadius ??= commonConfig.radiusSm; - - this.flatBoldTextStyle = selectionConfig.flatBoldTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.flatBoldTextStyle)); - - this.flatSelectedTextStyle = selectionConfig.flatSelectedTextStyle.merge( - BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.flatSelectedTextStyle)); - - this.flayNormalTextStyle = selectionConfig.flayNormalTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.flayNormalTextStyle)); - - this.moreTextStyle = selectionConfig.moreTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextSecondary, - fontSize: commonConfig.fontSizeCaption) - .merge(this.moreTextStyle)); - - this.optionTextStyle = selectionConfig.optionTextStyle.merge(BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeBase) - .merge(this.optionTextStyle)); - - this.titleForMoreTextStyle = selectionConfig.titleForMoreTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeBase) - .merge(this.titleForMoreTextStyle)); - - this.resetTextStyle = selectionConfig.resetTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextImportant, - fontSize: commonConfig.fontSizeCaption) - .merge(this.resetTextStyle)); - - this.itemBoldTextStyle = selectionConfig.itemBoldTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeBase) - .merge(this.itemBoldTextStyle)); - - this.itemSelectedTextStyle = selectionConfig.itemSelectedTextStyle.merge( - BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeBase) - .merge(this.itemSelectedTextStyle)); - - this.itemNormalTextStyle = selectionConfig.itemNormalTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeBase) - .merge(this.itemNormalTextStyle)); - - this.inputTextStyle = selectionConfig.inputTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeBase) - .merge(this.inputTextStyle)); - - this.hintTextStyle = selectionConfig.hintTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextHint, - fontSize: commonConfig.fontSizeBase) - .merge(this.hintTextStyle)); - - this.rangeTitleTextStyle = selectionConfig.rangeTitleTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.rangeTitleTextStyle)); - - this.tagSelectedTextStyle = selectionConfig.tagSelectedTextStyle.merge( - BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeCaption) - .merge(this.tagSelectedTextStyle)); - - this.tagNormalTextStyle = selectionConfig.tagNormalTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeCaption) - .merge(this.tagNormalTextStyle)); - - this.menuNormalTextStyle = selectionConfig.menuNormalTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeBase) - .merge(this.menuNormalTextStyle)); - - this.menuSelectedTextStyle = selectionConfig.menuSelectedTextStyle.merge( - BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeBase) - .merge(this.menuSelectedTextStyle)); + _lightSelectBgColor ??= selectionConfig._lightSelectBgColor; + _lightNormalBgColor ??= selectionConfig._lightNormalBgColor; + _middleSelectBgColor ??= selectionConfig._middleSelectBgColor; + _middleNormalBgColor ??= selectionConfig._middleNormalBgColor; + _deepSelectBgColor ??= selectionConfig._deepSelectBgColor; + _deepNormalBgColor ??= selectionConfig._deepNormalBgColor; + _tagSelectedBackgroundColor ??= + commonConfig.brandPrimary.withOpacity(0.12); + _tagNormalBackgroundColor ??= commonConfig.fillBody; + _tagRadius ??= commonConfig.radiusSm; + _flayerBoldTextStyle = selectionConfig.flayerBoldTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_flayerBoldTextStyle), + ); + _flayerSelectedTextStyle = selectionConfig.flayerSelectedTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_flayerSelectedTextStyle), + ); + _flayerNormalTextStyle = selectionConfig.flayerNormalTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_flayerNormalTextStyle), + ); + _moreTextStyle = selectionConfig.moreTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextSecondary, + fontSize: commonConfig.fontSizeCaption, + ).merge(_moreTextStyle), + ); + _optionTextStyle = selectionConfig.optionTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeBase, + ).merge(_optionTextStyle), + ); + _titleForMoreTextStyle = selectionConfig.titleForMoreTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase, + ).merge(_titleForMoreTextStyle), + ); + _resetTextStyle = selectionConfig.resetTextStyle.merge(BrnTextStyle( + color: commonConfig.colorTextImportant, + fontSize: commonConfig.fontSizeCaption, + ).merge(_resetTextStyle)); + _itemBoldTextStyle = selectionConfig.itemBoldTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase, + ).merge(_itemBoldTextStyle), + ); + _itemSelectedTextStyle = selectionConfig.itemSelectedTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeBase, + ).merge(_itemSelectedTextStyle), + ); + _itemNormalTextStyle = selectionConfig.itemNormalTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase, + ).merge(_itemNormalTextStyle), + ); + _inputTextStyle = selectionConfig.inputTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase, + ).merge(_inputTextStyle), + ); + _hintTextStyle = selectionConfig.hintTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextHint, + fontSize: commonConfig.fontSizeBase, + ).merge(_hintTextStyle), + ); + _rangeTitleTextStyle = selectionConfig.rangeTitleTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_rangeTitleTextStyle), + ); + _tagSelectedTextStyle = selectionConfig.tagSelectedTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeCaption, + ).merge(_tagSelectedTextStyle), + ); + _tagNormalTextStyle = selectionConfig.tagNormalTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeCaption, + ).merge(_tagNormalTextStyle), + ); + _menuNormalTextStyle = selectionConfig.menuNormalTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeBase, + ).merge(_menuNormalTextStyle), + ); + _menuSelectedTextStyle = selectionConfig.menuSelectedTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeBase, + ).merge(_menuSelectedTextStyle), + ); } BrnSelectionConfig copyWith({ - BrnTextStyle menuNormalTextStyle, - BrnTextStyle menuSelectedTextStyle, - BrnTextStyle tagTextStyle, - BrnTextStyle tagSelectedTextStyle, - double tagRadius, - Color tagBackgroundColor, - Color tagSelectedBackgroundColor, - BrnTextStyle hintTextStyle, - BrnTextStyle rangeTitleTextStyle, - BrnTextStyle inputTextStyle, - BrnTextStyle itemNormalTextStyle, - BrnTextStyle itemSelectedTextStyle, - BrnTextStyle itemBoldTextStyle, - Color deepNormalBgColor, - Color deepSelectBgColor, - Color middleNormalBgColor, - Color middleSelectBgColor, - Color lightNormalBgColor, - Color lightSelectBgColor, - BrnTextStyle resetTextStyle, - BrnTextStyle titleForMoreTextStyle, - BrnTextStyle optionTextStyle, - BrnTextStyle moreTextStyle, - BrnTextStyle flayNormalTextStyle, - BrnTextStyle flatSelectedTextStyle, - BrnTextStyle flatBoldTextStyle, + BrnTextStyle? menuNormalTextStyle, + BrnTextStyle? menuSelectedTextStyle, + BrnTextStyle? tagTextStyle, + BrnTextStyle? tagSelectedTextStyle, + double? tagRadius, + Color? tagBackgroundColor, + Color? tagSelectedBackgroundColor, + BrnTextStyle? hintTextStyle, + BrnTextStyle? rangeTitleTextStyle, + BrnTextStyle? inputTextStyle, + BrnTextStyle? itemNormalTextStyle, + BrnTextStyle? itemSelectedTextStyle, + BrnTextStyle? itemBoldTextStyle, + Color? deepNormalBgColor, + Color? deepSelectBgColor, + Color? middleNormalBgColor, + Color? middleSelectBgColor, + Color? lightNormalBgColor, + Color? lightSelectBgColor, + BrnTextStyle? resetTextStyle, + BrnTextStyle? titleForMoreTextStyle, + BrnTextStyle? optionTextStyle, + BrnTextStyle? moreTextStyle, + BrnTextStyle? flayerNormalTextStyle, + BrnTextStyle? flayerSelectedTextStyle, + BrnTextStyle? flayerBoldTextStyle, }) { return BrnSelectionConfig( - menuNormalTextStyle: menuNormalTextStyle ?? this.menuNormalTextStyle, - menuSelectedTextStyle: - menuSelectedTextStyle ?? this.menuSelectedTextStyle, - tagNormalTextStyle: tagTextStyle ?? this.tagNormalTextStyle, - tagSelectedTextStyle: tagSelectedTextStyle ?? this.tagSelectedTextStyle, - tagRadius: tagRadius ?? this.tagRadius, - tagNormalBackgroundColor: - tagBackgroundColor ?? this.tagNormalBackgroundColor, - tagSelectedBackgroundColor: - tagSelectedBackgroundColor ?? this.tagSelectedBackgroundColor, - hintTextStyle: hintTextStyle ?? this.hintTextStyle, - rangeTitleTextStyle: rangeTitleTextStyle ?? this.rangeTitleTextStyle, - inputTextStyle: inputTextStyle ?? this.inputTextStyle, - itemNormalTextStyle: itemNormalTextStyle ?? this.itemNormalTextStyle, - itemSelectedTextStyle: - itemSelectedTextStyle ?? this.itemSelectedTextStyle, - itemBoldTextStyle: itemBoldTextStyle ?? this.itemBoldTextStyle, - deepNormalBgColor: deepNormalBgColor ?? this.deepNormalBgColor, - deepSelectBgColor: deepSelectBgColor ?? this.deepSelectBgColor, - middleNormalBgColor: middleNormalBgColor ?? this.middleNormalBgColor, - middleSelectBgColor: middleSelectBgColor ?? this.middleSelectBgColor, - lightNormalBgColor: lightNormalBgColor ?? this.lightNormalBgColor, - lightSelectBgColor: lightSelectBgColor ?? this.lightSelectBgColor, - resetTextStyle: resetTextStyle ?? this.resetTextStyle, - titleForMoreTextStyle: - titleForMoreTextStyle ?? this.titleForMoreTextStyle, - optionTextStyle: optionTextStyle ?? this.optionTextStyle, - moreTextStyle: moreTextStyle ?? this.moreTextStyle, - flayNormalTextStyle: flayNormalTextStyle ?? this.flayNormalTextStyle, - flatSelectedTextStyle: - flatSelectedTextStyle ?? this.flatSelectedTextStyle, - flatBoldTextStyle: flatBoldTextStyle ?? this.flatBoldTextStyle); + menuNormalTextStyle: menuNormalTextStyle ?? _menuNormalTextStyle, + menuSelectedTextStyle: menuSelectedTextStyle ?? _menuSelectedTextStyle, + tagNormalTextStyle: tagTextStyle ?? _tagNormalTextStyle, + tagSelectedTextStyle: tagSelectedTextStyle ?? _tagSelectedTextStyle, + tagRadius: tagRadius ?? _tagRadius, + tagNormalBackgroundColor: tagBackgroundColor ?? _tagNormalBackgroundColor, + tagSelectedBackgroundColor: + tagSelectedBackgroundColor ?? _tagSelectedBackgroundColor, + hintTextStyle: hintTextStyle ?? _hintTextStyle, + rangeTitleTextStyle: rangeTitleTextStyle ?? _rangeTitleTextStyle, + inputTextStyle: inputTextStyle ?? _inputTextStyle, + itemNormalTextStyle: itemNormalTextStyle ?? _itemNormalTextStyle, + itemSelectedTextStyle: itemSelectedTextStyle ?? _itemSelectedTextStyle, + itemBoldTextStyle: itemBoldTextStyle ?? _itemBoldTextStyle, + deepNormalBgColor: deepNormalBgColor ?? _deepNormalBgColor, + deepSelectBgColor: deepSelectBgColor ?? _deepSelectBgColor, + middleNormalBgColor: middleNormalBgColor ?? _middleNormalBgColor, + middleSelectBgColor: middleSelectBgColor ?? _middleSelectBgColor, + lightNormalBgColor: lightNormalBgColor ?? _lightNormalBgColor, + lightSelectBgColor: lightSelectBgColor ?? _lightSelectBgColor, + resetTextStyle: resetTextStyle ?? _resetTextStyle, + titleForMoreTextStyle: titleForMoreTextStyle ?? _titleForMoreTextStyle, + optionTextStyle: optionTextStyle ?? _optionTextStyle, + moreTextStyle: moreTextStyle ?? _moreTextStyle, + flayerNormalTextStyle: flayerNormalTextStyle ?? _flayerNormalTextStyle, + flayerSelectedTextStyle: + flayerSelectedTextStyle ?? _flayerSelectedTextStyle, + flayerBoldTextStyle: flayerBoldTextStyle ?? _flayerBoldTextStyle, + ); } BrnSelectionConfig merge(BrnSelectionConfig other) { return copyWith( - menuNormalTextStyle: this.menuNormalTextStyle?.merge(other.menuNormalTextStyle) ?? - other.menuNormalTextStyle, - menuSelectedTextStyle: - this.menuSelectedTextStyle?.merge(other.menuSelectedTextStyle) ?? - other.menuSelectedTextStyle, - tagTextStyle: this.tagNormalTextStyle?.merge(other.tagNormalTextStyle) ?? - other.tagNormalTextStyle, - tagSelectedTextStyle: - this.tagSelectedTextStyle?.merge(other.tagSelectedTextStyle) ?? - other.tagSelectedTextStyle, - tagRadius: other.tagRadius, - tagBackgroundColor: other.tagNormalBackgroundColor, - tagSelectedBackgroundColor: other.tagSelectedBackgroundColor, - hintTextStyle: this.hintTextStyle?.merge(other.hintTextStyle) ?? - other.hintTextStyle, - rangeTitleTextStyle: this.rangeTitleTextStyle?.merge(other.rangeTitleTextStyle) ?? - other.rangeTitleTextStyle, - inputTextStyle: this.inputTextStyle?.merge(other.inputTextStyle) ?? - other.inputTextStyle, - itemNormalTextStyle: - this.itemNormalTextStyle?.merge(other.itemNormalTextStyle) ?? - other.itemNormalTextStyle, - itemSelectedTextStyle: - this.itemSelectedTextStyle?.merge(other.itemSelectedTextStyle) ?? - other.itemSelectedTextStyle, - itemBoldTextStyle: this.itemBoldTextStyle?.merge(other.itemBoldTextStyle) ?? - other.itemBoldTextStyle, - deepNormalBgColor: other.deepNormalBgColor, - deepSelectBgColor: other.deepSelectBgColor, - middleNormalBgColor: other.middleNormalBgColor, - middleSelectBgColor: other.middleSelectBgColor, - lightNormalBgColor: other.lightNormalBgColor, - lightSelectBgColor: other.lightSelectBgColor, - resetTextStyle: this.resetTextStyle?.merge(other.resetTextStyle) ?? other.resetTextStyle, - titleForMoreTextStyle: this.titleForMoreTextStyle?.merge(other.titleForMoreTextStyle) ?? other.titleForMoreTextStyle, - optionTextStyle: this.optionTextStyle?.merge(other.optionTextStyle) ?? other.optionTextStyle, - moreTextStyle: this.moreTextStyle?.merge(other.moreTextStyle) ?? other.moreTextStyle, - flayNormalTextStyle: this.flayNormalTextStyle?.merge(other.flayNormalTextStyle) ?? other.flayNormalTextStyle, - flatSelectedTextStyle: this.flatSelectedTextStyle?.merge(other.flatSelectedTextStyle) ?? other.flatSelectedTextStyle, - flatBoldTextStyle: this.flatBoldTextStyle?.merge(other.flatBoldTextStyle) ?? other.flatBoldTextStyle); + menuNormalTextStyle: menuNormalTextStyle.merge(other._menuNormalTextStyle), + menuSelectedTextStyle: + menuSelectedTextStyle.merge(other._menuSelectedTextStyle), + tagTextStyle: tagNormalTextStyle.merge(other._tagNormalTextStyle), + tagSelectedTextStyle: + tagSelectedTextStyle.merge(other._tagSelectedTextStyle), + tagRadius: other._tagRadius, + tagBackgroundColor: other._tagNormalBackgroundColor, + tagSelectedBackgroundColor: other._tagSelectedBackgroundColor, + hintTextStyle: hintTextStyle.merge(other._hintTextStyle), + rangeTitleTextStyle: rangeTitleTextStyle.merge(other._rangeTitleTextStyle), + inputTextStyle: inputTextStyle.merge(other._inputTextStyle), + itemNormalTextStyle: itemNormalTextStyle.merge(other._itemNormalTextStyle), + itemSelectedTextStyle: + itemSelectedTextStyle.merge(other._itemSelectedTextStyle), + itemBoldTextStyle: itemBoldTextStyle.merge(other._itemBoldTextStyle), + deepNormalBgColor: other._deepNormalBgColor, + deepSelectBgColor: other._deepSelectBgColor, + middleNormalBgColor: other._middleNormalBgColor, + middleSelectBgColor: other._middleSelectBgColor, + lightNormalBgColor: other._lightNormalBgColor, + lightSelectBgColor: other._lightSelectBgColor, + resetTextStyle: resetTextStyle.merge(other._resetTextStyle), + titleForMoreTextStyle: + titleForMoreTextStyle.merge(other._titleForMoreTextStyle), + optionTextStyle: optionTextStyle.merge(other._optionTextStyle), + moreTextStyle: moreTextStyle.merge(other._moreTextStyle), + flayerNormalTextStyle: + flayerNormalTextStyle.merge(other._flayerNormalTextStyle), + flayerSelectedTextStyle: + flayerSelectedTextStyle.merge(other._flayerSelectedTextStyle), + flayerBoldTextStyle: flayerBoldTextStyle.merge(other._flayerBoldTextStyle), + ); } } diff --git a/lib/src/theme/configs/brn_tabbar_config.dart b/lib/src/theme/configs/brn_tabbar_config.dart index 6c5145cc..457ae2c8 100644 --- a/lib/src/theme/configs/brn_tabbar_config.dart +++ b/lib/src/theme/configs/brn_tabbar_config.dart @@ -1,189 +1,272 @@ -import 'dart:ui'; - -import 'package:bruno/src/theme/brn_theme.dart'; +import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; +import 'package:bruno/src/theme/base/brn_text_style.dart'; +import 'package:bruno/src/theme/brn_theme_configurator.dart'; +import 'package:bruno/src/theme/configs/brn_common_config.dart'; import 'package:flutter/material.dart'; /// TabBar配置类 class BrnTabBarConfig extends BrnBaseConfig { - ///遵循外部主题配置,Bruno默认配置[BrnDefaultConfigUtils.defaultNumberInfoConfig] + /// 遵循外部主题配置 + /// 默认为 [BrnDefaultConfigUtils.tabBarConfig] BrnTabBarConfig({ - this.tabHeight, - this.indicatorHeight, - this.indicatorWidth, - this.labelStyle, - this.unselectedLabelStyle, - this.backgroundColor, - this.tagNormalTextStyle, - this.tagNormalBgColor, - this.tagSelectedTextStyle, - this.tagSelectedBgColor, - this.tagRadius, - this.tagSpacing, - this.preLineTagCount, - this.tagHeight, - String configId: BrnThemeConfigurator.GLOBAL_CONFIG_ID, - }) : super(configId: configId); - - /// Tabbar的整体高度 - /// default value is 50 - double tabHeight; + double? tabHeight, + double? indicatorHeight, + double? indicatorWidth, + BrnTextStyle? labelStyle, + BrnTextStyle? unselectedLabelStyle, + Color? backgroundColor, + BrnTextStyle? tagNormalTextStyle, + Color? tagNormalBgColor, + BrnTextStyle? tagSelectedTextStyle, + Color? tagSelectedBgColor, + double? tagRadius, + double? tagSpacing, + int? preLineTagCount, + double? tagHeight, + String configId: GLOBAL_CONFIG_ID, + }) : _tabHeight = tabHeight, + _indicatorHeight = indicatorHeight, + _indicatorWidth = indicatorWidth, + _labelStyle = labelStyle, + _unselectedLabelStyle = unselectedLabelStyle, + _backgroundColor = backgroundColor, + _tagNormalTextStyle = tagNormalTextStyle, + _tagNormalBgColor = tagNormalBgColor, + _tagSelectedTextStyle = tagSelectedTextStyle, + _tagSelectedBgColor = tagSelectedBgColor, + _tagRadius = tagRadius, + _tagSpacing = tagSpacing, + _preLineTagCount = preLineTagCount, + _tagHeight = tagHeight, + super(configId: configId); + + /// TabBar 的整体高度 + /// 默认为 50 + double? _tabHeight; /// 指示器的高度 - /// default value is 2 - double indicatorHeight; + /// 默认为 2 + double? _indicatorHeight; /// 指示器的宽度 - /// default value is 24 - double indicatorWidth; + /// 默认为 24 + double? _indicatorWidth; - /// 选中Tab文本的样式 - /// default value is TextStyle(color:[BrnCommonConfig.brandPrimary],fontSize:[BrnCommonConfig.fontSizeSubHead]) - BrnTextStyle labelStyle; + /// 选中 Tab 文本的样式 + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// ) + BrnTextStyle? _labelStyle; - /// 未选中Tab文本的样式 - /// default value is TextStyle(color:[BrnCommonConfig.colorTextBase],fontSize:[BrnCommonConfig.fontSizeSubHead]) - BrnTextStyle unselectedLabelStyle; + /// 未选中 Tab 文本的样式 + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeSubHead], + /// ) + BrnTextStyle? _unselectedLabelStyle; /// 背景色 - /// default value is [BrnCommonConfig.fillBase] - Color backgroundColor; + /// 默认为 [BrnCommonConfig.fillBase] + Color? _backgroundColor; /// 标签字体样式 - /// default value is BrnTextStyle(color: [BrnCommonConfig.colorTextBase], fontSize: [BrnCommonConfig.fontSizeCaption]) - BrnTextStyle tagNormalTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeCaption], + /// ) + BrnTextStyle? _tagNormalTextStyle; /// 标签背景色 - /// default value is [BrnCommonConfig.brandPrimary].withAlpha(0x14), - Color tagNormalBgColor; + /// 默认为 [BrnCommonConfig.brandPrimary].withAlpha(0x14), + Color? _tagNormalBgColor; /// 标签字体样式 - /// default value is BrnTextStyle(color:[BrnCommonConfig.brandPrimary], fontSize: [BrnCommonConfig.fontSizeCaption]) - BrnTextStyle tagSelectedTextStyle; + /// + /// BrnTextStyle( + /// color:[BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeCaption], + /// ) + BrnTextStyle? _tagSelectedTextStyle; /// 标签选中背景色 - /// default value is [BrnCommonConfig.fillBody] - Color tagSelectedBgColor; + /// 默认为 [BrnCommonConfig.fillBody] + Color? _tagSelectedBgColor; /// tag圆角 - /// default value is [BrnCommonConfig.radiusSm] - double tagRadius; + /// 默认为 [BrnCommonConfig.radiusSm] + double? _tagRadius; /// tag间距 - /// default value is 12 - double tagSpacing; + /// 默认为 12 + double? _tagSpacing; /// 每行的tag数 - /// default value is 4 - int preLineTagCount; + /// 默认为 4 + int? _preLineTagCount; /// tag高度 - /// default value is 32 - double tagHeight; + /// 默认为 32 + double? _tagHeight; + + double get tabHeight => + _tabHeight ?? BrnDefaultConfigUtils.defaultTabBarConfig.tabHeight; + + double get indicatorHeight => + _indicatorHeight ?? + BrnDefaultConfigUtils.defaultTabBarConfig.indicatorHeight; + + double get indicatorWidth => + _indicatorWidth ?? + BrnDefaultConfigUtils.defaultTabBarConfig.indicatorWidth; + + BrnTextStyle get labelStyle => + _labelStyle ?? BrnDefaultConfigUtils.defaultTabBarConfig.labelStyle; + + BrnTextStyle get unselectedLabelStyle => + _unselectedLabelStyle ?? + BrnDefaultConfigUtils.defaultTabBarConfig.unselectedLabelStyle; + + Color get backgroundColor => + _backgroundColor ?? + BrnDefaultConfigUtils.defaultTabBarConfig.backgroundColor; + + BrnTextStyle get tagNormalTextStyle => + _tagNormalTextStyle ?? + BrnDefaultConfigUtils.defaultTabBarConfig.tagNormalTextStyle; + + Color get tagNormalBgColor => + _tagNormalBgColor ?? + BrnDefaultConfigUtils.defaultTabBarConfig.tagNormalBgColor; + + BrnTextStyle get tagSelectedTextStyle => + _tagSelectedTextStyle ?? + BrnDefaultConfigUtils.defaultTabBarConfig.tagSelectedTextStyle; + + Color get tagSelectedBgColor => + _tagSelectedBgColor ?? + BrnDefaultConfigUtils.defaultTabBarConfig.tagSelectedBgColor; + + double get tagRadius => + _tagRadius ?? BrnDefaultConfigUtils.defaultTabBarConfig.tagRadius; + + double get tagSpacing => + _tagSpacing ?? BrnDefaultConfigUtils.defaultTabBarConfig.tagSpacing; + + int get preLineTagCount => + _preLineTagCount ?? + BrnDefaultConfigUtils.defaultTabBarConfig.preLineTagCount; + + double get tagHeight => + _tagHeight ?? BrnDefaultConfigUtils.defaultTabBarConfig.tagHeight; @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); BrnTabBarConfig tabBarConfig = BrnThemeConfigurator.instance .getConfig(configId: configId) .tabBarConfig; - this.tabHeight ??= tabBarConfig.tabHeight; - this.indicatorHeight ??= tabBarConfig.indicatorHeight; - this.indicatorWidth ??= tabBarConfig.indicatorWidth; - - this.labelStyle = tabBarConfig.labelStyle.merge(BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.labelStyle)); - - this.unselectedLabelStyle = tabBarConfig.unselectedLabelStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeSubHead) - .merge(this.unselectedLabelStyle)); - - this.backgroundColor ??= tabBarConfig.backgroundColor; - - this.tagNormalTextStyle = tabBarConfig.tagNormalTextStyle.merge( - BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeCaption) - .merge(this.tagNormalTextStyle)); - - this.tagSelectedTextStyle = tabBarConfig.tagSelectedTextStyle.merge( - BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeCaption) - .merge(this.tagSelectedTextStyle)); - - this.tagNormalBgColor ??= tabBarConfig.tagNormalBgColor; - this.tagSelectedBgColor ??= tabBarConfig.tagSelectedBgColor; - this.tagRadius ??= commonConfig.radiusSm; - this.tagSpacing ??= tabBarConfig.tagSpacing; - this.preLineTagCount ??= tabBarConfig.preLineTagCount; - this.tagHeight ??= tabBarConfig.tagHeight; + _tabHeight ??= tabBarConfig._tabHeight; + _indicatorHeight ??= tabBarConfig._indicatorHeight; + _indicatorWidth ??= tabBarConfig._indicatorWidth; + _labelStyle = tabBarConfig.labelStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_labelStyle), + ); + _unselectedLabelStyle = tabBarConfig.unselectedLabelStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeSubHead, + ).merge(_unselectedLabelStyle), + ); + _backgroundColor ??= tabBarConfig._backgroundColor; + _tagNormalTextStyle = tabBarConfig.tagNormalTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeCaption, + ).merge(_tagNormalTextStyle), + ); + _tagSelectedTextStyle = tabBarConfig.tagSelectedTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeCaption, + ).merge(_tagSelectedTextStyle), + ); + _tagNormalBgColor ??= tabBarConfig._tagNormalBgColor; + _tagSelectedBgColor ??= tabBarConfig._tagSelectedBgColor; + _tagRadius ??= commonConfig.radiusSm; + _tagSpacing ??= tabBarConfig._tagSpacing; + _preLineTagCount ??= tabBarConfig._preLineTagCount; + _tagHeight ??= tabBarConfig._tagHeight; } BrnTabBarConfig copyWith({ - double tabHeight, - double indicatorHeight, - double indicatorWidth, - BrnTextStyle labelStyle, - BrnTextStyle unselectedLabelStyle, - Color backgroundColor, - BrnTextStyle tagNormalTextStyle, - Color tagNormalColor, - BrnTextStyle tagSelectedTextStyle, - Color tagSelectedColor, - double tagRadius, - double tagSpacing, - int preLineTagSize, - double tagHeight, + double? tabHeight, + double? indicatorHeight, + double? indicatorWidth, + BrnTextStyle? labelStyle, + BrnTextStyle? unselectedLabelStyle, + Color? backgroundColor, + BrnTextStyle? tagNormalTextStyle, + Color? tagNormalColor, + BrnTextStyle? tagSelectedTextStyle, + Color? tagSelectedColor, + double? tagRadius, + double? tagSpacing, + int? preLineTagSize, + double? tagHeight, }) { return BrnTabBarConfig( - tabHeight: tabHeight ?? this.tabHeight, - indicatorHeight: indicatorHeight ?? this.indicatorHeight, - indicatorWidth: indicatorWidth ?? this.indicatorWidth, - labelStyle: labelStyle ?? this.labelStyle, - unselectedLabelStyle: unselectedLabelStyle ?? this.unselectedLabelStyle, - backgroundColor: backgroundColor ?? this.backgroundColor, - tagNormalTextStyle: tagNormalTextStyle ?? this.tagNormalTextStyle, - tagNormalBgColor: tagNormalColor ?? this.tagNormalBgColor, - tagSelectedTextStyle: tagSelectedTextStyle ?? this.tagSelectedTextStyle, - tagSelectedBgColor: tagSelectedColor ?? this.tagSelectedBgColor, - tagRadius: tagRadius ?? this.tagRadius, - tagSpacing: tagSpacing ?? this.tagSpacing, - preLineTagCount: preLineTagSize ?? this.preLineTagCount, - tagHeight: tagHeight ?? this.tagHeight, + tabHeight: tabHeight ?? _tabHeight, + indicatorHeight: indicatorHeight ?? _indicatorHeight, + indicatorWidth: indicatorWidth ?? _indicatorWidth, + labelStyle: labelStyle ?? _labelStyle, + unselectedLabelStyle: unselectedLabelStyle ?? _unselectedLabelStyle, + backgroundColor: backgroundColor ?? _backgroundColor, + tagNormalTextStyle: tagNormalTextStyle ?? _tagNormalTextStyle, + tagNormalBgColor: tagNormalColor ?? _tagNormalBgColor, + tagSelectedTextStyle: tagSelectedTextStyle ?? _tagSelectedTextStyle, + tagSelectedBgColor: tagSelectedColor ?? _tagSelectedBgColor, + tagRadius: tagRadius ?? _tagRadius, + tagSpacing: tagSpacing ?? _tagSpacing, + preLineTagCount: preLineTagSize ?? _preLineTagCount, + tagHeight: tagHeight ?? _tagHeight, ); } - BrnTabBarConfig merge(BrnTabBarConfig other) { + BrnTabBarConfig merge(BrnTabBarConfig? other) { if (other == null) return this; return copyWith( - tabHeight: other.tabHeight, - indicatorHeight: other.indicatorHeight, - indicatorWidth: other.indicatorWidth, - labelStyle: this.labelStyle?.merge(other.labelStyle) ?? other.labelStyle, + tabHeight: other._tabHeight, + indicatorHeight: other._indicatorHeight, + indicatorWidth: other._indicatorWidth, + labelStyle: labelStyle.merge(other._labelStyle), unselectedLabelStyle: - this.unselectedLabelStyle?.merge(other.unselectedLabelStyle) ?? - other.unselectedLabelStyle, - backgroundColor: other.backgroundColor, - tagNormalTextStyle: - this.tagNormalTextStyle?.merge(other.tagNormalTextStyle) ?? - other.tagNormalTextStyle, - tagNormalColor: other.tagNormalBgColor, + unselectedLabelStyle.merge(other._unselectedLabelStyle), + backgroundColor: other._backgroundColor, + tagNormalTextStyle: tagNormalTextStyle.merge(other._tagNormalTextStyle), + tagNormalColor: other._tagNormalBgColor, tagSelectedTextStyle: - this.tagSelectedTextStyle?.merge(other.tagSelectedTextStyle) ?? - other.tagSelectedTextStyle, - tagSelectedColor: other.tagSelectedBgColor, - tagRadius: other.tagRadius, - tagSpacing: other.tagSpacing, - preLineTagSize: other.preLineTagCount, - tagHeight: other.tagHeight, + tagSelectedTextStyle.merge(other._tagSelectedTextStyle), + tagSelectedColor: other._tagSelectedBgColor, + tagRadius: other._tagRadius, + tagSpacing: other._tagSpacing, + preLineTagSize: other._preLineTagCount, + tagHeight: other._tagHeight, ); } } diff --git a/lib/src/theme/configs/brn_tag_config.dart b/lib/src/theme/configs/brn_tag_config.dart index ceda9a6c..6af4dae1 100644 --- a/lib/src/theme/configs/brn_tag_config.dart +++ b/lib/src/theme/configs/brn_tag_config.dart @@ -1,121 +1,168 @@ -import 'dart:ui'; - import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; import 'package:bruno/src/theme/base/brn_text_style.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_common_config.dart'; +import 'package:flutter/painting.dart'; /// 标签配置类 class BrnTagConfig extends BrnBaseConfig { - /// tag文本样式 - /// default TextStyle(fontSize: [BrnCommonConfig.fontSizeCaption],color: [BrnCommonConfig.colorTextBase]) - BrnTextStyle tagTextStyle; + BrnTagConfig({ + BrnTextStyle? tagTextStyle, + BrnTextStyle? selectTagTextStyle, + double? tagRadius, + Color? tagBackgroundColor, + Color? selectedTagBackgroundColor, + double? tagHeight, + double? tagWidth, + double? tagMinWidth, + String configId = GLOBAL_CONFIG_ID, + }) : _tagTextStyle = tagTextStyle, + _selectTagTextStyle = selectTagTextStyle, + _tagRadius = tagRadius, + _tagBackgroundColor = tagBackgroundColor, + _selectedTagBackgroundColor = selectedTagBackgroundColor, + _tagHeight = tagHeight, + _tagWidth = tagWidth, + _tagMinWidth = tagMinWidth, + super(configId: configId); + + /// tag 文本样式 + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.colorTextBase], + /// fontSize: [BrnCommonConfig.fontSizeCaption], + /// ) + BrnTextStyle? _tagTextStyle; /// tag选中文本样式 - /// default TextStyle(fontWeight: FontWeight.w600,fontSize: [BrnCommonConfig.fontSizeCaption],color: [BrnCommonConfig.brandPrimary]) - BrnTextStyle selectTagTextStyle; + /// + /// BrnTextStyle( + /// color: [BrnCommonConfig.brandPrimary], + /// fontSize: [BrnCommonConfig.fontSizeCaption], + /// fontWeight: FontWeight.w600, + /// ) + BrnTextStyle? _selectTagTextStyle; /// 标签背景色 /// default [BrnCommonConfig.fillBody] - Color tagBackgroundColor; + Color? _tagBackgroundColor; /// 选中背景色 /// default [BrnCommonConfig.brandPrimary] - Color selectedTagBackgroundColor; + Color? _selectedTagBackgroundColor; /// 标签圆角 - /// default value is [BrnCommonConfig.radiusXs] - double tagRadius; + /// 默认为 [BrnCommonConfig.radiusXs] + double? _tagRadius; /// 标签高度,跟 fixWidthMode 无关 - /// default value is 34 - double tagHeight; + /// 默认为 34 + double? _tagHeight; /// 标签宽度,且仅在组件设置了固定宽度(fixWidthMode 为 true)时才生效 - /// default value is 75 - double tagWidth; + /// 默认为 75 + double? _tagWidth; /// 标签最小宽度 - /// default value is 75 - double tagMinWidth; - - BrnTagConfig( - {this.tagTextStyle, - this.selectTagTextStyle, - this.tagRadius, - this.tagBackgroundColor, - this.selectedTagBackgroundColor, - this.tagHeight, - this.tagWidth, - this.tagMinWidth, - String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID}) - : super(configId: configId); + /// 默认为 75 + double? _tagMinWidth; - @override - void initThemeConfig(String configId, - {BrnCommonConfig currentLevelCommonConfig}) { - super.initThemeConfig(configId, - currentLevelCommonConfig: currentLevelCommonConfig); + BrnTextStyle get tagTextStyle => + _tagTextStyle ?? BrnDefaultConfigUtils.defaultTagConfig.tagTextStyle; - /// 用户全局组件配置 - BrnTagConfig tagConfig = - BrnThemeConfigurator.instance.getConfig(configId: configId).tagConfig; + BrnTextStyle get selectTagTextStyle => + _selectTagTextStyle ?? + BrnDefaultConfigUtils.defaultTagConfig.selectTagTextStyle; + + Color get tagBackgroundColor => + _tagBackgroundColor ?? + BrnDefaultConfigUtils.defaultTagConfig.tagBackgroundColor; - this.tagHeight ??= tagConfig.tagHeight; + Color get selectedTagBackgroundColor => + _selectedTagBackgroundColor ?? + BrnDefaultConfigUtils.defaultTagConfig.selectedTagBackgroundColor; - this.tagWidth ??= tagConfig.tagWidth; - this.tagMinWidth ??= tagConfig.tagMinWidth; + double get tagRadius => + _tagRadius ?? BrnDefaultConfigUtils.defaultTagConfig.tagRadius; - this.tagRadius ??= commonConfig.radiusXs; + double get tagHeight => + _tagHeight ?? BrnDefaultConfigUtils.defaultTagConfig.tagHeight; - this.tagBackgroundColor ??= commonConfig.fillBody; + double get tagWidth => + _tagWidth ?? BrnDefaultConfigUtils.defaultTagConfig.tagWidth; - this.selectedTagBackgroundColor ??= commonConfig.brandPrimary; + double get tagMinWidth => + _tagMinWidth ?? BrnDefaultConfigUtils.defaultTagConfig.tagMinWidth; - this.tagTextStyle = tagConfig.tagTextStyle.merge(BrnTextStyle( - color: commonConfig.colorTextBase, - fontSize: commonConfig.fontSizeCaption) - .merge(this.tagTextStyle)); + @override + void initThemeConfig( + String configId, { + BrnCommonConfig? currentLevelCommonConfig, + }) { + super.initThemeConfig( + configId, + currentLevelCommonConfig: currentLevelCommonConfig, + ); + + /// 用户全局组件配置 + BrnTagConfig tagConfig = + BrnThemeConfigurator.instance.getConfig(configId: configId).tagConfig; - this.selectTagTextStyle = tagConfig.selectTagTextStyle.merge(BrnTextStyle( - color: commonConfig.brandPrimary, - fontSize: commonConfig.fontSizeCaption) - .merge(this.selectTagTextStyle)); + _tagHeight ??= tagConfig._tagHeight; + _tagWidth ??= tagConfig._tagWidth; + _tagMinWidth ??= tagConfig._tagMinWidth; + _tagRadius ??= commonConfig.radiusXs; + _tagBackgroundColor ??= commonConfig.fillBody; + _selectedTagBackgroundColor ??= commonConfig.brandPrimary; + _tagTextStyle = tagConfig.tagTextStyle.merge( + BrnTextStyle( + color: commonConfig.colorTextBase, + fontSize: commonConfig.fontSizeCaption, + ).merge(_tagTextStyle), + ); + _selectTagTextStyle = tagConfig.selectTagTextStyle.merge( + BrnTextStyle( + color: commonConfig.brandPrimary, + fontSize: commonConfig.fontSizeCaption, + ).merge(_selectTagTextStyle), + ); } - BrnTagConfig copyWith( - {BrnTextStyle textStyle, - BrnTextStyle selectTextStyle, - double radius, - Color backgroundColor, - Color selectedBackgroundColor, - double height, - double width, - double tagMinWidth}) { + BrnTagConfig copyWith({ + BrnTextStyle? textStyle, + BrnTextStyle? selectTextStyle, + double? radius, + Color? backgroundColor, + Color? selectedBackgroundColor, + double? height, + double? width, + double? tagMinWidth, + }) { return BrnTagConfig( - tagTextStyle: textStyle ?? this.tagTextStyle, - selectTagTextStyle: selectTextStyle ?? this.selectTagTextStyle, - tagRadius: radius ?? this.tagRadius, - tagBackgroundColor: backgroundColor ?? this.tagBackgroundColor, - selectedTagBackgroundColor: - selectedBackgroundColor ?? this.selectedTagBackgroundColor, - tagHeight: height ?? this.tagHeight, - tagWidth: width ?? this.tagWidth, - tagMinWidth: tagMinWidth ?? this.tagMinWidth); + tagTextStyle: textStyle ?? _tagTextStyle, + selectTagTextStyle: selectTextStyle ?? _selectTagTextStyle, + tagRadius: radius ?? _tagRadius, + tagBackgroundColor: backgroundColor ?? _tagBackgroundColor, + selectedTagBackgroundColor: + selectedBackgroundColor ?? _selectedTagBackgroundColor, + tagHeight: height ?? _tagHeight, + tagWidth: width ?? _tagWidth, + tagMinWidth: tagMinWidth ?? _tagMinWidth, + ); } - BrnTagConfig merge(BrnTagConfig other) { + BrnTagConfig merge(BrnTagConfig? other) { + if (other == null) return this; return copyWith( - textStyle: - this.tagTextStyle?.merge(other.tagTextStyle) ?? other.tagTextStyle, - selectTextStyle: - this.selectTagTextStyle?.merge(other.selectTagTextStyle) ?? - other.selectTagTextStyle, - radius: other.tagRadius, - backgroundColor: other.tagBackgroundColor, - selectedBackgroundColor: other.selectedTagBackgroundColor, - height: other.tagHeight, - width: other.tagWidth, - tagMinWidth: other.tagMinWidth); + textStyle: tagTextStyle.merge(other._tagTextStyle), + selectTextStyle: selectTagTextStyle.merge(other._selectTagTextStyle), + radius: other._tagRadius, + backgroundColor: other._tagBackgroundColor, + selectedBackgroundColor: other._selectedTagBackgroundColor, + height: other._tagHeight, + width: other._tagWidth, + tagMinWidth: other._tagMinWidth, + ); } } diff --git a/lib/src/theme/img/brn_theme_default_utils.dart b/lib/src/theme/img/brn_theme_default_utils.dart deleted file mode 100644 index a8c8b0f6..00000000 --- a/lib/src/theme/img/brn_theme_default_utils.dart +++ /dev/null @@ -1,69 +0,0 @@ -import 'dart:ui'; - -import 'package:bruno/src/constants/brn_asset_constants.dart'; -import 'package:bruno/src/theme/img/brn_theme_img_utils.dart'; -import 'package:bruno/src/utils/brn_tools.dart'; -import 'package:flutter/material.dart'; - -class BrnThemeImg { - BrnThemeImgUtils _defaultBrunoImg; - - static BrnThemeImg _instance; - - BrnThemeImg._(BrnThemeImgUtils brunoImgUtils) { - this._defaultBrunoImg = brunoImgUtils ?? BrnDefaultThemeImgUtil(); - } - - factory BrnThemeImg.register({BrnThemeImgUtils brunoImgUtils}) { - _instance = BrnThemeImg._(brunoImgUtils); - return _instance; - } - - static BrnThemeImg get instance { - if (_instance == null) { - BrnThemeImg.register(); - } - return _instance; - } - - Image get ARROW_REFRESH_UP => - _defaultBrunoImg?.getARROW_REFRESH_UP() ?? - BrunoTools.getAssetImage(BrnAsset.refreshArrowUp); - - Image get ARROW_REFRESH_DOWN => - _defaultBrunoImg?.getARROW_REFRESH_DOWN() ?? - BrunoTools.getAssetImage(BrnAsset.refreshArrowDown); - - Image get CHECKED_STATUS => - _defaultBrunoImg?.getCHECKED_STATUS() ?? - BrunoTools.getAssetImage(BrnAsset.SELECT_CHECKED_STATUS); - - Image get STEP_ICON { - return _defaultBrunoImg?.getStepIcon() ?? - BrunoTools.getAssetImage(BrnAsset.stepTitle); - } -} - -///默认link绿 -class BrnDefaultThemeImgUtil extends BrnThemeImgUtils { - @override - Image getARROW_REFRESH_UP() { - return BrunoTools.getAssetImageWithBandColor(BrnAsset.refreshArrowUp); - } - - @override - Image getARROW_REFRESH_DOWN() { - return BrunoTools.getAssetImageWithBandColor(BrnAsset.refreshArrowDown); - } - - @override - Image getCHECKED_STATUS() { - return BrunoTools.getAssetImageWithBandColor( - BrnAsset.SELECT_CHECKED_STATUS); - } - - @override - Image getStepIcon() { - return BrunoTools.getAssetImageWithBandColor(BrnAsset.stepTitle); - } -} diff --git a/lib/src/theme/img/brn_theme_img_utils.dart b/lib/src/theme/img/brn_theme_img_utils.dart deleted file mode 100644 index a553f15d..00000000 --- a/lib/src/theme/img/brn_theme_img_utils.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; - -abstract class BrnThemeImgUtils { - /// 下啦刷新的向上icon - Image getARROW_REFRESH_UP(); - - /// 下啦刷新的向下icon - Image getARROW_REFRESH_DOWN(); - - /// 选中与否的Icon - Image getCHECKED_STATUS(); - - /// 步骤的title - Image getStepIcon(); -} diff --git a/lib/src/utils/brn_event_bus.dart b/lib/src/utils/brn_event_bus.dart index b59fa39a..9d3832a6 100644 --- a/lib/src/utils/brn_event_bus.dart +++ b/lib/src/utils/brn_event_bus.dart @@ -11,28 +11,42 @@ import 'dart:async'; /// filter events. /// /// github: https://github.com/marcojakob/dart-event-bus -/// class EventBus { - StreamController _streamController; - - /// Controller for the event bus stream. - StreamController get streamController => _streamController; - /// Creates an [EventBus]. /// /// If [sync] is true, events are passed directly to the stream's listeners /// during a [fire] call. If false (the default), the event will be passed to /// the listeners at a later time, after the code creating the event has /// completed. - EventBus({bool sync = false}) - : _streamController = StreamController.broadcast(sync: sync); + EventBus({ + bool sync = false, + }) : _streamController = StreamController.broadcast(sync: sync); /// Instead of using the default [StreamController] you can use this constructor /// to pass your own controller. /// /// An example would be to use an RxDart Subject as the controller. - EventBus.customController(StreamController controller) - : _streamController = controller; + EventBus.customController( + StreamController controller, + ) : _streamController = controller; + + static EventBus? _instance; + + factory EventBus._() { + if(_instance == null) { + _instance = EventBus(); + } + return _instance!; + } + + static EventBus get instance { + return EventBus._(); + } + + StreamController _streamController; + + /// Controller for the event bus stream. + StreamController get streamController => _streamController; /// Listens for events of Type [T] and its subtypes. /// @@ -46,40 +60,24 @@ class EventBus { /// /// Each listener is handled independently, and if they pause, only the pausing /// listener is affected. A paused listener will buffer events internally until - /// unpaused or canceled. So it's usually better to just cancel and later + /// resumed or cancelled. So it's usually better to just cancel and later /// subscribe again (avoids memory leak). /// Stream on() { if (T == dynamic) { - return streamController.stream; - } else { - return streamController.stream.where((event) => event is T).cast(); + return streamController.stream as Stream; } + return streamController.stream.where((dynamic e) => e is T).cast(); } /// Fires a new event on the event bus with the specified [event]. - /// void fire(event) { streamController.add(event); } /// Destroy this [EventBus]. This is generally only in a testing context. - /// void destroy() { _streamController.close(); } - static EventBus _instance; - - factory EventBus.init() { - _instance = EventBus(); - return _instance; - } - - static EventBus get instance { - if (_instance == null) { - EventBus.init(); - } - return _instance; - } } diff --git a/lib/src/utils/brn_multi_click_util.dart b/lib/src/utils/brn_multi_click_util.dart index a278b235..b2d6f36b 100644 --- a/lib/src/utils/brn_multi_click_util.dart +++ b/lib/src/utils/brn_multi_click_util.dart @@ -1,10 +1,12 @@ class BrnMultiClickUtils { - static DateTime _lastClickTime; + const BrnMultiClickUtils._(); - static bool isMultiClick({int intervalMilliseconds}) { + static DateTime? _lastClickTime; + + static bool isMultiClick({int intervalMilliseconds = 500}) { if (_lastClickTime == null || - DateTime.now().difference(_lastClickTime) > - Duration(milliseconds: intervalMilliseconds ?? 500)) { + DateTime.now().difference(_lastClickTime!) > + Duration(milliseconds: intervalMilliseconds)) { _lastClickTime = DateTime.now(); return false; } diff --git a/lib/src/utils/brn_rich_text.dart b/lib/src/utils/brn_rich_text.dart index ae864d1e..8f2d5018 100644 --- a/lib/src/utils/brn_rich_text.dart +++ b/lib/src/utils/brn_rich_text.dart @@ -1,36 +1,34 @@ import 'package:bruno/src/theme/brn_theme_configurator.dart'; +import 'package:bruno/src/utils/css/brn_core_funtion.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -/// 福文本填充生成器 +/// 富文本填充生成器 -/// 超链接的点击回调 -typedef BrnRichTextLinkClick = void Function(String text, String link); - -///用于链式去生成福文本样式的文案 如果是直接的标签可以用css +/// 用于链式去生成富文本样式的文案 如果是直接的标签可以用css class BrnRichTextGenerator { - BrnRichTextGenerator() { - _spanList = List(); - _maxLine = 100; - } + BrnRichTextGenerator(); - List _spanList; - int _maxLine; - TextOverflow _overflow; + List _spanList = []; + int _maxLine = 100; + TextOverflow? _overflow; /// 添加超链接部分的文案 - /// text是显示的文案 - /// url是超链接的url - /// fontsize是显示大小 + /// text 是显示的文案 + /// url 是超链接的 url + /// fontsize 是显示大小 /// richTextLinkClick 是超链接点击的回调 - BrnRichTextGenerator addTextWithLink(String text, - {String url, - TextStyle textStyle, - Color linkColor, - double fontSize, - FontWeight fontWeight, - BrnRichTextLinkClick richTextLinkClick}) { - _spanList.add(TextSpan( + BrnRichTextGenerator addTextWithLink( + String text, { + String? url, + TextStyle? textStyle, + Color? linkColor, + double? fontSize, + FontWeight? fontWeight, + BrnHyperLinkCallback? richTextLinkClick, + }) { + _spanList.add( + TextSpan( style: textStyle ?? TextStyle( color: linkColor ?? @@ -41,56 +39,63 @@ class BrnRichTextGenerator { fontWeight: fontWeight ?? FontWeight.normal, fontSize: fontSize ?? 16, ), - text: text ?? "", + text: text, recognizer: TapGestureRecognizer() ..onTap = () { if (richTextLinkClick != null) { richTextLinkClick(text, url); } - })); + }, + ), + ); return this; } /// 添加自定义文案 /// fontsize 是文案大小 默认是16 /// color 是文案的颜色 默认是深黑色 - BrnRichTextGenerator addText(String text, - {TextStyle textStyle, - double fontSize, - Color color, - FontWeight fontWeight}) { - _spanList.add(TextSpan( - text: text ?? "", + BrnRichTextGenerator addText( + String text, { + TextStyle? textStyle, + double? fontSize, + Color? color, + FontWeight? fontWeight, + }) { + _spanList.add( + TextSpan( + text: text, style: textStyle ?? TextStyle( - color: color ?? - BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .colorTextBase, - fontSize: fontSize ?? 16, - fontWeight: fontWeight ?? FontWeight.normal))); + color: color ?? + BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .colorTextBase, + fontSize: fontSize ?? 16, + fontWeight: fontWeight ?? FontWeight.normal, + ), + ), + ); return this; } /// 添加Icon - BrnRichTextGenerator addIcon(Widget icon, {PlaceholderAlignment alignment}) { + BrnRichTextGenerator addIcon( + Widget? icon, { + PlaceholderAlignment? alignment, + }) { _spanList.add( WidgetSpan( - child: icon != null - ? icon - : Container( - height: 0, - width: 0, - ), - alignment: alignment ?? PlaceholderAlignment.top), + alignment: alignment ?? PlaceholderAlignment.top, + child: icon ?? const SizedBox.shrink(), + ), ); return this; } /// 设置最多文案显示几行 默认是100行 BrnRichTextGenerator setMaxLines(int maxLine) { - if (maxLine != null && maxLine > 0) { + if (maxLine > 0) { _maxLine = maxLine; } return this; @@ -98,17 +103,14 @@ class BrnRichTextGenerator { /// 设置最多文案显示几行 默认是100行 BrnRichTextGenerator setTextOverflow(TextOverflow overflow) { - this._overflow = overflow; + _overflow = overflow; return this; } /// build出福文本 Widget build() { if (_spanList.isEmpty) { - return Container( - height: 0, - width: 0, - ); + return const SizedBox.shrink(); } return ExcludeSemantics( excluding: true, diff --git a/lib/src/utils/brn_text_util.dart b/lib/src/utils/brn_text_util.dart index 424c2837..18cb2692 100644 --- a/lib/src/utils/brn_text_util.dart +++ b/lib/src/utils/brn_text_util.dart @@ -1,17 +1,17 @@ -import 'dart:ui'; - import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/widgets.dart'; class BrnTextUtil { + const BrnTextUtil._(); + /// 根据 TextStyle 计算 text 宽度。 static Size textSize(String text, TextStyle style) { if (BrunoTools.isEmpty(text)) return Size(0, 0); final TextPainter textPainter = TextPainter( - text: TextSpan(text: text, style: style), - maxLines: 1, - textDirection: TextDirection.ltr) - ..layout(minWidth: 0, maxWidth: double.infinity); + text: TextSpan(text: text, style: style), + maxLines: 1, + textDirection: TextDirection.ltr, + )..layout(minWidth: 0, maxWidth: double.infinity); return textPainter.size; } } diff --git a/lib/src/utils/brn_tools.dart b/lib/src/utils/brn_tools.dart index b5b63290..a5d90958 100644 --- a/lib/src/utils/brn_tools.dart +++ b/lib/src/utils/brn_tools.dart @@ -4,22 +4,26 @@ import 'package:bruno/src/theme/configs/brn_common_config.dart'; import 'package:flutter/material.dart'; class BrunoTools { + const BrunoTools._(); + /// 将 icon 根据主题色变色后返回 - static Image getAssetImageWithBandColor(String assetFilePath, - {String configId = BrnThemeConfigurator.GLOBAL_CONFIG_ID}) { - BrnCommonConfig commonConfig = BrnThemeConfigurator.instance + static Image getAssetImageWithBandColor( + String assetFilePath, { + String configId = GLOBAL_CONFIG_ID, + }) { + final BrnCommonConfig? commonConfig = BrnThemeConfigurator.instance .getConfig(configId: configId) .commonConfig; - if (!assetFilePath.startsWith("assets")) { - assetFilePath = "assets/$assetFilePath"; + if (!assetFilePath.startsWith('assets')) { + assetFilePath = 'assets/$assetFilePath'; } - return getAssetImageWithColor(assetFilePath, commonConfig.brandPrimary); + return getAssetImageWithColor(assetFilePath, commonConfig?.brandPrimary); } /// 将 icon 根据传入颜色变后返回 - static Image getAssetImageWithColor(String assetFilePath, Color color) { - if (!assetFilePath.startsWith("assets")) { - assetFilePath = "assets/$assetFilePath"; + static Image getAssetImageWithColor(String assetFilePath, Color? color) { + if (!assetFilePath.startsWith('assets')) { + assetFilePath = 'assets/$assetFilePath'; } return Image.asset( assetFilePath, @@ -29,13 +33,16 @@ class BrunoTools { ); } - /// imgAssetPath: assets资源文件路径 - /// package 访问某个package里的资源,这里默认flutter_alliance_package - /// scale: 与所用的png资源是icon_2x.png (scale=2.0),icon_3x.png(scale=3.0) - static Image getAssetImage(String assetFilePath, - {BoxFit fit, bool gaplessPlayback = false}) { - if (!assetFilePath.startsWith("assets")) { - assetFilePath = "assets/$assetFilePath"; + /// [assetFilePath] assets 资源文件路径 + /// [package] 访问某个 package 里的资源,这里默认为 'bruno' + /// [scale] 与所用的 png 资源是 icon_2x.png (scale=2.0),icon_3x.png(scale=3.0) + static Image getAssetImage( + String assetFilePath, { + BoxFit? fit, + bool gaplessPlayback = false, + }) { + if (!assetFilePath.startsWith('assets')) { + assetFilePath = 'assets/$assetFilePath'; } return Image.asset( assetFilePath, @@ -47,8 +54,8 @@ class BrunoTools { } static Image getAssetScaleImage(String assetFilePath) { - if (!assetFilePath.startsWith("assets")) { - assetFilePath = "assets/$assetFilePath"; + if (!assetFilePath.startsWith('assets')) { + assetFilePath = 'assets/$assetFilePath'; } return Image.asset( assetFilePath, @@ -56,10 +63,14 @@ class BrunoTools { ); } - static Image getAssetSizeImage(String assetFilePath, double w, double h, - {Color color}) { - if (!assetFilePath.startsWith("assets")) { - assetFilePath = "assets/$assetFilePath"; + static Image getAssetSizeImage( + String assetFilePath, + double w, + double h, { + Color? color, + }) { + if (!assetFilePath.startsWith('assets')) { + assetFilePath = 'assets/$assetFilePath'; } return Image.asset( assetFilePath, @@ -71,46 +82,48 @@ class BrunoTools { ); } - //从16进制数字字符串,生成Color,例如EDF0F3 - static Color colorFromHexString(String s) { + /// 从16进制数字字符串,生成Color,例如EDF0F3 + static Color colorFromHexString(String? s) { if (s == null || s.length != 6 || int.tryParse(s, radix: 16) == null) { return Colors.black; } return Color(int.parse(s, radix: 16) + 0xFF000000); } - // 获取本地AssetImage - /// [imgAssetPath]: assets资源文件路径 + /// 获取本地 [AssetImage] + /// [assetFilePath] assets资源文件路径 static ImageProvider getAssetImageProvider(String assetFilePath) { - if (!assetFilePath.startsWith("assets")) { - assetFilePath = "assets/$assetFilePath"; + if (!assetFilePath.startsWith('assets')) { + assetFilePath = 'assets/$assetFilePath'; } - AssetImage asimg = AssetImage( + final AssetImage image = AssetImage( assetFilePath, package: BrnStrings.flutterPackageName, ); - return asimg; + return image; } /// 根据 TextStyle 计算 text 宽度。 static Size textSize(String text, TextStyle style) { if (isEmpty(text)) return Size(0, 0); final TextPainter textPainter = TextPainter( - text: TextSpan(text: text, style: style), - maxLines: 1, - textDirection: TextDirection.ltr) - ..layout(minWidth: 0, maxWidth: double.infinity); + text: TextSpan(text: text, style: style), + maxLines: 1, + textDirection: TextDirection.ltr, + )..layout(minWidth: 0, maxWidth: double.infinity); return textPainter.size; } /// 判空 - static bool isEmpty(Object obj) { + static bool isEmpty(Object? obj) { if (obj is String) { return obj.isEmpty; - } else if (obj is Iterable) { + } + if (obj is Iterable) { return obj.isEmpty; - } else if (obj is Map) { + } + if (obj is Map) { return obj.length == 0; } return obj == null; @@ -118,7 +131,7 @@ class BrunoTools { /// 去掉最后一位小数 //static double formatNumRemoveLastNum(double num){ -// int count = num.toString().length - num.toString().lastIndexOf(".") - 1; +// int count = num.toString().length - num.toString().lastIndexOf('.') - 1; // if(count >1){ // // } diff --git a/lib/src/utils/css/brn_core_funtion.dart b/lib/src/utils/css/brn_core_funtion.dart index 56baaf45..3aa03742 100644 --- a/lib/src/utils/css/brn_core_funtion.dart +++ b/lib/src/utils/css/brn_core_funtion.dart @@ -4,38 +4,40 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:xml/xml_events.dart' as xml; -typedef BrnHyperLinkCallback = Function(String text, String url); +/// 超链接的点击回调 +typedef BrnHyperLinkCallback = void Function(String text, String? url); -//用于将标签转为 style +/// 用于将标签转为 style class BrnConvert { - //超链接的点击回调 - BrnHyperLinkCallback _linkCallBack; - - //标签的集合 - Iterable _eventList = []; - - //标签对应的style - List stack = []; - - //外部传入的默认文本样式 - TextStyle _defaultStyle; - - BrnConvert(String cssContent, - {Function linkCallBack, TextStyle defaultStyle}) { + BrnConvert( + String cssContent, { + BrnHyperLinkCallback? linkCallBack, + TextStyle? defaultStyle, + }) { _eventList = xml.parseEvents(cssContent); _linkCallBack = linkCallBack ?? null; _defaultStyle = defaultStyle; } - //转换的思路:将 开始标签 的属性转为 合适的style, 并将其存入集合中 - // font开始标签目前支持的属性:color、weight、size - // a开始标签支持的属性:href - // 文本标签 去获取style集合的最后一个元素 并应用style样式 - // 结束标签 则将集合的最后一个元素删除 + /// 超链接的点击回调 + BrnHyperLinkCallback? _linkCallBack; + + /// 外部传入的默认文本样式 + TextStyle? _defaultStyle; + /// 标签的集合 + Iterable _eventList = []; + + /// 标签对应的style + List<_Tag> stack = []; + + /// 转换的思路:将 开始标签 的属性转为 合适的style, 并将其存入集合中 + /// a开始标签支持的属性:href + /// 文本标签 去获取style集合的最后一个元素 并应用style样式 + /// 结束标签 则将集合的最后一个元素删除 List convert() { - //优先使用外部提供的样式 - TextStyle style = _defaultStyle ?? + // 优先使用外部提供的样式 + final TextStyle style = _defaultStyle ?? TextStyle( fontSize: 14, decoration: TextDecoration.none, @@ -46,51 +48,54 @@ class BrnConvert { .colorTextImportant, ); - List spans = []; + final List spans = []; _eventList.forEach((xmlEvent) { if (xmlEvent is xml.XmlStartElementEvent) { if (!xmlEvent.isSelfClosing) { - Tag tag = Tag(); + final _Tag tag = _Tag(); TextStyle textStyle = style.copyWith(); - if (xmlEvent.name == "font") { + if (xmlEvent.name == 'font') { xmlEvent.attributes.forEach((attr) { switch (attr.name) { - case "color": - Color textColor = - BrnConvertUtil.generateColorByString(attr.value); - textStyle = textStyle.apply(color: textColor); + case 'color': + textStyle = textStyle.apply( + color: BrnConvertUtil.generateColorByString(attr.value), + ); break; - case "weight": + case 'weight': FontWeight fontWeight = BrnConvertUtil.generateFontWidgetByString(attr.value); textStyle = textStyle.apply( - fontWeightDelta: - fontWeight.index - FontWeight.normal.index); + fontWeightDelta: fontWeight.index - FontWeight.normal.index, + ); break; - case "size": - double size = BrnConvertUtil.generateFontSize(attr.value); - textStyle = textStyle.apply(fontSizeDelta: size - 13); + case 'size': + textStyle = textStyle.apply( + fontSizeDelta: + BrnConvertUtil.generateFontSize(attr.value) - 13, + ); break; } }); tag.isLink = false; } - if (xmlEvent.name == "strong") { + if (xmlEvent.name == 'strong') { tag.isLink = false; textStyle = textStyle.apply(fontWeightDelta: 2); } - if (xmlEvent.name == "a") { + if (xmlEvent.name == 'a') { tag.isLink = true; xmlEvent.attributes.forEach((attr) { switch (attr.name) { - case "href": + case 'href': textStyle = textStyle.apply( - color: BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .brandPrimary); + color: BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary, + ); tag.linkUrl = attr.value; break; } @@ -100,14 +105,14 @@ class BrnConvert { tag.style = textStyle; stack.add(tag); } else { - if (xmlEvent.name == "br") { - spans.add(TextSpan(text: "\n")); + if (xmlEvent.name == 'br') { + spans.add(TextSpan(text: '\n')); } } } if (xmlEvent is xml.XmlTextEvent) { - Tag tag = Tag(); + _Tag tag = _Tag(); tag.style = style.copyWith(); if (stack.isNotEmpty) { tag = stack.last; @@ -117,9 +122,9 @@ class BrnConvert { } if (xmlEvent is xml.XmlEndElementEvent) { - Tag top = stack.removeLast(); + _Tag top = stack.removeLast(); if (top.name != xmlEvent.name) { - debugPrint("Error format HTML"); + debugPrint('Error format HTML'); return; } } @@ -128,24 +133,23 @@ class BrnConvert { return spans; } - TextSpan _createTextSpan(String text, Tag tag) { - if (text.isEmpty) return TextSpan(text: ""); - TapGestureRecognizer tapGestureRecognizer = TapGestureRecognizer(); - tapGestureRecognizer.onTap = () { - if (_linkCallBack != null) { - _linkCallBack(text, tag.linkUrl); - } - }; + TextSpan _createTextSpan(String text, _Tag tag) { + if (text.isEmpty) return TextSpan(text: ''); + final TapGestureRecognizer recognizer = TapGestureRecognizer() + ..onTap = () { + _linkCallBack?.call(text, tag.linkUrl); + }; return TextSpan( - style: tag.style, - text: text, - recognizer: tag.isLink ? tapGestureRecognizer : null); + style: tag.style, + text: text, + recognizer: tag.isLink ? recognizer : null, + ); } } -class Tag { - String name; - TextStyle style; - String linkUrl; +class _Tag { + String? name; + TextStyle? style; + String? linkUrl; bool isLink = false; } diff --git a/lib/src/utils/css/brn_css_2_text.dart b/lib/src/utils/css/brn_css_2_text.dart index dd35d20f..beb13bde 100644 --- a/lib/src/utils/css/brn_css_2_text.dart +++ b/lib/src/utils/css/brn_css_2_text.dart @@ -3,24 +3,36 @@ import 'package:flutter/material.dart'; /// 将CSS格式的标签转为文本 class BrnCSS2Text { - static TextSpan toTextSpan(String htmlContent, - {BrnHyperLinkCallback linksCallback, TextStyle defaultStyle}) { + const BrnCSS2Text._(); + + static TextSpan toTextSpan( + String htmlContent, { + BrnHyperLinkCallback? linksCallback, + TextStyle? defaultStyle, + }) { return TextSpan( - children: BrnConvert(htmlContent, - linkCallBack: linksCallback, defaultStyle: defaultStyle) - .convert(), + children: BrnConvert( + htmlContent, + linkCallBack: linksCallback, + defaultStyle: defaultStyle, + ).convert(), ); } - static Text toTextView(String htmlContent, - {BrnHyperLinkCallback linksCallback, - TextStyle defaultStyle, - int maxLines, - TextAlign textAlign, - TextOverflow textOverflow}) { + static Text toTextView( + String htmlContent, { + BrnHyperLinkCallback? linksCallback, + TextStyle? defaultStyle, + int? maxLines, + TextAlign? textAlign, + TextOverflow? textOverflow, + }) { return Text.rich( - toTextSpan(htmlContent, - linksCallback: linksCallback, defaultStyle: defaultStyle), + toTextSpan( + htmlContent, + linksCallback: linksCallback, + defaultStyle: defaultStyle, + ), maxLines: maxLines, textAlign: textAlign, overflow: textOverflow ?? TextOverflow.clip, diff --git a/lib/src/utils/css/brn_util.dart b/lib/src/utils/css/brn_util.dart index bcbe5753..31f64996 100644 --- a/lib/src/utils/css/brn_util.dart +++ b/lib/src/utils/css/brn_util.dart @@ -1,50 +1,53 @@ -import 'dart:ui'; - import 'package:bruno/src/theme/brn_theme_configurator.dart'; +import 'package:flutter/painting.dart'; -//将标签属性 转为 相当的style +/// 将标签属性转为对应的 style class BrnConvertUtil { - //将标签color 转为 颜色 - static Color generateColorByString(String hexColor, - {String defColor: 'ffffffff'}) { - Color color = + const BrnConvertUtil._(); + + /// 将标签 color 转为 颜色 + static Color? generateColorByString( + String hexColor, { + Color defaultColor = const Color(0xffffffff), + }) { + Color? color = BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary; - if (hexColor == null || hexColor.isEmpty) return color; - hexColor = hexColor.toUpperCase().replaceAll("#", ""); + if (hexColor.isEmpty) return color; + hexColor = hexColor.toUpperCase().replaceAll('#', ''); hexColor = hexColor.replaceAll('0X', ''); if (hexColor.length == 6) { - hexColor = "FF" + hexColor; + hexColor = 'FF' + hexColor; } try { color = Color(int.parse(hexColor, radix: 16)); - } catch (e) {} - return color; + } catch (_) {} + return color ?? defaultColor; } - //将标签字体 转为 合适的字体 + /// 将标签字体转为合适的字体 static FontWeight generateFontWidgetByString(String fontWeight) { FontWeight defaultWeight = FontWeight.normal; switch (fontWeight) { - case "Bold": + case 'Bold': defaultWeight = FontWeight.w600; break; - case "Medium": + case 'Medium': defaultWeight = FontWeight.w500; break; - case "Light": + case 'Light': defaultWeight = FontWeight.w300; break; } return defaultWeight; } - //将标签字体大小 转为 合适大小的字体 + /// 将标签字体大小转为合适大小的字体 static double generateFontSize(String size) { double defaultSize = 13; try { defaultSize = double.parse(size); - } catch (e) {} + } catch (_) {} return defaultSize; } } diff --git a/lib/src/utils/font/brn_font.dart b/lib/src/utils/font/brn_font.dart deleted file mode 100644 index 59de256b..00000000 --- a/lib/src/utils/font/brn_font.dart +++ /dev/null @@ -1,13 +0,0 @@ -class BrnFont { - static const double FONT_12 = 12; - - static const double FONT_14 = 14; - - static const double FONT_16 = 16; - - static const double FONT_18 = 18; - - static const double FONT_20 = 20; - - static const double FONT_22 = 22; -} diff --git a/lib/src/utils/i18n/brn_date_picker_i18n.dart b/lib/src/utils/i18n/brn_date_picker_i18n.dart index 2438c270..0d90a097 100755 --- a/lib/src/utils/i18n/brn_date_picker_i18n.dart +++ b/lib/src/utils/i18n/brn_date_picker_i18n.dart @@ -1,4 +1,4 @@ -import 'dart:math'; +import 'dart:math' as math; part 'brn_strings_zh_cn.dart'; @@ -63,65 +63,69 @@ enum DateTimePickerLocale { } /// Default value of date locale -const DateTimePickerLocale DATETIME_PICKER_LOCALE_DEFAULT = +const DateTimePickerLocale datetimePickerLocaleDefault = DateTimePickerLocale.zh_cn; const Map datePickerI18n = { - DateTimePickerLocale.zh_cn: const _StringsZhCn(), + DateTimePickerLocale.zh_cn: _StringsZhCn(), }; class DatePickerI18n { + const DatePickerI18n._(); + /// Get done button text static String getLocaleDone(DateTimePickerLocale locale) { - _StringsI18n i18n = datePickerI18n[locale] ?? - datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT]; - return i18n.getDoneText() ?? - datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT].getDoneText(); + final _StringsI18n? i18n = datePickerI18n[locale] ?? + datePickerI18n[datetimePickerLocaleDefault]; + return i18n?.getDoneText() ?? + datePickerI18n[datetimePickerLocaleDefault]!.getDoneText(); } /// Get cancel button text static String getLocaleCancel(DateTimePickerLocale locale) { - _StringsI18n i18n = datePickerI18n[locale] ?? - datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT]; - return i18n.getCancelText() ?? - datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT].getCancelText(); + final _StringsI18n? i18n = datePickerI18n[locale] ?? + datePickerI18n[datetimePickerLocaleDefault]; + return i18n?.getCancelText() ?? + datePickerI18n[datetimePickerLocaleDefault]!.getCancelText(); } /// Get locale month array static List getLocaleMonths(DateTimePickerLocale locale) { - _StringsI18n i18n = datePickerI18n[locale] ?? - datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT]; - List months = i18n.getMonths(); + final _StringsI18n? i18n = datePickerI18n[locale] ?? + datePickerI18n[datetimePickerLocaleDefault]; + final List? months = i18n?.getMonths(); if (months != null && months.isNotEmpty) { return months; } - return datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT].getMonths(); + return datePickerI18n[datetimePickerLocaleDefault]!.getMonths(); } /// Get locale week array - static List getLocaleWeeks(DateTimePickerLocale locale, - [bool isFull = true]) { - _StringsI18n i18n = datePickerI18n[locale] ?? - datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT]; + static List getLocaleWeeks( + DateTimePickerLocale locale, [ + bool isFull = true, + ]) { + final _StringsI18n? i18n = datePickerI18n[locale] ?? + datePickerI18n[datetimePickerLocaleDefault]; if (isFull) { - List weeks = i18n.getWeeksFull(); + final List? weeks = i18n?.getWeeksFull(); if (weeks != null && weeks.isNotEmpty) { return weeks; } - return datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT].getWeeksFull(); + return datePickerI18n[datetimePickerLocaleDefault]!.getWeeksFull(); } - List weeks = i18n.getWeeksShort(); + final List? weeks = i18n?.getWeeksShort(); if (weeks != null && weeks.isNotEmpty) { return weeks; } - List fullWeeks = i18n.getWeeksFull(); + final List? fullWeeks = i18n?.getWeeksFull(); if (fullWeeks != null && fullWeeks.isNotEmpty) { return fullWeeks - .map((item) => item.substring(0, min(3, item.length))) + .map((item) => item.substring(0, math.min(3, item.length))) .toList(); } - return datePickerI18n[DATETIME_PICKER_LOCALE_DEFAULT].getWeeksShort(); + return datePickerI18n[datetimePickerLocaleDefault]!.getWeeksShort(); } } diff --git a/lib/src/utils/i18n/brn_strings_zh_cn.dart b/lib/src/utils/i18n/brn_strings_zh_cn.dart index 9248bb43..7f9294c0 100755 --- a/lib/src/utils/i18n/brn_strings_zh_cn.dart +++ b/lib/src/utils/i18n/brn_strings_zh_cn.dart @@ -5,56 +5,52 @@ class _StringsZhCn extends _StringsI18n { const _StringsZhCn(); @override - String getCancelText() { - return '取消'; - } + String getCancelText() => '取消'; @override - String getDoneText() { - return '确定'; - } + String getDoneText() => '确定'; @override List getMonths() { - return [ - "01", - "02", - "03", - "04", - "05", - "06", - "07", - "08", - "09", - "10", - "11", - "12" + return [ + '01', + '02', + '03', + '04', + '05', + '06', + '07', + '08', + '09', + '10', + '11', + '12', ]; } @override List getWeeksFull() { - return [ - "星期一", - "星期二", - "星期三", - "星期四", - "星期五", - "星期六", - "星期日", + return [ + '星期一', + '星期二', + '星期三', + '星期四', + '星期五', + '星期六', + '星期日', ]; } @override List getWeeksShort() { - return [ - "周一", - "周二", - "周三", - "周四", - "周五", - "周六", - "周日", + return [ + '周一', + '周二', + '周三', + '周四', + '周五', + '周六', + '周日', ]; } } diff --git a/pubspec.yaml b/pubspec.yaml index 4dfcf223..f40c9439 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ version: 2.0.0 homepage: https://github.com/LianjiaTech/bruno environment: - sdk: ">=2.1.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: From f18f1e344012d3f6fe9aeb9c66daed60acca2707 Mon Sep 17 00:00:00 2001 From: Sandy <15143015732@163.com> Date: Wed, 9 Mar 2022 11:20:30 +0800 Subject: [PATCH 10/24] migrate docs to null-safety (#112) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Null safe (#13) * remove useless comments * remove useless dependencies * adapt brn_expandable_text.dart null-safe * upgrade dependencies:collection to stable * migrate constants to null safety * migrate brn_multi_click_util to null safety * migrate font util to null safety * migrate brn_text_style to null safety * migrate brn picker constants to null safety * migrate brn appBar theme to null safety * optimize bruno theme's import (#16) * ♻️ [NNBD] Part 1. Migrate configs (#28) * ♻️ [NNBD] Part 2. Migrate utils (#30) * ♻️ Migrate utils to NNBD * 🎨 Improve the color getter * :art: BrnSearchText (#36) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null (#40) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 🎨 utils-EventBus添加null-safe (#23) * 🎨 utils-EventBus添加null-safe * 🎨 修改theme配置功能及utils/brn_tools工具函数 null-safe * 🎨 EventBus添加null-safe(其他提交请忽略,输入回退) Co-authored-by: 大脸儿 * refactor brn_toast (#33) * refactor brn_toast * refactor brn_toast * 优化修复 EventBus * 优化 EventBus 单例实现 (#43) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * brn_toast time change to seconds (#45) * migrate brn_loading to null safety (#32) * migrate brn_loading to null safety * mv loading content to brnString constants * optimization brn_theme_configurator instance constructor (#47) * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * Migrate BrnStateTag、BrnTagCustom、BrnSelectTag、BrnDeleteTag to null-safe (#46) * [null-safe]: BrnStateTag、BrnTagCustom、BrnSelectTag、BrnDeleteTag 空安全适配 * perf: BrnDeleteTag null-safe * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * reset and migrated package [rating] to null-safety. (#42) * 迁移example ,优化常量命名,增加export (#51) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * 空安全报错修改 (#55) * 空安全报错修改 * 优化sketch教程为视频教程 * Migrated package [selectcity] to null-safety (#56) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * migrate card_title to null safety (#59) * migrate card_title to null-safety * [fix] brn_action_card_title: _sub widget is not null * [optimize] empty widget use SizedBox instead of Container * replace empty widget SizedBox to SizedBox.shrink * Migrated package [radio] to null-safety (#62) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * 1.Migrated package [radio] to null-safety; 2.Modified not-need-nullable param in brn_single_select_city_page.dart; * Migrated tabbar to null-safety * Migrated package [guide] to null-safety (#65) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * 1.Migrated package [radio] to null-safety; 2.Modified not-need-nullable param in brn_single_select_city_page.dart; * Migrated package [guide] to null-safety * 🚀 Use the latest Podfile for the example (#68) * Null safe calendar (#64) * migrate calendar widget to null safety * brn_calendar_view fix _currentStartSelectedDate is not null * brn_calendar_view: simplify borderRadius usage * calendar widget late _displayMode * calendar widget add two constructors with date change * Card Components Null safe adapter (#53) * feat: support fvm * feat: Card components null-safey adpater * refactor: make code simple and clean * refactor: make code simple and clean * Migrated scroll_anchor to null-safety * fix #71 (#77) * fix content_card themeData is not null (#79) * Null safe of all buttons (#20) * icon button 增加null safe * null safe for normal button * null safe for normal button * null safe for button * null safe for all button * merge * rebase * rebase * merge * optimization * GlobalKey is not null * optimization * reset popup window * showButtonPanelPopList Co-authored-by: foreturn * Migrated package [navbar][input] to null-safety (#75) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * 1.Migrated package [radio] to null-safety; 2.Modified not-need-nullable param in brn_single_select_city_page.dart; * Migrated package [guide] to null-safety * Migrated package [navbar][input] to null-safety * Optimized codes in brn_appbar.dart * Restore partial modification * fix:修复迁移tabar问题 * Migrated tabbar & scroll_anchor to null-safety (#66) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * Migrate Selection to null-safe (#54) * [null-safe]: BrnStateTag、BrnTagCustom、BrnSelectTag、BrnDeleteTag 空安全适配 * perf: BrnDeleteTag null-safe * Migrate Selection to null-safe * Migrate Selection to null-safe * perf: ItemEntity name 字段的初始化 * Migrate Selection to null-safe * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * Migrated package [dialog] to null-safety (#81) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * 1.Migrated package [radio] to null-safety; 2.Modified not-need-nullable param in brn_single_select_city_page.dart; * Migrated package [guide] to null-safety * Migrated package [navbar][input] to null-safety * Optimized codes in brn_appbar.dart * Restore partial modification * Migrated package [dialog] to null-safety * Modified some params's default value or nullable type * migrate brn_horizontal_steps、brn_step_line to null safety (#89) * migrate charts to null safety (#80) * migrate DoughuntChart to null safety * migrate progress bar chart to null safety * update progress bar chart document * migrate progress chart to null safety * migrate radar chart to null safety * migrate funnel chart to null safety * migrate broken line chart to null safety * fix progress bar chart some value is required * fix progress bar chart some value is required * fix brn_line_paint _path is not null * fix brn_funnel_chart properties is not null * fix brn_radar_chart properties is not null * fix brn_line_painter not null values * fix brn_progress_bar_chart error * brn_broken_line some properties is not null value * replace empty Container to SizedBox.shrink * update progress_bar_chart null safety value by hand * update broken_line null safety values by hand * update funnel_chart null safety value by hand * make LineCanvasModel immutable * migrate actionsheet into null-safe (#73) * migrate actionsheet into null-safe * sheet: code review Co-authored-by: yuanjunliang * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate form to null safety (#86) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * migrate popup to null safety (#69) * migrate popup to null safety * fix MeasureSize null safe problems * fix popup migrate to null-safety review problems * migrate gallery to null safety (#90) * migrate gallery to null safety * change the type error * remove @ * change String? to String * fix:修复picker空安全迁移问题 * migrate appraise dir to null safety (#84) * migrate appraise dir to null safety * fix appraise migrate to null-safety review problems * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate picker to null safety (#91) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * fix:修复picker空安全迁移问题 * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate example to null safty * fix:修复部分example warning * fix:修复demo报错问题 * fix:追加未跟踪修复 * fix:优化部分接口可空参数为非空 * Perf:Button Null safe (#93) * perf: Migrate Button Null-Safe * perf:优化 HorizontalStep Null-Safe * fix: null exception when parse json to entity * perf Button Null-Safe, fix NullException perf more layer icon color when item selected * migrate example to null safety (#94) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * fix:修复picker空安全迁移问题 * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate example to null safty * fix:修复部分example warning * fix:修复demo报错问题 * fix:追加未跟踪修复 * fix:优化部分接口可空参数为非空 Co-authored-by: violinday * fix:修复tabar showmore overflow 问题 #98 以及 tabbar 标签颜色默认设置倒置问题 * Fix #98 问题及优化部分代码 (#99) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * fix:修复picker空安全迁移问题 * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate example to null safty * fix:修复部分example warning * fix:修复demo报错问题 * fix:追加未跟踪修复 * fix:优化部分接口可空参数为非空 * fix:修复tabar showmore overflow 问题 #98 以及 tabbar 标签颜色默认设置倒置问题 Co-authored-by: violinday * refactor:优化 BrnInputItemType 常量命名 * refactor:优化枚举值命名 * fix:修改docs目录下form相关常量命名及所有枚举命名 * 优化 BrnInputItemType 常量命名 (#100) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * fix:修复picker空安全迁移问题 * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate example to null safty * fix:修复部分example warning * fix:修复demo报错问题 * fix:追加未跟踪修复 * fix:优化部分接口可空参数为非空 * fix:修复tabar showmore overflow 问题 #98 以及 tabbar 标签颜色默认设置倒置问题 * refactor:优化 BrnInputItemType 常量命名 * refactor:优化枚举值命名 * fix:修改docs目录下form相关常量命名及所有枚举命名 Co-authored-by: violinday * refactor: 更新 changelog * refactor:BrnBubbleText 增加属性 bgColor、textStyle,修复demo actionSheet、gallery、selection、picker错误 * fix:修复changelog 错误,brn_gallery_summary_page.dart 中标题空处理 * fix:修复部分问题 * fix:修复部分问题 * migrate docs to null-safety * feat:changelog 增加 BrnHorizontalStepsManager 改动 * fix:优化changelog Co-authored-by: laiiihz Co-authored-by: LAIIIHZ <35956195+laiiihz@users.noreply.github.com> Co-authored-by: Alex Li Co-authored-by: kalifun <37646342+kalifun@users.noreply.github.com> Co-authored-by: kkkman22 <2594387207@qq.com> Co-authored-by: 大脸儿 Co-authored-by: leftcoding <137387869@qq.com> Co-authored-by: violinday Co-authored-by: jojinshallar Co-authored-by: HappyImp Co-authored-by: Kenneth Co-authored-by: donywan Co-authored-by: foreturn Co-authored-by: Junl <17602153700@163.com> Co-authored-by: yuanjunliang Co-authored-by: Nayuta403 <40540394+Nayuta403@users.noreply.github.com> --- CHANGELOG.md | 1 + .../BrnBottomButtonPanel.md | 26 +-- .../BrnMultipleBottomButton.md | 31 ++-- .../BrnButtonPanel/BrnButtonPanel.md | 20 +-- .../BrnTextButtonPanel/BrnTextButtonPanel.md | 12 +- .../charts/BrnBrokenLine/BrnBrokenLine.md | 92 +++++----- .../BrnDoughnutChart/BrnDoughnutChart.md | 38 +++-- .../charts/BrnFunnelChart/BrnFunnelChart.md | 52 +++--- .../BrnProgressBarChart.md | 59 ++++--- .../BrnProgressChart/BrnProgressChart.md | 28 ++-- .../charts/BrnRadarChart/BrnRadarChart.md | 158 +++++++++--------- docs/components/dialog/BrnDialog/BrnDialog.md | 128 +++++++------- .../BrnEnhanceOperationDialog.md | 48 +++--- .../BrnLoadingDialog/BrnLoadingDialog.md | 3 +- .../BrnMiddleInputDialog.md | 55 +++--- .../BrnMultiSelectDialog.md | 104 ++++++------ .../BrnScrollableTextDialog.md | 69 ++++---- .../dialog/BrnShareDialog/BrnShareDialog.md | 60 +++---- .../BrnSingleSelectDialog.md | 52 +++--- .../iconButton/BrnIconButton/BrnIconButton.md | 38 ++--- .../BrnVerticalIconButton.md | 11 +- .../input/BrnInputText/BrnInputText.md | 116 ++++++------- .../loading/BrnPageLoading/BrnPageLoading.md | 3 +- .../BrnBigGhostButton/BrnBigGhostButton.md | 17 +- .../BrnBigMainButton/BrnBigMainButton.md | 17 +- .../BrnBigOutlineButton.md | 19 ++- .../BrnSmallMainButton/BrnSmallMainButton.md | 50 +++--- .../BrnSmallOutlineButton.md | 29 ++-- .../picker/BrnBottomPicker/BrnBottomPicker.md | 30 ++-- .../BrnBottomWritePicker.md | 40 ++--- .../picker/BrnDatePicker/BrnDatePicker.md | 42 ++--- .../BrnDateRangePicker/BrnDateRangePicker.md | 53 +++--- .../BrnMultiColumnPicker.md | 27 +-- .../BrnMultiDataPicker/BrnMultiDataPicker.md | 72 ++++---- .../BrnMultiSelectListPicker.md | 34 ++-- .../BrnMultiSelectTagsPicker.md | 54 +++--- .../BrnSelectTagsWithInputPicker.md | 46 ++--- .../tips/BrnPopupWindow/BrnPopupWindow.md | 55 +++--- docs/components/toast/BrnToast/BrnToast.md | 84 ++++++---- .../button/brn_text_button_panel_example.dart | 5 +- lib/src/components/dialog/brn_dialog.dart | 85 +--------- .../dialog/brn_middle_input_diaolg.dart | 5 - .../bean/brn_multi_column_picker_entity.dart | 3 +- 43 files changed, 972 insertions(+), 999 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70537f23..7aed7f0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Add build test thank to **AlexV525**. #### components +- **Breaking change**: remove BrnHorizontalStepsManager and put function forwardStep() backStep() into BrnStepsController thanks to leftcoding. - BrnCalendarView: add BrnCalendarView.single() and BrnCalendarView.range() constructor and had its argument startEndDateChange removed. - BrnSelectionEntityListBean: fromMap is renamed to fromJson. - BrnRadioButton: optimize click area [#31](https://github.com/LianjiaTech/bruno/pull/31) , thanks to **a1017480401** . diff --git a/docs/components/bottomButtonPanel/BrnBottomButtonPanel/BrnBottomButtonPanel.md b/docs/components/bottomButtonPanel/BrnBottomButtonPanel/BrnBottomButtonPanel.md index c2eb8ac1..232526b3 100644 --- a/docs/components/bottomButtonPanel/BrnBottomButtonPanel/BrnBottomButtonPanel.md +++ b/docs/components/bottomButtonPanel/BrnBottomButtonPanel/BrnBottomButtonPanel.md @@ -45,25 +45,25 @@ group: ```dart const BrnBottomButtonPanel( - {Key key, - @required this.mainButtonName, - @required this.mainButtonOnTap, - this.secondaryButtonName, - this.secondaryButtonOnTap, - this.enableMainButton = true, - this.enableSecondaryButton = true, - this.iconButtonList}) - : super(key: key); + {Key? key, + required this.mainButtonName, + required this.mainButtonOnTap, + this.secondaryButtonName, + this.secondaryButtonOnTap, + this.enableMainButton = true, + this.enableSecondaryButton = true, + this.iconButtonList}) + : super(key: key); ``` ### 参数说明 | 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | | --- | --- | --- | --- | --- | -| mainButtonName | String | 主按钮的显示文案 | 否 | '' | +| mainButtonName | String | 主按钮的显示文案 | 否 | 无 | | mainButtonOnTap | VoidCallback | 主按钮的点击回调 | 否 | 无 | -| secondaryButtnoName | String | 次按钮显示文案 | 否 | '' | -| secondaryButtonOnTap | VoidCallback | 次按钮的点击回调 | 否 | 无 | -| iconButtonList | List | icon按钮的集合 | 否 | 无 | +| secondaryButtonName | String? | 次按钮显示文案 | 否 | 无 | +| secondaryButtonOnTap | VoidCallback? | 次按钮的点击回调 | 否 | 无 | +| iconButtonList | List? | icon按钮的集合 | 否 | 无 | | enableMainButton | bool | 主按钮是否可用 | 否 | true | | enableSecondaryButton | bool | 次按钮是否可用 | 否 | true | diff --git a/docs/components/bottomButtonPanel/BrnMultipleBottomButton/BrnMultipleBottomButton.md b/docs/components/bottomButtonPanel/BrnMultipleBottomButton/BrnMultipleBottomButton.md index 8bc3441e..da3ad294 100644 --- a/docs/components/bottomButtonPanel/BrnMultipleBottomButton/BrnMultipleBottomButton.md +++ b/docs/components/bottomButtonPanel/BrnMultipleBottomButton/BrnMultipleBottomButton.md @@ -27,16 +27,17 @@ group: ### 构造函数 ```dart -BrnMultipleBottomButton( - {Key key, - this.mainButtonName, - this.subButtonName, - this.onSelectAllTap, - this.onMainButtonTap, - this.onSelectedButtonTap, - this.onSubButtonTap, - this.hasArrow = false, - this.bottomController}) +const BrnMultipleBottomButton( + {Key? key, + this.mainButton, + this.subButton, + this.onMainButtonTap, + this.onSubButtonTap, + this.onSelectedButtonTap, + this.onSelectAll, + this.hasArrow = false, + this.bottomController}) + : super(key: key); ``` @@ -47,13 +48,13 @@ BrnMultipleBottomButton( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | | mainButton | dynamic | 主按钮的显示文案,传入String即使用默认的Text样式,传入其他样式则使用对应的Widget | 否 | | -| onMainButtonTap | VoidCallback | 主按钮点击回调 | 否 | | +| onMainButtonTap | VoidCallback? | 主按钮点击回调 | 否 | | | subButton | dynamic | 次按钮的显示文案,传入String即使用默认的Text样式,传入其他样式则使用对应的Widget | 否 | | -| onSubButtonTap | VoidCallback | 次按钮点击回调 | 否 | | -| onSelectedButtonTap | Function(int) | selectedButtonOnTap', '点击已选的回调,存在三种状态:-1:不可展开(当value为0的时候),0:收起,1:展开 | 否 | | -| onSelectAll | Function(bool) | 全选的点击回调,不传则不展示多选按钮,回传参数true表示选中全选,false表示取消全选 | 否 | | +| onSubButtonTap | VoidCallback? | 次按钮点击回调 | 否 | | +| onSelectedButtonTap | Function(BrnMultipleButtonArrowState)? | selectedButtonOnTap', '点击已选的回调,存在三种状态:-1:不可展开(当value为0的时候),0:收起,1:展开 | 否 | | +| onSelectAll | void Function(bool?)? | 全选的点击回调,不传则不展示多选按钮,回传参数true表示选中全选,false表示取消全选 | 否 | | | hasArrow | bool | 已选侧边是否需要小箭头 | 否 | false | -| bottomController | BrnMultipleBottomController | 暴露给外界设置按钮状态的控制器 | 否 | | +| bottomController | BrnMultipleBottomController? | 暴露给外界设置按钮状态的控制器 | 否 | | diff --git a/docs/components/buttonPanel/BrnButtonPanel/BrnButtonPanel.md b/docs/components/buttonPanel/BrnButtonPanel/BrnButtonPanel.md index b3e914c5..0d39e998 100644 --- a/docs/components/buttonPanel/BrnButtonPanel/BrnButtonPanel.md +++ b/docs/components/buttonPanel/BrnButtonPanel/BrnButtonPanel.md @@ -33,16 +33,16 @@ group: ```dart const BrnButtonPanel( - {Key key, - @required this.mainButtonName, - @required this.mainButtonOnTap, - this.isMainBtnEnable = true, - this.secondaryButtonNameList, - this.secondaryButtonOnTap, - this.secondaryButtonList, - this.horizontalPadding = 20, - this.popDirection = BrnPopupDirection.bottom}) - : super(key: key); + {Key? key, + required this.mainButtonName, + required this.mainButtonOnTap, + this.isMainBtnEnable = true, + this.secondaryButtonNameList, + this.secondaryButtonOnTap, + this.secondaryButtonList, + this.horizontalPadding = 20, + this.popDirection = BrnPopupDirection.bottom}) + : super(key: key); ``` ### 参数说明 diff --git a/docs/components/buttonPanel/BrnTextButtonPanel/BrnTextButtonPanel.md b/docs/components/buttonPanel/BrnTextButtonPanel/BrnTextButtonPanel.md index e4a0a0ef..73e88777 100644 --- a/docs/components/buttonPanel/BrnTextButtonPanel/BrnTextButtonPanel.md +++ b/docs/components/buttonPanel/BrnTextButtonPanel/BrnTextButtonPanel.md @@ -30,12 +30,12 @@ group: ### 构造函数 ```dart -BrnTextButtonPanel( - {Key key, - @required this.nameList, - this.onTap, - this.popDirection = BrnPopupDirection.bottom}) - : super(key: key); +const BrnTextButtonPanel({ + Key? key, + required this.nameList, + this.onTap, + this.popDirection = BrnPopupDirection.bottom, + }) : super(key: key); ``` ### 参数说明 diff --git a/docs/components/charts/BrnBrokenLine/BrnBrokenLine.md b/docs/components/charts/BrnBrokenLine/BrnBrokenLine.md index 92521285..c34e53e9 100644 --- a/docs/components/charts/BrnBrokenLine/BrnBrokenLine.md +++ b/docs/components/charts/BrnBrokenLine/BrnBrokenLine.md @@ -30,9 +30,9 @@ group: ```dart BrnBrokenLine({ - Key key, - @required this.size, - @required this.lines, + Key? key, + required this.size, + required this.lines, this.contentPadding = const EdgeInsets.only(left: 10, right: 10), this.backgroundColor, this.xyDialLineWidth = 2, @@ -44,8 +44,8 @@ BrnBrokenLine({ this.xDialMin, this.xDialMax, this.xDialValues, - this.yDialMin, - this.yDialMax, + required this.yDialMin, + required this.yDialMax, this.yDialValues, this.isShowXHintLine = true, this.isShowYHintLine = false, @@ -54,36 +54,42 @@ BrnBrokenLine({ this.isTipWindowAutoDismiss = true, this.isShowXDialText = false, this.isShowYDialText = false, - }) + }) : super(key: key) { + // 设置自定义 X 轴时,检查 x轴的最大、最小刻度范围 + if (xDialValues != null) { + assert(xDialMin != null); + assert(xDialMax != null); + } + } ``` ### 参数说明: -| 参数名 | 参数类型 | 作用 | 是否必填 | 默认值 | 备注 | -| ---------------------- | --------------------- | ------------------------------------------------------------------- | -------- | ------ | ---- | -| size | Size | 表格宽高 | 是 | | | -| lines | `List` | 要绘制的折线集合 | 是 | | | -| contentPadding | EdgeInsets | 图标内容区域 padding(不包含坐标轴) | 否 | | | -| backgroundColor | Color | 绘制表格的背景色 | 否 | | | -| xyDialLineWidth | double | xy 轴线条的宽度 | 否 | 2 | | -| xDialColor | Color | x 轴的颜色 | 否 | | | -| yDialColor | Color | y 轴的颜色 | 否 | | | -| yHintLineOffset | double | Y 轴辅助线向右偏移量,默认 20(X 轴刻度线也会跟随该偏移量向右偏移) | 否 | 20 | | -| showPointDashLine | bool | 是否展示数据点选中时的辅助线 | 否 | true | | -| dialWidth | double | Y 轴刻度的宽度,和 X 轴刻度的高度 | 否 | 4 | | -| xDialMin | double | X 轴展示范围最小值 | 否 | 0 | | -| xDialMax | double | X 轴展示范围最大值 | 否 | 1 | | -| yDialMin | double | Y 轴展示范围最小值 | 是 | 0 | | -| yDialMax | double | Y 轴展示范围最大值 | 是 | 1 | | -| xDialValues | `List` | X 轴刻度数据 | 否 | | | -| yDialValues | `List` | Y 轴刻度数据 | 否 | | | -| isShowXHintLine | bool | 是否展示 X 轴辅助线 | | true | | -| isShowYHintLine | bool | 是否展示 Y 轴辅助线 | | false | | -| isHintLineSolid | bool | 辅助线是否为虚线 | | true | | -| hintLineColor | Color | 辅助线颜色 | | | | -| isTipWindowAutoDismiss | bool | 点击弹出的 tip 提示框,是否自动消失 | | true | | -| isShowXDialText | bool | 是否展示 X 坐标刻度文案 | | false | | -| isShowYDialText | bool | 是否展示 Y 坐标刻度文案 | | false | | +| 参数名 | 参数类型 | 作用 | 是否必填 | 默认值 | 备注 | +| ---------------------- | --------------------- | ------------------------------------------------------------ | -------- | ------------------------------------ | ---- | +| size | Size | 表格宽高 | 是 | | | +| lines | `List` | 要绘制的折线集合 | 是 | | | +| contentPadding | EdgeInsets | 图标内容区域 padding(不包含坐标轴) | 否 | EdgeInsets.only(left: 10, right: 10) | | +| backgroundColor | Color? | 绘制表格的背景色 | 否 | | | +| xyDialLineWidth | double | xy 轴线条的宽度 | 否 | 2 | | +| xDialColor | Color? | x 轴的颜色 | 否 | | | +| yDialColor | Color? | y 轴的颜色 | 否 | | | +| yHintLineOffset | double | Y 轴辅助线向右偏移量,默认 20(X 轴刻度线也会跟随该偏移量向右偏移) | 否 | 20.0 | | +| showPointDashLine | bool | 是否展示数据点选中时的辅助线 | 否 | true | | +| dialWidth | double | Y 轴刻度的宽度,和 X 轴刻度的高度 | 否 | 4 | | +| xDialMin | double | X 轴展示范围最小值 | 否 | | | +| xDialMax | double | X 轴展示范围最大值 | 否 | | | +| yDialMin | double | Y 轴展示范围最小值 | 是 | | | +| yDialMax | double | Y 轴展示范围最大值 | 是 | | | +| xDialValues | `List` | X 轴刻度数据 | 否 | | | +| yDialValues | `List`? | Y 轴刻度数据 | 否 | | | +| isShowXHintLine | bool | 是否展示 X 轴辅助线 | | true | | +| isShowYHintLine | bool | 是否展示 Y 轴辅助线 | | false | | +| isHintLineSolid | bool | 辅助线是否为虚线 | | true | | +| hintLineColor | Color? | 辅助线颜色 | | | | +| isTipWindowAutoDismiss | bool | 点击弹出的 tip 提示框,是否自动消失 | | true | | +| isShowXDialText | bool | 是否展示 X 坐标刻度文案 | | false | | +| isShowYDialText | bool | 是否展示 Y 坐标刻度文案 | | false | | ### 其他数据结构 @@ -101,15 +107,14 @@ class BrnPointData { Offset offset; /// 点要展示的内容 - String pointText; + String? pointText; /// 点展示内容样式 - TextStyle pointTextStyle; + TextStyle? pointTextStyle; /// 折线节点的点击击事件是否可用 bool isClickable; - /// 每个点的点击行为配置数据 BrnLineTouchData lineTouchData; } ``` @@ -119,7 +124,7 @@ class BrnPointData { ``` class BrnLineTouchData { /// 用于临时存储要展示 tip 内容在坐标的位置 - double x, y; + double? x, y; /// 要展示 tip 的相对偏移量 Offset tipOffset; @@ -127,11 +132,8 @@ class BrnLineTouchData { /// 要展示的 tip 的宽高 Size tipWindowSize; - /// 折线节点点击事件是否可用 - bool enabled; - /// 点击回调,由于返回 展示内容(String 或 Widget) - Function() onTouch; + Function()? onTouch; } ``` @@ -147,22 +149,22 @@ class BrnPointsLine { double lineWidth; /// Line渐变色,从曲线到x轴从上到下的闭合颜色集 - List shaderColors; + List? shaderColors; /// 曲线或折线的颜色 Color lineColor; /// 点外圈的颜色 - Color pointColor; + Color? pointColor; /// 点的外半径参数 double pointRadius; /// 点内圈的颜色 - Color pointInnerColor; + Color? pointInnerColor; /// 点内圈的半径 - double pointInnerRadius; + double? pointInnerRadius; /// 是否显示x轴的文字,用来处理多个线条绘制的时候,同一x轴坐标不需要绘制多次,则只需要将多条线中一个标记绘制即可 bool isShowXDial; @@ -183,10 +185,10 @@ class BrnPointsLine { ```dart class BrnDialItem { /// 刻度标志内容 - String dialText; + String? dialText; /// 刻度标志样式 - TextStyle dialTextStyle; + TextStyle? dialTextStyle; /// x,y 轴刻度值。用于刻度在坐标的真实定位 double value; diff --git a/docs/components/charts/BrnDoughnutChart/BrnDoughnutChart.md b/docs/components/charts/BrnDoughnutChart/BrnDoughnutChart.md index d9d6206c..69f0ae97 100644 --- a/docs/components/charts/BrnDoughnutChart/BrnDoughnutChart.md +++ b/docs/components/charts/BrnDoughnutChart/BrnDoughnutChart.md @@ -29,37 +29,39 @@ group: ```dart BrnDoughnutChart( - {this.width = 0, - this.height = 0, - this.padding = EdgeInsets.zero, - this.ringWidth = 50, - this.data, - this.fontSize = 12, - this.fontColor = Colors.white, - this.selectedItem, - this.showTitleWhenSelected = false, - this.brnDoughnutSelectCallback}); + {this.width = 0, + this.height = 0, + this.padding = EdgeInsets.zero, + this.ringWidth = 50, + required this.data, + this.fontSize = 12, + this.fontColor = Colors.white, + this.selectedItem, + this.showTitleWhenSelected = false, + this.selectCallback}); ``` ### 参数说明 | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| width | double | 宽 | 是 | 0 | -| height | double | 高 | 是 | 0 | +| width | double | 宽 | 否 | 0 | +| height | double | 高 | 否 | 0 | | padding | EdgeInsetsGeometry | 内边距 | 否 | EdgeInsets.zero | | ringWidth | double | 圆环宽度 | 否 | 50 | | data | `List` | 饼图数据 | 是 | | | fontSize | double | 选中时展示文字大小 | 否 | 12 | -| fontColor | Color | 选中时展示文字颜色 | 否 | | -| selectedItem | BrnDoughnutDataItem | 选中的项目 | 否 | | -| selectCallback | BrnDoughnutSelectCallback | 选中项目时候的回掉 | 否 | | -| showTitleWhenSelected | bool | 是否仅在选中时展示 title | 否 | | +| fontColor | Color | 选中时展示文字颜色 | 否 | Colors.white | +| selectedItem | BrnDoughnutDataItem? | 选中的项目 | 否 | | +| selectCallback | BrnDoughnutSelectCallback? | 选中项目时候的回掉 | 否 | | +| showTitleWhenSelected | bool | 是否仅在选中时展示 title | 否 | false | ### 其他数据 ```dart -DoughnutChartLegend({this.legendStyle = BrnDoughnutChartLegendStyle.wrap, this.data}); +DoughnutChartLegend( + {this.legendStyle = BrnDoughnutChartLegendStyle.wrap, + required this.data}); ``` ## 四、代码演示 @@ -79,7 +81,7 @@ Column( data: dataList, selectedItem: selectedItem, showTitleWhenSelected: true, - selectCallback: (BrnDoughnutDataItem selectedItem) { + selectCallback: (BrnDoughnutDataItem? selectedItem) { setState(() { this.selectedItem = selectedItem; }); diff --git a/docs/components/charts/BrnFunnelChart/BrnFunnelChart.md b/docs/components/charts/BrnFunnelChart/BrnFunnelChart.md index e7002b9e..0ef3f561 100644 --- a/docs/components/charts/BrnFunnelChart/BrnFunnelChart.md +++ b/docs/components/charts/BrnFunnelChart/BrnFunnelChart.md @@ -47,36 +47,36 @@ group: ```dart BrnFunnelChart({ - Key key, - @required this.layerCount, - @required this.markerCount, - @required this.layerPainter, - @required MarkerBuilder builder, - this.shape = FunnelShape.LeftAndRight, - this.maxLayerWidth = 200, - this.minLayerWidth = 0, - this.layerHeight = 40, - this.layerMargin = 0, - this.childOffset = Offset.zero, - this.alignment = MarkerAlignment.right, -}) + Key? key, + required this.layerCount, + required this.markerCount, + required this.layerPainter, + required MarkerBuilder builder, + this.shape = FunnelShape.leftAndRight, + this.maxLayerWidth = 200, + this.minLayerWidth = 0, + this.layerHeight = 40, + this.layerMargin = 0, + this.childOffset = Offset.zero, + this.alignment = MarkerAlignment.right, + }) ``` ### 参数说明 -| 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | 备注 | -| ------------- | --------------------- | --------------------------- | -------- | ------------------------ | -------------------------------------------------------------------------------------------- | -| layerCount | int | 漏斗图的层级数 | 是 | | | -| markerCount | int | 漏斗图的标签个数 | 是 | | 标签个数和层技数必须相等或者是少一个 | -| layerPainer | BrnFunnelLayerPainter | 用于控制绘制每一次层的文案 | 是 | | 见详细 BrnFunnelLayerPainter 介绍 | -| builder | Function | 用于提供每一层的标签 Widget | 是 | | | +| 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | 备注 | +| ------------- | --------------------- | --------------------------- | -------- | ------------------------ | ------------------------------------------------------------ | +| layerCount | int | 漏斗图的层级数 | 是 | | | +| markerCount | int | 漏斗图的标签个数 | 是 | | 标签个数和层技数必须相等或者是少一个 | +| layerPainer | BrnFunnelLayerPainter | 用于控制绘制每一次层的文案 | 是 | | 见详细 BrnFunnelLayerPainter 介绍 | +| builder | Function | 用于提供每一层的标签 Widget | 是 | | | | shape | FunnelShape | 用于控制漏斗的形状 | 否 | FunnelShape.LeftAndRight | FunnelShape.LeftAndRight 表示倒三角的漏斗图形状 FunnelShape.LeftorRight 表示梯形形状的漏斗图 | -| maxLayerWidth | double | 漏斗每层的最大宽度 | 否 | 200 | | -| minLayerWidth | double | 漏斗每层的最小宽度 | 否 | 0 | | -| layerHeight | double | 漏斗每层的高度 | 否 | 40 | | -| layerMargin | double | 漏斗每层的间距 | 否 | 0 | | -| childOffset | Offset | 标签的偏移量 | 否 | Offset.Zero | 标签在初始摆放位置上的相对偏移量 | -| alignment | MarkerAlignment | 标签的对齐方式 | 否 | | 总共有三种情况偏左,居中和偏右。当漏斗 shape 为 FunnelShape.LeftorRight 时不能设置成居中 | +| maxLayerWidth | double | 漏斗每层的最大宽度 | 否 | 200 | | +| minLayerWidth | double | 漏斗每层的最小宽度 | 否 | 0 | | +| layerHeight | double | 漏斗每层的高度 | 否 | 40 | | +| layerMargin | double | 漏斗每层的间距 | 否 | 0 | | +| childOffset | Offset | 标签的偏移量 | 否 | Offset.Zero | 标签在初始摆放位置上的相对偏移量 | +| alignment | MarkerAlignment | 标签的对齐方式 | 否 | MarkerAlignment.right | 总共有三种情况偏左,居中和偏右。当漏斗 shape 为 FunnelShape.leftOrRight 时不能设置成居中 | #### BrnFunnelLayerPainter @@ -107,7 +107,7 @@ abstract class BrnFunnelLayerPainter { ```dart BrnFunnelChart( - shape: FunnelShape.LeftOrRight, + shape: FunnelShape.leftOrRight, alignment: MarkerAlignment.right, maxLayerWidth: maxLayerWidth, minLayerWidth: minLayerWidth, diff --git a/docs/components/charts/BrnProgressBarChart/BrnProgressBarChart.md b/docs/components/charts/BrnProgressBarChart/BrnProgressBarChart.md index d989efcb..ac64e1c4 100644 --- a/docs/components/charts/BrnProgressBarChart/BrnProgressBarChart.md +++ b/docs/components/charts/BrnProgressBarChart/BrnProgressBarChart.md @@ -32,40 +32,49 @@ group: ```dart BrnProgressBarChart( - {Key key, - this.minWidth = 0, - this.padding = const EdgeInsets.all(20), - this.barChartStyle = BarChartStyle.vertical, - this.xAxis, - this.yAxis, - this.barBundleList, - this.barGroupSpace = 30, - this.singleBarWidth = 30, - this.barMaxValue, - this.selectedHintTextColor = Colors.white, - this.selectedHintTextBackgroundColor = Colors.black, - this.onBarItemClickInterceptor, - this.barChartSelectCallback, - this.height = 300}) + {Key? key, + this.minWidth = 0, + this.padding = const EdgeInsets.all(20), + this.barChartStyle = BarChartStyle.vertical, + required this.xAxis, + required this.yAxis, + required this.barBundleList, + this.barGroupSpace = 30, + this.singleBarWidth = 30, + this.barMaxValue = 0, + this.selectedHintTextColor = Colors.white, + this.selectedHintTextBackgroundColor = Colors.black, + this.onBarItemClickInterceptor, + this.barChartSelectCallback, + this.height = 300}) + : super(key: key) { + if (BarChartStyle.horizontal == barChartStyle) { + assert(barBundleList[0].barList.length == yAxis.axisItemList.length, + '水平柱状图个数与Y轴坐标数目要相等'); + } else if (BarChartStyle.vertical == barChartStyle) { + assert(barBundleList[0].barList.length == xAxis.axisItemList.length, + '竖直柱状图个数与X轴坐标数目要相等'); + } + } ``` ### 参数说明 | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| minWidth | double | 最小宽度 | | 0 | +| minWidth | double | 最小宽度 | 否 | 0 | | height | double | 图标高度 | 否 | 300 | -| padding | EdgeInsetsGeometry | 内边距 | | EdgeInsets.all(20) | -| barChartStyle | BarChartStyle | 水平/竖直方向条形图 | | BarChartStyle.vertical | +| padding | EdgeInsetsGeometry | 内边距 | 否 | EdgeInsets.all(20) | +| barChartStyle | BarChartStyle | 水平/竖直方向条形图 | 否 | BarChartStyle.vertical | | xAxis | ChartAxis | x轴数据 | 是 | | | yAxis | ChartAxis | y轴数据 | 是 | | | barBundleList | `List` | 柱形数据 | 是 | | -| barGroupSpace | double | 柱状图间距 | | 30 | -| singleBarWidth | double | 条形宽度 | | 30 | -| barMaxValue | double | 柱状图最大值 | | | -| selectedHintTextColor | Color | 选中柱状图提示文案文本颜色 | | Colors.white | -| selectedHintTextBackgroundColor | Color | 选中柱状图提示文案文本背景颜色 | | Colors.black | -| barChartSelectCallback | void Function(BarItem barItem) | 选中柱状图时候的回调 | | | -| onBarItemClickInterceptor | bool OnBarItemClickInterceptor(int barBundleIndex, BarBundle barBundle, int barGroupIndex, BarItem barItem) | 柱状图是否可点击回调 | | | +| barGroupSpace | double | 柱状图间距 | 否 | 30 | +| singleBarWidth | double | 条形宽度 | 否 | 30 | +| barMaxValue | double | 柱状图最大值 | 否 | 0 | +| selectedHintTextColor | Color | 选中柱状图提示文案文本颜色 | 否 | Colors.white | +| selectedHintTextBackgroundColor | Color | 选中柱状图提示文案文本背景颜色 | 否 | Colors.black | +| barChartSelectCallback | void Function(BarItem barItem) | 选中柱状图时候的回调 | 否 | | +| onBarItemClickInterceptor | bool OnBarItemClickInterceptor(int barBundleIndex, BarBundle barBundle, int barGroupIndex, BarItem barItem) | 柱状图是否可点击回调 | 否 | | ## 四、代码演示 diff --git a/docs/components/charts/BrnProgressChart/BrnProgressChart.md b/docs/components/charts/BrnProgressChart/BrnProgressChart.md index f87aea85..197001b8 100644 --- a/docs/components/charts/BrnProgressChart/BrnProgressChart.md +++ b/docs/components/charts/BrnProgressChart/BrnProgressChart.md @@ -31,19 +31,19 @@ value属性值必须在0 到 1 之间。 ```dart -BrnProgressChart( - {Key key, - this.width = 0, - this.height = 0, - this.value = 0.2, - this.indicatorLeftPadding = 10, - this.textStyle = const TextStyle(color: Colors.white), - this.brnProgressIndicatorBuilder, - this.colors = const [Colors.blueAccent, Colors.blue], - this.backgroundColor = Colors.lightBlueAccent, - this.showAnimation = false}) - : assert(0 <= value && value <= 1, 'value 必须在 0 到 1 之间'), - super(key: key); +const BrnProgressChart( + {Key? key, + this.width = 0, + this.height = 0, + this.value = 0.2, + this.indicatorLeftPadding = 10, + this.textStyle = const TextStyle(color: Colors.white), + this.brnProgressIndicatorBuilder, + this.colors = const [Colors.blueAccent, Colors.blue], + this.backgroundColor = Colors.lightBlueAccent, + this.showAnimation = false}) + : assert(0 <= value && value <= 1, 'value 必须在 0 到 1 之间'), + super(key: key); ``` ### 参数说明 @@ -51,7 +51,7 @@ BrnProgressChart( | --- | --- | --- | --- | --- | | width | double | 宽度 | 是 | 0 | | height | double | 高度 | 是 | 0 | -| value | double | 进度图进度值,必须在 0 到 1 之间 | 是 | 0 | +| value | double | 进度图进度值,必须在 0 到 1 之间 | 是 | 0.2 | | indicatorLeftPadding | double | 进度条上自定义Widget的左侧padding | 否 | 10 | | textStyle | TextStyle | 展示默认进度indicator的时候的文本样式 | 否 | TextStyle(color: Colors.white) | | brnProgressIndicatorBuilder | BrnProgressIndicatorBuilder | 自定义进度条上面的Widget,默认显示为文本 | 否 | null | diff --git a/docs/components/charts/BrnRadarChart/BrnRadarChart.md b/docs/components/charts/BrnRadarChart/BrnRadarChart.md index 5530194e..4ce76c92 100644 --- a/docs/components/charts/BrnRadarChart/BrnRadarChart.md +++ b/docs/components/charts/BrnRadarChart/BrnRadarChart.md @@ -38,21 +38,31 @@ group: ```dart BrnRadarChart({ - Key key, - @required this.provider, - @required MarkerBuilder builder, - this.radius = 50, - this.levelCount = 3, - this.maxValue = 10, - this.minValue = 0, - this.markerMargin = 4, - this.sidesCount = 5, - this.offset, - this.axisLineColor = const Color(0xFFCCCCCC), - this.crossedAxisLine = false, - this.animateProgress = 1.0, - this.rotateAngle = 0, -}) + Key? key, + required this.provider, + required MarkerBuilder builder, + this.radius = 50, + this.levelCount = 3, + this.maxValue = 10, + this.minValue = 0, + this.markerMargin = 4, + this.sidesCount = 5, + this.offset, + this.axisLineColor = const Color(0xFFCCCCCC), + this.crossedAxisLine = false, + this.animateProgress = 1.0, + this.rotateAngle = 0, + }) : assert(minValue < maxValue), + assert(sidesCount >= 3), + super( + key: key, + children: () { + List children = []; + for (int i = 0; i < sidesCount; i++) { + children.add(builder(i)); + } + return children; + }()); ``` #### 默认风格 @@ -61,71 +71,69 @@ BrnRadarChart({ ```dart BrnRadarChart.defaultStyle({ - Key key, - this.radius = 50, - this.levelCount = 3, - this.maxValue = 10, - this.minValue = 0, - this.markerMargin = 4, - this.sidesCount = 5, - this.rotateAngle = 0, - this.crossedAxisLine = false, - this.offset, - @required List tagNames, - @required List> data, - }) : assert(sidesCount != null), - assert(tagNames != null), - assert(data != null), - assert(tagNames.length == sidesCount), - assert(minValue < maxValue), - assert(data.length <= defaultRadarChartStyles.length), - this.animateProgress = 1.0, - this.axisLineColor = const Color(0xFFCCCCCC), - this.provider = DefaultRadarProvider(data), - super( - key: key, - children: () { - List children = List(); - for (int i = 0; i < sidesCount; i++) { - children.add(Container( - constraints: BoxConstraints( - maxWidth: 60, - maxHeight: 32, - ), - child: Text( - tagNames[i], - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: Color(0xFF222222), - fontSize: 12, - fontWeight: FontWeight.w600), - ), - )); - } - return children; -}()); + Key? key, + this.radius = 50, + this.levelCount = 3, + this.maxValue = 10, + this.minValue = 0, + this.markerMargin = 4, + this.sidesCount = 5, + this.rotateAngle = 0, + this.crossedAxisLine = false, + this.offset, + required List tagNames, + required List> data, + }) : assert(sidesCount >= 3), + assert(tagNames.length == sidesCount), + assert(minValue < maxValue), + assert(data.length <= defaultRadarChartStyles.length), + this.animateProgress = 1.0, + this.axisLineColor = const Color(0xFFCCCCCC), + this.provider = DefaultRadarProvider(data), + super( + key: key, + children: () { + List children = []; + for (int i = 0; i < sidesCount; i++) { + children.add(Container( + constraints: BoxConstraints( + maxWidth: 60, + maxHeight: 32, + ), + child: Text( + tagNames[i], + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: Color(0xFF222222), + fontSize: 12, + fontWeight: FontWeight.w600), + ), + )); + } + return children; + }()); ``` ### 参数说明 -| 参数名 | 参数类型 | 作用 | 是否必填 | 默认值 | 备注 | -| --------------- | ------------------------- | ---------------------------------------------- | ---------------------------------------------------- | ----------------- | -------------------------------------------------------------------------------------- | -| radius | double | 雷达图半径(多边形外接圆的半径) | 否 | 50 | | -| levelCount | int | 数据可划分的区间个数 | 否 | 3 | 每个区间取值范围等分 | -| maxValue | double | 数据的最大值 | 否 | 10 | 提供的数据要不大于最大值,否则当最大值处理 | -| minValue | double | 数据的最小值 | 否 | 0 | 提供的数据要不小于最小值,否则当最小值处理 | -| markerMargin | double | 标签和雷达图顶点的间距 | 否 | 4 | | -| sidesCount | int | 雷达数据的维度(多边形的边数) | 否 | 5 | 边数应该和单个雷达数据的个数一致,否则可能出错 | +| 参数名 | 参数类型 | 作用 | 是否必填 | 默认值 | 备注 | +| --------------- | ------------------------- | ---------------------------------------------- | ---------------------------------------------------- | ----------------- | ------------------------------------------------------------ | +| radius | double | 雷达图半径(多边形外接圆的半径) | 否 | 50 | | +| levelCount | int | 数据可划分的区间个数 | 否 | 3 | 每个区间取值范围等分 | +| maxValue | double | 数据的最大值 | 否 | 10 | 提供的数据要不大于最大值,否则当最大值处理 | +| minValue | double | 数据的最小值 | 否 | 0 | 提供的数据要不小于最小值,否则当最小值处理 | +| markerMargin | double | 标签和雷达图顶点的间距 | 否 | 4 | | +| sidesCount | int | 雷达数据的维度(多边形的边数) | 否 | 5 | 边数应该和单个雷达数据的个数一致,否则可能出错 | | data | `List>` | 提供所需绘制的雷达图个数以及各雷达图顶点的数值 | 是 | | 是个二维数组,第一维决定了需要绘制多少个雷达在图表中,第二维表示每雷达每一个顶点的数值 | -| tagNames | `List` | 各个顶点的标签文案 | 是 | | 文案的个数与顶点个数应保持一致 | -| rotateAngle | double | 整个雷达图旋转角度 | 否 | 0 | | -| crossedAxisLine | bool | 是否展示中间十字交叉线 | | | | -| offset | `List` | 每个标注文案的偏移量 | 否 | [Offset.zero] | 个数应与 sidesCount 保持一致 | -| provider | BrnRadarChartDataProvider | 提供绘制雷达图所需要的数据 | 使用默认构造方法必传。默认样式无此参数配置。 | | | -| builder | MarkerBuilder | 自定义雷达图的标签(标签由使用者提供 widget) | 使用默认构造方法必传。默认样式无此参数配置。 | | | -| axisLineColor | Color | 背景多边形轴颜色 | 默认构造方法有此配置,非必传。默认样式无此参数配置。 | Color(0xFFCCCCCC) | | -| animateProgress | double | 控制带动画效果绘制时的绘制快慢 | 默认构造方法有此配置,非必传。默认样式无此参数配置。 | 1.0 | | +| tagNames | `List` | 各个顶点的标签文案 | 是 | | 文案的个数与顶点个数应保持一致 | +| rotateAngle | double | 整个雷达图旋转角度 | 否 | 0 | | +| crossedAxisLine | bool | 是否展示中间十字交叉线 | | | | +| offset | `List?` | 每个标注文案的偏移量 | 否 | [Offset.zero] | 个数应与 sidesCount 保持一致 | +| provider | BrnRadarChartDataProvider | 提供绘制雷达图所需要的数据 | 使用默认构造方法必传。默认样式无此参数配置。 | | | +| builder | MarkerBuilder | 自定义雷达图的标签(标签由使用者提供 widget) | 使用默认构造方法必传。默认样式无此参数配置。 | | | +| axisLineColor | Color | 背景多边形轴颜色 | 默认构造方法有此配置,非必传。默认样式无此参数配置。 | Color(0xFFCCCCCC) | | +| animateProgress | double | 控制带动画效果绘制时的绘制快慢 | 默认构造方法有此配置,非必传。默认样式无此参数配置。 | 1.0 | | 首先介绍两个构造函数中涉及到的相关的类 diff --git a/docs/components/dialog/BrnDialog/BrnDialog.md b/docs/components/dialog/BrnDialog/BrnDialog.md index 2568564c..4a272260 100644 --- a/docs/components/dialog/BrnDialog/BrnDialog.md +++ b/docs/components/dialog/BrnDialog/BrnDialog.md @@ -35,45 +35,43 @@ group: ```dart BrnDialog({ - this.showIcon = false, - this.iconImage, - this.titleText, - this.messageText, - this.titleWidget, - this.contentWidget, - this.warningText, - this.warningWidget, - this.actionsWidget, - this.brnDialogStyle, - this.divider = cDividerLine, - this.verticalDivider = cVerticalDivider, - this.actionsText, - this.indexedActionCallback, - this.dismiss = true, - this.themeData, - this.titleMaxLines = cTitleMaxLines, -}); + Key? key, + this.showIcon = false, + this.iconImage, + this.titleText, + this.messageText, + this.titleWidget, + this.contentWidget, + this.warningText, + this.warningWidget, + this.actionsWidget, + this.divider = cDividerLine, + this.verticalDivider = cVerticalDivider, + this.actionsText, + this.indexedActionCallback, + this.themeData, + this.titleMaxLines = cTitleMaxLines, + }) : super(key: key); ``` ### 参数配置 | **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | | showIcon | bool | 是否显示icon | 否 | false | -| iconImage | Image | 头部显示的icon 默认为alert | 否 | 主题色alert | -| titleText | String | 对话框的标题文案 | 否 | 无 | -| messageText | String | 对话框中间的显示文本 | 否 | 无 | -| warningText | String | 对话框的警示文案文本 | 否 | 无 | -| actionsText | List | 对话框底部的按钮 | 否 | 无 | -| titleWidget | Widget | 自定义widget的标题 | 否 | 无 | -| contentWidget | Widget | 自定义widget的内容 | 否 | 无 | -| warningWidget | Widget | 自定义widget的警示内容 | 否 | 无 | -| actionsWidget | List | 对话框底部的自定义widget按钮 | 否 | 无 | -| indexedActionCallback | DialogIndexedActionClickCallback | 对话框底部的点击回调 | 否 | 无 | -| brnDialogStyle | BrnDialogStyle | 对话框的样式:主色调间距等等 | 否 | 自定义样式 | +| iconImage | Image? | 头部显示的icon 默认为alert | 否 | 主题色alert | +| titleText | String? | 对话框的标题文案 | 否 | 无 | +| messageText | String? | 对话框中间的显示文本 | 否 | 无 | +| warningText | String? | 对话框的警示文案文本 | 否 | 无 | +| actionsText | List? | 对话框底部的按钮 | 否 | 无 | +| titleWidget | Widget? | 自定义widget的标题 | 否 | 无 | +| contentWidget | Widget? | 自定义widget的内容 | 否 | 无 | +| warningWidget | Widget? | 自定义widget的警示内容 | 否 | 无 | +| actionsWidget | List? | 对话框底部的自定义widget按钮 | 否 | 无 | +| indexedActionCallback | DialogIndexedActionClickCallback? | 对话框底部的点击回调 | 否 | 无 | | divider | Divider | 底部按钮的水平和上面内容的水平分割线 | 否 | 高1像素的L1分割线 | | verticalDivider | VerticalDivider | 底部按钮之间的分割线 | 否 | 宽1像素的L1分割线 | | titleMaxLines | int | 标题文本的最大展示行数 | 否 | 2 | -| dismiss | bool | 点击底部按钮是否关闭弹窗 | 否 | true | +| themeData | BrnDialogConfig? | 主题配置 | 否 | 无 | ### 快捷使用类BrnDialogManager @@ -86,19 +84,18 @@ BrnDialog({ | context | BuildContext | 用于显示弹窗的上下文 | 是 | 五 | | label | String | 弹窗的按钮文案 | 是 | 无 | | showIcon | bool | 是否显示icon | 否 | false | -| iconImage | Image | 头部显示的icon 默认为alert | 否 | 主题色alert | -| title | String | 对话框的标题文案 | 否 | 无 | -| titleWidget | Widget | 自定义widget的标题 | 否 | 无 | -| message | String | 对话框中间的显示文本 | 否 | 无 | -| messageWidget | Widget | 自定义widget的内容 | 否 | 无 | -| warning | String | 对话框的警示文案文本 | 否 | 无 | +| iconWidget | Image? | 头部显示的icon 默认为alert | 否 | 主题色alert | +| title | String? | 对话框的标题文案 | 否 | 无 | +| titleWidget | Widget? | 自定义widget的标题 | 否 | 无 | +| message | String? | 对话框中间的显示文本 | 否 | 无 | +| messageWidget | Widget? | 自定义widget的内容 | 否 | 无 | +| warning | String? | 对话框的警示文案文本 | 否 | 无 | | warningWidget | Widget | 自定义widget的警示内容 | 否 | 无 | -| dismiss | bool | 点击对话框按钮之后,对话框是否消失 | 否 | true 消失 | -| labelWidget | Widget | 对话框底部的自定义widget按钮 | 否 | 无 | -| onTap | GestureTapCallback | 对话框按钮的点击回调 | 否 | 无 | -| indexedActionCallback | DialogIndexedActionClickCallback | 对话框底部的点击回调 | 否 | 无 | -| dialogStyle | BrnDialogStyle | 对话框的样式:主色调间距等等 | 否 | B端样式 | +| labelWidget | Widget? | 对话框底部的自定义widget按钮 | 否 | 无 | +| onTap | GestureTapCallback? | 对话框按钮的点击回调 | 否 | 无 | | barrierDismissible | bool | 点击对话框遮罩是否消失对话框 | 否 | true 关闭 | +| titleMaxLines | int | 标题最大行数 | 否 | 3 | +| themeData | BrnDialogConfig? | 主题配置 | 否 | 无 | #### 效果2: showConfirmDialog(双按钮) @@ -110,20 +107,21 @@ BrnDialog({ | cancel | String | 弹窗的左侧文案 | 是 | 无 | | confirm | String | 弹窗的右侧文案 | 是 | 无 | | showIcon | bool | 是否显示icon | 否 | false | -| iconImage | Image | 头部显示的icon 默认为alert | 否 | 主题色alert | -| title | String | 对话框的标题文案 | 否 | 无 | -| titleWidget | Widget | 自定义widget的标题 | 否 | 无 | -| message | String | 对话框中间的显示文本 | 否 | 无 | -| messageWidget | Widget | 自定义widget的内容 | 否 | 无 | -| warning | String | 对话框的警示文案文本 | 否 | 无 | -| warningWidget | Widget | 自定义widget的警示内容 | 否 | 无 | +| iconWidget | Image? | 头部显示的icon 默认为alert | 否 | 主题色alert | +| title | String? | 对话框的标题文案 | 否 | 无 | +| titleWidget | Widget? | 自定义widget的标题 | 否 | 无 | +| message | String? | 对话框中间的显示文本 | 否 | 无 | +| messageWidget | Widget? | 自定义widget的内容 | 否 | 无 | +| warning | String? | 对话框的警示文案文本 | 否 | 无 | +| warningWidget | Widget? | 自定义widget的警示内容 | 否 | 无 | | dismiss | bool | 点击对话框按钮之后,对话框是否消失 | 否 | true 消失 | -| cancelWidget | Widget | 对话框底部左侧的自定义widget按钮 | 否 | 无 | -| conformWidget | Widget | 对话框底部右侧的自定义widget按钮 | 否 | 无 | -| cancelTap | GestureTapCallback | 对话框左侧按钮的点击回调 | 否 | 无 | -| confirmTap | GestureTapCallback | 对话框右侧按钮的点击回调 | 否 | 无 | -| dialogStyle | BrnDialogStyle | 对话框的样式:主色调间距等等 | 否 | B端样式 | +| cancelWidget | Widget? | 对话框底部左侧的自定义widget按钮 | 否 | 无 | +| conformWidget | Widget? | 对话框底部右侧的自定义widget按钮 | 否 | 无 | +| onCancel | GestureTapCallback? | 对话框左侧按钮的点击回调 | 否 | 无 | +| onConfirm | GestureTapCallback? | 对话框右侧按钮的点击回调 | 否 | 无 | | barrierDismissible | bool | 点击对话框遮罩是否消失对话框 | 否 | true 关闭 | +| titleMaxLines | int | 标题最大行数 | 否 | 3 | +| themeData | BrnDialogConfig? | 主题配置 | 否 | 无 | #### 效果3: showMoreButtonDialog(多按钮) @@ -132,20 +130,20 @@ BrnDialog({ | **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | | context | BuildContext | 用于显示弹窗的上下文 | 是 | 五 | -| actionsText | List | 对话框底部的按钮 | 否 | 无 | +| actions | List | 对话框底部的按钮 | 否 | 无 | | showIcon | bool | 是否显示icon | 否 | false | -| iconWidget | Image | 头部显示的icon 默认为alert | 否 | 主题色alert | -| title | String | 对话框的标题文案 | 否 | 无 | -| titleWidget | Widget | 自定义widget的标题 | 否 | 无 | -| message | String | 对话框中间的显示文本 | 否 | 无 | -| messageWidget | Widget | 自定义widget的内容 | 否 | 无 | -| warning | String | 对话框的警示文案文本 | 否 | 无 | -| warningWidget | Widget | 自定义widget的警示内容 | 否 | 无 | -| dismiss | bool | 点击对话框按钮之后,对话框是否消失 | 否 | true 消失 | -| actionsWidget | List | 对话框底部的自定义widget按钮 | 否 | 无 | -| indexedActionClickCallback | DialogIndexedActionClickCallback | 对话按钮点击的回调 | 否 | 无 | -| dialogStyle | BrnDialogStyle | 对话框的样式:主色调间距等等 | 否 | B端样式 | +| iconWidget | Image? | 头部显示的icon 默认为alert | 否 | 主题色alert | +| title | String? | 对话框的标题文案 | 否 | 无 | +| titleWidget | Widget? | 自定义widget的标题 | 否 | 无 | +| message | String? | 对话框中间的显示文本 | 否 | 无 | +| messageWidget | Widget? | 自定义widget的内容 | 否 | 无 | +| warning | String? | 对话框的警示文案文本 | 否 | 无 | +| warningWidget | Widget? | 自定义widget的警示内容 | 否 | 无 | +| actionsWidget | List? | 对话框底部的自定义widget按钮 | 否 | 无 | +| indexedActionClickCallback | DialogIndexedActionClickCallback? | 对话按钮点击的回调 | 否 | 无 | +| titleMaxLines | int | 标题最大行数 | 否 | 3 | | barrierDismissible | bool | 点击对话框遮罩是否消失对话框 | 否 | true 关闭 | +| themeData | BrnDialogConfig? | 主题配置 | 否 | 无 | ## 四、效果及代码展示 diff --git a/docs/components/dialog/BrnEnhanceOperationDialog/BrnEnhanceOperationDialog.md b/docs/components/dialog/BrnEnhanceOperationDialog/BrnEnhanceOperationDialog.md index 725c797c..a51e29c7 100644 --- a/docs/components/dialog/BrnEnhanceOperationDialog/BrnEnhanceOperationDialog.md +++ b/docs/components/dialog/BrnEnhanceOperationDialog/BrnEnhanceOperationDialog.md @@ -31,23 +31,23 @@ group: ```dart BrnEnhanceOperationDialog({ - this.iconType, - this.customIconWidget, - this.context, - this.titleText, - this.descText, - this.mainButtonText, - this.secondaryButtonText, - this.mainButtonCallback, - this.secondaryButtonCallback, - this.themeData, -}) { - this.themeData ??= BrnDialogConfig(); - this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) - .dialogConfig - .merge(this.themeData); -} + this.iconType = BrnDialogConstants.iconAlert, + this.customIconWidget, + required this.context, + this.titleText, + this.descText, + this.mainButtonText = '确认', + this.secondaryButtonText, + this.onMainButtonClick, + this.onSecondaryButtonClick, + this.themeData, + }) { + this.themeData ??= BrnDialogConfig(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .dialogConfig + .merge(this.themeData); + } ``` @@ -57,14 +57,14 @@ BrnEnhanceOperationDialog({ | --- | --- | --- | --- | --- | | context | BuildContext | BuidContext | 是 | 空 | | iconType | int | 在预设的提示图标中选择一个座位图标(提示:BrnDialogConstants**.**ICON\_ALERT警示:BrnDialogConstants**.**ICON\_WARNNING成功:BrnDialogConstants**.**ICON\_SUCCESS自定义图标:BrnDialogConstants.ICON\_CUSTOM) | 否 | 0,ICON\_ALERT | -| customIconWidget | Widget | 自定义图标 | 否 | | -| titleText | String | 弹框标题文案(为空则**不显示**标题) | 否 | 无 | -| descText | String | 弹框辅助信息文案(为空则**不显示**辅助信息) | 否 | 无 | +| customIconWidget | Widget? | 自定义图标 | 否 | | +| titleText | String? | 弹框标题文案(为空则**不显示**标题) | 否 | 无 | +| descText | String? | 弹框辅助信息文案(为空则**不显示**辅助信息) | 否 | 无 | | mainButtonText | String | 主要按钮文案 | 否 | 无 | -| secondaryButtonText | String | 次要按钮文案(为空则**不显示**次要按钮) | 否 | 无 | -| mainButtonCallBack | VoidCallback | 点击**主要按钮**后回调方法,使用者**根据参数自行配置响应动作**。 | 否 | 空 | -| secondaryButtonCallBack | VoidCallback | 点击**次要按钮**后回调方法,使用者**根据参数自行配置响应动作**。 | 否 | 空 | -| themeData | BrnDialogConfig | 弹窗主题配置 | 否 | 默认取全局配置 | +| secondaryButtonText | String? | 次要按钮文案(为空则**不显示**次要按钮) | 否 | 无 | +| mainButtonCallBack | VoidCallback? | 点击**主要按钮**后回调方法,使用者**根据参数自行配置响应动作**。 | 否 | 空 | +| secondaryButtonCallBack | VoidCallback? | 点击**次要按钮**后回调方法,使用者**根据参数自行配置响应动作**。 | 否 | 空 | +| themeData | BrnDialogConfig? | 弹窗主题配置 | 否 | 默认取全局配置 | ## 四、代码演示 diff --git a/docs/components/dialog/BrnLoadingDialog/BrnLoadingDialog.md b/docs/components/dialog/BrnLoadingDialog/BrnLoadingDialog.md index 28c9c828..69263fe8 100644 --- a/docs/components/dialog/BrnLoadingDialog/BrnLoadingDialog.md +++ b/docs/components/dialog/BrnLoadingDialog/BrnLoadingDialog.md @@ -24,7 +24,8 @@ group: ### 构造函数 ```dart - BrnLoadingDialog({Key key, this.content = "加载中..."}) : super(key: key); +const BrnLoadingDialog({Key? key, this.content = BrnStrings.loadingContent}) + : super(key: key); ``` ### 参数说明 diff --git a/docs/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md b/docs/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md index af1bf338..a8ace15f 100644 --- a/docs/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md +++ b/docs/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md @@ -25,42 +25,41 @@ group: ```dart const BrnMiddleInputDialog( - {this.title, - this.message, - this.hintText, - this.maxLength = 20, - this.maxLines, - this.minLines: 1, - this.inputFocusNode, - this.inputEditingController, - this.inputFormatters, - this.cancelText = '取消', - this.confirmText = '确定', - this.dialogStyle, - this.onConfirm, - this.onCancel, - this.dismissOnActionsTap = true, - this.barrierDismissible = true, - this.autoFoucs = false}); + {this.title, + this.message, + this.hintText, + this.maxLength = 20, + this.maxLines, + this.minLines: 1, + this.inputFocusNode, + this.inputEditingController, + this.inputFormatters, + this.textInputAction = TextInputAction.newline, + this.cancelText = '取消', + this.confirmText = '确定', + this.onConfirm, + this.onCancel, + this.dismissOnActionsTap = true, + this.barrierDismissible = true, + this.autoFocus = false}); ``` ### 参数说明 | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| title | String | 标题 | 否 | | -| message | String | 辅助内容 | 否 | | -| hintText | String | 提示语 | 否 | | -| maxLength | int | 最大输入长度 | 否 | | -| maxLines | int | 可输入的最maxLines多行数。超过 [maxLines] 指定的行数后,输入内容会变成可滑动 | 否 | | +| title | String? | 标题 | 否 | | +| message | String? | 辅助内容 | 否 | | +| hintText | String? | 提示语 | 否 | | +| maxLength | int | 最大输入长度 | 否 | 20 | +| maxLines | int? | 可输入的最maxLines多行数。超过 [maxLines] 指定的行数后,输入内容会变成可滑动 | 否 | | | minLines | int | 可输入的最少行数 | 否 | 1 | -| inputFocusNode | FocusNode | 焦点控制 | 否 | | -| inputEditingController | TextEditingController | 输入控制器。如果有初始状态的填充文字,可以通过 [inputEditingController] 设置 | 否 | | +| inputFocusNode | FocusNode? | 焦点控制 | 否 | | +| inputEditingController | TextEditingController? | 输入控制器。如果有初始状态的填充文字,可以通过 [inputEditingController] 设置 | 否 | | | cancelText | String | 取消文案 | 否 | 取消 | | confirmText | String | 确定文案 | 否 | 确定 | -| inputFormatters | TextInputAction | 键盘操作按钮类型,可参见系统的 TextField.textInputAction | 否 | TextInputAction.newline | -| textInputAction | `List` | 用于控制输入的内容范围比如只能输入数字可以填写:`FilteringTextInputFormatter.digitsOnly` | 否 | 无 | -| dialogStyle | BrnDialogStyle | Dialog 风格设置 | 否 | BrnDialogStyle | -| onConfirm | Function(String value) | 确定回调,返回输入的值 | 否 | | +| inputFormatters | List? | 键盘操作按钮类型,可参见系统的 TextField.textInputAction | 否 | TextInputAction.newline | +| textInputAction | `TextInputAction` | 用于控制输入的内容范围比如只能输入数字可以填写:`FilteringTextInputFormatter.digitsOnly` | 否 | 无 | +| onConfirm | void Function(String value)? | 确定回调,返回输入的值 | 否 | | | onCancel | VoidCallback | 取消回调 | 否 | | | dismissOnActionsTap | bool | 点击取消/确认按钮之后,是否自动关闭弹窗 | 否 | true | | barrierDismissible | bool | 点击蒙层背景,弹窗是否可关闭。 | 否 | true | diff --git a/docs/components/dialog/BrnMultiSelectDialog/BrnMultiSelectDialog.md b/docs/components/dialog/BrnMultiSelectDialog/BrnMultiSelectDialog.md index 5902abb1..4d035372 100644 --- a/docs/components/dialog/BrnMultiSelectDialog/BrnMultiSelectDialog.md +++ b/docs/components/dialog/BrnMultiSelectDialog/BrnMultiSelectDialog.md @@ -25,37 +25,37 @@ group: ```dart BrnMultiSelectDialog({ - this.isClose = true, - this.title = "", - this.conditions, - this.messageText, - this.messageWidget, - this.customWidget, - this.isCustomFollowScroll = true, - this.submitText = "提交", - this.submitBgColor, - this.onSubmitClick, - this.onItemClick, - this.isShowOperateWidget = true, -}); + this.isClose = true, + this.title = "", + required this.conditions, + this.messageText, + this.messageWidget, + this.customWidget, + this.isCustomFollowScroll = true, + this.submitText = "提交", + this.submitBgColor, + this.onSubmitClick, + this.onItemClick, + this.isShowOperateWidget = true, + }); ``` ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| -------------------- | ----------------------------------------------------------------------------------------------- | ---------------------------------- | ------------ | ---------- | -| isClose | bool | 是否展示右上角【X】按钮 | 是 | | -| conditions | List | 数据源 | 否 | | -| title | String | Dialog title | 否 | | -| messageText | String | 描述文案 | 否 | | -| messageWidget | Widget | 自定义描述 widget | 否 | | -| customWidget | Widget | 底部自定义 widget | 否 | | -| isCustomFollowScroll | bool | 是否支持滚动 | 否 | true | -| onSubmitClick | `bool Function(List data)` | 点击【完成】时回调给外部选中的数据 | 否 | | -| onItemClick | BrnMultiSelectDialogOnItemClickCallback = void Function( BuildContext dialogContext, int index) | Item 被点击的回调 | 否 | | -| submitText | bool | 底部提交按钮的文案 | 否 | 提交 | -| submitBgColor | Color | 底部按钮的主题色 | 否 | 主题色 | -| isShowOperateWidget | bool | 是否展示底部操作区域 | 否 | true | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| -------------------- | ---------------------------------------- | ---------------------------------- | ------------ | ---------- | +| isClose | bool | 是否展示右上角【X】按钮 | 否 | true | +| conditions | List | 数据源 | 否 | | +| title | String | Dialog title | 否 | "" | +| messageText | String? | 描述文案 | 否 | | +| messageWidget | Widget? | 自定义描述 widget | 否 | | +| customWidget | Widget? | 底部自定义 widget | 否 | | +| isCustomFollowScroll | bool | 是否支持滚动 | 否 | true | +| onSubmitClick | BrnMultiSelectDialogClickSubmitCallback? | 点击【完成】时回调给外部选中的数据 | 否 | | +| onItemClick | BrnMultiSelectDialogOnItemClickCallback? | Item 被点击的回调 | 否 | | +| submitText | String | 底部提交按钮的文案 | 否 | 提交 | +| submitBgColor | Color? | 底部按钮的主题色 | 否 | 主题色 | +| isShowOperateWidget | bool | 是否展示底部操作区域 | 否 | true | ## 四、代码演示 @@ -64,29 +64,29 @@ BrnMultiSelectDialog({ ```dart -List data = new List(); -data.add(new MultiSelectItem("100", "感兴趣待跟进")); -data.add(new MultiSelectItem("101", "感兴趣但对本商圈没兴趣", isChecked: true)); -data.add(new MultiSelectItem("102", "接通后挂断/不感兴趣", isChecked: true)); -data.add(new MultiSelectItem("103", "未接通")); -data.add(new MultiSelectItem("104", "投诉威胁")); -data.add(new MultiSelectItem("104", "号码错误")); -data.add(new MultiSelectItem("104", "号码错误")); -data.add(new MultiSelectItem("104", "号码错误")); -showDialog( - context: context, - builder: (_) => BrnMultiSelectDialog( - title: "请您评价该条线索", - isClose: true, - conditions: data, - onSubmitClick: (List data) { - var str = ""; - data.forEach((item) { - str = str + item.content + " "; - }); - BrnToast.show(str, context); - return true; - })); +List data = []; + data.add(new MultiSelectItem("100", "感兴趣待跟进")); + data.add(new MultiSelectItem("101", "感兴趣但对本商圈没兴趣", isChecked: true)); + data.add(new MultiSelectItem("102", "接通后挂断/不感兴趣", isChecked: true)); + data.add(new MultiSelectItem("103", "未接通")); + data.add(new MultiSelectItem("104", "投诉威胁")); + data.add(new MultiSelectItem("104", "号码错误")); + data.add(new MultiSelectItem("104", "号码错误")); + data.add(new MultiSelectItem("104", "号码错误")); + showDialog( + context: context, + builder: (_) => BrnMultiSelectDialog( + title: "请您评价该条线索", + isClose: true, + conditions: data, + onSubmitClick: (List data) { + var str = ""; + data.forEach((item) { + str = str + item.content + " "; + }); + BrnToast.show(str, context); + return true; + })); ``` ### 效果 2 @@ -94,7 +94,7 @@ showDialog( ```dart - List data = new List(); + List data = []; data.add(new MultiSelectItem("100", "感兴趣待跟进")); data.add(new MultiSelectItem("101", "感兴趣但对本商圈没兴趣", isChecked: true)); data.add(new MultiSelectItem("102", "接通后挂断/不感兴趣", isChecked: true)); @@ -126,7 +126,7 @@ showDialog( ```dart String hintText = "感兴趣待跟进"; -List data = new List(); +List data = []; data.add(new MultiSelectItem("100", "感兴趣待跟进")); data.add(new MultiSelectItem("101", "感兴趣但对本商圈没兴趣", isChecked: true)); data.add(new MultiSelectItem("102", "接通后挂断/不感兴趣", isChecked: true)); diff --git a/docs/components/dialog/BrnScrollableTextDialog/BrnScrollableTextDialog.md b/docs/components/dialog/BrnScrollableTextDialog/BrnScrollableTextDialog.md index 51215495..fa6c0742 100644 --- a/docs/components/dialog/BrnScrollableTextDialog/BrnScrollableTextDialog.md +++ b/docs/components/dialog/BrnScrollableTextDialog/BrnScrollableTextDialog.md @@ -36,33 +36,33 @@ group: ### 构造函数 ```dart -BrnScrollableTextDialog( - {this.title, - this.isClose = true, - this.contentText, - this.textColor = const Color(0xFF666666), - this.textFontSize = 16, - this.submitText, - this.onSubmitClick, - this.submitBgColor, - this.linksCallback, - this.isShowOperateWidget = true}); +const BrnScrollableTextDialog( + {this.title, + this.isClose = true, + required this.contentText, + this.textColor = const Color(0xFF666666), + this.textFontSize = 16, + this.submitText, + this.onSubmitClick, + this.submitBgColor, + this.linksCallback, + this.isShowOperateWidget = true}); ``` ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| ------------------- | -------------------- | -------------------- | ------------ | ----------------- | -| title | String | 弹框标题 | 否 | 无 | -| isClose | bool | 是否可关闭 | 否 | true | -| contentText | String | 内容 | 否 | 无 | -| textColor | Color | 文字颜色 | 否 | Color(0xFF666666) | -| textFontSize | double | 文字大小 | 否 | 16 | -| submitText | String | 操作按钮文字 | 否 | 无 | -| submitBgColor | Color | 操作按钮背景色 | 否 | 默认主题色 | -| onSubmitClick | VoidCallback | 提交操作 | 否 | 无 | -| linksCallback | BrnHyperLinkCallback | 富文本链接点击回调 | 否 | 无 | -| isShowOperateWidget | bool | 是否展示底部操作区域 | 否 | true | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| ------------------- | --------------------- | -------------------- | ------------ | ----------------- | +| title | String? | 弹框标题 | 否 | "" | +| isClose | bool | 是否可关闭 | 否 | true | +| contentText | String | 内容 | 否 | 无 | +| textColor | Color | 文字颜色 | 否 | Color(0xFF666666) | +| textFontSize | double | 文字大小 | 否 | 16 | +| submitText | String? | 操作按钮文字 | 否 | 无 | +| submitBgColor | Color? | 操作按钮背景色 | 否 | 默认主题色 | +| onSubmitClick | VoidCallback? | 提交操作 | 否 | 无 | +| linksCallback | BrnHyperLinkCallback? | 富文本链接点击回调 | 否 | 无 | +| isShowOperateWidget | bool | 是否展示底部操作区域 | 否 | true | ### 其他数据 @@ -70,12 +70,19 @@ BrnScrollableTextDialog( ```dart BrnContentExportWidget(this.contentWidget, - {this.title, - this.isClose, - this.submitText, - this.onSubmitClick, - this.submitBgColor, - this.isShowOperateWidget}); + {this.title, + required this.isClose, + this.submitText, + this.onSubmit, + this.submitBgColor, + required this.isShowOperateWidget, + this.themeData}) { + this.themeData ??= BrnDialogConfig(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: themeData!.configId) + .dialogConfig + .merge(themeData); + } ``` ## 四、代码演示 @@ -125,8 +132,8 @@ showDialog( "文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文" "呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表纯本文呢表", submitText: "提交", - linksCallback: (String text, String url) { - BrnToast.show(text, context); + linksCallback: (String? text, String? url) { + BrnToast.show(text!, context); }, onSubmitClick: () { BrnToast.show("点击了纯文本弹框", context); diff --git a/docs/components/dialog/BrnShareDialog/BrnShareDialog.md b/docs/components/dialog/BrnShareDialog/BrnShareDialog.md index 9fabf885..59109a4d 100644 --- a/docs/components/dialog/BrnShareDialog/BrnShareDialog.md +++ b/docs/components/dialog/BrnShareDialog/BrnShareDialog.md @@ -37,11 +37,11 @@ group: ```dart BrnShareDialog({ - @required this.context, - this.titleText, + required this.context, + required this.titleText, this.descText, this.separatorText, - this.shareChannels, + required this.shareChannels, this.clickCallBack, this.getCustomChannelTitle, this.getCustomChannelWidget, @@ -53,7 +53,7 @@ BrnShareDialog({ }) { this.themeData ??= BrnDialogConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) + .getConfig(configId: themeData!.configId) .dialogConfig .merge(themeData); } @@ -65,32 +65,32 @@ BrnShareDialog({ | **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| titleText | String | 弹框标题文案 | 否 | 无 | -| descText | String | 弹框辅助信息文案(为空则**不显示**辅助信息) | 否 | 无 | -| separatorText | String | 文案与分享渠道图标间的分割线内嵌文案 | 否 | 你可以通过以下方式分享给客户 | +| titleText | String | 弹框标题文案 | 是 | 无 | +| descText | String? | 弹框辅助信息文案(为空则**不显示**辅助信息) | 否 | 无 | +| separatorText | String? | 文案与分享渠道图标间的分割线内嵌文案 | 否 | 你可以通过以下方式分享给客户 | | shareChannels | `List` | 用于表示所展示的分享渠道图标的索引(列表内容可直接填写渠道对应的**int**值,或使用**BrnShareItemConstants**的静态变量,例如**BrnShareItemConstants.SHARE\_WEIXIN**)。自定义为100或**BrnShareItemConstants.SHARE\_CUSTOM**。 | 是 | 空 | -| clickCallBack | BrnShareDialogItemClickCallBack(int shareChannel, int customIndex) | 点击分享渠道图标后回调方法(方法传参为被点击的分享渠道图标在**BrnShareItemConstants**中的索引值shareChannel, 及改列表在使用者自定义的*shareChannels*中的索引值customIndex),使用者**根据参数自行配置响应动作**。 | 是 | 空 | -| getCustomChannelTitle | BrnShareDialogGetCustomShareItemTitle(int index) | 获取自定义分享渠道对应的显示**文案**(方法传参为该自定义分享渠道在*shareChannels*中的索引值index)。回调返回值为**String**,如果返回值为空,则**不显示**该自定义分享渠道。 | 否 | 空 | -| getCustomChannelWidget | BrnShareDialogGetCustomShareItemIcon(int index) | 获取自定义分享渠道对应的显示**图标**(方法传参为该自定义分享渠道在*shareChannels*中的索引值index)。回调返回值为**Widget**,如果返回值为空,则**不显示**该自定义分享渠道。 | 否 | 空 | -| context | BuildContext | BuidContext | 是 | 空 | +| clickCallBack | BrnShareDialogItemClickCallBack(int shareChannel, int customIndex) | 点击分享渠道图标后回调方法(方法传参为被点击的分享渠道图标在**BrnShareItemConstants**中的索引值shareChannel, 及改列表在使用者自定义的*shareChannels*中的索引值customIndex),使用者**根据参数自行配置响应动作**。 | 否 | 空 | +| getCustomChannelTitle | BrnShareDialogGetCustomShareItemTitle? | 获取自定义分享渠道对应的显示**文案**(方法传参为该自定义分享渠道在*shareChannels*中的索引值index)。回调返回值为**String**,如果返回值为空,则**不显示**该自定义分享渠道。 | 否 | 空 | +| getCustomChannelWidget | BrnShareDialogGetCustomShareItemIcon? | 获取自定义分享渠道对应的显示**图标**(方法传参为该自定义分享渠道在*shareChannels*中的索引值index)。回调返回值为**Widget**,如果返回值为空,则**不显示**该自定义分享渠道。 | 否 | 空 | +| context | BuildContext | BuildContext | 是 | 空 | | titleColor | Color | 标题颜色 | 否 | **Color(0xff222222)** 黑色 | | descColor | Color | 分享渠道文案颜色 | 否 | **Color(0xff666666)**灰色 | -| separatorLineColor | Color | 分割线颜色 | 否 | **Color(0xffEEEEEE)**浅灰 | +| separatorLineColor | Color | 分割线颜色 | 否 | **Color(0xfff0f0f0)**浅灰 | | shareTextColor | Color | 分享渠道文案颜色 | 否 | **Color(0xff999999)**灰色 | | themeData | BrnDialogConfig | 弹窗配置,配置详情见BrnDialogConfig | 否 | | ### 其他数据 -| 常量名 | 渠道名 | -| ----------------------------------- | ------------------------------------------------------------ | -| BrnShareItemConstants.SHARE\_WEIXIN | 微信 | -| BrnShareItemConstants.SHARE\_FRIEND | 朋友圈 | -| BrnShareItemConstants.SHARE\_QQ | qq | -| BrnShareItemConstants.SHARE\_QZONE | qq空间 | -| BrnShareItemConstants.SHARE\_WEIBO | 微博 | -| BrnShareItemConstants.SHARE\_LINK | 链接 | -| BrnShareItemConstants.SHARE\_SMS | 短信 | -| BrnShareItemConstants.SHARE\_CUSTOM | 自定义自定义图标需在**getCustomChannelTitle**方法中设置文案,在**getCustomChannelWidget**方法中设定图标。如其中一个为空,则不显示自定义图标。 | +| 常量名 | 渠道名 | +| --------------------------------- | ------------------------------------------------------------ | +| BrnShareItemConstants.shareWeiXin | 微信 | +| BrnShareItemConstants.shareFriend | 朋友圈 | +| BrnShareItemConstants.shareQQ | qq | +| BrnShareItemConstants.shareQZone | qq空间 | +| BrnShareItemConstants.shareWeiBo | 微博 | +| BrnShareItemConstants.shareLink | 链接 | +| BrnShareItemConstants.shareSms | 短信 | +| BrnShareItemConstants.shareCustom | 自定义自定义图标需在**getCustomChannelTitle**方法中设置文案,在**getCustomChannelWidget**方法中设定图标。如其中一个为空,则不显示自定义图标。 | ## 四、代码演示 @@ -101,9 +101,9 @@ BrnShareDialog({ BrnShareDialog brnShareDialog = BrnShareDialog( context: context, shareChannels: [ - BrnShareItemConstants.SHARE_WEIXIN, - BrnShareItemConstants.SHARE_LINK, - BrnShareItemConstants.SHARE_CUSTOM + BrnShareItemConstants.shareWeiXin, + BrnShareItemConstants.shareLink, + BrnShareItemConstants.shareCustom ], titleText: "测试标题", descText: "测试辅助信息测试辅助信息测试辅助信息测试辅助信息测试辅助信息", @@ -134,11 +134,11 @@ brnShareDialog.show(); BrnShareDialog brnShareDialog = new BrnShareDialog( context: context, shareChannels: [ - BrnShareItemConstants.SHARE_WEIXIN, - BrnShareItemConstants.SHARE_CUSTOM, - BrnShareItemConstants.SHARE_CUSTOM, - BrnShareItemConstants.SHARE_LINK, - BrnShareItemConstants.SHARE_CUSTOM + BrnShareItemConstants.shareWeiXin, + BrnShareItemConstants.shareCustom, + BrnShareItemConstants.shareCustom, + BrnShareItemConstants.shareLink, + BrnShareItemConstants.shareCustom ], titleText: "测试标题", descText: "测试辅助信息测试辅助信息测试辅助信息测试辅助信息测试辅助信息", diff --git a/docs/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md b/docs/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md index 9c5242e8..b6d46bd4 100644 --- a/docs/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md +++ b/docs/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md @@ -24,35 +24,35 @@ group: ### 构造函数 ```dart -BrnSingleSelectDialog( - {this.isClose: true, - this.title: "", - this.conditions, - this.submitText: "提交", - this.submitBgColor, - this.onSubmitClick, - this.onItemClick, - this.checkedItem, - this.customWidget, - this.canDismissOnConfirmClick = true, - this.isCustomFollowScroll = true}); +const BrnSingleSelectDialog( + {this.isClose: true, + this.title: "", + required this.conditions, + this.submitText: "提交", + this.submitBgColor, + this.onSubmitClick, + this.onItemClick, + this.checkedItem, + this.customWidget, + this.canDismissOnConfirmClick = true, + this.isCustomFollowScroll = true}); ``` ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| ------------------------ | ----------------------------------------------- | --------------------------------------------------------- | ------------ | ---------- | -| isClose | bool | 用于控制弹窗是否相应电机外部关闭,true 关闭,false 不关闭 | 否 | true | -| title | String | 弹窗标题名称 | 否 | 无 | -| conditions | List | 备选项数组 | 否 | | -| checkedItem | String | 选中的选项名称 | 否 | | -| submitText | String | 确定/提交 按钮文案 | 否 | | -| submitBgColor | Color | 提交按钮背景颜色 | 否 | | -| customWidget | Widget | 在单选列表底部自定义 Widget | 否 | null | -| isCustomFollowScroll | bool | 内容是否可滑动 | 否 | true | -| canDismissOnConfirmClick | bool | 是否在点击时让 Diallog 消失 | 否 | true | -| onSubmitClick | Function(String data) | 提交按钮点击的回调 | 否 | | -| onItemClick | void Function( BuildContext context, int index) | item 的点击回调 | 否 | | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| ------------------------ | ----------------------------------- | --------------------------------------------------------- | ------------ | ---------- | +| isClose | bool | 用于控制弹窗是否相应电机外部关闭,true 关闭,false 不关闭 | 否 | true | +| title | String | 弹窗标题名称 | 否 | "" | +| conditions | List | 备选项数组 | 否 | | +| checkedItem | String | 选中的选项名称 | 否 | | +| submitText | String | 确定/提交 按钮文案 | 否 | | +| submitBgColor | Color | 提交按钮背景颜色 | 否 | | +| customWidget | Widget | 在单选列表底部自定义 Widget | 否 | null | +| isCustomFollowScroll | bool | 内容是否可滑动 | 否 | true | +| canDismissOnConfirmClick | bool | 是否在点击时让 Diallog 消失 | 否 | true | +| onSubmitClick | BrnSingleSelectOnSubmitCallback? | 提交按钮点击的回调 | 否 | | +| onItemClick | BrnSingleSelectOnItemClickCallback? | item 的点击回调 | 否 | | ## 三、代码演示 @@ -92,7 +92,7 @@ String hintText = "感兴趣待跟进"; //光标圆角弧度 cursorRadius: Radius.circular(2.0), style: TextStyle(fontSize: 14, color: Color(0xFF222222)), - maxLengthEnforced: true, + maxLengthEnforcement: MaxLengthEnforcement.enforced, onChanged: (value) {}, decoration: InputDecoration( contentPadding: EdgeInsets.all(8.0), diff --git a/docs/components/iconButton/BrnIconButton/BrnIconButton.md b/docs/components/iconButton/BrnIconButton/BrnIconButton.md index fa31e9d7..b19b6fbd 100644 --- a/docs/components/iconButton/BrnIconButton/BrnIconButton.md +++ b/docs/components/iconButton/BrnIconButton/BrnIconButton.md @@ -27,22 +27,21 @@ group: ### 构造函数 ``` dart -BrnIconButton({ - Key key, - @required this.name, - this.iconWidget, - this.onTap, - this.iconWidth = 24, - this.iconHeight = 24, - this.fontSize = 11, - this.widgetWidth = 80, - this.widgetHeight = 80, - this.direction = Direction.top, - this.padding = 4, - this.style, - this.isGrey = true, - this.mainAxisAlignment = MainAxisAlignment.center, -}) : assert(isGrey != null); +const BrnIconButton({ + Key? key, + required this.name, + this.iconWidget, + this.onTap, + this.iconWidth = 24, + this.iconHeight = 24, + this.fontSize = 11, + this.widgetWidth = 80, + this.widgetHeight = 80, + this.direction = Direction.top, + this.padding = 4, + this.style, + this.mainAxisAlignment = MainAxisAlignment.center, + }): super(key: key); ``` ### 参数说明 @@ -50,16 +49,15 @@ BrnIconButton({ | 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | | ----------------- | -------------------------------------------- | ------------------------------------------------------------ | -------- | ------------------------------------------------------------ | | name | String | 图文组合文字的名称 | 否 | 空 | -| isGrey | bool | 是否是置灰状态 | 否 | true | -| iconWidget | Widget | 图文组合需要展示的图片/可以是置灰的图片 | 否 | 空 | -| onTap | VoidCallback | 点击的回调 | 否 | 空 | +| iconWidget | Widget? | 图文组合需要展示的图片/可以是置灰的图片 | 否 | 空 | +| onTap | VoidCallback? | 点击的回调 | 否 | 空 | | direction | enum Direction { left, right, top, bottom, } | 文字相对于图片的位置。 bottom:文字在下 icon 在上, top:文字在上 icon 在下 ,left:文字在左 icon 在右,right:文字在右 icon 在左 | 否 | top | | iconWidth | double | 图片的宽度 | 否 | 24 | | iconHeight | Color | 图片的高度 | 否 | 24 | | widgetWidth | double | 图文组合的宽度 | 否 | 80 | | widgetHeight | double | 图文组合的高度 | 否 | 80 | | padding | double | 文字和图片的间距 | 否 | 4 | -| style | TextStyle | 文字样式 | 否 | TextStyle( fontSize: 11, color: BrunoColor.instance.F2Color, ), | +| style | TextStyle? | 文字样式 | 否 | TextStyle( fontSize: 11, color: BrunoColor.instance.F2Color, ), | | fontSize | double | 文字字体大小 | 否 | 11 | | mainAxisAlignment | MainAxisAlignment | 图文对齐方式 | 否 | MainAxisAlignment.center | diff --git a/docs/components/iconButton/BrnVerticalIconButton/BrnVerticalIconButton.md b/docs/components/iconButton/BrnVerticalIconButton/BrnVerticalIconButton.md index 67bdf5d1..050930a8 100644 --- a/docs/components/iconButton/BrnVerticalIconButton/BrnVerticalIconButton.md +++ b/docs/components/iconButton/BrnVerticalIconButton/BrnVerticalIconButton.md @@ -21,9 +21,12 @@ group: ```dart -BrnVerticalIconButton( - {Key key, @required this.name, @required this.iconWidget, this.onTap}) - : super(key: key) +const BrnVerticalIconButton({ + Key? key, + required this.name, + required this.iconWidget, + this.onTap, + }) : super(key: key); ``` ### 参数说明 @@ -32,7 +35,7 @@ BrnVerticalIconButton( | key | Key | 视图绑定的 key | 否 | 无 | | name | String | 需要显示的文案 | 是 | 无 | | iconWidget | Widget | 需要显示的图标 widget | 是 | 无 | -| onTap | VoidCallback | 按钮点击的回调处理 | 否 | 无 | +| onTap | VoidCallback? | 按钮点击的回调处理 | 否 | 无 | ## 四、代码演示 diff --git a/docs/components/input/BrnInputText/BrnInputText.md b/docs/components/input/BrnInputText/BrnInputText.md index 3170c722..10dbfdc8 100644 --- a/docs/components/input/BrnInputText/BrnInputText.md +++ b/docs/components/input/BrnInputText/BrnInputText.md @@ -28,49 +28,49 @@ group: ### 构造函数 ```dart -BrnInputText({ - this.onTextChange, - this.onSubmit, - this.maxHeight = 200, - this.minHeight = 50, - this.bgColor = Colors.white, - this.maxLength = 200, - this.minLines = 1, - this.hint = "请输入", - this.maxHintLines, - this.padding = EdgeInsets.zero, - this.textString = "", - this.autoFocus, - this.textEditingController, - this.focusNode, - this.textInputAction = TextInputAction.done, - this.borderRadius, - this.borderColor, -}); + BrnInputText({ + this.onTextChange, + this.onSubmit, + this.maxHeight = 200, + this.minHeight = 50, + this.bgColor = Colors.white, + this.maxLength = 200, + this.minLines = 1, + this.hint = "请输入", + this.maxHintLines, + this.padding = EdgeInsets.zero, + this.textString = "", + this.autoFocus, + this.textEditingController, + this.focusNode, + this.textInputAction = TextInputAction.done, + this.borderRadius, + this.borderColor, + }); ``` ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| --------------------- | --------------------------------------------------- | ------------------------------------------------------------ | ------------ | -------------------- | -| hint | String | 输入提示语,默认为"请输入..." | 否 | "请输入..." | -| textString | String | 输入框初始值 | 否 | "请输入..." | -| maxHintLines | 最大 hint 行数 | 最大 hint 行数 | | | -| textEditingController | TextEditingController | 用于对 TextField 更精细的控制,若传入该字段,[textString] 参数将失效,可使用 TextEditingController.text 进行赋值 | 否 | | -| onTextChange | BrnInputTextChangeCallback = Function(String input) | 搜索框输入内容改变时候的回调函数,str 为输入内容 | 否 | 无 | -| onSubmit | BrnInputTextSubmitCallback = Function(String input) | 输入内容点击确定后的回调,str 为输入内容 | 否 | 空 | -| maxHeight | double | 容器的最大高度、输入框最大可以伸缩的高度 | 否 | 空 | -| minHeight | double | 容器的最小高度、输入框最小可以伸缩的高度 | 否 | 空 | -| bgColor | Color | 整个容器的背景颜色 | 否 | 白色 | -| maxLength | int | 最大字数 | 否 | 200 | -| minLines | int | 最少几行、文字可以输入几行 | 否 | 1 | -| padding | EdgeInsetsGeometry | 文字离容器的上下左右的距离 | 否 | EdgeInsets.zero | -| borderColor | Color | 边框颜色 | 否 | | -| borderRadius | double | 背景圆角 | 否 | | -| autoFocus | bool | 光标展示 | 否 | | -| focusNode | FocusNode | 搜索框的焦点控制器 | 否 | | -| padding | EdgeInsetsGeometry | 文字距离边框的边距 | 否 | EdgeInsets.zero | -| textEditingController | TextInputAction | 键盘输入行为 | 否 | TextInputAction.done | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| --------------------- | ---------------------------------------------------- | ------------------------------------------------------------ | ------------ | -------------------- | +| hint | String | 输入提示语,默认为"请输入..." | 否 | "请输入..." | +| textString | String | 输入框初始值 | 否 | "" | +| maxHintLines | int? | 最大 hint 行数 | | | +| textEditingController | TextEditingController? | 用于对 TextField 更精细的控制,若传入该字段,[textString] 参数将失效,可使用 TextEditingController.text 进行赋值 | 否 | | +| onTextChange | BrnInputTextChangeCallback = Function(String input)? | 搜索框输入内容改变时候的回调函数,str 为输入内容 | 否 | 无 | +| onSubmit | BrnInputTextSubmitCallback = Function(String input)? | 输入内容点击确定后的回调,str 为输入内容 | 否 | 空 | +| maxHeight | double | 容器的最大高度、输入框最大可以伸缩的高度 | 否 | 空 | +| minHeight | double | 容器的最小高度、输入框最小可以伸缩的高度 | 否 | 空 | +| bgColor | Color | 整个容器的背景颜色 | 否 | Colors.white | +| maxLength | int | 最大字数 | 否 | 200 | +| minLines | int | 最少几行、文字可以输入几行 | 否 | 1 | +| padding | EdgeInsetsGeometry | 文字离容器的上下左右的距离 | 否 | EdgeInsets.zero | +| borderColor | Color? | 边框颜色 | 否 | | +| borderRadius | double? | 背景圆角 | 否 | | +| autoFocus | bool? | 光标展示 | 否 | | +| focusNode | FocusNode | 搜索框的焦点控制器 | 否 | | +| padding | EdgeInsetsGeometry | 文字距离边框的边距 | 否 | EdgeInsets.zero | +| textEditingController | TextInputAction | 键盘输入行为 | 否 | TextInputAction.done | ## 三、效果及代码展示 @@ -82,23 +82,23 @@ BrnInputText({ ```dart BrnInputText( - maxHeight: 200, - minHeight: 30, - minLines: 1, - maxLength: 10, - bgColor: Colors.grey[200], - textString: model.text, - textInputAction: TextInputAction.newline, - maxHintLines: 20, - hint: 'input动态算高input动态算高input动态算高input动态算高input动态算高', - padding: EdgeInsets.fromLTRB(20, 10, 20, 14), - onTextChange: (text) { - print(text); - model.text = text; - setState(() {}); - }, - onSubmit: (text) { - print(text); - }, -); + maxHeight: 200, + minHeight: 30, + minLines: 1, + maxLength: 10, + bgColor: Colors.grey[200]!, + textString: model.text ?? '', + textInputAction: TextInputAction.newline, + maxHintLines: 20, + hint: 'input动态算高input动态算高input动态算高input动态算高input动态算高', + padding: EdgeInsets.fromLTRB(20, 10, 20, 14), + onTextChange: (text) { + print(text); + model.text = text; + setState(() {}); + }, + onSubmit: (text) { + print(text); + }, + ); ``` diff --git a/docs/components/loading/BrnPageLoading/BrnPageLoading.md b/docs/components/loading/BrnPageLoading/BrnPageLoading.md index 78bb7482..dde58c04 100644 --- a/docs/components/loading/BrnPageLoading/BrnPageLoading.md +++ b/docs/components/loading/BrnPageLoading/BrnPageLoading.md @@ -22,7 +22,8 @@ group: ### 构造函数 ```dart -BrnPageLoading({this.content}); + const BrnLoadingDialog({Key? key, this.content = BrnStrings.loadingContent}) + : super(key: key); ``` ### 参数配置 diff --git a/docs/components/normalButton/BrnBigGhostButton/BrnBigGhostButton.md b/docs/components/normalButton/BrnBigGhostButton/BrnBigGhostButton.md index 0fd4ac27..4b4df7f8 100644 --- a/docs/components/normalButton/BrnBigGhostButton/BrnBigGhostButton.md +++ b/docs/components/normalButton/BrnBigGhostButton/BrnBigGhostButton.md @@ -24,14 +24,14 @@ group: ```dart const BrnBigGhostButton({ - Key key, - this.title = '确认', - this.titleColor, - this.bgColor, - this.onTap, - this.width, - this.themeData, -}) : super(key: key); + Key? key, + this.title = '确认', + this.titleColor, + this.bgColor, + this.onTap, + this.width, + this.themeData, + }) : super(key: key); ``` ### 参数说明 @@ -42,6 +42,7 @@ const BrnBigGhostButton({ | bgColor | Color | 按钮的背景色 | 否 | 主题色为5透明度的颜色 | | width | double | 按钮的宽度 | 否 | double.infinity | | titleColor | Color | 按钮的文字颜色 | 否 | 主题色 | +| themeData | BrnButtonConfig | button主题定制 | 否 | 无 | diff --git a/docs/components/normalButton/BrnBigMainButton/BrnBigMainButton.md b/docs/components/normalButton/BrnBigMainButton/BrnBigMainButton.md index 5c09831f..7b4c1b70 100644 --- a/docs/components/normalButton/BrnBigMainButton/BrnBigMainButton.md +++ b/docs/components/normalButton/BrnBigMainButton/BrnBigMainButton.md @@ -26,14 +26,14 @@ group: ```dart const BrnBigMainButton({ - Key key, - this.title = '确认', - this.width, - this.isEnable = true, - this.onTap, - this.themeData, - this.bgColor, -}) : super(key: key); + Key? key, + this.title = '确认', + this.width, + this.isEnable = true, + this.onTap, + this.themeData, + this.bgColor, + }) : super(key: key); ``` ### 参数说明 @@ -44,6 +44,7 @@ const BrnBigMainButton({ | isEnable | bool | 按钮是否可用 | 否 | false | | bgColor | Color | 按钮的背景色 | 否 | 主题色 | | width | double | 按钮的宽度 | 否 | double.infinity | +| themeData | BrnButtonConfig | 按钮主题配置 | 否 | 无 | diff --git a/docs/components/normalButton/BrnBigOutlineButton/BrnBigOutlineButton.md b/docs/components/normalButton/BrnBigOutlineButton/BrnBigOutlineButton.md index 184e37db..3c33346b 100644 --- a/docs/components/normalButton/BrnBigOutlineButton/BrnBigOutlineButton.md +++ b/docs/components/normalButton/BrnBigOutlineButton/BrnBigOutlineButton.md @@ -25,15 +25,15 @@ group: ```dart const BrnBigOutlineButton({ - Key key, - this.title = '确认', - this.lineColor, - this.textColor, - this.isEnable = true, - this.width, - this.onTap, - this.themeData, -}) : super(key: key); + Key? key, + this.title = '确认', + this.lineColor, + this.textColor, + this.isEnable = true, + this.width, + this.onTap, + this.themeData, + }) : super(key: key); ``` ### 参数说明 @@ -45,6 +45,7 @@ const BrnBigOutlineButton({ | lineColor | Color | 边框颜色 | 否 | 主题色 | | textColor | Color | 按钮文本颜色 | 否 | 黑色 | | width | double | 按钮的宽度 | 否 | double.infinity | +| themeData | BrnButtonConfig | 按钮主题配置 | 否 | 无 | ## 四、效果及代码演示 diff --git a/docs/components/normalButton/BrnSmallMainButton/BrnSmallMainButton.md b/docs/components/normalButton/BrnSmallMainButton/BrnSmallMainButton.md index 5929217d..208a5334 100644 --- a/docs/components/normalButton/BrnSmallMainButton/BrnSmallMainButton.md +++ b/docs/components/normalButton/BrnSmallMainButton/BrnSmallMainButton.md @@ -24,34 +24,36 @@ group: ```dart const BrnSmallMainButton({ - this.title = '确认', - this.onTap, - this.isEnable = true, - this.textColor, - this.bgColor, - this.fontWeight, - this.fontSize, - this.radius, - this.maxWidth, - this.width, - this.themeData, -}); + Key? key, + this.title = '确认', + this.onTap, + this.isEnable = true, + this.bgColor, + this.textColor = Colors.white, + this.fontWeight = FontWeight.w600, + this.fontSize, + this.radius, + this.maxWidth, + this.width, + this.themeData, + }): super(key: key); ``` ### 参数说明 -| 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | -| ---------- | ------------ | -------------- | -------- | --------------- | -| title | String | 按钮显示文案 | 否 | 确认 | -| onTap | VoidCallback | 点击的回调 | 否 | 无 | -| isEnable | bool | 按钮是否可用 | 否 | True | -| bgColor | Color | 按钮的背景色 | 否 | 主题色 | -| width | double | 按钮的宽度 | 否 | double.infinity | -| textColor | Color | 文本的颜色 | 否 | 白色 | -| fontWeight | FontWeight | 文本的粗细 | 否 | bold | -| fontSize | double | 文字的大小 | 否 | 14 | -| radius | double | 按钮的圆角 | 否 | 4 | -| maxWidth | double | 按钮的最大宽度 | 否 | null | +| 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | +| ---------- | --------------- | -------------- | -------- | --------------- | +| title | String | 按钮显示文案 | 否 | 确认 | +| onTap | VoidCallback | 点击的回调 | 否 | 无 | +| isEnable | bool | 按钮是否可用 | 否 | True | +| bgColor | Color | 按钮的背景色 | 否 | 主题色 | +| width | double | 按钮的宽度 | 否 | double.infinity | +| textColor | Color | 文本的颜色 | 否 | 白色 | +| fontWeight | FontWeight | 文本的粗细 | 否 | bold | +| fontSize | double | 文字的大小 | 否 | 14 | +| radius | double | 按钮的圆角 | 否 | 4 | +| maxWidth | double | 按钮的最大宽度 | 否 | null | +| themeData | BrnButtonConfig? | 按钮主题配置 | 否 | 无 | ## 四、代码演示 diff --git a/docs/components/normalButton/BrnSmallOutlineButton/BrnSmallOutlineButton.md b/docs/components/normalButton/BrnSmallOutlineButton/BrnSmallOutlineButton.md index 6c6cff3f..83c3bcdd 100644 --- a/docs/components/normalButton/BrnSmallOutlineButton/BrnSmallOutlineButton.md +++ b/docs/components/normalButton/BrnSmallOutlineButton/BrnSmallOutlineButton.md @@ -24,17 +24,18 @@ group: ```dart const BrnSmallOutlineButton({ - this.title = '确认', - this.onTap, - this.isEnable = true, - this.lineColor, - this.textColor, - this.radius, - this.width, - this.fontSize = 14, - this.fontWeight, - this.themeData, -}); + Key? key, + this.title = '确认', + this.onTap, + this.isEnable = true, + this.lineColor, + this.textColor, + this.radius, + this.width, + this.fontSize = 14, + this.fontWeight = FontWeight.w600, + this.themeData, + }): super(key: key); ``` ### 参数说明 @@ -45,11 +46,11 @@ const BrnSmallOutlineButton({ | onTap | VoidCallback | 点击的回调 | 否 | 无 | | isEnable | bool | 按钮是否可用 | 否 | true | | lineColor | Color | 边框的背景色 | 否 | 主题色 | -| width | double | 按钮的宽度 | 否 | double.infinity | +| width | double | 按钮的宽度 | 否 | 无 | | textColor | Color | 文本的颜色 | 否 | 白色 | -| fontWeight | FontWeight | 文本的粗细 | 否 | bold | +| fontWeight | FontWeight | 文本的粗细 | 否 | FontWeight.w600 | | fontSize | double | 文字的大小 | 否 | 14 | -| radius | double | 按钮的圆角 | 否 | 4 | +| radius | double | 按钮的圆角 | 否 | 无 | ## 四、代码演示 diff --git a/docs/components/picker/BrnBottomPicker/BrnBottomPicker.md b/docs/components/picker/BrnBottomPicker/BrnBottomPicker.md index ab3e6698..ce16acb3 100644 --- a/docs/components/picker/BrnBottomPicker/BrnBottomPicker.md +++ b/docs/components/picker/BrnBottomPicker/BrnBottomPicker.md @@ -26,19 +26,21 @@ group: ``` dart static void show( - BuildContext context, { - @required contentWidget, - String title = '请选择', - dynamic confirm, - dynamic cancel, - Function() onConfirmClick, - Function() onCancelClick, - bool barrierDismissible = true, - bool cancelDismiss = true, - bool confirmDismiss = true, - bool showTitle = true, + BuildContext context, { + required contentWidget, + String title = '请选择', + dynamic confirm, + dynamic cancel, + VoidCallback? onConfirm, + VoidCallback? onCancel, + bool barrierDismissible = true, + bool showTitle = true, }) ``` + + + + ### 参数说明 | 参数名 | 参数类型 | 作用 | 是否必填 | 默认值 | @@ -48,13 +50,11 @@ static void show( | title | String | Picker的标题 | 否 | 请选择 | | confirm | dynamic | 标题的确认按钮UI,支持传入String或者Widget,默认是确认 | 否 | 确认 | | cancel | dynamic | 标题的取消按钮UI,支持传入String或者Widget,默认是确认 | 否 | 取消 | -| onConfirmClick | Function | 确认按钮点击的回调 | 否 | 否 | -| onCancelClick | Function | 取消按钮点击的回道 | 否 | 否 | +| onConfirm | VoidCallback? | 确认按钮点击的回调 | 否 | 否 | +| onCancel | VoidCallback? | 取消按钮点击的回道 | 否 | 否 | | rightTextColor | Color | 右侧文案 Color | 否 | 主题色 | | cursorColor | Color | 光标颜色 | 否 | 主题色 | | barrierDismissible | bool | 点击对话框外部 是否取消对话框 | 否 | true | -| cancelDismiss | bool | 点击 取消 之后是否自动关闭弹窗 | 否 | true | -| confirmDismiss | bool | 点击 确认 之后是否自动关闭弹窗 | 否 | true | | showTitle | bool | 是否展示标题 | 否 | true | ## 四、效果及代码展示 diff --git a/docs/components/picker/BrnBottomWritePicker/BrnBottomWritePicker.md b/docs/components/picker/BrnBottomWritePicker/BrnBottomWritePicker.md index e6ed02b7..792ba7d3 100644 --- a/docs/components/picker/BrnBottomWritePicker/BrnBottomWritePicker.md +++ b/docs/components/picker/BrnBottomWritePicker/BrnBottomWritePicker.md @@ -28,20 +28,18 @@ group: ### 构造函数 ```dart -BrnBottomWritePicker( - {this.maxLength = 200, - this.hintText = "请输入", - this.leftTag = "取消", - this.title = "", - this.rightTag = "确认", - this.cancel, - this.confirm, - this.confirmDismiss = false, - this.cancelDismiss = true, - this.rightTextColor, - this.cursorColor, - this.defaultText, - this.textEditingController}); +const BrnBottomWritePicker( + {this.maxLength = 200, + this.hintText = "请输入", + this.leftTag = "取消", + this.title = "", + this.rightTag = "确认", + this.onCancel, + this.onConfirm, + this.rightTextColor, + this.cursorColor, + this.defaultText, + this.textEditingController}); ``` ### 参数说明 @@ -53,14 +51,12 @@ BrnBottomWritePicker( | leftTag | String | 左侧按钮文案 | 否 | 取消 | | title | String | 标题文案 | 否 | | | rightTag | String | 右侧按钮文案 | 否 | 确认 | -| cancel | BrnBottomWritePickerClickCallback = Future Function(String content) | 取消输入事件回调 | 否 | | -| confirm | BrnBottomWritePickerConfirmClickCallback = Future Function( BuildContext dialogContext, String content) | 确认输入事件回调 | 否 | | -| rightTextColor | Color | 右侧文案 Color | 否 | 主题色 | -| cursorColor | Color | 光标颜色 | 否 | 主题色 | -| defaultText | String | 输入框默认文字 | 否 | | -| cancelDismiss | bool | 点击 取消 之后是否自动关闭弹窗 | 否 | true | -| confirmDismiss | bool | 点击 确认 之后是否自动关闭弹窗 | 否 | false | -| textEditingController | TextEditingController | 用于对 TextField 更精细的控制,若传入该字段,[defaultText] 参数将失效,可使用 TextEditingController.text 进行赋值 | 否 | | +| cancel | BrnBottomWritePickerClickCallback = Future Function(String content)? | 取消输入事件回调 | 否 | | +| confirm | BrnBottomWritePickerConfirmClickCallback = Future Function( BuildContext dialogContext, String content)? | 确认输入事件回调 | 否 | | +| rightTextColor | Color? | 右侧文案 Color | 否 | 主题色 | +| cursorColor | Color? | 光标颜色 | 否 | 主题色 | +| defaultText | String? | 输入框默认文字 | 否 | | +| textEditingController | TextEditingController? | 用于对 TextField 更精细的控制,若传入该字段,[defaultText] 参数将失效,可使用 TextEditingController.text 进行赋值 | 否 | | ## 四、效果及代码展示 diff --git a/docs/components/picker/BrnDatePicker/BrnDatePicker.md b/docs/components/picker/BrnDatePicker/BrnDatePicker.md index 3d7dd9c7..c595eb73 100644 --- a/docs/components/picker/BrnDatePicker/BrnDatePicker.md +++ b/docs/components/picker/BrnDatePicker/BrnDatePicker.md @@ -37,20 +37,20 @@ group: static void showDatePicker( BuildContext context, { bool rootNavigator = false, - bool canBarrierDismissible, - DateTime minDateTime, - DateTime maxDateTime, - DateTime initialDateTime, - String dateFormat, + bool? canBarrierDismissible, + DateTime? minDateTime, + DateTime? maxDateTime, + DateTime? initialDateTime, + String? dateFormat, int minuteDivider: 1, DateTimePickerLocale locale: DATETIME_PICKER_LOCALE_DEFAULT, BrnDateTimePickerMode pickerMode: BrnDateTimePickerMode.date, BrnPickerTitleConfig pickerTitleConfig, - DateVoidCallback onCancel, - DateVoidCallback onClose, - DateValueCallback onChange, - DateValueCallback onConfirm, - BrnPickerConfig themeData, + DateVoidCallback? onCancel, + DateVoidCallback? onClose, + DateValueCallback? onChange, + DateValueCallback? onConfirm, + BrnPickerConfig? themeData, }) ``` @@ -60,20 +60,20 @@ static void showDatePicker( | --- | --- | --- | --- | --- | | context | Buildcontext | | 是 | | | rootNavigator | bool | 是否使用根路由 | 否 | false | -| canBarrierDismissible | bool | 点击弹框外部区域能否消失 | 否 | | -| initialDateTime | DateTime | 初始选择的时间 | 否 | 当前时间 | -| minDateTime | DateTime | 能滚动到的最小日期 | 是 | minDateTime ≤ maxDateTime | -| maxDateTime | DateTime | 能滚动到的最大日期 | 是 | minDateTime ≤ maxDateTime | +| canBarrierDismissible | bool? | 点击弹框外部区域能否消失 | 否 | | +| initialDateTime | DateTime? | 初始选择的时间 | 否 | 当前时间 | +| minDateTime | DateTime? | 能滚动到的最小日期 | 否 | minDateTime ≤ maxDateTime | +| maxDateTime | DateTime? | 能滚动到的最大日期 | 否 | minDateTime ≤ maxDateTime | | locale | DateTimePickerLocale | 设置本地语言 | 否 | DateTimePickerLocale.zh\_cn | | pickerMode | BrnDateTimePickerMode | 时间选择组件显示的时间类型 | 否 | BrnDateTimePickerMode.date | -| pickerTitleConfig | BrnPickerTitleConfig | 时间选择组件的主题样式 | 否 | | -| dateFormat | String | 时间格式化的格式 | 是 | | -| onConfirm | DateValueCallback | 点击【完成】回调给调用方的数据 | 否 | | -| onCancel | DateVoidCallback | 点击【取消】回调给调用方的回调事件 | 否 | | -| onClose | DateVoidCallback | 弹框点击外围消失的回调事件 | 否 | | -| onChange | DateValueCallback | 时间滚动选择时候的回调事件 | 否 | | +| pickerTitleConfig | BrnPickerTitleConfig | 时间选择组件的主题样式 | 否 | BrnPickerTitleConfig.Default | +| dateFormat | String? | 时间格式化的格式 | 是 | | +| onConfirm | DateValueCallback? | 点击【完成】回调给调用方的数据 | 否 | | +| onCancel | DateVoidCallback? | 点击【取消】回调给调用方的回调事件 | 否 | | +| onClose | DateVoidCallback? | 弹框点击外围消失的回调事件 | 否 | | +| onChange | DateValueCallback? | 时间滚动选择时候的回调事件 | 否 | | | minuteDivider | int | 分钟间切换的差值 | 否 | 1 | -| themeData | BrnPickerConfig | picker配置 配置详见BrnPickerConfig | 否 | | +| themeData | BrnPickerConfig? | picker配置 配置详见BrnPickerConfig | 否 | | diff --git a/docs/components/picker/BrnDateRangePicker/BrnDateRangePicker.md b/docs/components/picker/BrnDateRangePicker/BrnDateRangePicker.md index 4c1b0db1..c2c3a4bb 100644 --- a/docs/components/picker/BrnDateRangePicker/BrnDateRangePicker.md +++ b/docs/components/picker/BrnDateRangePicker/BrnDateRangePicker.md @@ -41,22 +41,23 @@ group: ```dart static void showDatePicker( - BuildContext context, { - bool isDismissible, - DateTime minDateTime, - DateTime maxDateTime, - bool isLimitTimeRange, - DateTime initialStartDateTime, - DateTime initialEndDateTime, - String dateFormat, - int minuteDivider, - DateTimePickerLocale locale: DATETIME_PICKER_LOCALE_DEFAULT, - DateTimeRangePickerMode pickerMode: DateTimeRangePickerMode.date, - DateTimePickerTheme pickerTheme: DateTimePickerTheme.Default, - DateVoidCallback onCancel, - DateVoidCallback onClose, - DateRangeValueCallback onChange, - DateRangeValueCallback onConfirm, + BuildContext context, { + bool isDismissible = true, + DateTime? minDateTime, + DateTime? maxDateTime, + bool isLimitTimeRange = true, + DateTime? initialStartDateTime, + DateTime? initialEndDateTime, + String? dateFormat, + int minuteDivider = 1, + DateTimePickerLocale locale = datetimePickerLocaleDefault, + BrnDateTimeRangePickerMode pickerMode = BrnDateTimeRangePickerMode.date, + BrnPickerTitleConfig pickerTitleConfig = BrnPickerTitleConfig.Default, + DateVoidCallback? onCancel, + DateVoidCallback? onClose, + DateRangeValueCallback? onChange, + DateRangeValueCallback? onConfirm, + BrnPickerConfig? themeData, }) ``` ### 参数配置 @@ -64,21 +65,21 @@ static void showDatePicker( | **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | | isDismissible | bool | 用于控制弹窗是否相应电机外部关闭,true 关闭,false 不关闭 | 否 | true | -| minDateTime | DateTime | 时间区间最小值 | 否 | "1900-01-01 00:00:00" | -| maxDateTime | DateTime | 时间区间最大值 | 否 | "2100-12-31 23:59:59" | +| minDateTime? | DateTime | 时间区间最小值 | 否 | "1900-01-01 00:00:00" | +| maxDateTime? | DateTime | 时间区间最大值 | 否 | "2100-12-31 23:59:59" | | isLimitTimeRange | bool | 是否限制时间选择范围
true: 开始时间必须≤结束时间
false: 不限制开始时间,结束时间的值大小 | 否 | true | -| initialStartDateTime | DateTime | 初始设置选中的开始时间 | 否 | DateTime.now() | -| initialEndDateTime | DateTime | 初始设置选中的结束时间 | 否 | DateTime.now() | -| dateFormat | String | 展示格式,仅在pickerMode 为 DateTimeRangePickerMode.date时生效。可设置为”MM月-dd日“、”yyyy-年MM月-dd日“等年月日格式,将数据带上单位显示 | 否 | 'MM-dd' | +| initialStartDateTime | DateTime? | 初始设置选中的开始时间 | 否 | DateTime.now() | +| initialEndDateTime | DateTime? | 初始设置选中的结束时间 | 否 | DateTime.now() | +| dateFormat | String? | 展示格式,仅在pickerMode 为 DateTimeRangePickerMode.date时生效。可设置为”MM月-dd日“、”yyyy-年MM月-dd日“等年月日格式,将数据带上单位显示 | 否 | 'MM-dd' | | minuteDivider | int | 刻度值,仅在pickerMode 为DateTimeRangePickerMode.time时生效 | 否 | 1 | | locale | DateTimePickerLocale | 时区 | 否 | DateTimePickerLocale.zh\_cn | | pickerMode | DateTimeRangePickerMode | 要展示的时间范围选择类型,date 还是 time | 否 | DateTimeRangePickerMode.date | | pickerTitleConfig | `BrnPickerTitleConfig` | picker title 内容配置 | 否 | BrnPickerTitleConfig.Default | -| onCancel | DateVoidCallback | 取消回调 | 否 | | -| onClose | DateVoidCallback | 关闭回调 | 否 | | -| onChange | DateRangeValueCallback | 滚动变化回调 | 否 | | -| onConfirm | DateRangeValueCallback | 点击确定选中日期范围回调 | 否 | | -| themeData | BrnPickerConfig | 设置 Picker 相关主题 | 否 | BrnDefaultConfigUtils.defaultAllConfig.pickerConfig | +| onCancel | DateVoidCallback? | 取消回调 | 否 | | +| onClose | DateVoidCallback? | 关闭回调 | 否 | | +| onChange | DateRangeValueCallback? | 滚动变化回调 | 否 | | +| onConfirm | DateRangeValueCallback? | 点击确定选中日期范围回调 | 否 | | +| themeData | BrnPickerConfig? | 设置 Picker 相关主题 | 否 | BrnDefaultConfigUtils.defaultAllConfig.pickerConfig | ### 其它数据结构 diff --git a/docs/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md b/docs/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md index 0781a113..b674bbc6 100644 --- a/docs/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md +++ b/docs/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md @@ -25,7 +25,7 @@ ```dart BrnMultiColumnPicker( - {Key key, + {Key? key, @required this.entity, this.maxHeight = 280.0, this.showSelectedCount = false, @@ -68,16 +68,19 @@ enum PickerFilterType { ```dart class BrnPickerEntity { - String uniqueId; //唯一的id,可选 - String name; //筛选显示的文案 - String key; //回传给服务器的 key - String value; //回传给服务器的 value - String type; //类型 是单选、复选还是有自定义输入 - List children; //下级筛选项 - String defaultValue; //默认选中下一级的值,若 defaultValue 与 children 字段中筛选项的 value 值相同,则在数据初始化时将 isSelected 置为 true。 - Map extMap; //扩展字段,目前只有min和max,最大值,最小值范围;unit单位,例如居室、万,适配自定义区间填写的内容 - /// 支持最大选中个数,用于限制子节点可选中的最大个数。默认为 65535 + String? uniqueId; //唯一的id + String? type; //类型 目前支持的类型有不限(unlimit)、单选(radio)、复选(checkbox), 最终被解析成 PickerFilterType 类型 + String? key; //回传给服务器 + String? value; //回传给服务器 + String name; //显示的文案 + String? defaultValue; + List children; //下级筛选项 + Map? extMap; //扩展字段,目前只有min和max + + bool isSelected; //是否选中 int maxSelectedCount; + BrnPickerEntity? parent; //上级筛选项 + PickerFilterType? filterType; //筛选类型 } ``` @@ -95,8 +98,8 @@ rootBundle.loadString('assets/list_picker.json').then((data) { List _selectionData = List() ..addAll((JsonDecoder().convert(data)["data"]['list'] as List ?? []) .map((o) => BrnPickerEntity.fromMap(o))); - if (_selectionData != null && _selectionData.length > 0) { - _selectionData?.forEach((f) => f.configRelationshipAndDefaultValue()); + if (_selectionData.length > 0) { + _selectionData.forEach((f) => f.configRelationshipAndDefaultValue()); if (dataList.length == 0) { dataList.addAll(_selectionData); } diff --git a/docs/components/picker/BrnMultiDataPicker/BrnMultiDataPicker.md b/docs/components/picker/BrnMultiDataPicker/BrnMultiDataPicker.md index efb9cfc9..5e7c7d61 100644 --- a/docs/components/picker/BrnMultiDataPicker/BrnMultiDataPicker.md +++ b/docs/components/picker/BrnMultiDataPicker/BrnMultiDataPicker.md @@ -28,24 +28,24 @@ group: ```dart BrnMultiDataPickerWidget( - {Key key, - @required this.context, - @required this.delegate, - this.title = "", - this.titleTextStyle, - this.confirmTextStyle, - this.cancelTextStyle, - this.pickerTitles, - this.pickerTitleFontSize = 16, - this.pickerTitleColor = const Color(0XFF4A4E59), - this.textFontSize = 18, - this.textColor = const Color(0xff222222), - this.textSelectedColor, - this.behavior, - this.confirmClick, - this.createItemWidget, - this.sync = true, - this.themeData}) + {Key? key, + required this.context, + required this.delegate, + this.title = "", + this.titleTextStyle, + this.confirmTextStyle, + this.cancelTextStyle, + this.pickerTitles, + this.pickerTitleFontSize, + this.pickerTitleColor, + this.textFontSize, + this.textColor, + this.textSelectedColor, + this.behavior, + this.confirmClick, + this.createItemWidget, + this.themeData, + this.sync = true}) ``` ### 参数说明 @@ -54,21 +54,21 @@ BrnMultiDataPickerWidget( | --- | --- | --- | --- | --- | | context | Buildcontext | | 是 | | | delegate | BrnMultiDataPickerDelegate | 滚动组件每一列、每一行的具体内容设置,自定义delegate继承这个类,实现具体方法。 | 是 | | -| title | String | 滚动选择弹框的标题 | 否 | | -| titleTextStyle | TextStyle | 标题样式 | 否 | | -| confirmTextStyle | TextStyle | 确认文案样式 | 否 | | -| cancelTextStyle | TextStyle | 取消文案样式 | 否 | | -| pickerTitles | List | 多级数据选择每一级的默认标题 | 否 | 无 | -| pickerTitleFontSize | double | 多级数据选择每一级默认标题的字体大小 | 否 | 16 | -| pickerTitleColor | Color | 多级数据选择每一级默认标题的文案颜色 | 否 | Color(0XFF4A4E59) | -| textFontSize | double | 多级数据选择数据字体大小 | 否 | 18 | -| textColor | Color | 多级数据选择数据文案颜色 | 否 | Color(0xff222222) | -| textSelectedColor | Color | 多级数据选择数据选中文案颜色 | 否 | | -| behavior | ScrollBehavior | 选择轮盘的滚动行为 | 否 | | -| confirmClick | ConfirmButtonClick | 点击【完成】回调数据给调用方 | 否 | | -| createItemWidget | BrnMultiDataPickerCreateWidgetCallback | 返回自定义itemwidget | 否 | | +| title | String | 滚动选择弹框的标题 | 否 | "" | +| titleTextStyle | TextStyle? | 标题样式 | 否 | | +| confirmTextStyle | TextStyle? | 确认文案样式 | 否 | | +| cancelTextStyle | TextStyle? | 取消文案样式 | 否 | | +| pickerTitles | List? | 多级数据选择每一级的默认标题 | 否 | 无 | +| pickerTitleFontSize | double? | 多级数据选择每一级默认标题的字体大小 | 否 | 16 | +| pickerTitleColor | Color? | 多级数据选择每一级默认标题的文案颜色 | 否 | Color(0XFF4A4E59) | +| textFontSize | double? | 多级数据选择数据字体大小 | 否 | 18 | +| textColor | Color? | 多级数据选择数据文案颜色 | 否 | Color(0xff222222) | +| textSelectedColor | Color? | 多级数据选择数据选中文案颜色 | 否 | | +| behavior | ScrollBehavior? | 选择轮盘的滚动行为 | 否 | | +| confirmClick | ConfirmButtonClick? | 点击【完成】回调数据给调用方 | 否 | | +| createItemWidget | BrnMultiDataPickerCreateWidgetCallback? | 返回自定义itemwidget | 否 | | | sync | bool | 是否复位数据位置 | 否 | true | -| themeData | BrnPickerConfig | Picker配置类,配置详情见BrnPickerConfig | 否 | | +| themeData | BrnPickerConfig? | Picker配置类,配置详情见BrnPickerConfig | 否 | | ### 其它数据 @@ -158,7 +158,7 @@ class Brn1RowDelegate implements BrnMultiDataPickerDelegate { } @override - double rowHeightForComponent(int component) { + double? rowHeightForComponent(int component) { return PICKER_ITEM_HEIGHT; } @@ -283,7 +283,7 @@ class Brn1RowDelegate implements BrnMultiDataPickerDelegate { } @override - double rowHeightForComponent(int component) { + double? rowHeightForComponent(int component) { return null; } @@ -369,7 +369,7 @@ class Brn2RowDelegate implements BrnMultiDataPickerDelegate { } @override - double rowHeightForComponent(int component) { + double? rowHeightForComponent(int component) { return null; } @@ -483,7 +483,7 @@ class Brn2RowCustomDelegate implements BrnMultiDataPickerDelegate { } @override - double rowHeightForComponent(int component) { + double? rowHeightForComponent(int component) { return null; } diff --git a/docs/components/picker/BrnMultiSelectListPicker/BrnMultiSelectListPicker.md b/docs/components/picker/BrnMultiSelectListPicker/BrnMultiSelectListPicker.md index 252db42c..c14b2de8 100644 --- a/docs/components/picker/BrnMultiSelectListPicker/BrnMultiSelectListPicker.md +++ b/docs/components/picker/BrnMultiSelectListPicker/BrnMultiSelectListPicker.md @@ -32,25 +32,25 @@ group: ```dart BrnMultiSelectListPicker({ - Key key, - this.title, - this.items, - this.pickerTitleConfig = BrnPickerTitleConfig.Default, - this.onSubmit, - this.onCancel, - this.onItemClick, -}) + Key? key, + this.title, + required this.items, + this.pickerTitleConfig = BrnPickerTitleConfig.Default, + this.onSubmit, + this.onCancel, + this.onItemClick, + }) : super(key: key); ``` ### 参数说明 -| 参数名 | 参数类型 | 作用 | 是否必填 | 默认值 | -| ----------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------- | -------- | ---------------------------- | -| items | `List` | 数据源 | 是 | | -| pickerTitleConfig | BrnPickerTitleConfig | 设置 Picker 主题 | 否 | BrnPickerTitleConfig.Default | -| onSubmit | `BrnMultiSelectListPickerSubmit = bool Function(List checkedItems)` | 点击【完成】时回调给外部选中的数据 | 否 | | -| onItemClick | BrnMultiSelectListPickerItemClick = void Function(BuildContext context, int index) | Item 被点击的回调 | 否 | | -| isDismissible | bool | 是否可电机外部关闭弹窗,true 点击外部关闭弹窗 | 否 | true | +| 参数名 | 参数类型 | 作用 | 是否必填 | 默认值 | +| ----------------- | ------------------------------------------------------------ | --------------------------------------------- | -------- | ---------------------------- | +| items | `List` | 数据源 | 是 | | +| pickerTitleConfig | BrnPickerTitleConfig | 设置 Picker 主题 | 否 | BrnPickerTitleConfig.Default | +| onSubmit | `BrnMultiSelectListPickerSubmit = bool Function(List checkedItems)`? | 点击【完成】时回调给外部选中的数据 | 否 | | +| onItemClick | BrnMultiSelectListPickerItemClick = void Function(BuildContext context, int index)? | Item 被点击的回调 | 否 | | +| isDismissible | bool | 是否可电机外部关闭弹窗,true 点击外部关闭弹窗 | 否 | true | ### 其它数据结构 @@ -84,7 +84,7 @@ BrnPickerTitleConfig({ ```dart -List items = new List(); +List items = []; items.add(new BrnMultiSelectBottomPickerItem("100", "这里是标题1")); items.add(new BrnMultiSelectBottomPickerItem("101", "这里是标题2")); items.add(new BrnMultiSelectBottomPickerItem("102", "这里是标题3", isChecked: true)); @@ -112,7 +112,7 @@ BrnMultiSelectListPicker.show( ```dart -List items = new List(); +List items = []; items.add(new BrnMultiSelectBottomPickerItem("100", "这里是标题1")); items.add(new BrnMultiSelectBottomPickerItem("101", "这里是标题2")); items.add(new BrnMultiSelectBottomPickerItem("102", "这里是标题3", isChecked: true)); diff --git a/docs/components/picker/BrnMultiSelectTagsPicker/BrnMultiSelectTagsPicker.md b/docs/components/picker/BrnMultiSelectTagsPicker/BrnMultiSelectTagsPicker.md index 45fa8aa4..fc7b58ef 100644 --- a/docs/components/picker/BrnMultiSelectTagsPicker/BrnMultiSelectTagsPicker.md +++ b/docs/components/picker/BrnMultiSelectTagsPicker/BrnMultiSelectTagsPicker.md @@ -26,37 +26,36 @@ group: ```dart BrnMultiSelectTagsPicker({ - Key key, - @required this.context, - @required this.onConfirm, - this.onCancel, - @required this.tagPickerConfig, - @required this.onTagValueGetter, - this.onMaxSelectClick, - this.onItemClick, - this.maxSelectItemCount = 0, - this.brnCrossAxisCount, - this.itemHeight = 34.0, - this.layoutStyle = BrnMultiSelectTagsLayoutStyle.average, - BrnPickerTitleConfig pickerTitleConfig = BrnPickerTitleConfig.Default, - BrnPickerConfig themeData, -}) + Key? key, + required this.context, + required this.onConfirm, + this.onCancel, + required this.tagPickerConfig, + required this.onTagValueGetter, + this.onMaxSelectClick, + this.onItemClick, + this.maxSelectItemCount = 0, + this.crossAxisCount, + this.itemHeight = 34.0, + this.layoutStyle = BrnMultiSelectTagsLayoutStyle.average, + BrnPickerTitleConfig pickerTitleConfig = BrnPickerTitleConfig.Default, + BrnPickerConfig? themeData, + }) ``` ### 参数说明 | 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | | --- | --- | --- | --- | --- | | context | Buildcontext | | 是 | | -| headerBean | LJPickerHeaderBean | 设置弹框头部相关数据 | 否 | | | onConfirm | ValueChanged | 点击【完成】时回调给外部选中的数据 | 是 | | -| onCancel | VoidCallback | 点击【取消】时回调给外部的事件 | 否 | | +| onCancel | VoidCallback? | 点击【取消】时回调给外部的事件 | 否 | | | tagPickerConfig | BrnTagsPickerConfig | 设置弹框的tags数据,配置详情见BrnTagsPickerConfig | 否 | | | onTagValueGetter | TagValueGetter | 传入的泛型数据转换为字符串 以填充Widget | 是 | | -| crossAxisCount | int | 一行展示多少个item | 否 | | +| crossAxisCount | int? | 一行展示多少个item | 否 | | | maxSelectItemCount | int | 最大选中多少个item | 否 | 0 | | layoutStyle | BrnMultiSelectTagsLayoutStyle | 枚举.等分布局流式布局 | 否 | BrnMultiSelectTagsLayoutStyle.average | -| onMaxSelectClick | VoidCallback | 当点击到最大数目时的点击事件 | 否 | | -| onItemClick | BrnMultiSelectTagOnItemClick | 点击某个按钮的回调 | 否 | | +| onMaxSelectClick | VoidCallback? | 当点击到最大数目时的点击事件 | 否 | | +| onItemClick | BrnMultiSelectTagOnItemClick? | 点击某个按钮的回调 | 否 | | | itemHeight | double | item高度 | 否 | 34.0 | ### 其它数据 @@ -92,26 +91,27 @@ class BrnTagsPickerConfig { this.selectedTagBackgroudColor, this.chipPadding, this.tagItemSource = const []}) { - this.tagTitleColor = BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; + this.tagTitleColor = + BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; } ///tag 文字大小 double tagTitleFontSize; ///tag 文字颜色 - Color tagTitleColor; + Color? tagTitleColor; ///选中的tag颜色 - Color selectedTagTitleColor; + Color? selectedTagTitleColor; ///tag 背景颜色 - Color tagBackgroudColor; + Color? tagBackgroudColor; ///选中的颜色 - Color selectedTagBackgroudColor; + Color? selectedTagBackgroudColor; ///内部item的边距 - EdgeInsets chipPadding; + EdgeInsets? chipPadding; ///数据源 List tagItemSource; @@ -143,7 +143,7 @@ void _showMulSelectTagPicker(BuildContext context) { '可爱多', ]; - List items = List(); + List items = []; for (int i = 0; i < tags.length ;i++){ String it = tags[i]; BrnTagItemBean item = BrnTagItemBean(name: it,code: it,index: i, isSelect: true); diff --git a/docs/components/picker/BrnSelectTagsWithInputPicker/BrnSelectTagsWithInputPicker.md b/docs/components/picker/BrnSelectTagsWithInputPicker/BrnSelectTagsWithInputPicker.md index fa82b4a7..f8fac20e 100644 --- a/docs/components/picker/BrnSelectTagsWithInputPicker/BrnSelectTagsWithInputPicker.md +++ b/docs/components/picker/BrnSelectTagsWithInputPicker/BrnSelectTagsWithInputPicker.md @@ -39,19 +39,19 @@ group: ```dart -BrnSelectTagsWithInputPicker( - {this.maxLength = 200, - this.hintText = "请输入", - this.title = "", - this.confirm, - this.cancelCallBack, - this.cursorColor, - this.forceShowTextInput = false, - this.multiSelect = false, - this.defaultText, - this.textEditingController, - @required this.tagPickerConfig, - @required this.onTagValueGetter}); +const BrnSelectTagsWithInputPicker( + {this.maxLength = 200, + this.hintText = "请输入", + this.title = "", + this.confirm, + this.cancelCallBack, + this.cursorColor, + this.forceShowTextInput = false, + this.multiSelect = false, + this.defaultText, + this.textEditingController, + required this.tagPickerConfig, + required this.onTagValueGetter}); ``` ### 参数配置 @@ -60,15 +60,15 @@ BrnSelectTagsWithInputPicker( | title | String | Picker显示标题 | 否 | 空字符串 | | hintText | String | 默认输入框提示文本 | 否 | 请输入 | | maxLength | int | 输入框最长文本字符数 | 否 | 200 | -| confirm | BrnTagInputConfirmClickCallback | 点击“确定”按钮事件回调 | 否 | - | -| cancelCallBack | BrnTagInputCancelClickCallBack | 关闭Picker事件回调 | 否 | - | -| cursorColor | Color | 输入框光标颜色 | 否 | 主题色 | -| defaultText | String | 输入框默认文本 | 否 | 空字符串 | +| confirm | BrnTagInputConfirmClickCallback? | 点击“确定”按钮事件回调 | 否 | - | +| cancelCallBack | BrnTagInputCancelClickCallBack? | 关闭Picker事件回调 | 否 | - | +| cursorColor | Color? | 输入框光标颜色 | 否 | 主题色 | +| defaultText | String? | 输入框默认文本 | 否 | 空字符串 | | forceShowTextInput | bool | 强制显示输入框 | 否 | FALSE | | multiSelect | bool | 标签是否多选 | 否 | FALSE | | tagPickerConfig | BrnTagsInputPickerConfig | 标签数据源 | 是 | null | | onTagValueGetter | SelectTagWithInputValueGetter | 标签文案显示回调 | 是 | null | -| textEditingController | TextEditingController | 用于对 TextField 更精细的控制,若传入该字段,[defaultText] 参数将失效,可使用 TextEditingController.text 进行赋值 | 否 | | +| textEditingController | TextEditingController? | 用于对 TextField 更精细的控制,若传入该字段,[defaultText] 参数将失效,可使用 TextEditingController.text 进行赋值 | 否 | | ### 其他数据 @@ -77,10 +77,10 @@ BrnSelectTagsWithInputPicker( ```dart ///提交按钮事件回调 -typedef BrnTagInputConfirmClickCallback = Future Function( - BuildContext dialogContext, - List selectedTags, - String content); +typedef BrnTagInputConfirmClickCallback = Future? Function( + BuildContext dialogContext, + List? selectedTags, + String content); ``` #### BrnTagInputCancelClickCallBack @@ -88,7 +88,7 @@ typedef BrnTagInputConfirmClickCallback = Future Function( ```dart ///关闭 picker回调 -typedef BrnTagInputCancelClickCallBack = void Function(BuildContext context); +typedef BrnTagInputCancelClickCallBack = void Function(BuildContext context); ``` #### SelectTagWithInputValueGetter diff --git a/docs/components/tips/BrnPopupWindow/BrnPopupWindow.md b/docs/components/tips/BrnPopupWindow/BrnPopupWindow.md index df6c7526..45938484 100644 --- a/docs/components/tips/BrnPopupWindow/BrnPopupWindow.md +++ b/docs/components/tips/BrnPopupWindow/BrnPopupWindow.md @@ -29,23 +29,26 @@ group: ``` dart BrnPopupWindow(this.context, - {this.arrowHeight, - this.text, - this.popKey, - this.textStyle, - this.backgroundColor, - this.hasCloseIcon, - this.offset, - this.popDirection, - this.widget, - this.paddingInsets, - this.borderRadius, - this.canWrap = false, - this.spaceMargin, - this.borderColor, - this.arrowOffset, - this.onDismiss, - this.turnOverFromBottom = 50.0}) + {Key? key, + this.text, + required this.popKey, + this.arrowHeight = 6.0, + this.textStyle, + this.backgroundColor, + this.isShowCloseIcon = false, + this.offset = 0, + this.popDirection = BrnPopupDirection.bottom, + this.widget, + this.paddingInsets = + const EdgeInsets.only(left: 18, top: 14, right: 18, bottom: 14), + this.borderRadius = 4, + this.borderColor, + this.canWrap = false, + this.spaceMargin = 20, + this.arrowOffset, + this.onDismiss, + this.turnOverFromBottom = 50.0}) + : super(key: key); ``` @@ -54,23 +57,23 @@ BrnPopupWindow(this.context, | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | | context | BuildContext | 路由跳转Push和退出Pop的时候需要使用 | 是 | 无 | -| text | String | Tips的文本内容 | 是 | 无 | +| text | String? | Tips的文本内容 | 是 | 无 | | popKey | GlobalKey | 目标组件和当前组件传入的同一个GlobalKey值,便于计算目标组件位置等 | 是 | 无 | -| arrowHeight | double | 箭头的高度 | 否 | 6 | -| arrowOffset | double | 箭头偏移量 | 否 | arrowOffset = popKey 对应的 Widget 左右居中 - spaceMargin | -| textStyle | TextStyle | 显示的文本的样式 | 否 | TextStyle(fontSize: 16, color: Color(0xFFFFFFFF)) | -| backgroundColor | Color | Tips的背景颜色 | 否 | Color(0xFF1A1A1A) | +| arrowHeight | double | 箭头的高度 | 否 | 6.0 | +| arrowOffset | double? | 箭头偏移量 | 否 | arrowOffset = popKey 对应的 Widget 左右居中 - spaceMargin | +| textStyle | TextStyle? | 显示的文本的样式 | 否 | TextStyle(fontSize: 16, color: Color(0xFFFFFFFF)) | +| backgroundColor | Color? | Tips的背景颜色 | 否 | Color(0xFF1A1A1A) | | isShowCloseIcon | bool | 是否显示关闭图标 | 否 | false | | offset | double | Tips距离目标组件的偏移量 | 否 | 0 | | popDirection | PopDirection | 位于targetView的方向 | 否 | PopDirection.bottom | -| widget | Widget | 自定义显示的Widget | 否 | 无 | +| widget | Widget? | 自定义显示的Widget | 否 | 无 | | paddingInsets | EdgeInsets | Tips的内部Padding | 否 | EdgeInsets.only(left: 18, top: 14, right: 18, bottom: 14) | | borderRadius | double | Tips的外部圆角 | 否 | 4 | -| borderColor | Color | 边框颜色 | 否 | Colors.transparent | +| borderColor | Color? | 边框颜色 | 否 | Colors.transparent | | canWrap | bool | 是否能多行显示 默认false:单行显示 | 否 | false | | spaceMargin | double | Tips距离目标组件左右边线的距离 | 否 | 20 | -| onDismiss | VoidCallback | Tips消失时候的接口回调 | 否 | 无 | -| turnOverFromBottom | int | popWindow距离底部的距离小于此值的时候,自动将popWindow在targetView上面弹出 | 否 | 50 | +| onDismiss | VoidCallback? | Tips消失时候的接口回调 | 否 | 无 | +| turnOverFromBottom | double | popWindow距离底部的距离小于此值的时候,自动将popWindow在targetView上面弹出 | 否 | 50 | diff --git a/docs/components/toast/BrnToast/BrnToast.md b/docs/components/toast/BrnToast/BrnToast.md index 0ce8379b..ad2f7bb2 100644 --- a/docs/components/toast/BrnToast/BrnToast.md +++ b/docs/components/toast/BrnToast/BrnToast.md @@ -27,22 +27,34 @@ group: ```dart -static void show(String text, BuildContext context, - {int duration, - int gravity = BOTTOM, - Color backgroundColor = const Color(0xFF222222), - textStyle = const TextStyle(fontSize: 16, color: Colors.white), - double backgroundRadius = 5, - Image preIcon, - OnDismiss onDismiss}) +static void show( + String text, + BuildContext context, { + Duration? duration, + Color? background, + TextStyle? textStyle, + double? radius, + Image? preIcon, + double? verticalOffset, + VoidCallback? onDismiss, + BrnToastGravity? gravity, + }) ``` ```dart /// 显示在中间。如不设置duration则会自动根据内容长度来计算(更友好,最长5秒) -static void showInCenter(String text, BuildContext context, {int duration}) { - show(text, context, duration: duration, gravity: CENTER); -} +static void showInCenter( + {required String text, + required BuildContext context, + Duration? duration}) { + show( + text, + context, + duration: duration, + gravity: BrnToastGravity.center, + ); + } ``` ### 参数说明 @@ -51,12 +63,14 @@ static void showInCenter(String text, BuildContext context, {int duration}) { | --- | --- | --- | --- | --- | | text | String | 显示的文本 | 是 | 无 | | context | BuildContext | 创建OverlayState需要context | 是 | 无 | -| duration | int | Toast显示时间的长短 | 否 | BrnToast.LENGTH\_SHORT | -| gravity | int | Toast显示在顶部还是底部 | 否 | 0:显示在底部 | -| backgroundColor | Color | Toast的背景颜色 | 否 | Color(0xFF222222) | -| textStyle | TextStyle | Toast显示文本的样式 | 否 | TextStyle(fontSize: 16, color: Colors.white) | -| backgroundRadius | double | Toast的圆角大小 | 否 | 5 | -| preIcon | Image | 文字前面的图标 | 否 | 无 | +| duration | Duration? | Toast显示时间的长短 | 否 | BrnToast.LENGTH\_SHORT | +| gravity | BrnToastGravity? | Toast显示在顶部还是底部 | 否 | 0:显示在底部 | +| backgroundColor | Color? | Toast的背景颜色 | 否 | Color(0xFF222222) | +| textStyle | TextStyle? | Toast显示文本的样式 | 否 | TextStyle(fontSize: 16, color: Colors.white) | +| radius | double? | Toast的圆角大小 | 否 | 5 | +| preIcon | Image? | 文字前面的图标 | 否 | 无 | +| onDismiss | VoidCallback? | 是否可关闭 | 否 | 无 | +| verticalOffset | double? | 据中心偏移量 | 否 | 无 | ## 四、代码演示 @@ -74,14 +88,16 @@ BrnToast.show("共找到10932个结果", context, duration: BrnToast.LENGTH_LONG ```dart -BrnToast.show("失败文案", - context, - preIcon: Image.asset( - "assets/image/icon\_toast\_fail.png", - width: 24, - height: 24, - ), -duration: BrnToast.LENGTH_SHORT); +BrnToast.show( + "失败图标Toast", + context, + preIcon: Image.asset( + "assets/image/icon_toast_fail.png", + width: 24, + height: 24, + ), + duration: BrnDuration.short, + ); ``` ### 效果3:Toast/成功 @@ -91,12 +107,14 @@ duration: BrnToast.LENGTH_SHORT); ```dart -BrnToast.show("成功文案", - context, - preIcon: Image.asset( - "assets/image/icon\_toast\_success.png", - width: 24, - height: 24, - ), -duration: BrnToast.LENGTH_SHORT); +BrnToast.show( + "成功图标Toast", + context, + preIcon: Image.asset( + "assets/image/icon_toast_success.png", + width: 24, + height: 24, + ), + duration: BrnDuration.short, +); ``` diff --git a/example/lib/sample/components/button/brn_text_button_panel_example.dart b/example/lib/sample/components/button/brn_text_button_panel_example.dart index 0ebc055e..50cf4e80 100644 --- a/example/lib/sample/components/button/brn_text_button_panel_example.dart +++ b/example/lib/sample/components/button/brn_text_button_panel_example.dart @@ -26,7 +26,10 @@ class BrnTextButtonPanelExample extends StatelessWidget { text: '平分屏幕展示,不超过4个时全部展示,超过4个了,则只展示3个,剩余的放在更多里面', ), Text( - '正常案例', + '正常案例AAA', + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + maxLines: 1, style: TextStyle( color: Color(0xFF222222), fontSize: 18, diff --git a/lib/src/components/dialog/brn_dialog.dart b/lib/src/components/dialog/brn_dialog.dart index 44e06d0e..e3fb2adf 100644 --- a/lib/src/components/dialog/brn_dialog.dart +++ b/lib/src/components/dialog/brn_dialog.dart @@ -92,85 +92,6 @@ enum _ButtonType { right, } -/// 对话框的样式 -class BrnDialogStyle { - /// title的间距 - EdgeInsets? titlePadding; - - /// 主色调按钮样式 - TextStyle? mainTextStyle; - - /// 主色调按钮的背景 - Color? mainBackgroundColor; - - /// 其他按钮的样式 - TextStyle? greyActionsTextStyle; - - /// 其他按钮的背景 - Color? greyActionsBackgroundColor; - - /// 标题的文字样式 - TextStyle? titleTextStyle; - - /// 标题的文字对齐 - TextAlign? titleTextAlign; - - /// 内容文字的对齐 - TextAlign? contentTextAlign; - - /// 内容widget的间距 - EdgeInsets? contentPadding; - - /// 内容文字的样式 - TextStyle? contentTextStyle; - - /// 对话框的背景 - Color? backgroundColor; - - /// 对话框的底部按钮的高度 - double? bottomHeight; - - /// 对话框圆角的大小 - double? radius; - - /// 边框阴影 - double? elevation; - - /// 警示文案的样式 - TextStyle? warningTextStyle; - - /// 警示文案文字的对齐 - TextAlign? warningTextAlign; - - /// 警示文案的间距 - EdgeInsets? warningPadding; - - /// icon的间距 - EdgeInsets? iconPadding; - - /// 标题最大行数 - int? titleMaxLines; - - BrnDialogStyle({ - this.titlePadding, - this.titleTextAlign, - this.titleTextStyle, - this.contentPadding, - this.contentTextStyle, - this.warningTextStyle, - this.backgroundColor, - this.contentTextAlign, - this.mainBackgroundColor, - this.mainTextStyle, - this.greyActionsBackgroundColor, - this.greyActionsTextStyle, - this.bottomHeight, - this.warningPadding, - this.warningTextAlign, - this.iconPadding, - this.radius, - }); -} ///高度灵活的通用的弹窗组件 /// @@ -255,6 +176,7 @@ class BrnDialog extends AlertDialog { final int titleMaxLines; BrnDialog({ + Key? key, this.showIcon = false, this.iconImage, this.titleText, @@ -270,7 +192,7 @@ class BrnDialog extends AlertDialog { this.indexedActionCallback, this.themeData, this.titleMaxLines = cTitleMaxLines, - }); + }) : super(key: key); @override Widget build(BuildContext context) { @@ -676,7 +598,6 @@ class BrnDialogManager { String? warning, Widget? warningWidget, Widget? labelWidget, - BrnDialogStyle? dialogStyle, GestureTapCallback? onTap, bool barrierDismissible = true, int titleMaxLines = cTitleMaxLines, @@ -735,7 +656,6 @@ class BrnDialogManager { Widget? warningWidget, Widget? cancelWidget, Widget? conformWidget, - BrnDialogStyle? dialogStyle, GestureTapCallback? onCancel, GestureTapCallback? onConfirm, bool barrierDismissible = true, @@ -800,7 +720,6 @@ class BrnDialogManager { Widget? warningWidget, List? actionsWidget, bool barrierDismissible = true, - BrnDialogStyle? dialogStyle, int titleMaxLines = cTitleMaxLines, BrnDialogConfig? themeData, DialogIndexedActionClickCallback? indexedActionClickCallback, diff --git a/lib/src/components/dialog/brn_middle_input_diaolg.dart b/lib/src/components/dialog/brn_middle_input_diaolg.dart index ec66d2ff..35ae8b3c 100644 --- a/lib/src/components/dialog/brn_middle_input_diaolg.dart +++ b/lib/src/components/dialog/brn_middle_input_diaolg.dart @@ -26,9 +26,6 @@ class BrnMiddleInputDialog { /// 点击确定时的回调,参数为输入框中的字符 final void Function(String value)? onConfirm; - /// 弹窗样式。具体参见 [BrnDialogStyle] - final BrnDialogStyle? dialogStyle; - /// 点击取消时的回调 final VoidCallback? onCancel; @@ -72,7 +69,6 @@ class BrnMiddleInputDialog { this.textInputAction = TextInputAction.newline, this.cancelText = '取消', this.confirmText = '确定', - this.dialogStyle, this.onConfirm, this.onCancel, this.dismissOnActionsTap = true, @@ -162,7 +158,6 @@ class BrnMiddleInputDialog { confirm: confirmText, title: title, barrierDismissible: barrierDismissible, - dialogStyle: dialogStyle ?? BrnDialogStyle(), messageWidget: Padding( padding: const EdgeInsets.only(top: 12, left: 24, right: 24), child: Column( diff --git a/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart b/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart index b64f03df..f62db1ec 100644 --- a/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart +++ b/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart @@ -16,8 +16,7 @@ enum PickerWindowType { class BrnPickerEntity { String? uniqueId; //唯一的id - String? - type; //类型 目前支持的类型有不限(unlimit)、单选(radio)、复选(checkbox), 最终被解析成 PickerFilterType 类型 + String? type; //类型 目前支持的类型有不限(unlimit)、单选(radio)、复选(checkbox), 最终被解析成 PickerFilterType 类型 String? key; //回传给服务器 String? value; //回传给服务器 String name; //显示的文案 From fe2a99f5b5f6626b519e7e2e410e7a3a3c2f9bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E8=84=B8=E5=84=BF?= Date: Thu, 10 Mar 2022 16:13:31 +0800 Subject: [PATCH 11/24] merge null safe to 2.2.x (#122) * merge null safe to 2.2.x * remove dialogStyle --- CHANGELOG.md | 1 - .../BrnAbnormalStateWidget.md | 33 +- .../BrnCommonActionSheet.md | 119 +++--- .../BrnSelectedListActionSheet.md | 360 ++++++++++-------- .../BrnShareActionSheet.md | 159 ++++---- .../anchor/BrnAnchorTab/BrnAnchorTab.md | 48 ++- docs/components/appbar/BrnAppBar/BrnAppBar.md | 163 ++++---- .../appbar/BrnSearchAppbar/BrnSearchAppbar.md | 37 +- .../img/BrnSearchAppbarDemo2.png | Bin 13196 -> 17088 bytes .../appraise/BrnAppraise/BrnAppraise.md | 127 +++--- .../BrnAppraiseBottomPicker.md | 37 +- .../BrnBottomTabBar/BrnBottomTabBar.md | 65 +++- .../form/BrnAddLabel/BrnAddLabel.md | 16 +- .../form/BrnBaseTitle/BrnBaseTitle.md | 52 +-- .../BrnExpandFormGroup/BrnExpandFormGroup.md | 41 +- .../BrnExpandableGroup/BrnExpandableGroup.md | 27 +- .../BrnMultiChoiceInputFormItem.md | 66 ++-- .../BrnMultiChoicePortraitInputFormItem.md | 69 ++-- .../BrnNormalFormGroup/BrnNormalFormGroup.md | 33 +- .../BrnPortraitRadioGroup.md | 77 ++-- .../BrnRadioInputFormItem.md | 71 ++-- .../BrnRadioPortraitInputFormItem.md | 43 +-- .../BrnRangeInputFormItem.md | 49 +-- .../BrnRatioInputFormItem.md | 27 +- .../BrnSelectAllTitle/BrnSelectAllTitle.md | 36 +- .../form/BrnStarsFormItem/BrnStarsFormItem.md | 22 +- .../BrnStepInputFormItem.md | 63 +-- .../BrnTextBlockInputFormItem.md | 47 ++- .../BrnTextInputFormItem.md | 46 +-- .../BrnTextQuickSelectFormItem.md | 39 +- .../BrnTextSelectFormItem.md | 27 +- .../form/BrnTitleFormItem/BrnTitleFormItem.md | 30 +- .../BrnTitleSelectInputFormItem.md | 80 ++-- .../BrnFlatSelection/BrnFlatSelection.md | 19 +- .../BrnSelectionView/BrnSelectionView.md | 28 +- .../BrnSimpleSelection/BrnSimpleSelection.md | 24 +- docs/components/tabbar/BrnTabBar/BrnTabBar.md | 138 ++++--- .../text/BrnPairInfoTable/BrnPairInfoTable.md | 43 ++- .../components/appraise/appraise_example.dart | 2 +- .../components/dialog/dialog_entry_page.dart | 1 + .../navbar/nav_bar_example_page.dart | 5 +- ...selectionview_customview_example_page.dart | 2 +- .../brn_selected_list_action_sheet.dart | 36 +- .../card/bubble_card/brn_bubble_text.dart | 5 +- .../content_card/brn_pair_info_table.dart | 18 +- .../charts/broken_line/brn_broken_line.dart | 2 +- .../charts/broken_line/brn_line_painter.dart | 6 +- lib/src/components/dialog/brn_dialog.dart | 5 +- .../dialog/brn_middle_input_diaolg.dart | 2 +- .../dialog/brn_scrollable_text_dialog.dart | 6 +- .../general/brn_multi_choice_input_item.dart | 1 - .../brn_multi_choice_portrait_input_item.dart | 1 - .../general/brn_quick_select_input_item.dart | 1 - .../items/general/brn_radio_input_item.dart | 1 - .../brn_radio_portrait_input_item.dart | 7 - .../items/general/brn_ratio_input_item.dart | 1 - .../items/general/brn_star_input_item.dart | 1 - .../items/general/brn_step_input_item.dart | 6 - .../general/brn_text_block_input_item.dart | 1 - .../items/general/brn_text_select_item.dart | 1 - .../items/group/brn_portrait_radio_group.dart | 1 - .../form/items/misc/brn_title_item.dart | 1 - .../form/items/title/brn_base_title_item.dart | 1 - .../time_picker/brn_date_time_formatter.dart | 4 +- .../components/popup/brn_popup_window.dart | 58 +-- .../scroll_anchor/brn_scroll_anchor_tab.dart | 1 - .../selectcity/brn_base_azlistview_page.dart | 2 +- .../components/selectcity/brn_index_bar.dart | 2 +- .../bottom/brn_bottom_tab_bar_item.dart | 4 - .../bottom/brn_bottom_tab_bar_main.dart | 1 - .../components/tabbar/normal/brn_tab_bar.dart | 3 - lib/src/theme/configs/brn_common_config.dart | 2 + 72 files changed, 1335 insertions(+), 1218 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7aed7f0f..cbb050d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,4 +42,3 @@ Thanks again to **leftcoding**, **jojinshallar**, **laiiihz**, **donywan**, - First publish adapt flutter sdk 1.22.4 - diff --git a/docs/components/abnormalCard/BrnAbnormalStateWidget/BrnAbnormalStateWidget.md b/docs/components/abnormalCard/BrnAbnormalStateWidget/BrnAbnormalStateWidget.md index 3d1d6bb2..f90d1542 100644 --- a/docs/components/abnormalCard/BrnAbnormalStateWidget/BrnAbnormalStateWidget.md +++ b/docs/components/abnormalCard/BrnAbnormalStateWidget/BrnAbnormalStateWidget.md @@ -42,29 +42,30 @@ BrnAbnormalStateWidget({ this.topPercent: 0.08, this.themeData, }) { - this.themeData ??= BrnEmptyConfig(); + this.themeData ??= BrnAbnormalStateConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) - .emptyConfig + .getConfig(configId: this.themeData!.configId) + .abnormalStateConfig .merge(this.themeData); } ``` ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| ---------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | ------------ | -------------------------- | -| img | Image | 图片 | 否 | | -| title | String | 标题 | 否 | | -| content | String | 内容 | 否 | | -| operateAreaType | enum OperateAreaType { singleButton, doubleButton, textButton } | 操作区类型。SingleButton 为【单按钮】效果 DoubleButton 为【双按钮】效果 TextButton 为【文字链】效果 | 否 | OperateAreaType.TextButton | -| operateTexts | List | | | | -| action | BrnEmptyStatusIndexedActionClickCallback = void Function(int index)index 点击的位置 | 点击回调,在 SingleButton 类型或者 enablePageTap = true 点击空白区域时返回 0;其他根据点击的位置返回。 | 否 | | -| enablePageTap | bool | 空白区域是否可点击 | 否 | false | -| topOffset | double | 顶部距离,默认为 null,走自动计算逻辑:父视图高度的 8%,可自己指定高度 | 否 | null | -| bgColor | Color | 背景色 | 否 | Colors.white | -| isCenterVertical | bool | 内容是否垂直居中 | 否 | false | -| topPercent | double | 距顶部高度百分比 | 否 | 0.08 | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| ---------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------ | -------------------------- | +| img | Image? | 图片 | 否 | null | +| title | String? | 标题 | 否 | null | +| content | String? | 内容 | 否 | null | +| operateAreaType | enum OperateAreaType { SingleButton, DoubleButton, TextButton } | 操作区类型。SingleButton 为【单按钮】效果 DoubleButton 为【双按钮】效果 TextButton 为【文字链】效果 | 否 | OperateAreaType.TextButton | +| operateTexts | `List?` | 操作区文案 | 否 | null | +| action | `BrnEmptyStatusIndexedActionClickCallback? = void Function(int index)index?` | 点击回调,在 SingleButton 类型或者 enablePageTap = true 点击空白区域时返回 0;其他根据点击的位置返回。 | 否 | | +| enablePageTap | bool | 空白区域是否可点击 | 否 | false | +| topOffset | double? | 顶部距离,默认为 null,走自动计算逻辑:父视图高度的 8%,可自己指定高度 | 否 | null | +| bgColor | Color | 背景色 | 否 | Colors.white | +| isCenterVertical | bool | 内容是否垂直居中 | 否 | false | +| topPercent | double | 距顶部高度百分比 | 否 | 0.08 | +| themeData | BrnAbnormalStateConfig? | 主题配置 | 否 | 无 | ## 四、代码演示 diff --git a/docs/components/actionsheet/BrnCommonActionSheet/BrnCommonActionSheet.md b/docs/components/actionsheet/BrnCommonActionSheet/BrnCommonActionSheet.md index ee2b9834..80a3f201 100644 --- a/docs/components/actionsheet/BrnCommonActionSheet/BrnCommonActionSheet.md +++ b/docs/components/actionsheet/BrnCommonActionSheet/BrnCommonActionSheet.md @@ -31,7 +31,7 @@ group: ```dart BrnCommonActionSheet({ - @required this.actions, + required this.actions, this.title, this.titleWidget, this.cancelTitle, @@ -42,10 +42,10 @@ BrnCommonActionSheet({ this.maxSheetHeight = 0, this.onItemClickInterceptor, this.themeData, -}) : assert(actions != null) { +}) { themeData ??= BrnActionSheetConfig(); themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) + .getConfig(configId: themeData!.configId) .actionSheetConfig .merge(themeData); } @@ -53,19 +53,19 @@ BrnCommonActionSheet({ ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ------------------------- | -| actions | `List` | 用于存储每个选项的相关配置信息的列表(\*BrnActionItem 含有参数 title---选项标题文案(**必填**),desc----辅助信息文案,actionEleStyle----普通项或警示项,titleStyle---自定义主标题文本样式(覆盖 actionEleStyle)descStyle---自定义辅助信息文本样式(覆盖 actionEleStyle)) | 是 | 空 | -| title | String | 列表标题的文案 | 否 | 空 | -| titleWidget | Widget | 列表标题区域自定义 Widget | 否 | 空 | -| cancelTitle | String | 取消按钮的文案 | 否 | **“取消”** | -| maxTitleLines | Int | 列表标题文案最大行数 | 否 | 2 | -| onItemClickInterceptor | BrnCommonActionSheetItemClickInterceptor( int index, BrnCommonActionSheetItem actionItem) | **返回值为 bool**,返回值用于判断是否拦截点击事件,如果为**true**将拦截,用户点击将**不会触发 clickCallBack**,当前 actionSheet 也**不会消失**。如果为**false**,则不会造成任何影响,只是提前拦截了一下点击事件。 | 否 | 空 | -| clickCallBack(默认回调后会执行 pop 操作,如过不想 pop,请使用 onItemClickInterceptor) | BrnCommonActionSheetItemClickCallBack( int index, BrnCommonActionSheetItem actionItem) | **返回值为 void**,点击后回调方法(方法传参为被点击的按钮的**index**及相关配置信息**BrnActionItem**),使用者**根据参数自行配置响应动作**。 | 是 | 空 | -| spaceColor | Color | “取消”按钮上方间隔颜色 | 否 | **Color(0xfff8f8f8)**浅灰 | -| separatorLineColor | Color | 分割线颜色 | 否 | **Color(0xfff0f0f0)**浅灰 | -| maxSheetHeight | double | 列表最大高度限制 | 否 | 屏幕高度减去上下安全距离 | -| themeData | BrnActionSheetConfig | ActionSheet 主题配置类,支持配置字段详见 BrnActionSheetConfig | 否 | | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------ | ------------------------- | +| actions | `List` | 用于存储每个选项的相关配置信息的列表(\*BrnActionItem 含有参数 title---选项标题文案(**必填**),desc----辅助信息文案,actionEleStyle----普通项或警示项,titleStyle---自定义主标题文本样式(覆盖 actionEleStyle)descStyle---自定义辅助信息文本样式(覆盖 actionEleStyle)) | 是 | 空 | +| title | String? | 列表标题的文案 | 否 | 空 | +| titleWidget | Widget? | 列表标题区域自定义 Widget | 否 | 空 | +| cancelTitle | String? | 取消按钮的文案 | 否 | ''取消'' | +| maxTitleLines | Int | 列表标题文案最大行数 | 否 | 2 | +| onItemClickInterceptor | BrnCommonActionSheetItemClickInterceptor? =void( int index, BrnCommonActionSheetItem actionItem)? | **返回值为 bool**,返回值用于判断是否拦截点击事件,如果为**true**将拦截,用户点击将**不会触发 clickCallBack**,当前 actionSheet 也**不会消失**。如果为**false**,则不会造成任何影响,只是提前拦截了一下点击事件。 | 否 | 空 | +| clickCallBack(默认回调后会执行 pop 操作,如过不想 pop,请使用 onItemClickInterceptor) | BrnCommonActionSheetItemClickCallBack?=void ( int index, BrnCommonActionSheetItem actionItem)? | **返回值为 void**,点击后回调方法(方法传参为被点击的按钮的**index**及相关配置信息**BrnActionItem**),使用者**根据参数自行配置响应动作**。 | 是 | 空 | +| spaceColor | Color | “取消”按钮上方间隔颜色 | 否 | **Color(0xfff8f8f8)**浅灰 | +| separatorLineColor | Color? | 分割线颜色 | 否 | **Color(0xfff0f0f0)**浅灰 | +| maxSheetHeight | double | 列表最大高度限制 | 否 | 默认为0 | +| themeData | BrnActionSheetConfig? | ActionSheet 主题配置类,支持配置字段详见 BrnActionSheetConfig | 否 | | ## 四、代码演示 @@ -74,7 +74,7 @@ BrnCommonActionSheet({ ```dart -List actions = List(); +List actions = []; actions.add(BrnCommonActionSheetItem( '选项一(警示项)', desc: '辅助信息辅助信息辅助信息', @@ -113,7 +113,7 @@ showModalBottomSheet( ```dart -List actions = List(); +List actions = []; actions.add(BrnCommonActionSheetItem( '选项一(警示项)', actionStyle: BrnCommonActionSheetItemStyle.alert, @@ -129,21 +129,20 @@ List actions = List(); // 展示actionSheet showModalBottomSheet( - context: context, - backgroundColor: Colors.transparent, - builder: (BuildContext context) { - return BrnCommonActionSheet( - actions: actions, - clickCallBack: ( - int index, - BrnCommonActionSheetItem actionEle, - ) { - String title = actionEle.title; - BrnToast.show("title: $title, index: $index", context); - }, - ); - }); - + context: context, + backgroundColor: Colors.transparent, + builder: (BuildContext context) { + return BrnCommonActionSheet( + actions: actions, + clickCallBack: ( + int index, + BrnCommonActionSheetItem actionEle, + ) { + String title = actionEle.title; + BrnToast.show("title: $title, index: $index", context); + }, + ); + }); ``` ### 效果 3:无独立辅助信息+蓝色样式 @@ -151,7 +150,7 @@ List actions = List(); ```dart -List actions = List(); +List actions = []; actions.add(BrnCommonActionSheetItem( '选项一: (010)1234567', actionStyle: BrnCommonActionSheetItemStyle.link, @@ -189,40 +188,40 @@ List actions = List(); ```dart -List actions = List(); +List actions = []; actions.add( -BrnCommonActionSheetItem( - '选项一: 自定义主标题样式', - desc: '辅助信息默认样式', - titleStyle: TextStyle( - fontSize: 18, - color: Color(0xFF123984), + BrnCommonActionSheetItem( + '选项一: 自定义主标题样式', + desc: '辅助信息默认样式', + titleStyle: TextStyle( + fontSize: 18, + color: Color(0xFF123984), + ), ), -), ); actions.add( -BrnCommonActionSheetItem( - '选项二: 自定义辅助信息样式', - desc: '自定义辅助信息样式', - descStyle: TextStyle( - fontSize: 14, - color: Color(0xFF129834), + BrnCommonActionSheetItem( + '选项二: 自定义辅助信息样式', + desc: '自定义辅助信息样式', + descStyle: TextStyle( + fontSize: 14, + color: Color(0xFF129834), + ), ), -), ); actions.add( -BrnCommonActionSheetItem( - '选项三: 自定义拦截点击事件,点击无效', - desc: '辅助信息', - titleStyle: TextStyle( - fontSize: 16, - color: Color(0xFF999999), - ), - descStyle: TextStyle( - fontSize: 14, - color: Color(0xFF999999), + BrnCommonActionSheetItem( + '选项三: 自定义拦截点击事件,点击无效', + desc: '辅助信息', + titleStyle: TextStyle( + fontSize: 16, + color: Color(0xFF999999), + ), + descStyle: TextStyle( + fontSize: 14, + color: Color(0xFF999999), + ), ), -), ); // 展示actionSheet diff --git a/docs/components/actionsheet/BrnSelectedListActionSheet/BrnSelectedListActionSheet.md b/docs/components/actionsheet/BrnSelectedListActionSheet/BrnSelectedListActionSheet.md index 3939dd99..9af650b9 100644 --- a/docs/components/actionsheet/BrnSelectedListActionSheet/BrnSelectedListActionSheet.md +++ b/docs/components/actionsheet/BrnSelectedListActionSheet/BrnSelectedListActionSheet.md @@ -52,7 +52,7 @@ WillPopScope( ```dart BrnSelectedListActionSheet( - {this.context, + {required this.context, this.maxHeight = 290, this.bottomOffset = 82, this.title, @@ -60,8 +60,8 @@ BrnSelectedListActionSheet( this.isClearButtonHidden = false, this.isDeleteButtonHidden = false, this.itemIconImage, - this.items, - this.itemTitleBuilder, + required this.items, + required this.itemTitleBuilder, this.onClear, this.onClearConfirmed, this.onClearCanceled, @@ -76,27 +76,27 @@ BrnSelectedListActionSheet( | **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | | `context` | `BuildContext` | 构建context | 是 | 无 | -| `selectedModelList` | `List` | 数据列表模型 | 是 | 无 | -| `itemTitleBuilder` | `dynamic Function(int index, T entity)` | 每行视图构建的回调。可返回 `String`或者`Widget`。返回 `String` 的话,内部会通过默认方式创建 `Text`,自动折行并展示文字。返回 `widget` ,默认是业务方自定义每一行的视图,此时左侧的`itemIconImage`自动隐藏,自定义视图显示的范围为从最左到右边的删除按钮的左侧(可通过`isDeleteButtonHidden`隐藏删除按钮) | 是 | 无 | -| controller | BrnSelectedItemListActionSheetWidgetController | 控制视图隐藏/刷新列表等方法 | 否 | 无 | +| `items` | `List` | 数据列表模型 | 是 | 无 | +| `itemTitleBuilder` | `void dynamic Function(int index, T entity)` | 每行视图构建的回调。可返回 `String`或者`Widget`。返回 `String` 的话,内部会通过默认方式创建 `Text`,自动折行并展示文字。返回 `widget` ,默认是业务方自定义每一行的视图,此时左侧的`itemIconImage`自动隐藏,自定义视图显示的范围为从最左到右边的删除按钮的左侧(可通过`isDeleteButtonHidden`隐藏删除按钮) | 是 | 无 | +| controller | `BrnSelectedItemListActionSheetWidgetController?` | 控制视图隐藏/刷新列表等方法 | 否 | 无 | | `maxHeight` | `double` | 列表的最大高度,小于这个高度视图自适应,超过该值,组件高度固定,列表内容滑动。列表内容的高度=maxHeight-65 | 否 | 290 | -| bottomOffset | double | 列表关闭动画结束时底部的 y。0 会和屏幕的底部重合。不能为负值! | 否 | 默认值 82。 | -| `title` | `String` | 弹窗标题 | 否 | 无,标题默认样式 `TextStyle(fontSize: 18,color: Color(0xff222222),fontWeight: FontWeight.w600,decoration: TextDecoration.none)` | -| `titleWidget` | `Widget` | 自定义标题视图。默认外层有 `const EdgeInsets.fromLTRB(20, 20, 20, 15)` 的 padding,且优先级比 title 高 | 否 | 无 | +| `bottomOffset` | `double` | 列表关闭动画结束时底部的 y。0 会和屏幕的底部重合。不能为负值! | 否 | 默认值 82 | +| `title` | `String?` | 弹窗标题 | 否 | 无,标题默认样式 `TextStyle(fontSize: 18,color: Color(0xff222222),fontWeight: FontWeight.w600,decoration: TextDecoration.none)` | +| `titleWidget` | `Widget?` | 自定义标题视图。默认外层有 `const EdgeInsets.fromLTRB(20, 20, 20, 15)` 的 padding,且优先级比 title 高 | 否 | 无 | | `isClearButtonHidden` | `bool` | 是否隐藏顶部工具条中的清空按钮 | 否 | `false` | | `isDeleteButtonHidden` | `bool` | 每一行删除按钮是否隐藏。如果不显示,自定义每一行 `widget` 时内容可以填充整行 | 否 | `false` | -| `itemIconImage` | `Image` | 每一行前边的 `icon`,可不传,如果该 `image` 没有设置,并且 `itemTitleBuilder` 返回的是自定义 `widget`,则该 `widget`自动填充整行区域 | 否 | 无 | -| `onClear` | `VoidCallback` | 清空按钮点击之后,确认弹窗 确定 按钮的点击回调 | 否 | 无 | -| `onClearCanceled` | `VoidCallback` | 清空按钮点击之后,确认弹窗 `取消` 按钮的点击回调 | 否 | 无 | -| `onClearConfirmed` | `VoidCallback` | 清空按钮点击显示默认确认弹窗之后,`确定` 按钮的点击回调 | 否 | 无 | -| `onItemDelete` | `bool Function(int deleteIdx, T deleteEntity)` | 每一行删除按钮的点击回调。返回值:是否要删除该 entity,如果该回调没有实现或者返回 true,则删除 | 否 | 无 | -| `onListDismissed` | `void Function(bool isClosedByClearButton)` | 视图隐藏时的回调,`isClosedByClearButton`是否是清空按钮触发的关闭视图 | 否 | 无 | -| `onListShowed` | `VoidCallback` | 视图显示时的回调 | 否 | 无 | +| `itemIconImage` | `Image?` | 每一行前边的 `icon`,可不传,如果该 `image` 没有设置,并且 `itemTitleBuilder` 返回的是自定义 `widget`,则该 `widget`自动填充整行区域 | 否 | 无 | +| `onClear` | `VoidCallback?` | 清空按钮点击之后,确认弹窗 确定 按钮的点击回调 | 否 | 无 | +| `onClearCanceled` | `VoidCallback?` | 清空按钮点击之后,确认弹窗 `取消` 按钮的点击回调 | 否 | 无 | +| `onClearConfirmed` | `VoidCallback?` | 清空按钮点击显示默认确认弹窗之后,`确定` 按钮的点击回调 | 否 | 无 | +| `onItemDelete` | `bool Function(int deleteIdx, T deleteEntity)?` | 每一行删除按钮的点击回调。返回值:是否要删除该 entity,如果该回调没有实现或者返回 true,则删除 | 否 | 无 | +| `onListDismissed` | `void Function(bool isClosedByClearButton)?` | 视图隐藏时的回调,`isClosedByClearButton`是否是清空按钮触发的关闭视图 | 否 | 无 | +| `onListShowed` | `VoidCallback?` | 视图显示时的回调 | 否 | 无 | -| 方法名称 | 作用 | -| ----------------------------------------------------- | ------------------------------------------------------------ | -| `void showWithTargetKey({GlobalKey bottomWidgetKey})` | 显示已选列表。bottomWidgetKey: 已选列表下边操作视图绑定的 GlobalKey,组件内会自动与操作区域左右对齐,且从操作区域的顶部滑出 | -| `void show()` | 展示列表。请通过 controller 控制关闭列表 | +| 方法名称 | 作用 | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| `void showWithTargetKey({required GlobalKey bottomWidgetKey})` | 显示已选列表。bottomWidgetKey: 已选列表下边操作视图绑定的 GlobalKey,组件内会自动与操作区域左右对齐,且从操作区域的顶部滑出 | +| `void show()` | 展示列表。请通过 controller 控制关闭列表 | ### 其他参数说明 @@ -123,77 +123,108 @@ List _data = [ ]; BrnSelectedListActionSheetController controller = BrnSelectedListActionSheetController(); -BrnVerticalIconButton( - name: '已选(${_data.length})', - iconWidget: BrunoTools.getAssetImage( - 'icons/grey_place_holder.png'), - onTap: () { - if (!controller.isHidden) { - controller.dismiss(); - } else { - if (_data == null || _data.length <= 0) { - BrnToast.show('数据为空,弹窗不展示', context); - return; +@override +Widget build(BuildContext context) { + /// 要拦截 Android 的系统返回行为,请务必自行添加以下 WillPopScope 逻辑 + return WillPopScope( + onWillPop: () async { + if (!controller.isHidden) { + controller.dismiss(); + return false; } - BrnSelectedListActionSheet( - context: context, - isClearButtonHidden: false, - isDeleteButtonHidden: false, - items: _data, - bottomOffset: 82, - controller: controller, - title: '已选标题,优先级没有titleWidget高', - titleWidget: Container( - color: Colors.blueGrey, - child: Center( - child: Text( - '自定义的视图', - style: TextStyle( - color: Colors.white, - fontSize: 16, - decoration: TextDecoration.none, - ), - ), - ), + return true; + }, + child: Scaffold( + appBar: BrnAppBar( + title: '已选菜单列表', + ), + body: SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + BrnBottomButtonPanel( + mainButtonName: 'BrnBottomButtonPanel', + mainButtonOnTap: () { + BrnToast.show('确定!sheet 的数据源长度 ${_data.length}', context); + }, + iconButtonList: [ + BrnVerticalIconButton( + name: '已选(${_data.length})', + iconWidget: BrunoTools.getAssetImage( + 'icons/grey_place_holder.png'), + onTap: () { + if (!controller.isHidden) { + controller.dismiss(); + } else { + if ( _data.length <= 0) { + BrnToast.show('数据为空,弹窗不展示', context); + return; + } + BrnSelectedListActionSheet( + context: context, + isClearButtonHidden: false, + isDeleteButtonHidden: false, + items: _data, + bottomOffset: 82, + controller: controller, + title: '已选标题,优先级没有titleWidget高', + titleWidget: Container( + color: Colors.blueGrey, + child: Center( + child: Text( + '自定义的视图', + style: TextStyle( + color: Colors.white, + fontSize: 16, + decoration: TextDecoration.none, + ), + ), + ), + ), + itemTitleBuilder: (int index, String entity) { + return entity; + }, + onClear: () { + controller.dismiss(); + // 自定义清空的操作,可以不实现,会走默认的清空操作。 + BrnDialogManager.showConfirmDialog(context, + title: "确定要清空已选列表吗?", + cancel: '取消', + confirm: '确定', onConfirm: () { + setState(() {}); + _data.clear(); + }, onCancel: () {}); + }, + onClearCanceled: () { + BrnToast.show("取消!!!!", context); + }, + onClearConfirmed: () { + setState(() {}); + BrnToast.show("确定!!!!", context); + }, + onListDismissed: + (bool isClosedByClearButton) { + BrnToast.show( + "消失了!!!!$isClosedByClearButton", + context); + }, + onListShowed: () { + BrnToast.show("显示了哦~~", context); + }, + onItemDelete: (int idx, String entity) { + _data[idx] = '$idx 变化了哈'; + controller.reloadData(); + BrnToast.show("$idx 奇数行无法删除", context); + return true; + }).show(); + } + }) + ]), + ], ), - itemTitleBuilder: (int index, String entity) { - return entity; - }, - onClear: () { - controller.dismiss(); - // 自定义清空的操作,可以不实现,会走默认的清空操作。 - BrnDialogManager.showConfirmDialog(context, - title: "确定要清空已选列表吗?", - cancel: '取消', - confirm: '确定', confirmTap: () { - setState(() {}); - _data.clear(); - }, cancelTap: () {}); - }, - onClearCanceled: () { - BrnToast.show("取消!!!!", context); - }, - onClearConfirmed: () { - setState(() {}); - BrnToast.show("确定!!!!", context); - }, - onListDismissed: - (bool isClosedByClearButton) { - BrnToast.show( - "消失了!!!!$isClosedByClearButton", - context); - }, - onListShowed: () { - BrnToast.show("显示了哦~~", context); - }, - onItemDelete: (int idx, String entity) { - _data[idx] = '$idx 变化了哈'; - controller.reloadData(); - BrnToast.show("$idx 奇数行无法删除", context); - return true; - }).show(); - } - }) + )), + ); +} ``` ### 效果2:自定义列表每行视图 @@ -201,76 +232,93 @@ BrnVerticalIconButton( ```dart -List back = [ - '数据源1', - '数据源2', - '数据源3', - '数据源4' -]; +List _data = ['数据源1', '数据源2', '数据源3', '数据源4']; var _bottomActionKey = GlobalKey(); controller = BrnSelectedItemListActionSheetWidgetController(); -BrnBottomButtonPanel( - key: _bottomActionKey, - mainButtonName: 'BrnBottomButtonPanel', - mainButtonOnTap: () { - BrnToast.show('确定!sheet 的数据源长度 ${_data.length}', context); - }, - iconButtonList: [ - BrnVerticalIconButton( - name: '已选(${_data.length})', - iconWidget: BrunoTools.getAssetImage( - 'icons/grey_place_holder.png'), - onTap: () { - if (!controller.isHidden) { - controller.dismiss(); - } else { - if (_data == null || _data.length <= 0) { - BrnToast.show('数据为空,弹窗不展示', context); - return; - } - BrnSelectedListActionSheet( - context: context, - isClearButtonHidden: false, - isDeleteButtonHidden: true, - items: _data, - bottomOffset: 82, - maxHeight: 400, - controller: controller, - title: '自定义行视图例子', - itemTitleBuilder: (int index, String entity) { - return Material( - child: BrnStepInputFormItem( - title: 'BrnStepInputFormItemWidget', - subTitle: 'subtitle,可不传。最小值、最大值可自定义', - minLimit: 0, - maxLimit: 10, - onChanged: - (int oldValue, int newValue) { - BrnToast.show( - "onChanged 回调$oldValue ---- $newValue", - context); - }, - ), - ); - }, - onClear: () { - controller.dismiss(); - // 自定义清空的操作,可以不实现,会走默认的清空操作。 - BrnDialogManager.showConfirmDialog( - context, - title: "确定要清空已选列表吗?", - cancel: '取消', - confirm: '确定', confirmTap: () { - setState(() {}); - _data.clear(); - }, cancelTap: () {}); - }) - .showWithTargetKey( - bottomWidgetKey: _bottomActionKey); - } - }) - ]), +@override +Widget build(BuildContext context) { + /// 要拦截 Android 的系统返回行为,请务必自行添加以下 WillPopScope 逻辑 + return WillPopScope( + onWillPop: () async { + if (!controller.isHidden) { + controller.dismiss(); + return false; + } + return true; + }, + child: Scaffold( + appBar: BrnAppBar( + title: '已选菜单列表', + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + BrnBottomButtonPanel( + key: _bottomActionKey, + mainButtonName: 'BrnBottomButtonPanel', + mainButtonOnTap: () { + BrnToast.show('确定!sheet 的数据源长度 ${_data.length}', context); + }, + iconButtonList: [ + BrnVerticalIconButton( + name: '已选(${_data.length})', + iconWidget: BrunoTools.getAssetImage( + 'icons/grey_place_holder.png'), + onTap: () { + if (!controller.isHidden) { + controller.dismiss(); + } else { + if (_data.length <= 0) { + BrnToast.show('数据为空,弹窗不展示', context); + return; + } + BrnSelectedListActionSheet( + context: context, + isClearButtonHidden: false, + isDeleteButtonHidden: true, + items: _data, + bottomOffset: 82, + maxHeight: 400, + controller: controller, + title: '自定义行视图例子', + itemTitleBuilder: (int index, String entity) { + return Material( + child: BrnStepInputFormItem( + title: 'BrnStepInputFormItemWidget', + subTitle: 'subtitle,可不传。最小值、最大值可自定义', + minLimit: 0, + maxLimit: 10, + onChanged: + (int oldValue, int newValue) { + BrnToast.show( + "onChanged 回调$oldValue ---- $newValue", + context); + }, + ), + ); + }, + onClear: () { + controller.dismiss(); + // 自定义清空的操作,可以不实现,会走默认的清空操作。 + BrnDialogManager.showConfirmDialog( + context, + title: "确定要清空已选列表吗?", + cancel: '取消', + confirm: '确定', onConfirm: () { + setState(() {}); + _data.clear(); + }, onCancel: () {}); + }) + .showWithTargetKey( + bottomWidgetKey: _bottomActionKey); + } + }) + ]), + ], + )), + ); +} ``` ### 效果3:空数据 diff --git a/docs/components/actionsheet/BrnShareActionSheet/BrnShareActionSheet.md b/docs/components/actionsheet/BrnShareActionSheet/BrnShareActionSheet.md index c00ec3a5..f37fef55 100644 --- a/docs/components/actionsheet/BrnShareActionSheet/BrnShareActionSheet.md +++ b/docs/components/actionsheet/BrnShareActionSheet/BrnShareActionSheet.md @@ -61,39 +61,39 @@ BrnShareActionSheet({ | 参数名 | 参数类型 | 描述 | | --- | --- | --- | | shareType | int | 分享类型(参考BrnShareItemConstants中的枚举,如果此项不为自定义,则自定义名称和图标不生效) | -| customTitle | String | 自定义标题 | -| customImage | Widget | 自定义图标 | +| customTitle | String? | 自定义标题 | +| customImage | Widget? | 自定义图标 | | canClick | bool | 是否可点击(如果为预设类型,设置为不可点击后会变为相应的置灰图标)默认为true | #### BrnShareActionSheet | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| firstShareChannels | `List` | 第一行渠道列表 | 否 | 空 | -| secondShareChannels | `List` | 第二行渠道列表 | 否 | | -| mainTitle | String | 列表标题 | 否 | | -| clickCallBack | void ShareActionSheetItemClickCallBack( int section, int index, BrnShareItem shareItem) | 点击分享渠道图标后回调方法 | 否 | 空 | -| getCustomChannelTitle | **ShareActionSheetGetCustomShareItemTitle**( int index) | 获取自定义分享渠道对应的显示**文案**(方法传参为该自定义分享渠道在*shareChannels*中的索引值index)。回调返回值为**String**,如果返回值为空,则**不显示**该自定义分享渠道。 | 否 | 空 | -| cancelTitle | String | 取消按钮的文案 | 否 | **“取消”** | +| firstShareChannels | `List?` | 第一行渠道列表 | 否 | 空 | +| secondShareChannels | `List?` | 第二行渠道列表 | 否 | | +| mainTitle | String? | 列表标题 | 否 | | +| clickCallBack | BrnShareActionSheetItemClickCallBack=void ( int section, int index, BrnShareItem shareItem)? | 点击分享渠道图标后回调方法 | 否 | 空 | +| cancelTitle | String? | 取消按钮的文案 | 否 | ''取消'' | | context | BuildContext | BuidContext | 是 | 空 | -| shareTextColor | Color | 分享渠道文案颜色 | 否 | **Color(0xff999999)**灰色 | -| textColor | Color | 选项标题颜色 | 否 | **Color(0xff222222)** 黑色 | -| clickInterceptor | BrnShareActionSheetOnItemClickInterceptor( int section, int index, BrnShareItem shareItem) | 是否可点击(如果为预设类型,设置为不可点击后会变为相应的置灰图标)默认为true | 否 | | - - +| shareTextColor | Color | 分享渠道文案颜色 | 否 | Color(0xff999999)灰色 | +| textColor | Color | 选项标题颜色 | 否 | Color(0xff222222)黑色 | +| clickInterceptor | BrnShareActionSheetOnItemClickInterceptor? = void (int section, int index, BrnShareItem shareItem)? | 是否可点击(如果为预设类型,设置为不可点击后会变为相应的置灰图标)默认为true | 否 | | ### 其他数据 -| 常量名 | 渠道名 | -| ----------------------------------- | ------------------------------------------------------------ | -| BrnShareItemConstants.SHARE\_WEIXIN | 微信 | -| BrnShareItemConstants.SHARE\_FRIEND | 朋友圈 | -| BrnShareItemConstants.SHARE\_QQ | qq | -| BrnShareItemConstants.SHARE\_QZONE | qq空间 | -| BrnShareItemConstants.SHARE\_WEIBO | 微博 | -| BrnShareItemConstants.SHARE\_LINK | 链接 | -| BrnShareItemConstants.SHARE\_SMS | 短信 | -| BrnShareItemConstants.SHARE\_CUSTOM | 自定义自定义图标需在**getCustomChannelTitle**方法中设置文案,在**getCustomChannelWidget**方法中设定图标。如其中一个为空,则不显示自定义图标。 | +| 常量名 | 渠道名 | +| ------------------------------------ | ------------------------------------------------------------ | +| BrnShareItemConstants.shareWeiXin | 微信 | +| BrnShareItemConstants.shareFriend | 朋友圈 | +| BrnShareItemConstants.shareQQ | qq | +| BrnShareItemConstants.shareQZone | qq空间 | +| BrnShareItemConstants.shareWeiBo | 微博 | +| BrnShareItemConstants.shareLink | 链接 | +| BrnShareItemConstants.shareSms | 短信 | +| BrnShareItemConstants.shareCopyLink | 剪贴板 | +| BrnShareItemConstants.shareBrowser | 浏览器 | +| BrnShareItemConstants.shareSaveImage | 相册 | +| BrnShareItemConstants.shareCustom | 自定义自定义图标需在`getCustomChannelTitle`方法中设置文案,在`getCustomChannelWidget`方法中设定图标。如其中一个为空,则不显示自定义图标。 | @@ -106,47 +106,46 @@ BrnShareActionSheet({ ```dart -List firstRowList = List(); - firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_WEIXIN, - canClick: true, - )); - firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_BROWSER, - canClick: true, - )); - firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_COPY_LINK, - canClick: true, - )); - firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_FRIEND, - canClick: true, - )); - firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_LINK, - canClick: true, - )); - firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_QQ, - canClick: true, - )); - firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_CUSTOM, - customImage: BrunoTools.getAssetImage("images/icon_custom_share.png"), - customTitle: "自定义", - canClick: true, - )); - BrnShareActionSheet actionSheet = new BrnShareActionSheet( - firstShareChannels: firstRowList, - clickCallBack: (int section, int index, BrnShareItem shareItem) { - int channel = shareItem.shareType; - BrnToast.show("channel: $channel, section: $section, index: $index", context); - }, - cancelTitle: "自定义取消名字", // 取消按钮title可自定义 - ); - actionSheet.show(context); - +List firstRowList = []; +firstRowList.add(BrnShareItem( + BrnShareItemConstants.shareWeiXin, + canClick: true, +)); +firstRowList.add(BrnShareItem( + BrnShareItemConstants.shareBrowser, + canClick: true, +)); +firstRowList.add(BrnShareItem( + BrnShareItemConstants.shareCopyLink, + canClick: true, +)); +firstRowList.add(BrnShareItem( + BrnShareItemConstants.shareFriend, + canClick: true, +)); +firstRowList.add(BrnShareItem( + BrnShareItemConstants.shareLink, + canClick: true, +)); +firstRowList.add(BrnShareItem( + BrnShareItemConstants.shareQQ, + canClick: true, +)); +firstRowList.add(BrnShareItem( + BrnShareItemConstants.shareCustom, + customImage: BrunoTools.getAssetImage("images/icon_custom_share.png"), + customTitle: "自定义", + canClick: true, +)); +BrnShareActionSheet actionSheet = new BrnShareActionSheet( + firstShareChannels: firstRowList, + clickCallBack: (int section, int index, BrnShareItem shareItem) { + int channel = shareItem.shareType; + BrnToast.show("channel: $channel, section: $section, index: $index", context); + }, + cancelTitle: "自定义取消名字", // 取消按钮title可自定义 +); +actionSheet.show(context); ``` ### 效果2:四个分享渠道+四个自定义 @@ -156,35 +155,35 @@ List firstRowList = List(); List firstRowList = List(); List secondRowList = List(); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_QZONE, + BrnShareItemConstants.shareQZone, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_SAVE_IMAGE, + BrnShareItemConstants.shareSaveImage, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_SMS, + BrnShareItemConstants.shareSms, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_WEIBO, + BrnShareItemConstants.shareWeiBo, canClick: true, )); secondRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_QZONE, + BrnShareItemConstants.shareQZone, canClick: false, )); secondRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_SAVE_IMAGE, + BrnShareItemConstants.shareSaveImage, canClick: false, )); secondRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_SMS, + BrnShareItemConstants.shareSms, canClick: false, )); secondRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_WEIBO, + BrnShareItemConstants.shareWeiBo, canClick: false, )); BrnShareActionSheet actionSheet = new BrnShareActionSheet( @@ -211,18 +210,18 @@ actionSheet.show(context); ```dart -List firstRowList = List(); -List secondRowList = List(); +List firstRowList = []; +List secondRowList = []; firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_WEIXIN, + BrnShareItemConstants.shareWeiXin, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_FRIEND, + BrnShareItemConstants.shareFriend, canClick: true, )); secondRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_CUSTOM, + BrnShareItemConstants.shareCustom, customImage: BrunoTools.getAssetImage("images/icon_custom_share.png"), customTitle: "自定义", canClick: true, @@ -245,13 +244,13 @@ actionSheet.show(context); ```dart -List firstRowList = List(); +List firstRowList = []; firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_WEIXIN, + BrnShareItemConstants.shareWeiXin, canClick: true, )); firstRowList.add(BrnShareItem( - BrnShareItemConstants.SHARE_FRIEND, + BrnShareItemConstants.shareFriend, canClick: true, )); BrnShareActionSheet actionSheet = new BrnShareActionSheet( diff --git a/docs/components/anchor/BrnAnchorTab/BrnAnchorTab.md b/docs/components/anchor/BrnAnchorTab/BrnAnchorTab.md index 8f2140ec..f1c614e7 100644 --- a/docs/components/anchor/BrnAnchorTab/BrnAnchorTab.md +++ b/docs/components/anchor/BrnAnchorTab/BrnAnchorTab.md @@ -29,9 +29,9 @@ group: ```dart BrnAnchorTab( - {@required this.widgetIndexedBuilder, - @required this.tabIndexedBuilder, - @required this.itemCount, + {required this.widgetIndexedBuilder, + required this.tabIndexedBuilder, + required this.itemCount, this.tabDivider, this.tabBarStyle = const BrnAnchorTabBarStyle()}); ``` @@ -46,7 +46,7 @@ BrnAnchorTab( | widgetIndexedBuilder | ScrollWidgetIndexedBuilder | 指定index的卡片widget | 是 | 无 | | tabIndexedBuilder | TabIndexedBuilder | 指定index的Tab | 是 | 无 | | itemCount | int | Tab和卡片Widget的数量 | 是 | 无 | -| tabDivider | Widget | tab间填充的Widget | 否 | 无 | +| tabDivider | Widget? | tab间填充的Widget | 否 | 无 | ## 四、效果及代码展示 @@ -55,20 +55,28 @@ BrnAnchorTab( ```dart -BrnAnchorTab( - itemCount: 10, - widgetIndexedBuilder: (context, index) { - return Container( - child: Center(child: Text('$index')), - height: Random().nextInt(400).toDouble(), - color: Color.fromARGB(Random().nextInt(255), Random().nextInt(255), - Random().nextInt(255), Random().nextInt(255)), - ); - }, - tabIndexedBuilder: (context, index) { - return Tab( - child: Text(index.toString()), - ); - }, -) +@override +Widget build(BuildContext context) { + return Scaffold( + appBar: BrnAppBar( + title: '锚点', + ), + body: BrnAnchorTab( + itemCount: 10, + widgetIndexedBuilder: (context, index) { + return Container( + child: Center(child: Text('$index')), + height: Random().nextInt(400).toDouble(), + color: Color.fromARGB(Random().nextInt(255), Random().nextInt(255), + Random().nextInt(255), Random().nextInt(255)), + ); + }, + tabIndexedBuilder: (context, index) { + return BadgeTab( + text: 'index $index' + ); + }, + ), + ); +} ``` diff --git a/docs/components/appbar/BrnAppBar/BrnAppBar.md b/docs/components/appbar/BrnAppBar/BrnAppBar.md index ac4f752b..9c3f500a 100644 --- a/docs/components/appbar/BrnAppBar/BrnAppBar.md +++ b/docs/components/appbar/BrnAppBar/BrnAppBar.md @@ -30,14 +30,14 @@ group: ``` dart BrnAppBar( - {Key key, + {Key? key, this.leading, this.showLeadingDivider = false, this.title, this.actions, this.backgroundColor, this.bottom, - this.elevation, + this.elevation = 0, this.automaticallyImplyLeading = true, this.brightness, this.toolbarOpacity = 1.0, @@ -52,41 +52,42 @@ BrnAppBar( this.shape, this.iconTheme, this.actionsIconTheme, - this.excludeHeaderSemantics, - this.primary, + this.excludeHeaderSemantics = false, + this.primary = true, this.textTheme, this.titleSpacing}) : assert( actions == null || actions is Widget || (actions is List)), assert(title == null || title is String || title is Widget), - super(key: key, child: null, preferredSize: null); + super(key: key, child: Container(), preferredSize: Size(0, 0)); ``` | **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| leading | Widget | 导航栏左侧显示的Widget | 否 | automaticallyImplyLeading为true时,默认赋值为点击事件为maybePop的返回Icon | -| title | String或者Widget | AppBar中间显示的内容 | 否 | 为String时,会使用[BrnAppBarTitle]来加载title | -| actions | Widget或者List | 标题右侧的内容 | 否 | 如果为null则不现实,会自动添加右边距和action之间的间距 | +| leading | Widget? | 导航栏左侧显示的Widget | 否 | automaticallyImplyLeading为true时,默认赋值为点击事件为maybePop的返回Icon | +| title | dynamic | AppBar中间显示的内容 | 否 | 必须是String或者Widget。为String时,会使用[BrnAppBarTitle]来加载title | +| actions | dynamic | 标题右侧的内容 | 否 | 为了方便业务使用,可以设置为Widget或者`List`,传入的Widget会自动添加边距并转化为`List`,传入的`List`会自动添加右边距和action之间的间距 | | automaticallyImplyLeading | bool | 是否自动添加Leading实现 | 否 | true | -| backgroundColor | Color | AppBar的背景色 | 否 | 深色主题为白色,白色主题为深色 | -| bottom | PreferredSizeWidget | AppBar底部紧挨着的Widget | 否 | 无 | +| backgroundColor | Color? | AppBar的背景色 | 否 | 深色主题为白色,白色主题为深色 | +| bottom | PreferredSizeWidget? | AppBar底部紧挨着的Widget | 否 | 无 | | bottomOpacity | double | AppBar 底部Widget透明度,即 bottom 字段的透明度 | 否 | 1.0 | | elevation | double | AppBar 阴影高度 | 否 | 0 | -| brightness | Brightness | AppBar 主题,包括 dark、light 两种类型 | 否 | Brightness.dark | +| brightness | Brightness? | AppBar 主题,包括 dark、light 两种类型 | 否 | Brightness.dark | | toolbarOpacity | double | Appbar 透明度 | 否 | 1.0 | | titleAlignment | Alignment | title 对齐方式 | 否 | Alignment.center | -| backLeadCallback | VoidCallback | 自定义的返回事件 | 否 | 无 | +| backLeadCallback | VoidCallback? | 自定义的返回事件 | 否 | 无 | | showDefaultBottom | bool | 是否展示 AppBar 底部分割线(浅色主题时生效) | 否 | true | | showLeadingDivider | bool | 搜索场景下是否展示leading的分割线 | 否 | true | -| flexibleSpace | Widget | 一个可以显示在appbar下方的控件,高度和APpbar高度一样 | 否 | | -| shadowColor | Color | 阴影颜色 | 否 | | -| shape | ShapeBorder | 边框形状,只有当elevation大于0的时候展示 | 否 | | -| iconTheme | IconThemeData | icon样式定制 | 否 | | -| actionsIconTheme | IconThemeData | icon主题定制 | 否 | | -| textTheme | TextTheme | text主题定制 | 否 | | +| flexibleSpace | Widget? | 一个可以显示在appbar下方的控件,高度和APpbar高度一样 | 否 | | +| shadowColor | Color? | 阴影颜色 | 否 | | +| shape | ShapeBorder? | 边框形状,只有当elevation大于0的时候展示 | 否 | | +| iconTheme | IconThemeData? | icon样式定制 | 否 | | +| actionsIconTheme | IconThemeData? | icon主题定制 | 否 | | +| textTheme | TextTheme? | text主题定制 | 否 | | | primary | bool | 此应用栏是否显示在屏幕顶部 | 否 | | | excludeHeaderSemantics | bool | 是否用Semantics包裹 | 否 | | +| themeData | BrnAppBarConfig? | BrnAppBar对应的主题定制类 | 否 | | ## 四、效果及代码展示 @@ -99,30 +100,28 @@ BrnAppBar( ``` dart -BrnAppBar( - //不显示左侧icon - automaticallyImplyLeading: false, - //自定义title - title: Row( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - "标题名称", - style: commonHeiStyle, - ), - Padding( - padding: const EdgeInsets.only(left: 4), - child: Image.asset( - 'assets/image/icon\_navbar\_xiala\_bai.png', - scale: 3.0, - width: 20, - height: 20, - ), - ) - ], - ), -); +BrnAppBar( + brightness: Brightness.dark, + title: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + "标题名称", + style: commonHeiStyle, + ), + Padding( + padding: const EdgeInsets.only(left: 4), + child: Image.asset( + 'assets/image/icon_navbar_xiala_bai.png', + scale: 3.0, + width: 20, + height: 20, + ), + ) + ], + ), + ); ``` ### 效果2:深色+无左侧Icon+右侧Icon+文本title @@ -138,11 +137,12 @@ BrnAppBar( BrnAppBar( //自定义左侧icon leading: Image.asset( - 'assets/image/icon\_navbar\_sousuo\_bai.png', + 'assets/image/icon_navbar_sousuo_bai.png', scale: 3.0, width: 20, height: 20, - ), + ), + brightness: Brightness.dark, //文本title title: '标题名称', ); @@ -178,32 +178,28 @@ BrnAppBar( ``` dart var actionKey = GlobalKey(); - -BrnAppBar( - title: '名称名称', - //左侧多icon - leading: BrnDoubleLeading( - first: BrnBackLeading(), - second: BrnBackLeading( - child: Image.asset( - 'assets/image/icon\_navbar\_close\_bai.png', - scale: 3.0, - height: 20, - width: 20, - ), - ), - ), - //文本action - actions: BrnTextAction( - '文本', - key: actionKey, - brightness: Brightness.dark, - //自定义action的点击 - iconPressed: (){ - //show pop - BrnPopupListWindow.showPopListWindow(context, actionKey, offset: 10, data: ["aaaa", "bbbbb"]); - }, - ), + +BrnAppBar( + title: '标题名称', + leading: BrnDoubleLeading( + first: BrnBackLeading(), + second: BrnBackLeading( + child: Image.asset( + 'assets/image/icon_navbar_close_bai.png', + scale: 3.0, + height: 20, + width: 20, + ), + ), + ), + actions: BrnTextAction( + '弹出菜单', + key: actionKey, + iconPressed: () { + BrnPopupListWindow.showPopListWindow(context, actionKey, + offset: 10, data: ["买卖买卖", "租赁租"]); + }, + ), ); ``` ### 效果5:(无左侧Icon+三个Tab+右侧Icon) @@ -237,7 +233,7 @@ BrnAppBar( //自定义右侧action actions: BrnIconAction( child: Image.asset( - 'assets/image/icon\_navbar\_add\_bai.png', + 'assets/image/icon_navbar_add_bai.png', scale: 3.0, height: 20, width: 20, @@ -253,7 +249,7 @@ return GestureDetector( setState(() {}); }, child: Text( - currentIndex == index ? '标题选中' : '标题文案', + currentIndex == index ? '标题命中' : '标题文案', style: currentIndex == 0 ? selectedHeiStyle : unSelectedHeiStyle, ), ) @@ -273,7 +269,7 @@ BrnAppBar( //自定义leading leading: BrnBackLeading( child: Image.asset( - 'assets/image/icon\_navbar\_sousuo\_bai.png', + 'assets/image/icon_navbar_sousuo_bai.png', scale: 3.0, height: 20, width: 20, @@ -313,7 +309,7 @@ BrnAppBar( ), actions: BrnIconAction( child: Image.asset( - 'assets/image/icon\_navbar\_add\_bai.png', + 'assets/image/icon_navbar_add_bai.png', scale: 3.0, height: 20, width: 20, @@ -331,14 +327,15 @@ BrnAppBar( ``` dart -BrnAppBar( +BrnAppBar( + brightness: Brightness.dark, automaticallyImplyLeading: true, //多icon actions: [ BrnIconAction( iconPressed: () {}, child: Image.asset( - 'assets/image/icon\_navbar\_pin\_bai.png', + 'assets/image/icon_navbar_pin_bai.png', scale: 3.0, height: 20, width: 20, @@ -347,7 +344,7 @@ BrnAppBar( BrnIconAction( iconPressed: () {}, child: Image.asset( - 'assets/image/icon\_navbar\_focus\_bai.png', + 'assets/image/icon_navbar_focus_bai.png', scale: 3.0, height: 20, width: 20, @@ -356,7 +353,7 @@ BrnAppBar( BrnIconAction( iconPressed: () {}, child: Image.asset( - 'assets/image/icon\_navbar\_im\_hei.png', + 'assets/image/icon_navbar_im_hei.png', scale: 3.0, height: 20, width: 20, @@ -366,7 +363,7 @@ BrnAppBar( BrnIconAction( iconPressed: () {}, child: Image.asset( - 'assets/image/icon\_navbar\_share\_bai.png', + 'assets/image/icon_navbar_share_bai.png', scale: 3.0, height: 20, width: 20, @@ -378,11 +375,11 @@ BrnAppBar( ### 效果8:白色+默认返回+右侧Icon+文本title ``` dart -BrnAppBar( +BrnAppBar( //默认显示返回按钮 - automaticallyImplyLeading: true, - brightness: Brightness.light, - title: '名称名称', + automaticallyImplyLeading: true, + brightness: Brightness.light, + title: '名称名称', //自定义的右侧文本 actions: BrnTextAction( '文本按钮', diff --git a/docs/components/appbar/BrnSearchAppbar/BrnSearchAppbar.md b/docs/components/appbar/BrnSearchAppbar/BrnSearchAppbar.md index aae6e976..96fa61e2 100644 --- a/docs/components/appbar/BrnSearchAppbar/BrnSearchAppbar.md +++ b/docs/components/appbar/BrnSearchAppbar/BrnSearchAppbar.md @@ -40,28 +40,28 @@ const BrnSearchAppbar( this.autoFocus = true, this.brightness = Brightness.dark, this.onClearTap, - this.inputTextStyle}); + this.inputTextStyle}) + : super(child: const Center(), preferredSize: const Size(0, 0)); ``` | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| controller | TextEditingController | 输入框的文本控制器 | 否 | 无 | -| focusNode | FocusNode | 搜索框的焦点控制器 | 否 | 无 | -| leading | String 或者 Widget | 输入框左侧的Leading,可以是字符串也可以是widget | 否 | 无 | -| leadClickCallback | BrnSearchBarLeadClickCallback | 搜索框左侧的点击回调,参数为文本控制器和setState方法 | 否 | 无 | -| dismissClickCallback | BrnSearchBarDismissClickCallback | 搜索框右侧Action的点击回调, 参数为文本控制器和setState方法 | 否 | 无 | -| searchBarInputChangeCallback | BrnSearchBarInputChangeCallback | 搜索框的文本变化监听 | 否 | 无 | -| searchBarInputSubmitCallback | BrnSearchBarInputSubmitCallback | 搜索框提交的回调 | 否 | 无 | -| hint | String | 搜索框的hint内容 | 否 | 无 | -| hintStyle | TextStyle | 输入框的hint的Style | 否 | 无 | -| style | TextStyle | 输入框的文本Style | 否 | 无 | -| dismissStyle | TextStyle | 右侧Action的文本Style | 否 | 无 | +| controller | TextEditingController? | 输入框的文本控制器 | 否 | 无 | +| focusNode | FocusNode? | 搜索框的焦点控制器 | 否 | 无 | +| leading | dynamic | String 或者 Widget。输入框左侧的Leading,可以是字符串也可以是widget | 否 | 无 | +| leadClickCallback | BrnSearchBarLeadClickCallback? | 搜索框左侧的点击回调,参数为文本控制器和setState方法 | 否 | 无 | +| dismissClickCallback | BrnSearchBarDismissClickCallback? | 搜索框右侧Action的点击回调, 参数为文本控制器和setState方法 | 否 | 无 | +| searchBarInputChangeCallback | BrnSearchBarInputChangeCallback? | 搜索框的文本变化监听 | 否 | 无 | +| searchBarInputSubmitCallback | BrnSearchBarInputSubmitCallback? | 搜索框提交的回调 | 否 | 无 | +| hint | String? | 搜索框的hint内容 | 否 | 无 | +| hintStyle | TextStyle? | 输入框的hint的Style | 否 | 无 | +| inputTextStyle | TextStyle? | 输入框的文本Style | 否 | 无 | +| dismissStyle | TextStyle? | 右侧Action的文本Style | 否 | 无 | | showDivider | bool | 是否展示底部分割线 | 否 | bool | | autoFocus | bool | 是否自动聚焦 | 否 | bool | | brightness | Brightness | 主题配置 | 否 | Brightness.dark | -| onClearTap | VoidCallback | 点击清除按钮回调 | 否 | | -| inputTextStyle | TextStyle | 输入框的文本Style | 否 | | +| onClearTap | VoidCallback? | 点击清除按钮回调 | 否 | | ## 四、效果及代码展示 @@ -131,14 +131,7 @@ BrnSearchAppbar( leadClickCallback: (controller, update) { //controller 是文本控制器,通过controller 可以拿到输入的内容 以及 对输入的内容更改 //update 是setState方法的方法命,update() 就可以刷新输入框 - BrnPopupListWindow.showPopListWindow( - context, - keyleading, - data: ["aaaa", "bbbbb"], - borderColor: Color(0xffCCCCCC), - backgroundColor: Colors.white, - textStyle: TextStyle(color: Color(0xFF222222), fontSize: 16), - ); + BrnPopupListWindow.showPopListWindow(context, keyleading, data: ["aaaa", "bbbbb"], offset: 10); }, //输入框 文本内容变化的监听 searchBarInputChangeCallback: (input) { diff --git a/docs/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarDemo2.png b/docs/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarDemo2.png index edda1ab9e732d3fb123b295f5afb7e2ee455a894..7fa1a756e7801a1e3d14365a91e9aceb9eb45400 100644 GIT binary patch literal 17088 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℞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 literal 13196 zcmdVBbyQSu^e;>^bPp&sG{VpVf^ zy=&cn-?iTLzN|H@bC~m-r}ne={(Sa_2vy}*IG9f{5fBh?lB#l&k`PsA2McRka|8tDkETXOgmO^k0b^q$qk$3DXPC|&ufxNmUmN)k zb&Pb3bqqs>I+D`#^j665SCHR!A$(Emthd3AhTK%K55VXs_;3~#QkRz!NSWw;&mG9W zz9;TTPSDB3&VNL3(s347!$3wh#f&f2GkA?);(_psR$A;8;x8AmeOHh-a(EVsF*RZd z28J_Ql>@>rq`@Z0NZHrnV9qVhm>tFDV%uK8f#XB1FgA;y665=0Z z8mek1rDv<a#oSB=+70(l^;^QWvmH>Cq*c)vtO-m7_h6b<9ytgzwc zylZ`Ud^|dMe0*(;oD!L>`$agk!B3c~j0@n3~xt5%Tk`e+7a1BC046{Z+0j>~% z&r{%ofPj>X^gn+=EXhUwpKFAC_?N6cqTvV#Ty1hv;%_|>53UzqvoRV74+@9m zL1@LL33>yX(7t;Sa7Lv`$Gf>*>WXSEPAP4LXh#>>$f${l&wyz2XcJKALGt+G@h>{s zbC3&LeYf4m6vtd&PTo()Ww)&^5G@fc6$`p$1Q~aKuzMbXkB=lF1_A}jM~l_U>+!2A zfk22f5R{MrNinm6K==jlL^2iPNA-duT6NWb-%4pbMTWORq*2`=z}Hs4VSkMp3V%=n zXvFpZtWjW>;`DJho@h;_Y5&{@9CE_QU*1Qp2l0})at$fFW(RY%d^Xe23?9qaQtj$K zhDG;zyHfMvl<5Yi^|x_fTk8Gp-Uuk8QE%_(x5TM3{g>sH1ND8D zNwB`?C#E>$d^I=cd;L!OZ9a`LHWpI8|NWUEU(xq=O4G3RsO@%iuHM1HZTF{K zmgni>UP@iPif9fAT|wS#G6Ppt_k0b6h8YQsq95A{JuutYcu&|Pkm=4ileRK*_*FDU-^kzeX6E3bbpP%qSoK4 zE%zyS;8Ou+Wi??OMrl#1Q!8(^IPcJIhs_85%AD7+=C%8+FuF5xQ{EoBT1kHNXf{7XgE)2tIUV7gPM-JuyCYFpKuxlEc)FZT=WpB%mTy6tYDX#YO&J) z7<2Cmn}TUi9`B-rHr^gKA3X(=FMT3X5gLCtRZODt=b(Oh?)IqtXvlsVmY(IhCa2Nh zMa8by@Wa6SfY-FuB<9`ZSEai~Gjtw{?-guyvt7zB4{FThhFr7igdeWf-Iu(!3w-Q* zBS|j$$Q@?$q@!SfjeQ7O{wx`mKjw2f!vDc?Kh@B$@}O>hR9SE*-^76V(D&}7ziv$A zmMlNr`kUXhw&h~{Hwi0HfRR4UdVie99Ln_fIMD|yL*Mh{>QC;o#$h2WMkfe|t6|jk zg_+KgT(V?h@$*e?dkZ}AT3=*hV1T97JwDvN^q|X^(lMk;=Z;6iqp}T9X#`1y?criM z?3LE@4P73Jp&cOO39Ufew?;CW&%Qlyezsb_yFNY0bQzUPe(vY6uy%fNh{ucELu^{4 zGiA3fidQE}S@os$h1m9J?e`Z^HBePSnx;6Bn*lG8PkeT}TTQR<#&G0MfEG5dsJ!xZ6AipJNnWl5 zAnPR@wLdOB+%7*h@rKui+lBKl`E-}^(+AMAw_TaM3ZS@se|O~n=pyfuR2arvY}y}t zv6*T(hbMZcdWhG9{`s)&_Rt<@!6L(M%_iM}X>ZH-aⅆ{{G1SC>ovEW+0vSIh1*Y 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 | 点击表情时对应等级的提示文案。若 `type=BrnAppraiseType.Emoji`,则 list 长度为 5,不足 5 个时请在对应位置补空字符串。若 `type=BrnAppraiseType.Star`,list 长度不能比传入的 BrnAppraiseConfig 中的 count 小。 | 否 | 无 | -| tags | `List` | 供选择的标签数据 | 否 | 无 | -| inputHintText | String | 输入框的提示文字 | 否 | 无 | -| onConfirm | `void Function(int index, List selectedTags, String input)` | 点击提交时的回调,其中 index 是选中的表情或者五角星的 index,selectedTags 是选中的标签,input 是输入框的内容 | 否 | 无 | -| config | BrnAppraiseConfig | 配置类,具体见下边其他参数说明 | 否 | BrnAppraiseConfig() | +| **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | +| ---------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------ | -------------------------------------- | +| title | String | 标题 | 否 | '' | +| headerType | BrnAppraiseHeaderType | 标题类型,居中还是两侧 | 否 | BrnAppraiseHeaderType.spaceBetween | +| type | BrnAppraiseType | 评价组件类型,表情包还是五角星 | 否 | BrnAppraiseType.Star | +| iconDescriptions | `List` | 点击表情时对应等级的提示文案。若 `type=BrnAppraiseType.Emoji`,则 list 长度为 5,不足 5 个时请在对应位置补空字符串。若 `type=BrnAppraiseType.Star`,list 长度不能比传入的 BrnAppraiseConfig 中的 count 小。 | 否 | ['不好','还行','满意','很棒','超惊喜'] | +| tags | `List?` | 供选择的标签数据 | 否 | 无 | +| inputHintText | String | 输入框的提示文字 | 否 | '' | +| onConfirm | `void Function(int index, List selectedTags, String input)?` | 点击提交时的回调,其中 index 是选中的表情或者五角星的 index,selectedTags 是选中的标签,input 是输入框的内容 | 否 | 无 | +| config | BrnAppraiseConfig | 配置类,具体见下边其他参数说明 | 否 | BrnAppraiseConfig() | ### 其他参数说明 #### BrnAppraiseConfig -| **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | -| ----------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -| showHeader | bool | 是否显示顶部标题和关闭按钮的 header 视图 | 否 | true | -| headerPadding | EdgeInsets | header 部分的 padding,只有居中样式支持设置 | 否 | `headerType=BrnAppraiseHeader.center`时,为 `EdgeInsets.only(top: 20, bottom: 20)`,其余为 `EdgeInsets.only(left: 20, top: 16, right: 16, bottom: 20)` | -| titleMaxLines | int | 标题的最大行数 | 否 | 1 | -| onCancel | `void Function(BuildContext context)` | 点击关闭按钮时的回调 | 否 | 无 | -| count | int | `type=BrnAppraiseType.Star`时所需五角星的个数 | 否 | 5 | -| iconDescriptions | `List` | 点击表情时的文案。`type=BrnAppraiseType.Star`时,该列表的数据个数不能比 count 少。`type=BrnAppraiseType.Emoji`时,list 长度应为 5,不足 5 个时请在对应位置补空字符串 | 否 | ['不好', '还行', '满意', '很棒', '超惊喜'] | -| indexes | `List` | 表情包打分组件所需表情的 index | 否 | [0,1,2,3,4] | -| starAppraiseHint | String | 五角星未打分时的提示文案 | 否 | 无 | -| multiSelect | bool | 标签是否支持多选 | 否 | true | -| tagCountEachRow | int | 每行显示的标签数 | 否 | 2 | -| showTextInput | bool | 是否显示输入框 | 否 | true | -| maxLength | int | 输入框能输入文字的最大长度 | 否 | 100 | -| maxHintLines | int | 提示文案的最大行数 | 否 | 1 | -| inputDefaultText | String | 输入框默认文案 | 否 | 无 | -| inputMaxHeight | double | 输入框的最大高度 | 否 | 120 | -| showConfirmButton | bool | 是否显示提交按钮 | 否 | true | -| confirmButtonText | String | 提交按钮自定义文案 | 否 | '提交' | -| isConfirmButtonEnabled | bool | 提交按钮的可用状态 | 否 | 默认 null,在打分之后 enable | -| iconClickCallback | `void Function(int index)` | 点击打分时的回调 | 否 | 无 | -| inputTextChangeCallback | `void Function(String input)` | 输入框内容改变的回调 | 否 | 无 | -| tagSelectCallback | `void Function(List selectedTags)` | 选择标签时的回调 | 否 | 无 | +| **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | +| ----------------------- | ------------------------------------------- | ------------------------------------------------------------ | ------------ | ------------------------------------------------------------ | +| showHeader | bool | 是否显示顶部标题和关闭按钮的 header 视图 | 否 | true | +| headerPadding | EdgeInsets? | header 部分的 padding,只有居中样式支持设置 | 否 | `headerType=BrnAppraiseHeader.center`时,为 `EdgeInsets.only(top: 20, bottom: 20)`,其余为 `EdgeInsets.only(left: 20, top: 16, right: 16, bottom: 20)` | +| titleMaxLines | int | 标题的最大行数 | 否 | 1 | +| onCancel | `void Function(BuildContext context)?` | 点击关闭按钮时的回调 | 否 | 无 | +| count | int | `type=BrnAppraiseType.Star`时所需五角星的个数 | 否 | 5 | +| iconDescriptions | `List` | 点击表情时的文案。`type=BrnAppraiseType.Star`时,该列表的数据个数不能比 count 少。`type=BrnAppraiseType.Emoji`时,list 长度应为 5,不足 5 个时请在对应位置补空字符串 | 否 | ['不好', '还行', '满意', '很棒', '超惊喜'] | +| indexes | `List` | 表情包打分组件所需表情的 index | 否 | [0,1,2,3,4] | +| starAppraiseHint | String | 五角星未打分时的提示文案 | 否 | '' | +| multiSelect | bool | 标签是否支持多选 | 否 | true | +| tagCountEachRow | int | 每行显示的标签数 | 否 | 2 | +| showTextInput | bool | 是否显示输入框 | 否 | true | +| maxLength | int | 输入框能输入文字的最大长度 | 否 | 100 | +| maxHintLines | int | 提示文案的最大行数 | 否 | 1 | +| inputDefaultText | String? | 输入框默认文案 | 否 | 无 | +| inputMaxHeight | double | 输入框的最大高度 | 否 | 120 | +| showConfirmButton | bool | 是否显示提交按钮 | 否 | true | +| confirmButtonText | String | 提交按钮自定义文案 | 否 | '提交' | +| isConfirmButtonEnabled | bool | 提交按钮的可用状态 | 否 | 默认 null,在打分之后 enable | +| iconClickCallback | `void Function(int index)?` | 点击打分时的回调 | 否 | 无 | +| inputTextChangeCallback | `void Function(String input)?` | 输入框内容改变的回调 | 否 | 无 | +| tagSelectCallback | `void Function(List selectedTags)?` | 选择标签时的回调 | 否 | 无 | + +```dart +const BrnAppraiseConfig({ + this.showHeader = true, + this.headerPadding, + this.titleMaxLines = 1, + this.onCancel, + this.indexes = const [0, 1, 2, 3, 4], + this.count = 5, + this.starAppraiseHint = '', + this.multiSelect = true, + this.tagCountEachRow = 2, + this.showTextInput = true, + this.maxLength = 100, + this.maxHintLines = 1, + this.inputDefaultText, + this.inputMaxHeight = 120, + this.showConfirmButton = true, + this.confirmButtonText = '提交', + this.isConfirmButtonEnabled, + this.iconClickCallback, + this.inputTextChangeCallback, + this.tagSelectCallback, + }); +``` + + ## 四、代码演示 @@ -188,18 +216,25 @@ BrnAppraise( type: BrnAppraiseType.Star, tags: tags, inputHintText: '这里是文本输入的组件', - // iconDescriptions: ['一星','二星','三星','四星','五星',], + iconDescriptions: [ + '一星', + '二星', + '三星', + '四星', + '五星', + ], config: BrnAppraiseConfig( showConfirmButton: false, starAppraiseHint: '星星未选择时的文案', + inputDefaultText: '这是一段默认文字', inputTextChangeCallback: (input) { BrnToast.show('输入的内容为' + input, context); }, iconClickCallback: (index) { - BrnToast.show('选中的评价为${index}', context); + BrnToast.show('选中的评价为$index', context); }, tagSelectCallback: (list) { BrnToast.show('选中的标签为:' + list.toString(), context); }), -), +) ``` diff --git a/docs/components/appraise/BrnAppraiseBottomPicker/BrnAppraiseBottomPicker.md b/docs/components/appraise/BrnAppraiseBottomPicker/BrnAppraiseBottomPicker.md index ad1038c1..15a0d259 100644 --- a/docs/components/appraise/BrnAppraiseBottomPicker/BrnAppraiseBottomPicker.md +++ b/docs/components/appraise/BrnAppraiseBottomPicker/BrnAppraiseBottomPicker.md @@ -24,35 +24,30 @@ group: ```dart BrnAppraiseBottomPicker({ - this.title, - this.headerType = BrnAppraiseHeaderType.spaceBetween, - this.type = BrnAppraiseType.Star, - this.iconDescriptions, - this.tags, - this.inputHintText, - this.onConfirm, - this.config, -}); + Key? key, + this.title = '', + this.headerType = BrnAppraiseHeaderType.spaceBetween, + this.type = BrnAppraiseType.Star, + this.iconDescriptions = _defaultIconDescriptions, + this.tags, + this.inputHintText = '', + this.onConfirm, + this.config = const BrnAppraiseConfig(), + }) : super(key: key); ``` ### 参数说明 | **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| title | String | 标题 | 否 | 无 | +| title | String | 标题 | 否 | '' | | headerType | BrnAppraiseHeaderType | 标题类型,居中还是两侧 | 否 | BrnAppraiseHeaderType.spaceBetween | | type | BrnAppraiseType | 评价组件类型,表情包还是五角星 | 否 | BrnAppraiseType.Star | | iconDescriptions | `List` | 点击表情时对应等级的提示文案。若 `type=BrnAppraiseType.Emoji`,则list长度为5,不足5个时请在对应位置补空字符串。若 `type=BrnAppraiseType.Star`,list长度不能比传入的 BrnAppraiseConfig中的 count 小。 | 否 | ['不好', '还行', '满意', '很棒', '超惊喜'] | -| tags | `List` | 供选择的标签数据 | 否 | 无 | -| inputHintText | String | 输入框的提示文字 | 否 | 无 | -| onConfirm | `void Function(int index, List selectedTags, String input)` | 点击提交时的回调,其中index是选中的表情或者五角星的index,selectedTags是选中的标签,input是输入框的内容 | 否 | 无 | -| config | BrnAppraiseConfig | 配置类,具体见下边其他参数说明 | 否 | BrnAppraiseConfig() | - -### 其他参数说明 - -#### BrnAppraiseConfig - -参见 [BrnAppraise](../brn-appraise/brn-appraise)。 +| tags | `List?` | 供选择的标签数据 | 否 | 无 | +| inputHintText | String | 输入框的提示文字 | 否 | '' | +| onConfirm | `void Function(int index, List selectedTags, String input)?` | 点击提交时的回调,其中index是选中的表情或者五角星的index,selectedTags是选中的标签,input是输入框的内容 | 否 | 无 | +| config | BrnAppraiseConfig | 配置类,具体参见 [BrnAppraise](../brn-appraise/brn-appraise) | 否 | BrnAppraiseConfig() | ### 四、代码演示 @@ -80,7 +75,7 @@ showDialog( BrnToast.show('输入的内容为' + input, context); }, iconClickCallback: (index) { - BrnToast.show('选中的评价为${index}', context); + BrnToast.show('选中的评价为$index', context); }, tagSelectCallback: (list) { BrnToast.show( diff --git a/docs/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md b/docs/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md index 1b49ad8c..3033aeeb 100644 --- a/docs/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md +++ b/docs/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md @@ -24,43 +24,66 @@ group: ```dart -BrnBottomTabBar({ - Key key, - @required this.items, - this.onTap, - this.currentIndex = 0, - BottomTabBarType type = BottomTabBarType.fixed, - this.fixedColor, - this.iconSize = 24.0, - this.isAnimation = false, - this.badgeColor, - this.isInkResponse = false, -}) +BrnBottomTabBar({ + Key? key, + required this.items, + this.onTap, + this.currentIndex = 0, + BrnBottomTabBarDisplayType type = BrnBottomTabBarDisplayType.fixed, + this.fixedColor, + this.iconSize = 24.0, + this.isAnimation = false, + this.badgeColor, + this.isInkResponse = false, +}) : assert(items.length >= 1), + assert( + items.every((BrnBottomTabBarItem item) => item.title != null) == true, + 'Every item must have a non-null title', + ), + assert(0 <= currentIndex && currentIndex < items.length), + type = items.length <= 3 + ? BrnBottomTabBarDisplayType.fixed + : BrnBottomTabBarDisplayType.shifting, + super(key: key); ``` | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | | items | `List` | Tab 数据 | 是 | 无 | -| fixedColor | Colors | 选中item后的颜色 | 否 | 无 | +| fixedColor | Color? | 选中item后的颜色 | 否 | 无 | | currentIndex | int | 当前选中的item索引值 | 否 | 无alert | -| onTap | DialogIndexedActionClickCallback | 导航项点击回调的点击回调 | 否 | 无 | +| onTap | `ValueChanged?` | 导航项点击回调的点击回调 | 否 | 无 | | type | BottomTabBarType | Tab样式(固定、动画) | 否 | BottomTabBarType.fixed | | iconSize | double | tab icon 大小 | 否 | 24 | | isAnimation | bool | 是否开启字体放大动画 | 否 | false | | isInkResponse | bool | 是否开启聚焦动画 | 否 | false | -| badgeColor | Colors | 未读信息Badge背景颜色 | 否 | Colors.Red | +| badgeColor | Color? | 未读信息Badge背景颜色 | 否 | Colors.Red | + +#### BrnBottomTabBarItem + +```dart +const BrnBottomTabBarItem({ + required this.icon, + this.title, + Widget? activeIcon, + this.backgroundColor, + this.badge, + this.badgeNo, + this.maxBadgeNo = 99, +}) : activeIcon = activeIcon ?? icon; +``` + -#### BottomTabBarItem | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | | icon | Widget | 未选中时的icon | 是 | 无 | -| activeIcon | Widget | 选中时的icon | 是 | 无 | -| title | Widget | Tab标题名调 | 是 | 无 | -| backgroundColor | Color | 背景色 | 否 | 无 | -| badge | Widget | 未读信息 | 否 | 无 | -| badgeNo | String | 未读信息个数 | 否 | 无 | +| activeIcon | Widget | 选中时的icon | 否 | 无 | +| title | Widget? | Tab标题名调 | 否 | 无 | +| backgroundColor | Color? | 背景色 | 否 | 无 | +| badge | Widget? | 未读信息 | 否 | 无 | +| badgeNo | String? | 未读信息个数 | 否 | 无 | | maxBadgeNo | int | 未读消息最大个数 | 否 | 99 | ## 四、代码演示 diff --git a/docs/components/form/BrnAddLabel/BrnAddLabel.md b/docs/components/form/BrnAddLabel/BrnAddLabel.md index a15e3676..b0d9650a 100644 --- a/docs/components/form/BrnAddLabel/BrnAddLabel.md +++ b/docs/components/form/BrnAddLabel/BrnAddLabel.md @@ -27,22 +27,22 @@ group: ```dart BrnAddLabel({ - Key key, - this.label, - this.title: "", - this.isEdit: true, - this.onTap, - }); + Key? key, + this.label, + this.title = "", + this.isEdit = true, + this.onTap, +}) : super(key: key); ``` ### 参数说明: | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | | type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.labelAdd | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | -| onTap | VoidCallback | 可操作区点击回调 | 否 | 无 | | +| onTap | VoidCallback? | 可操作区点击回调 | 否 | 无 | | ## 四、代码演示 diff --git a/docs/components/form/BrnBaseTitle/BrnBaseTitle.md b/docs/components/form/BrnBaseTitle/BrnBaseTitle.md index c8f342c4..965446f6 100644 --- a/docs/components/form/BrnBaseTitle/BrnBaseTitle.md +++ b/docs/components/form/BrnBaseTitle/BrnBaseTitle.md @@ -37,41 +37,41 @@ group: ```dart BrnBaseTitle({ - Key key, - this.title: "", - this.subTitle, - this.isRequire: false, - this.isEdit: true, - this.error: "", - this.tipLabel, - this.titleWidget, - this.subTitleWidget, - this.customActionWidget, - this.onTip, - this.themeData, - }) { - this.themeData ??= BrnFormItemConfig(); - this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) - .formItemConfig - .merge(this.themeData); - } + Key? key, + this.title= "", + this.subTitle, + this.isRequire= false, + this.isEdit= true, + this.error= "", + this.tipLabel, + this.titleWidget, + this.subTitleWidget, + this.customActionWidget, + this.onTip, + this.themeData, +}) : super(key: key) { + this.themeData ??= BrnFormItemConfig(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .formItemConfig + .merge(this.themeData); +} ``` ### 参数说明 | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | title | String | 录入项标题 | 否 | '' | | -| titleWidget | Widget | 录入项标题Widget | 否 | 无 | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| subTitleWidget | Widget | 录入项子标题Widget | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| titleWidget | Widget? | 录入项标题Widget | 否 | 无 | | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| subTitleWidget | Widget? | 录入项子标题Widget | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑,false:禁用 | -| customActionWidget | Widget | 自定义Widget | 否 | 无 | | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | -| themeData | BrnFormItemConfig | 表单主题配置 | 否 | 无 | | +| customActionWidget | Widget? | 自定义Widget | 否 | 无 | | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| themeData | BrnFormItemConfig? | 表单主题配置 | 否 | 无 | | ## 四、代码演示 diff --git a/docs/components/form/BrnExpandFormGroup/BrnExpandFormGroup.md b/docs/components/form/BrnExpandFormGroup/BrnExpandFormGroup.md index a6bc1820..ec78491a 100644 --- a/docs/components/form/BrnExpandFormGroup/BrnExpandFormGroup.md +++ b/docs/components/form/BrnExpandFormGroup/BrnExpandFormGroup.md @@ -36,37 +36,37 @@ group: ```dart BrnExpandFormGroup({ - Key key, - this.label, - this.title: "", - this.subTitle, - this.tipLabel, - this.error: "", - this.isEdit: true, - this.isRequire: false, - this.onRemoveTap, - this.onTip, - this.isExpand: true, - this.deleteLabel, - this.children, - }); + Key? key, + this.label, + this.title = "", + this.subTitle, + this.tipLabel, + this.error = "", + this.isEdit = true, + this.isRequire = false, + this.onRemoveTap, + this.onTip, + this.isExpand = true, + this.deleteLabel, + required this.children, +}) : super(key: key); ``` ### 参数说明 | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | | type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.normalGroupType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑,false:禁用 | -| onTip | VoidCallback | 点击"+"图标回调 | 否 | 点击"?"图标回调 | 见**tipLabel**字段 | -| onRemoveTap | VoidCallback | 点击删除按钮回调 | 否 | 无 | | +| onTip | VoidCallback? | 点击"+"图标回调 | 否 | 点击"?"图标回调 | 见**tipLabel**字段 | +| onRemoveTap | VoidCallback? | 点击删除按钮回调 | 否 | 无 | | | isExpand | bool | 设置初始“展开/收起”状态true: 展开false:收起 | 否 | true | | -| deleteLabel | String | 删除按钮文案 | 否 | 无 | | +| deleteLabel | String? | 删除按钮文案 | 否 | 无 | | | children | `List` | 子组件list | 否 | 无 | | ## 四、代码演示 @@ -181,4 +181,3 @@ BrnExpandFormGroup( ], ) ``` - diff --git a/docs/components/form/BrnExpandableGroup/BrnExpandableGroup.md b/docs/components/form/BrnExpandableGroup/BrnExpandableGroup.md index 2f6b5ca0..6d68ff76 100644 --- a/docs/components/form/BrnExpandableGroup/BrnExpandableGroup.md +++ b/docs/components/form/BrnExpandableGroup/BrnExpandableGroup.md @@ -27,19 +27,18 @@ group: ```dart BrnExpandableGroup({ - Key key, - @required this.title, + Key? key, + required this.title, this.subtitle, this.backgroundColor, this.onExpansionChanged, this.children = const [], this.initiallyExpanded = false, this.themeData, -}) : assert(initiallyExpanded != null), - super(key: key) { +}) : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -47,15 +46,15 @@ BrnExpandableGroup({ ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| ------------------ | -------------------- | -------------------------------------------------- | ------------ | ----------- | -| title | String | 标题 | 否 | 无 | -| subTitle | String | 子标题 | 否 | 无 | -| backgroundColor | Color | 背景色 | 否 | transparent | -| onExpansionChanged | `ValueChanged` | 状态变化回调 | 否 | 无 | -| children | `List` | 内容 Widget List 表 | 否 | 无 | -| initiallyExpanded | bool | 初始状态(true 展开,false 不展开) | 否 | false | -| themeData | BrnFormItemConfig | 表单项主题配置,具体配置信息详见 BrnFormItemConfig | 否 | | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| ------------------ | --------------------- | -------------------------------------------------- | ------------ | ----------- | +| title | String | 标题 | 是 | 无 | +| subTitle | String? | 子标题 | 否 | 无 | +| backgroundColor | Color? | 背景色 | 否 | transparent | +| onExpansionChanged | `ValueChanged?` | 状态变化回调 | 否 | 无 | +| children | `List` | 内容 Widget List 表 | 否 | 无 | +| initiallyExpanded | bool | 初始状态(true 展开,false 不展开) | 否 | false | +| themeData | BrnFormItemConfig? | 表单项主题配置,具体配置信息详见 BrnFormItemConfig | 否 | | ## 四、代码演示 diff --git a/docs/components/form/BrnMultiChoiceInputFormItem/BrnMultiChoiceInputFormItem.md b/docs/components/form/BrnMultiChoiceInputFormItem/BrnMultiChoiceInputFormItem.md index e42ccd61..b4119a32 100644 --- a/docs/components/form/BrnMultiChoiceInputFormItem/BrnMultiChoiceInputFormItem.md +++ b/docs/components/form/BrnMultiChoiceInputFormItem/BrnMultiChoiceInputFormItem.md @@ -41,53 +41,54 @@ group: ### 构造函数 ```dart -BrnMultiChoiceInputFormItem({ - Key key, - this.label, - this.title: "", - this.subTitle, - this.tipLabel, - this.prefixIconType: BrnPrefixIconType.normal, - this.error: "", - this.isEdit: true, - this.isRequire: true, - this.onAddTap, - this.onRemoveTap, - this.onTip, - this.value, - this.options, - this.enableList, - this.onChanged, - this.themeData}) - : super() { +BrnMultiChoiceInputFormItem( + {Key? key, + this.label, + this.title = "", + this.subTitle, + this.tipLabel, + this.prefixIconType = BrnPrefixIconType.normal, + this.error = "", + this.isEdit = true, + this.isRequire = true, + this.onAddTap, + this.onRemoveTap, + this.onTip, + this.value = const [], + this.options = const [], + this.enableList = const [], + this.onChanged, + this.themeData}) + : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); +} ``` ### 参数说明: | **参数名** | 参数类型 | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | | type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.multiChoicePortraitInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发 onTip 回调。 | 否 | 备注中类型 3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为 null 时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal2. 展示加号图标:BrnPrefixIconType.add3. 展示减号图标:BrnPrefixIconType.remove | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发 onTip 回调。 | 否 | 备注中类型 3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为 null 时,不显示提示项 | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 BrnPrefixIconType 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示\*图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑 false:禁用 | -| onAddTap | VoidCallback | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onRemoveTap | VoidCallback | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | -| value | List | 设置选中的选项文案 | 否 | 无 | | -| options | List | 所有选项文案 | 否 | | | -| enableList | List | 标识每个选项是否禁用,false:禁用 | 否 | | | -| onChanged | `OnBrnFormMultiChoiceValueChanged` | 用户在选项间切换时调用 | 否 | | | -| themeData | BrnFormItemConfig | form 配置 | 否 | 无 | | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| value | `List` | 设置选中的选项文案 | 否 | 无 | | +| options | `List` | 所有选项文案 | 否 | | | +| enableList | `List` | 标识每个选项是否禁用,false:禁用 | 否 | | | +| onChanged | `OnBrnFormMultiChoiceValueChanged?` | 用户在选项间切换时调用 | 否 | | | +| themeData | BrnFormItemConfig? | form 配置 | 否 | 无 | | ### 其他数据说明: @@ -166,3 +167,4 @@ BrnMultiChoiceInputFormItem( }, ) ``` + diff --git a/docs/components/form/BrnMultiChoicePortraitInputFormItem/BrnMultiChoicePortraitInputFormItem.md b/docs/components/form/BrnMultiChoicePortraitInputFormItem/BrnMultiChoicePortraitInputFormItem.md index 9bb04350..5d1a1cf6 100644 --- a/docs/components/form/BrnMultiChoicePortraitInputFormItem/BrnMultiChoicePortraitInputFormItem.md +++ b/docs/components/form/BrnMultiChoicePortraitInputFormItem/BrnMultiChoicePortraitInputFormItem.md @@ -43,52 +43,53 @@ group: ``` dart BrnMultiChoicePortraitInputFormItem( - {Key key, - this.label, - this.title: "", - this.subTitle, - this.tipLabel, - this.prefixIconType: BrnPrefixIconType.normal, - this.error: "", - this.isEdit: true, - this.isRequire: false, - this.onAddTap, - this.onRemoveTap, - this.onTip, - this.value, - this.options, - this.enableList, - this.onChanged, - this.themeData}) - : super() { -this.themeData ??= BrnFormItemConfig(); -this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) - .formItemConfig - .merge(this.themeData); + {Key? key, + this.label, + this.title = "", + this.subTitle = "", + this.tipLabel, + this.prefixIconType = BrnPrefixIconType.normal, + this.error = "", + this.isEdit = true, + this.isRequire = false, + this.onAddTap, + this.onRemoveTap, + this.onTip, + this.value = const [], + this.options = const [], + this.enableList = const [], + this.onChanged, + this.themeData}) + : super(key: key) { + this.themeData ??= BrnFormItemConfig(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .formItemConfig + .merge(this.themeData); +} ``` ### 参数说明: | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | | type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.multiChoicePortraitInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | | prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | -| onAddTap | VoidCallback | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onRemoveTap | VoidCallback | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | -| value | List | 设置选中的选项文案 | 否 | 无 | | -| options | List | 所有选项文案 | 否 | 无 | | -| enableList | List | 标识每个选项是否禁用,false:禁用 | 否 | 无 | | -| onChanged | OnBrnFormMultiChoiceValueChanged | 选项选中状态变化回调 | 否 | 无 | | -| themeData | BrnFormItemConfig | form配置 | 否 | 无 | | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| value | `List` | 设置选中的选项文案 | 否 | `const []` | | +| options | `List` | 所有选项文案 | 否 | `const []` | | +| enableList | `List` | 标识每个选项是否禁用,false:禁用 | 否 | `const []` | | +| onChanged | OnBrnFormMultiChoiceValueChanged? | 选项选中状态变化回调 | 否 | 无 | | +| themeData | BrnFormItemConfig? | form配置 | 否 | 无 | | ### 其他数据说明: ###### BrnPrefixIconType: diff --git a/docs/components/form/BrnNormalFormGroup/BrnNormalFormGroup.md b/docs/components/form/BrnNormalFormGroup/BrnNormalFormGroup.md index 3a1d2905..e4f0eb5e 100644 --- a/docs/components/form/BrnNormalFormGroup/BrnNormalFormGroup.md +++ b/docs/components/form/BrnNormalFormGroup/BrnNormalFormGroup.md @@ -34,23 +34,22 @@ group: ```dart BrnNormalFormGroup({ - Key key, + Key? key, this.label, - this.title: "", + this.title = "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.TYPE_NORMAL, - this.error: "", - this.isEdit: true, - this.isRequire: false, + this.error = "", + this.isEdit = true, + this.isRequire = false, this.onRemoveTap, this.onTip, this.deleteLabel, - this.children, -}) : super() { + required this.children, +}) : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -59,19 +58,19 @@ BrnNormalFormGroup({ | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | | type | String | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.normalGroupType | 外部可用此字段判断表单类型 | | title | String | 录入项标题 | 否 | 无 | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | null | 1. 若赋值为 空字符串("")时仅展示"问号"图标,2. 若赋值为非空字符串时 展示"问号图标&文案",3. 若不赋值或赋值为null时 不显示提示项 | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 无 | 1. 若赋值为 空字符串("")时仅展示"问号"图标,2. 若赋值为非空字符串时 展示"问号图标&文案",3. 若不赋值或赋值为null时 不显示提示项 | | error | String | 录入项错误提示 | 否 | 无 | | | isRequire | bool | 录入项是否为必填项(展示*图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | -| onRemoveTap | VoidCallback | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | -| deleteLabel | String | 右侧文案 | 否 | 无 | | -| children | `List` | 子组件list | 否 | 无 | | -| themeData | BrnFormItemConfig | form配置 | 否 | 无 | | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| deleteLabel | String? | 右侧文案 | 否 | 无 | | +| children | `List` | 子组件list | 是 | 无 | | +| themeData | BrnFormItemConfig? | form配置 | 否 | 无 | | ## 四、代码演示 diff --git a/docs/components/form/BrnPortraitRadioGroup/BrnPortraitRadioGroup.md b/docs/components/form/BrnPortraitRadioGroup/BrnPortraitRadioGroup.md index 66875bcb..4688bc03 100644 --- a/docs/components/form/BrnPortraitRadioGroup/BrnPortraitRadioGroup.md +++ b/docs/components/form/BrnPortraitRadioGroup/BrnPortraitRadioGroup.md @@ -28,63 +28,82 @@ group: ```dart -BrnPortraitRadioGroup.withSimpleList({ - Key key, - this.isEdit = true, - String selectedOption, - List options, - this.enableList, - this.onChanged, +BrnPortraitRadioGroup.withSimpleList({ + Key? key, + this.isEdit = true, + String selectedOption = "", + required List options, + this.enableList, + this.onChanged, this.themeData, - this.isCollapseContent = false, -}) + this.isCollapseContent = false, +}) : this.options = options + .map((item) => BrnPortraitRadioGroupOption(title: item)) + .toList(), + this.selectedOption = options.indexOf(selectedOption) > -1 + ? BrnPortraitRadioGroupOption( + title: options[options.indexOf(selectedOption)]) + : BrnPortraitRadioGroupOption(), + super(key: key) { + this.themeData ??= BrnFormItemConfig(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .formItemConfig + .merge(this.themeData); +} ``` ### 参数说明 | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | | isEdit | bool | 组件是否可编辑 | 否 | 无 | -| selectedOption | String | 默认选中的选项,与 options 中数据匹配 | 否 | 无 | -| options | `List` | 数据源 | 否 | 否 | +| selectedOption | String | 默认选中的选项,与 options 中数据匹配 | 否 | '' | +| options | `List` | 数据源 | 否 | 是 | | enableList | `List `| 是否可用的状态 | 否 | 否 | | onChanged | void Function(BrnRadioChoiceOption oldStr, BrnRadioChoiceOption newStr) | 返回选中未选中的数据格式 | 否 | 无 | | isCollapseContent | bool | options 中 title subTitle 是否换行展示。false: 换行展示true: 只展示一行,一行展示不下末尾[...]省略展示**默认值为 false:换行展示;** | 否 | false | -| themeData | BrnFormItemConfig | 表单项配置类,具体配置详见BrnFormItemConfig | 否 | | +| themeData | BrnFormItemConfig? | 表单项配置类,具体配置详见BrnFormItemConfig | 否 | | #### 带数据格式的构造函数 ```dart -BrnPortraitRadioGroup.withOptions({ - Key key, - this.isEdit = true, - this.selectedOption, - this.options, - this.enableList, - this.onChanged, - this.isCollapseContent = false, +BrnPortraitRadioGroup.withOptions({ + Key? key, + this.isEdit = true, + this.selectedOption, + this.options, + this.enableList, + this.onChanged, + this.isCollapseContent = false, this.themeData, -}) +}) :super(key: key){ + this.themeData ??= BrnFormItemConfig(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .formItemConfig + .merge(this.themeData); +} ``` ### 参数说明 | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| isEdit | bool | 组件是否可编辑 | 否 | 无 | -| selectedOption | BrnRadioChoiceOption | 默认选中的选项,与 options 中数据匹配 | 否 | 无 | -| options | `List` | 数据源 | 否 | 否 | -| enableList | `List` | 是否可用的状态 | 否 | 否 | +| isEdit | bool | 组件是否可编辑 | 否 | True | +| selectedOption | BrnRadioChoiceOption? | 默认选中的选项,与 options 中数据匹配 | 否 | 无 | +| options | `List?` | 数据源 | 否 | 否 | +| enableList | `List?` | 是否可用的状态 | 否 | 否 | | onChanged | void Function(BrnRadioChoiceOption oldStr, BrnRadioChoiceOption newStr) | 返回选中未选中的数据格式 | 否 | 无 | | isCollapseContent | bool | options 中 title subTitle 是否换行展示。false: 换行展示true: 只展示一行,一行展示不下末尾[...]省略展示默认值为 false:换行展示; | 否 | false | -| themeData | BrnFormItemConfig | 表单项配置类,具体配置详见BrnFormItemConfig | 否 | | +| themeData | BrnFormItemConfig? | 表单项配置类,具体配置详见BrnFormItemConfig | 否 | | #### 组件内部数据 Item 的结构(支持 subTitle 的展示) ```dart class BrnPortraitRadioGroupOption { - String title; - String subTitle; + String? title; + String? subTitle; BrnPortraitRadioGroupOption({this.title, this.subTitle}); } ``` @@ -94,6 +113,8 @@ class BrnPortraitRadioGroupOption { ![](./img/BrnPortraitRadioGroupDemo1.png) ```dart +BrnPortraitRadioGroupOption selectedValue; + BrnPortraitRadioGroup.withSimpleList( options: [ '用户报修项错误', diff --git a/docs/components/form/BrnRadioInputFormItem/BrnRadioInputFormItem.md b/docs/components/form/BrnRadioInputFormItem/BrnRadioInputFormItem.md index c799bf46..6de2655b 100644 --- a/docs/components/form/BrnRadioInputFormItem/BrnRadioInputFormItem.md +++ b/docs/components/form/BrnRadioInputFormItem/BrnRadioInputFormItem.md @@ -45,29 +45,29 @@ group: ```dart -BrnRadioInputFormItem( - {Key key, - this.label, - this.title: "", - this.subTitle, - this.tipLabel, - this.prefixIconType: BrnPrefixIconType.normal, - this.error: "", - this.isEdit: true, - this.isRequire: false, - this.onAddTap, - this.onRemoveTap, - this.onTip, - this.value, - this.options, - this.enableList, - this.onChanged, - this.themeData, - this.titleMaxLines,}) - : super(key: key) { +BrnRadioInputFormItem({ + Key? key, + this.label, + this.title: "", + this.subTitle, + this.tipLabel, + this.prefixIconType: BrnPrefixIconType.normal, + this.error: "", + this.isEdit: true, + this.isRequire: false, + this.onAddTap, + this.onRemoveTap, + this.onTip, + this.value, + this.options, + this.enableList, + this.onChanged, + this.themeData, + this.titleMaxLines, +}) : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); this._isAutoLayout = false; @@ -77,24 +77,25 @@ BrnRadioInputFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.radioInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add3. 展示减号图标:BrnPrefixIconType.remove | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示*图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | -| onAddTap | VoidCallback | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onRemoveTap | VoidCallback | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | -| value | String | 选中的选项文案 | 否 | 无 | | -| options | List | 所有选项文案 | 否 | 无 | | -| enableList | List | 标识每个选项是否禁用false:禁用 | 否 | 无 | | -| onChanged | OnBrnFormRadioValueChanged | 用户在选项间切换时调用 | 否 | 无 | void Function(String oldStr, String newStr) | -| titleMaxLines | int | 标题显示的最大行数 | 否 | 1 | | -| layoutRatio | double | 左边标题部分/右边选项部分的宽度比例。例如 1/2 显示就传 0.5 | 否 | 当左右内容超出默认比例且「有」提示语,则按比例 6:4 布局,当左右内容超出默认比例且「无」提示语,则按比例 4:6 布局 | 右边选项部分的显示宽度 = min(选项部分的实际宽度, 选项部分的比例计算宽度) | -| themeData | BrnFormItemConfig | 表单主题配置 | 否 | 无 | | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| value | String? | 选中的选项文案 | 否 | 无 | | +| options | `List?` | 所有选项文案 | 否 | 无 | | +| enableList | `List?` | 标识每个选项是否禁用false:禁用 | 否 | 无 | | +| onChanged | OnBrnFormRadioValueChanged? | 用户在选项间切换时调用 | 否 | 无 | void Function(String oldStr, String newStr) | +| titleMaxLines | int? | 标题显示的最大行数 | 否 | 1 | | +| layoutRatio | double? | 左边标题部分/右边选项部分的宽度比例。例如 1/2 显示就传 0.5 | 否 | 当左右内容超出默认比例且「有」提示语,则按比例 6:4 布局,当左右内容超出默认比例且「无」提示语,则按比例 4:6 布局 | 右边选项部分的显示宽度 = min(选项部分的实际宽度, 选项部分的比例计算宽度) | +| themeData | BrnFormItemConfig? | 表单主题配置 | 否 | 无 | | ### 其他数据说明 diff --git a/docs/components/form/BrnRadioPortraitInputFormItem/BrnRadioPortraitInputFormItem.md b/docs/components/form/BrnRadioPortraitInputFormItem/BrnRadioPortraitInputFormItem.md index 237dc555..2237cd0c 100644 --- a/docs/components/form/BrnRadioPortraitInputFormItem/BrnRadioPortraitInputFormItem.md +++ b/docs/components/form/BrnRadioPortraitInputFormItem/BrnRadioPortraitInputFormItem.md @@ -41,7 +41,7 @@ group: ```dart BrnRadioPortraitInputFormItem( - {Key key, + {Key? key, this.label, this.title: "", this.subTitle, @@ -59,10 +59,9 @@ BrnRadioPortraitInputFormItem( this.onChanged, this.themeData}) : super(key: key) { - this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -70,25 +69,25 @@ BrnRadioPortraitInputFormItem( ### 参数说明: -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | -| -------------- | -------------------------- | ------------------------------------------------------------------ | ------------ | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | -| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.radioInputType | 外部可根据此字段判断表单项类型 | -| title | String | 录入项标题 | 否 | 无 | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发 onTip 回调。 | 否 | 备注中类型 3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为 null 时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal2. 展示加号图标:BrnPrefixIconType.add3. 展示减号图标:BrnPrefixIconType.remove | -| error | String | 录入项错误提示 | 否 | 无 | | -| isRequire | bool | 录入项是否为必填项(展示\*图标) 默认为 false 不必填 | 否 | false | | -| isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑 false:禁用 | -| onAddTap | VoidCallback | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onRemoveTap | VoidCallback | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | -| value | String | 选中的选项文案 | 否 | 无 | | -| options | List | 所有选项文案 | 否 | 无 | | -| enableList | List | 标识每个选项是否禁用 false:禁用 | 否 | 无 | | -| onChanged | OnBrnFormRadioValueChanged | 选项选中状态变化回调 | 否 | 无 | | -| themeData | BrnFormItemConfig | form 配置 | 否 | 无 | | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | +| -------------- | --------------------------- | ------------------------------------------------------------ | ------------ | --------------------------------- | ------------------------------------------------------------ | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.radioInputType | 外部可根据此字段判断表单项类型 | +| title | String | 录入项标题 | 否 | '' | | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发 onTip 回调。 | 否 | 备注中类型 3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为 null 时,不显示提示项 | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | +| error | String | 录入项错误提示 | 否 | '' | | +| isRequire | bool | 录入项是否为必填项(展示\*图标) 默认为 false 不必填 | 否 | false | | +| isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑 false:禁用 | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| value | String? | 选中的选项文案 | 否 | 无 | | +| options | `List` | 所有选项文案 | 否 | 无 | | +| enableList | `List` | 标识每个选项是否禁用 false:禁用 | 否 | 无 | | +| onChanged | OnBrnFormRadioValueChanged? | 选项选中状态变化回调 | 否 | 无 | | +| themeData | BrnFormItemConfig? | form 配置 | 否 | 无 | | ### 其他数据说明: diff --git a/docs/components/form/BrnRangeInputFormItem/BrnRangeInputFormItem.md b/docs/components/form/BrnRangeInputFormItem/BrnRangeInputFormItem.md index 19abd429..09958c1d 100644 --- a/docs/components/form/BrnRangeInputFormItem/BrnRangeInputFormItem.md +++ b/docs/components/form/BrnRangeInputFormItem/BrnRangeInputFormItem.md @@ -41,7 +41,7 @@ group: ```dart BrnRangeInputFormItem( - {Key key, + {Key? key, this.label, this.title: "", this.subTitle, @@ -54,8 +54,8 @@ BrnRangeInputFormItem( this.onAddTap, this.onRemoveTap, this.onTip, - this.hintMin: "请输入", - this.hintMax: "请输入", + this.hintMin: '最小', + this.hintMax: '最大', this.minUnit, this.maxUnit, this.leftMaxCount, @@ -71,7 +71,7 @@ BrnRangeInputFormItem( : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -81,32 +81,33 @@ BrnRangeInputFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.textRangeInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | | prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标),默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | | isPrefixIconEnabled | bool | 录入项不可编辑时(isEdit: false) "+"、"-"号是否可点击,true: 可点击回调 false: 不可点击回调 | 否 | false | | -| onAddTap | VoidCallback | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onRemoveTap | VoidCallback | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | -| minUnit | String | 最小范围单位 | 否 | 无 | | -| maxUnit | String | 最大范围单位 | 否 | 无 | | -| hintMin | String | 最小范围录入项 hint 提示 | 否 | "请输入" | | -| hintMax | String | 最大范围录入项 hint 提示 | 否 | "请输入" | | -| leftMaxCount | int | 最小值输入框最大字符数 | 否 | 无 | | -| rightMaxCount | int | 最大值输入框最大字符数 | 否 | 无 | | -| inputType | String | 输入内容类型,指定键盘类型,参见 `BrnInputType` | 否 | 无 | 详见**BrnInputType**类,注意:无法通过指定键盘类型确保输入。比如不能通过指定数字键盘确保用户只输入数字。如果有要求用户只输入特定字符的需求请使用**inputFormatters**参数 | -| minInputFormatters | `List` | 指定对最小范围输入数据的格式化要求 | 否 | 无 | | -| maxInputFormatters | `List` | 指定对最大范围输入数据的格式化要求 | 否 | 无 | | -| onMinChanged | `ValueChanged` | 最小范围输入文案回调 | 否 | 无 | | -| onMaxChanged | `ValueChanged` | 最大范围输入文案回调 | 否 | 无 | | -| minController | TextEditingController | 最小范围文本输入controller | 否 | 无 | | -| maxController | TextEditingController | 最大范围文本输入controller | 否 | 无 | | -| themeData | BrnFormItemConfig | 表单主题配置 | 否 | 无 | | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| minUnit | String? | 最小范围单位 | 否 | 无 | | +| maxUnit | String? | 最大范围单位 | 否 | 无 | | +| hintMin | String | 最小范围录入项 hint 提示 | 否 | "最小" | | +| hintMax | String | 最大范围录入项 hint 提示 | 否 | "最大" | | +| leftMaxCount | int? | 最小值输入框最大字符数 | 否 | 无 | | +| rightMaxCount | int? | 最大值输入框最大字符数 | 否 | 无 | | +| inputType | String? | 输入内容类型,指定键盘类型,参见 `BrnInputType` | 否 | 无 | 详见**BrnInputType**类,注意:无法通过指定键盘类型确保输入。比如不能通过指定数字键盘确保用户只输入数字。如果有要求用户只输入特定字符的需求请使用**inputFormatters**参数 | +| minInputFormatters | `List?` | 指定对最小范围输入数据的格式化要求 | 否 | 无 | | +| maxInputFormatters | `List?` | 指定对最大范围输入数据的格式化要求 | 否 | 无 | | +| onMinChanged | `ValueChanged?` | 最小范围输入文案回调 | 否 | 无 | | +| onMaxChanged | `ValueChanged?` | 最大范围输入文案回调 | 否 | 无 | | +| minController | TextEditingController? | 最小范围文本输入controller | 否 | 无 | | +| maxController | TextEditingController? | 最大范围文本输入controller | 否 | 无 | | +| themeData | BrnFormItemConfig? | 表单主题配置 | 否 | 无 | | ### 其他数据说明: diff --git a/docs/components/form/BrnRatioInputFormItem/BrnRatioInputFormItem.md b/docs/components/form/BrnRatioInputFormItem/BrnRatioInputFormItem.md index a6548d3f..df2c48be 100644 --- a/docs/components/form/BrnRatioInputFormItem/BrnRatioInputFormItem.md +++ b/docs/components/form/BrnRatioInputFormItem/BrnRatioInputFormItem.md @@ -39,7 +39,7 @@ group: ```dart BrnRatioInputFormItem( - {Key key, + {Key? key, this.label, this.title: "", this.subTitle, @@ -61,7 +61,7 @@ BrnRatioInputFormItem( : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -71,26 +71,25 @@ BrnRatioInputFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | | type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.textInputRatioType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | | prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑,false:禁用 | | isPrefixIconEnabled | bool | 录入项不可编辑时(isEdit: false) "+"、"-"号是否可点击,true: 可点击回调 false: 不可点击回调 | 否 | false | | -| onAddTap | VoidCallback | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onRemoveTap | VoidCallback | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | | hint | String | 录入项 hint 提示 | 否 | "请输入" | | -| value | String | 录入项 值 | 否 | 无 | | -| inputType | String | 输入内容类型,指定键盘类型,参见 `BrnInputType` | 否 | 无 | 详见**BrnInputType**类,注意:无法通过指定键盘类型确保输入。比如不能通过指定数字键盘确保用户只输入数字。如果有要求用户只输入特定字符的需求请使用**inputFormatters**参数 | -| inputFormatters | `List` | 指定对输入数据的格式化要求 | 否 | 无 | | -| onChanged | `ValueChanged` | 输入文案回调 | 否 | 无 | | -| controller | TextEditingController | 文本输入controller | 否 | 无 | | -| themeData | BrnFormItemConfig | form配置 | 否 | 无 | | +| inputType | String? | 输入内容类型,指定键盘类型,参见 `BrnInputType` | 否 | 无 | 详见**BrnInputType**类,注意:无法通过指定键盘类型确保输入。比如不能通过指定数字键盘确保用户只输入数字。如果有要求用户只输入特定字符的需求请使用**inputFormatters**参数 | +| inputFormatters | `List?` | 指定对输入数据的格式化要求 | 否 | 无 | | +| onChanged | `ValueChanged?` | 输入文案回调 | 否 | 无 | | +| controller | TextEditingController? | 文本输入controller | 否 | 无 | | +| themeData | BrnFormItemConfig? | form配置 | 否 | 无 | | ### 其他数据说明: diff --git a/docs/components/form/BrnSelectAllTitle/BrnSelectAllTitle.md b/docs/components/form/BrnSelectAllTitle/BrnSelectAllTitle.md index 339e6926..e97ce4d3 100644 --- a/docs/components/form/BrnSelectAllTitle/BrnSelectAllTitle.md +++ b/docs/components/form/BrnSelectAllTitle/BrnSelectAllTitle.md @@ -38,12 +38,12 @@ group: ```dart BrnSelectAllTitle({ - Key key, - this.title: "", + Key? key, + this.title = "", this.subTitle, - this.isRequire: false, - this.isEdit: true, - this.error: "", + this.isRequire = false, + this.isEdit = true, + this.error = "", this.tipLabel, this.titleWidget, this.subTitleWidget, @@ -51,13 +51,13 @@ BrnSelectAllTitle({ this.onSelectAll, this.selectText, this.selectTextWidget, - this.selectState: true, + this.selectState = true, this.themeData, this.customActionWidget, -}) { +}):super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -67,20 +67,20 @@ BrnSelectAllTitle({ | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | | title | String | 录入项标题 | 否 | '' | | -| titleWidget | Widget | 录入项标题Widget | 否 | 无 | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| subTitleWidget | Widget | 录入项子标题Widget | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| titleWidget | Widget? | 录入项标题Widget | 否 | 无 | | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| subTitleWidget | Widget? | 录入项子标题Widget | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑,false:禁用 | | selectState | bool | 选中按钮的选中状态 | 否 | true | | -| selectText | String | “全选”文案 | 否 | 无 | | -| selectTextWidget | Widget | “全选”Widget | 否 | 无 | | -| customActionWidget | Widget | 右侧自定义Widget | 否 | 无 | | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | -| onSelectAll | OnBrnFormSelectAll | 点击“全选”选中/取消 | | | void Function(int index, bool isSelect) | -| themeData | BrnFormItemConfig | 表单主题配置 | 否 | 无 | | +| selectText | String? | “全选”文案 | 否 | 无 | | +| selectTextWidget | Widget? | “全选”Widget | 否 | 无 | | +| customActionWidget | Widget? | 右侧自定义Widget | 否 | 无 | | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| onSelectAll | OnBrnFormSelectAll? | 点击“全选”选中/取消 | 否 | 无 | void Function(int index, bool isSelect) | +| themeData | BrnFormItemConfig? | 表单主题配置 | 否 | 无 | | ## 四、代码演示 diff --git a/docs/components/form/BrnStarsFormItem/BrnStarsFormItem.md b/docs/components/form/BrnStarsFormItem/BrnStarsFormItem.md index d98d3e3d..dd02d640 100644 --- a/docs/components/form/BrnStarsFormItem/BrnStarsFormItem.md +++ b/docs/components/form/BrnStarsFormItem/BrnStarsFormItem.md @@ -36,7 +36,7 @@ group: ```dart BrnStarsFormItem( - {Key key, + {Key? key, this.label, this.title: "", this.subTitle, @@ -52,10 +52,10 @@ BrnStarsFormItem( this.value: 0, this.onChanged, this.themeData}) - : super() { + : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -65,22 +65,22 @@ BrnStarsFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | | type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.starInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | | prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | -| onAddTap | VoidCallback | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onRemoveTap | VoidCallback | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | | value | int | 外部设置点亮星标数量 | 否 | 0 | | | sumStar | int | 总星标数量 | 否 | 5 | | -| onChanged | OnBrnFormValueChanged | 点亮星标数量变化回调 | 否 | 无 | | -| themeData | BrnFormItemConfig | form配置 | 否 | 无 | | +| onChanged | OnBrnFormValueChanged? | 点亮星标数量变化回调 | 否 | 无 | | +| themeData | BrnFormItemConfig? | form配置 | 否 | 无 | | ### 其他数据说明: diff --git a/docs/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md b/docs/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md index b97f5f2d..8391b38b 100644 --- a/docs/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md +++ b/docs/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md @@ -36,29 +36,29 @@ group: ### 构造函数 ```dart -BrnStepInputFormItem( - {Key key, - this.label, - this.title: "", - this.subTitle, - this.tipLabel, - this.prefixIconType: BrnPrefixIconType.normal, - this.error: "", - this.isEdit: true, - this.isRequire: false, - this.onAddTap, - this.onRemoveTap, - this.onTip, - this.value: 0, - this.maxLimit: 10, - this.minLimit: 0, - this.defaultValue, - this.onChanged, - this.themeData, }) - : super() { +BrnStepInputFormItem({ + Key? key, + this.label, + this.title = "", + this.subTitle, + this.tipLabel, + this.prefixIconType = BrnPrefixIconType.normal, + this.error = "", + this.isEdit = true, + this.isRequire = false, + this.onAddTap, + this.onRemoveTap, + this.onTip, + this.value, + this.maxLimit = 10, + this.minLimit = 0, + this.onChanged, + this.themeData, +}) : assert(value == null || value >= minLimit && value <= maxLimit), + super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -68,28 +68,29 @@ BrnStepInputFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.textStepInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | | prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | -| onAddTap | VoidCallback | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onRemoveTap | VoidCallback | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | -| value | int | 外部设置初始值 | 否 | 0 | | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| value | int? | 外部设置初始值 | 否 | 0 | | | maxLimit | int | 单步上限值 | 否 | 10 | | | minLimit | int | 单步下限值 | 否 | 0 | | -| onChanged | OnBrnFormValueChanged | 递增值变化回调 | 否 | 无 | | -| themeData | BrnFormItemConfig | form配置 | 否 | 无 | | +| onChanged | OnBrnFormValueChanged? | 递增值变化回调 | 否 | 无 | | +| themeData | BrnFormItemConfig? | form配置 | 否 | 无 | | ### 其他数据说明: #### BrnPrefixIconType -``` +```dart class BrnPrefixIconType { static const String TYPE_NORMAL = "type_normal"; static const String TYPE_ADD = "type_add"; diff --git a/docs/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md b/docs/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md index 4c07ac49..82dc179d 100644 --- a/docs/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md +++ b/docs/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md @@ -41,22 +41,22 @@ group: ```dart BrnTextBlockInputFormItem( - {Key key, + {Key? key, this.label, this.type: BrnInputItemType.textBlockInputType, - this.title: "", + this.title = "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.normal, - this.error: "", - this.isEdit: true, - this.isRequire: false, - this.isPrefixIconEnabled: false, + this.prefixIconType = BrnPrefixIconType.normal, + this.error = "", + this.isEdit = true, + this.isRequire = false, + this.isPrefixIconEnabled = false, this.onAddTap, this.onRemoveTap, this.onTip, this.onChanged, - this.hint: "请选择", + this.hint = "请输入", this.maxCharCount, this.inputType, this.inputFormatters, @@ -67,7 +67,7 @@ BrnTextBlockInputFormItem( : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -76,29 +76,28 @@ BrnTextBlockInputFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | | type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.textBlockInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add3. 展示减号图标:BrnPrefixIconType.remove | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | | isPrefixIconEnabled | bool | 录入项不可编辑时(isEdit: false) "+"、"-"号是否可点击,true: 可点击回调 false: 不可点击回调 | 否 | false | | -| onAddTap | VoidCallback | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onRemoveTap | VoidCallback | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | -| hint | String | 录入项 hint 提示 | 否 | "请选择" | | -| value | String | 录入项 值 | 否 | 无 | | -| maxCharCount | int | 最大输入字符数 | 否 | 无 | | -| inputType | String | 输入内容类型,指定键盘类型,参见 `BrnInputType` | 否 | 无 | 详见**BrnInputType**类,注意:无法通过指定键盘类型确保输入。比如不能通过指定数字键盘确保用户只输入数字。如果有要求用户只输入特定字符的需求请使用**inputFormatters**参数 | -| inputFormatters | `List` | 指定对输入数据的格式化要求 | 否 | 无 | | -| onChanged | `ValueChanged` | 输入文案回调 | 否 | 无 | | -| controller | TextEditingController | 文本输入controller | 否 | 无 | | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| hint | String | 录入项 hint 提示 | 否 | "请输入" | | +| maxCharCount | int? | 最大输入字符数 | 否 | 无 | | +| inputType | String? | 输入内容类型,指定键盘类型,参见 `BrnInputType` | 否 | 无 | 详见**BrnInputType**类,注意:无法通过指定键盘类型确保输入。比如不能通过指定数字键盘确保用户只输入数字。如果有要求用户只输入特定字符的需求请使用**inputFormatters**参数 | +| inputFormatters | `List?` | 指定对输入数据的格式化要求 | 否 | 无 | | +| onChanged | `ValueChanged?` | 输入文案回调 | 否 | 无 | | +| controller | TextEditingController? | 文本输入controller | 否 | 无 | | | minLines | int | 最小行数 | 否 | 4 | | | maxLines | int | 最大行数 | 否 | 20 | | -| themeData | BrnFormItemConfig | 表单主题配置 | 否 | 无 | | +| themeData | BrnFormItemConfig? | 表单主题配置 | 否 | 无 | | ### 其他数据说明 diff --git a/docs/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md b/docs/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md index 284cc1ba..348eba16 100644 --- a/docs/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md +++ b/docs/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md @@ -41,22 +41,22 @@ group: ```dart BrnTextInputFormItem({ - Key key, + Key? key, this.label, this.type: BrnInputItemType.textInputType, - this.title: "", + this.title = "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.normal, - this.error: "", - this.isEdit: true, - this.isRequire: false, - this.isPrefixIconEnabled: false, + this.prefixIconType = BrnPrefixIconType.normal, + this.error = "", + this.isEdit = true, + this.isRequire = false, + this.isPrefixIconEnabled = false, this.onAddTap, this.onRemoveTap, this.onTip, this.prefixText, - this.hint: "请输入", + this.hint = "请输入", this.unit, this.maxCharCount, this.inputType, @@ -67,7 +67,7 @@ BrnTextInputFormItem({ }) : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -76,28 +76,28 @@ BrnTextInputFormItem({ | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | | type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.textInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | | prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | | isPrefixIconEnabled | bool | 录入项不可编辑时(isEdit: false) "+"、"-"号是否可点击,true: 可点击回调 false: 不可点击回调 | 否 | false | | -| onAddTap | VoidCallback | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onRemoveTap | VoidCallback | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | | -| prefixText | String | 固定前缀文案 | 否 | 无 | | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | | +| prefixText | String? | 固定前缀文案 | 否 | 无 | | | hint | String | 录入项 hint 提示 | 否 | "请输入" | | -| unit | String | 单位 | 否 | 无 | | -| maxCharCount | int | 最大输入字符数 | 否 | 无 | | -| inputType | String | 输入内容类型,指定键盘类型,参见 `BrnInputType` | 否 | 无 | 详见**BrnInputType**类,注意:无法通过指定键盘类型确保输入。比如不能通过指定数字键盘确保用户只输入数字。如果有要求用户只输入特定字符的需求请使用**inputFormatters**参数 | -| inputFormatters | `List` | 指定对输入数据的格式化要求 | 否 | 无 | | -| onChanged | `ValueChanged` | 输入文案回调 | 否 | 无 | | -| controller | TextEditingController | 文本输入controller | 否 | 无 | | -| themeData | BrnFormItemConfig | 表单主题配置 | 否 | 无 | | +| unit | String? | 单位 | 否 | 无 | | +| maxCharCount | int? | 最大输入字符数 | 否 | 无 | | +| inputType | String? | 输入内容类型,指定键盘类型,参见 `BrnInputType` | 否 | 无 | 详见**BrnInputType**类,注意:无法通过指定键盘类型确保输入。比如不能通过指定数字键盘确保用户只输入数字。如果有要求用户只输入特定字符的需求请使用**inputFormatters**参数 | +| inputFormatters | `List?` | 指定对输入数据的格式化要求 | 否 | 无 | | +| onChanged | `ValueChanged?` | 输入文案回调 | 否 | 无 | | +| controller | TextEditingController? | 文本输入controller | 否 | 无 | | +| themeData | BrnFormItemConfig? | 表单主题配置 | 否 | 无 | | ### 其他数据说明 diff --git a/docs/components/form/BrnTextQuickSelectFormItem/BrnTextQuickSelectFormItem.md b/docs/components/form/BrnTextQuickSelectFormItem/BrnTextQuickSelectFormItem.md index b174a09a..db8e021f 100644 --- a/docs/components/form/BrnTextQuickSelectFormItem/BrnTextQuickSelectFormItem.md +++ b/docs/components/form/BrnTextQuickSelectFormItem/BrnTextQuickSelectFormItem.md @@ -34,7 +34,7 @@ group: ```dart BrnTextQuickSelectFormItem( - {Key key, + {Key? key, this.label, this.title: "", this.subTitle, @@ -59,7 +59,7 @@ BrnTextQuickSelectFormItem( : super(key: key) { themeData ??= BrnFormItemConfig(); themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) + .getConfig(configId: themeData!.configId) .formItemConfig .merge(themeData); } @@ -68,32 +68,27 @@ BrnTextQuickSelectFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | | type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.textQuickSelectInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 BrnPrefixIconType 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal2. 展示加号图标:BrnPrefixIconType.add3. 展示减号图标:BrnPrefixIconType.remove | -| isBtnsScroll | bool | 快捷按钮是否可滑动 | 否 | 无 | true:可滚动false:不可滚动 | -| btnsTxt | List | 按钮文案 | 否 | 无 | | -| selectBtnList | List | 按钮是否默认选中 | 否 | 无 | true:选中false:未选中 | -| enableBtnList | List | 按钮是否默认禁用 | 否 | 无 | true:使能false:禁用 | -| value | String | 选择框文案 | 否 | 无 | | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | -| onAddTap | VoidCallback | 点击"+"图标回调 | 否 | 无 | 见prefixIconType字段 | -| onRemoveTap | VoidCallback | 点击"-"图标回调 | 否 | 无 | 见prefixIconType字段 | -| onBtnSelectChanged | ValueChanged | 按钮选中文案,会把选中的序号回调出去。 | 否 | 无 | | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 BrnPrefixIconType 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | +| isBtnsScroll | bool | 快捷按钮是否可滑动 | 否 | false | true:可滚动false:不可滚动 | +| value | String? | 选择框文案 | 否 | 无 | | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见prefixIconType字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见prefixIconType字段 | +| onBtnSelectChanged | `ValueChanged?` | 按钮选中文案,会把选中的序号回调出去。 | 否 | 无 | | | hint | String | 录入项 hint 提示 | 否 | '请选择' | | -| value | String | 录入项的值 | 否 | 无 | | -| btnsTxt | List | 快捷操作按钮选项文案列表 | 否 | 无 | | -| selectBtnList | List | 快捷按钮区的初始选中状态 | 否 | 无 | | -| enableBtnList | List | 快捷按钮区的是否可用状态 | 否 | 无 | | -| btns | Widget | 快捷按钮用户自定义视图 | 否 | 无 | | -| isBtnsScroll | bool | 快捷按钮较多时是否可滑动 | 否 | false | | -| themeData | BrnFormItemConfig | 表单主题配置 | 否 | 无 | | +| btnsTxt | `List?` | 快捷操作按钮选项文案列表 | 否 | 无 | | +| selectBtnList | `List?` | 快捷按钮区的初始选中状态 | 否 | 无 | | +| enableBtnList | `List?` | 快捷按钮区的是否可用状态 | 否 | 无 | | +| btns | Widget? | 快捷按钮用户自定义视图 | 否 | 无 | | +| themeData | BrnFormItemConfig? | 表单主题配置 | 否 | 无 | | ## 四、代码演示 diff --git a/docs/components/form/BrnTextSelectFormItem/BrnTextSelectFormItem.md b/docs/components/form/BrnTextSelectFormItem/BrnTextSelectFormItem.md index 3cfee756..3645a76b 100644 --- a/docs/components/form/BrnTextSelectFormItem/BrnTextSelectFormItem.md +++ b/docs/components/form/BrnTextSelectFormItem/BrnTextSelectFormItem.md @@ -35,7 +35,7 @@ group: ```dart BrnTextSelectFormItem({ - Key key, + Key? key, this.label, this.title: "", this.subTitle, @@ -57,7 +57,7 @@ BrnTextSelectFormItem({ this._isAutoLayout = false; this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -67,24 +67,25 @@ BrnTextSelectFormItem({ | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | | type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.textSelectInputType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.TYPE_NORMAL | 1. 不展示图标:BrnPrefixIconType.TYPE\_NORMAL 2. 展示加号图标:BrnPrefixIconType.TYPE\_ADD 3. 展示减号图标:BrnPrefixIconType.TYPE\_REMOVE | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标),默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑false:禁用 | -| onAddTap | VoidCallback | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onRemoveTap | VoidCallback | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | -| onTap | VoidCallback | 点击录入区回调 | 否 | 无 | | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| onTap | VoidCallback? | 点击录入区回调 | 否 | 无 | | | hint | String | 录入项 hint 提示 | 否 | '请选择' | | -| value | String | 录入项的值 | 否 | 无 | | +| value | String? | 录入项的值 | 否 | 无 | | | valueMaxLines | int | 选中文本最大行数 | 否 | 1 | | -| titleMaxLines | int | title最大行数 | 否 | 无 | | -| layoutRatio | double | 行布局左:右比例值,左边「标题+问号+提示语」 右边「选项值」,例如 左:右 = 6:4 则 ratio = 1.5 | 否 | 当左右内容超出默认比例且「有」提示语,则按比例 6:4 布局,当左右内容超出默认比例且「无」提示语,则按比例 4:6 布局,有用户自定义比例时用用户自定义比例 | | +| titleMaxLines | int? | title最大行数 | 否 | 无 | | +| layoutRatio | double? | 行布局左:右比例值,左边「标题+问号+提示语」 右边「选项值」,例如 左:右 = 6:4 则 ratio = 1.5 | 否 | 当左右内容超出默认比例且「有」提示语,则按比例 6:4 布局,当左右内容超出默认比例且「无」提示语,则按比例 4:6 布局,有用户自定义比例时用用户自定义比例 | | +| themeData | BrnFormItemConfig? | 表单主题配置 | 否 | 无 | | ### 其他数据说明: diff --git a/docs/components/form/BrnTitleFormItem/BrnTitleFormItem.md b/docs/components/form/BrnTitleFormItem/BrnTitleFormItem.md index 68776bf8..df60836d 100644 --- a/docs/components/form/BrnTitleFormItem/BrnTitleFormItem.md +++ b/docs/components/form/BrnTitleFormItem/BrnTitleFormItem.md @@ -27,15 +27,15 @@ group: ```dart BrnTitleFormItem( - {Key key, + {Key? key, this.label, - this.title: "", + this.title = "", this.subTitle, this.tipLabel, - this.prefixIconType: BrnPrefixIconType.normal, - this.error: "", - this.isEdit: true, - this.isRequire: false, + this.prefixIconType = BrnPrefixIconType.normal, + this.error = "", + this.isEdit = true, + this.isRequire = false, this.onTip, this.operationLabel, this.onTap, @@ -43,7 +43,7 @@ BrnTitleFormItem( : super(key: key) { this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) + .getConfig(configId: this.themeData!.configId) .formItemConfig .merge(this.themeData); } @@ -52,19 +52,19 @@ BrnTitleFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | | type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.labelTitle | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | -| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal2. 展示加号图标:BrnPrefixIconType.add3. 展示减号图标:BrnPrefixIconType.remove | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标), 默认为 false 不必填 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑,false:禁用 | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | -| operationLabel | String | 可操作区文案 | 否 | 无 | | -| onTap | VoidCallback | 可操作区点击回调 | 否 | 无 | | -| themeData | BrnFormItemConfig | form配置 | 否 | 无 | | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| operationLabel | String? | 可操作区文案 | 否 | 无 | | +| onTap | VoidCallback? | 可操作区点击回调 | 否 | 无 | | +| themeData | BrnFormItemConfig? | form配置 | 否 | 无 | | ## 四、代码演示 diff --git a/docs/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md b/docs/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md index 810e1cd3..b798f568 100644 --- a/docs/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md +++ b/docs/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md @@ -39,35 +39,35 @@ group: ```dart BrnTitleSelectInputFormItem( - {Key key, - this.label, - this.title: "", - this.subTitle, - this.tipLabel, - this.prefixIconType: BrnPrefixIconType.normal, - this.error: "", - this.isEdit: true, - this.isRequire: false, - this.isPrefixIconEnabled: false, - this.onAddTap, - this.onRemoveTap, - this.onTip, - this.hint: "请输入", - this.maxCount, - this.inputType: BrnInputType.TEXT, - this.selectedIndex: -1, - this.selectList, - this.inputFormatters, - this.onChanged, - this.onTitleSelected, - this.controller, - this.themeData}) - : super(key: key) { - this.themeData ??= BrnFormItemConfig(); - this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData.configId) - .formItemConfig - .merge(this.themeData); + {Key? key, + required this.selectList, + this.label, + this.title = "", + this.subTitle, + this.tipLabel, + this.prefixIconType = BrnPrefixIconType.normal, + this.error = "", + this.isEdit = true, + this.isRequire = false, + this.isPrefixIconEnabled = false, + this.onAddTap, + this.onRemoveTap, + this.onTip, + this.hint = "请输入", + this.maxCount, + this.inputType = BrnInputType.TEXT, + this.selectedIndex = -1, + this.inputFormatters, + this.onChanged, + this.onTitleSelected, + this.controller, + this.themeData}) + : super(key: key) { +this.themeData ??= BrnFormItemConfig(); +this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .formItemConfig + .merge(this.themeData); } ``` @@ -75,28 +75,28 @@ BrnTitleSelectInputFormItem( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | **备注** | | --- | --- | --- | --- | --- | --- | -| label | String | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | | type | Stirng | 录入项类型,主要用于录入类型页面框架中 | 否 | BrnInputItemType.textInputTitleSelectType | 外部可根据此字段判断表单项类型 | | title | String | 录入项标题 | 否 | '' | | -| subTitle | String | 录入项子标题 | 否 | 无 | | -| tipLabel | String | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 | 否 | 备注中类型3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为null时,不显示提示项 | | prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 **BrnPrefixIconType** 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | | error | String | 录入项错误提示 | 否 | '' | | | isRequire | bool | 录入项是否为必填项(展示`*`图标) 默认为 false 不必填 | 否 | false | | | isPrefixIconEnabled | bool | 录入项不可编辑时(isEdit: false) "+"、"-"号是否可点击,true: 可点击回调false: 不可点击回调 | 否 | false | | | isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑,false:禁用 | -| onAddTap | VoidCallback | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onRemoveTap | VoidCallback | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | -| onTip | VoidCallback | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | | hint | String | 录入项 hint 提示 | 否 | "请输入" | | -| maxCount | int | 最大输入字符数 | 否 | 无 | | +| maxCount | int? | 最大输入字符数 | 否 | 无 | | | inputType | String | 指定键盘类型 | 否 | BrnInputType.TEXT | 详见**BrnInputType**类,注意:无法通过指定键盘类型确保输入。比如不能通过指定数字键盘确保用户只输入数字。如果有要求用户只输入特定字符的需求请使用**inputFormatters**参数 | -| inputFormatters | `List` | 指定对输入数据的格式化要求 | 否 | 无 | | -| onChanged | `ValueChanged` | 输入文本变化回调 | 否 | 无 | | -| controller | TextEditingController | 文本输入controller | 否 | 无 | | +| inputFormatters | `List?` | 指定对输入数据的格式化要求 | 否 | 无 | | +| onChanged | `ValueChanged?` | 输入文本变化回调 | 否 | 无 | | +| controller | TextEditingController? | 文本输入controller | 否 | 无 | | | selectedIndex | int | 当前Title选中索引 | 否 | -1 | | | selectList | `List` | Title文案的所有可选项 | 否 | 无 | | -| themeData | BrnFormItemConfig | form配置 | 否 | 无 | | +| themeData | BrnFormItemConfig? | form配置 | 否 | 无 | | ### 其他数据说明: diff --git a/docs/components/selection/BrnFlatSelection/BrnFlatSelection.md b/docs/components/selection/BrnFlatSelection/BrnFlatSelection.md index 2bbb8a48..15651fe2 100644 --- a/docs/components/selection/BrnFlatSelection/BrnFlatSelection.md +++ b/docs/components/selection/BrnFlatSelection/BrnFlatSelection.md @@ -28,7 +28,8 @@ group: ```dart BrnFlatSelection( - {this.entityDataList, + {Key? key, + this.entityDataList, this.confirmCallback, this.onCustomFloatingLayerClick, this.preLineTagSize = 3, @@ -49,12 +50,12 @@ BrnFlatSelection( | 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | | --- | --- | --- | --- | --- | | entityDataList | `List` | 筛选原始数据 | 是 | 无 | -| confirmCallback | `Function(Map)` | 确定回调 | 否 | 无 | -| preLineTagSize | int | 每行展示tag数 | 否 | 3 | -| onCustomFloatingLayerClick | BrnOnCustomFloatingLayerClick | 自定义事件处理 | 否 | 无 | -| isNeedConfigChild | bool | 是否需要配置子选项 | 否 | true | -| controller | BrnFlatSelectionController | 自定义controller | 否 | | -| themeData | BrnSelectionConfig | 筛选项主题配置,配置详见BrnSelectionConfig | 否 | | +| confirmCallback | `Function(Map)?` | 确定回调 | 否 | 无 | +| preLineTagSize | int | 每行展示tag数 | 是 | 3 | +| onCustomFloatingLayerClick | BrnOnCustomFloatingLayerClick? | 自定义事件处理 | 否 | 无 | +| isNeedConfigChild | bool | 是否需要配置子选项 | 是 | true | +| controller | BrnFlatSelectionController? | 自定义controller | 否 | 无 | +| themeData | BrnSelectionConfig? | 筛选项主题配置,配置详见BrnSelectionConfig | 否 | | ## 四、代码演示 @@ -66,7 +67,7 @@ BrnFlatSelection( BrnFlatSelection( entityDataList: widget._filterData, confirmCallback: (data) { - var str = ""; + String str = ''; data.forEach((k, v) => str=str +" "+'${k}: ${v}'); BrnToast.show(str, context); }, @@ -81,7 +82,7 @@ BrnFlatSelection( preLineTagSize: 4, entityDataList: widget._filterData, confirmCallback: (data) { - var str = ""; + String str = ''; data.forEach((k, v) => str=str +" "+'${k}: ${v}'); BrnToast.show(str, context); }, diff --git a/docs/components/selection/BrnSelectionView/BrnSelectionView.md b/docs/components/selection/BrnSelectionView/BrnSelectionView.md index 8e84a036..9c49d99a 100644 --- a/docs/components/selection/BrnSelectionView/BrnSelectionView.md +++ b/docs/components/selection/BrnSelectionView/BrnSelectionView.md @@ -84,21 +84,21 @@ BrnSelectionView( ### 参数说明 -| **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | -| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ---------- | -| originalSelectionData | List<**BrnSelectionEntity**> | 筛选所需数据用于展示筛选菜单栏,以及展开的筛选弹窗。 | 否 | 空 | -| selectionViewController | BrnSelectionViewController | 用于主动控制筛选弹窗的关闭和刷新菜单的内容状态 | 否 | | +| **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | +| -------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------ | ---------- | +| originalSelectionData | List<**BrnSelectionEntity**> | 筛选所需数据用于展示筛选菜单栏,以及展开的筛选弹窗。 | 是 | 空 | +| selectionViewController | BrnSelectionViewController? | 用于主动控制筛选弹窗的关闭和刷新菜单的内容状态 | 否 | | | onSelectionChanged | `void Function(int menuIndex, Map selectedParams, Map customParams, BrnSetCustomSelectionMenuTitle setCustomMenuTitle)` | 点击筛选弹窗中的【确认】按钮时回调给外部选中的参数,包括:
menuIndex:当前展开的 menu 位置;
selectedParams 所有筛选弹窗中选中的参数;
customParams:拦截 CustomHandle 类型的筛选并设置的自定义参数;setCustomMenuTitle:对当前的筛选 Menu 设置 title 和高亮的回调函数,一般与 customParams 、**onCustomSelectionMenuClick**搭配使用,例如,通过 onCustomSelectionMenuClick 回调返回 customParams 参数,setCustomMenuTitle 根据 customParams 参数判断是否高亮,是否需要根据参数更新筛选菜单的 Title。 | 是 | | -| configRowCount | `BrnConfigTagCountPerRow(int index, BrnSelectionEntity entity)` | 仅适用于类型为 SelectionWindowType.Range 的筛选弹窗,用于对 SelectionWindowType.Range 类型的列数做配置,回调参数为 menu 的所在位置 index 和 menu 的数据。 | 否 | 空 | -| selectionConverterDelegate | DefaultSelectionConverter | 用于对处理 originalSelectionData 筛选数据,返回选中的参数。返回选中的参数返回类型为 Map。 | 否 | | -| onCustomSelectionMenuClick | `Function(int index, BrnSelectionEntity customMenuItem, BrnSetCustomSelectionParams customSelectionParams)` | 自定义(CustomHandle)类型的 menu 被点击的回调。
int index: 自定义 menu 所在位置 BrnSelectionEntity customMenuItem 自定义 menu 的数据
customSelectionParams:设置自定义参数 | 否 | | -| onCustomFloatingLayerClick | `Function(int index, BrnSelectionEntity customFloatingLayerEntity, BrnSetCustomFloatingLayerSelectionParams setCustomFloatingLayerSelectionParams);` | 用于【**更多-筛选**】中自定义二级浮层的点击回调(自定义二级浮层类型为 customfloatinglayer) | | | -| onMoreSelectionMenuClick | `void Function(int index, BrnOpenMorePage openMorePage)` | 点击【更多】筛选项时的回调。
index 为点击的位置
openMorePage:让用户触发的回调,用于展开更多筛选页面。`OpenMorePage = void Function({bool updateData, List moreSelections});` | 否 | | -| onDefaultParamsPrepared | `void Function(Map selectedParams);` | 数据初始化完成之后返回默认选中参数的回调,在 BrnSelectioinViewState **initState** 中回触发回调
Map selectedParams: 所有筛选菜单中的默认选中参数 | 否 | | -| onSelectionPreShow | `SelectionWindowType Function(int index, BrnSelectionEntity entity);` | 筛选弹窗打开前的回调方法, 并返回 SelectionWindowType 指定展示类型,是 Range 类型还是 List 类型。调用时机早于 onMenuItemClick
int index:点击筛选菜单的位置。
BrnSelectionEntity entity: index 菜单位置的筛选数据。 | 否 | | -| onMenuClickInterceptor | `bool Function(int index);` | 筛选菜单被点击时的回调函数,
返回 true 拦截 menu 点击事件
返回 false 不拦截
int index:被点击的菜单栏位置 | 否 | | -| constantTop | double | 指定筛选弹窗相对于屏幕的顶部距离,默认 null 不指定位置,依附于筛选菜单组件下方。 | 否 | | -| extraScrollController | ScrollController | 如需要在滚动视图中监听滚动状态并隐藏筛选弹窗,可以设置要监听的 ScrollController,当监听到滚动时筛选弹窗消失。 | 否 | | +| configRowCount | `BrnConfigTagCountPerRow(int index, BrnSelectionEntity entity)?` | 仅适用于类型为 SelectionWindowType.Range 的筛选弹窗,用于对 SelectionWindowType.Range 类型的列数做配置,回调参数为 menu 的所在位置 index 和 menu 的数据。 | 否 | 空 | +| selectionConverterDelegate | DefaultSelectionConverter | 用于对处理 originalSelectionData 筛选数据,返回选中的参数。返回选中的参数返回类型为 Map。 | 是 | | +| onCustomSelectionMenuClick | `Function(int index, BrnSelectionEntity customMenuItem, BrnSetCustomSelectionParams customSelectionParams)?` | 自定义(CustomHandle)类型的 menu 被点击的回调。
int index: 自定义 menu 所在位置 BrnSelectionEntity customMenuItem 自定义 menu 的数据
customSelectionParams:设置自定义参数 | 否 | | +| onCustomFloatingLayerClick | `Function(int index, BrnSelectionEntity customFloatingLayerEntity, BrnSetCustomFloatingLayerSelectionParams setCustomFloatingLayerSelectionParams)?` | 用于【**更多-筛选**】中自定义二级浮层的点击回调(自定义二级浮层类型为 customfloatinglayer) | 否 | | +| onMoreSelectionMenuClick | `void Function(int index, BrnOpenMorePage openMorePage)?` | 点击【更多】筛选项时的回调。
index 为点击的位置
openMorePage:让用户触发的回调,用于展开更多筛选页面。`OpenMorePage = void Function({bool updateData, List moreSelections});` | 否 | | +| onDefaultParamsPrepared | `void Function(Map selectedParams)?` | 数据初始化完成之后返回默认选中参数的回调,在 BrnSelectioinViewState **initState** 中回触发回调
Map selectedParams: 所有筛选菜单中的默认选中参数 | 否 | | +| onSelectionPreShow | `SelectionWindowType?`
`SelectionWindowType Function(int index, BrnSelectionEntity entity);` | 筛选弹窗打开前的回调方法, 并返回 SelectionWindowType 指定展示类型,是 Range 类型还是 List 类型。调用时机早于 onMenuItemClick
int index:点击筛选菜单的位置。
BrnSelectionEntity entity: index 菜单位置的筛选数据。 | 否 | | +| onMenuClickInterceptor | `bool Function(int index)?` | 筛选菜单被点击时的回调函数,
返回 true 拦截 menu 点击事件
返回 false 不拦截
int index:被点击的菜单栏位置 | 否 | | +| constantTop | double? | 指定筛选弹窗相对于屏幕的顶部距离,默认 null 不指定位置,依附于筛选菜单组件下方。 | 否 | | +| extraScrollController | ScrollController? | 如需要在滚动视图中监听滚动状态并隐藏筛选弹窗,可以设置要监听的 ScrollController,当监听到滚动时筛选弹窗消失。 | 否 | | ### 其它数据结构 diff --git a/docs/components/selection/BrnSimpleSelection/BrnSimpleSelection.md b/docs/components/selection/BrnSimpleSelection/BrnSimpleSelection.md index 7e606943..dd8dc52c 100644 --- a/docs/components/selection/BrnSimpleSelection/BrnSimpleSelection.md +++ b/docs/components/selection/BrnSimpleSelection/BrnSimpleSelection.md @@ -31,7 +31,7 @@ group: ```dart BrnSimpleSelection.radio({ - Key key, + Key? key, this.menuName, this.menuKey = defaultMenuKey, this.defaultValue, @@ -39,26 +39,22 @@ BrnSimpleSelection.radio({ this.maxSelectedCount = 1, @required this.onSimpleSelectionChanged, this.onMenuItemClick, -}) : super(key: key) { - this.isRadio = true; -} +}) ``` #### 多选 ```dart BrnSimpleSelection.checkbox({ + Key? key, this.menuName, this.menuKey, this.defaultValue, this.maxSelectedCount, this.items, - Key key, @required this.onSimpleSelectionChanged, this.onMenuItemClick, - }) : super(key: key) { - this.isRadio = false; -} + }) ``` @@ -67,13 +63,13 @@ BrnSimpleSelection.checkbox({ | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| menuName | String | 标题文案 | 否 | 无 | -| menuKey | String | 回传给服务端Key | 否 | 无 | -| defaultValue | String | 默认选中项值 | 否 | 无 | +| menuName | String | 标题文案 | 是 | 无 | +| menuKey | String | 回传给服务端Key | 是 | `'defaultMenuKey'` | +| defaultValue | String? | 默认选中项值 | 否 | 无 | | maxSelectedCount | int | 最大选中个数 | 否 | radio模式 默认65535 checkbox模式不设置 | -| items | `List` | 选项列表 | 否 | | -| onSimpleSelectionChanged | BrnSimpleSelectionOnSelectionChanged | 选择回调 | 否 | | -| onMenuItemClick | VoidCallback | 菜单点击事件 | 否 | | +| items | `List` | 选项列表 | 是 | | +| onSimpleSelectionChanged | BrnSimpleSelectionOnSelectionChanged | 选择回调 | 是 | | +| onMenuItemClick | VoidCallback? | 菜单点击事件 | 否 | | | isRadio | bool | 是否单选 默认 radio模式 is true , checkbox模式 is false | 否 | radio模式默认true checkbox模式默认false | ## 四、代码演示 diff --git a/docs/components/tabbar/BrnTabBar/BrnTabBar.md b/docs/components/tabbar/BrnTabBar/BrnTabBar.md index 7d060e43..d4e558ae 100644 --- a/docs/components/tabbar/BrnTabBar/BrnTabBar.md +++ b/docs/components/tabbar/BrnTabBar/BrnTabBar.md @@ -36,71 +36,87 @@ group: ```dart BrnTabBar({ - @required this.tabs, - this.mode = BrnTabBarBadgeMode.average, - this.isScroll = false, - this.tabHeight, - this.padding = EdgeInsets.zero, - this.controller, - this.backgroundcolor = const Color(0xffffffff), - this.indicatorColor, - this.indicatorWeight, - this.indicatorWidth, - this.indicatorPadding = EdgeInsets.zero, - this.labelColor, - this.labelStyle, - this.labelPadding = EdgeInsets.zero, - this.unselectedLabelColor, - this.unselectedLabelStyle, - this.dragStartBehavior = DragStartBehavior.start, - this.onTap, - this.tabWidth, - this.hasDivider = false, - this.hasIndex = false, - this.showMore = false, - this.moreWindowText, - this.onMorePop, - this.closeController, - this.themeData, - this.tagSpacing, - this.preLineTagCount, - this.tagHeight, - }) ; + required this.tabs, + this.mode = BrnTabBarBadgeMode.average, + this.isScroll = false, + this.tabHeight, + this.padding = EdgeInsets.zero, + this.controller, + this.backgroundcolor = const Color(0xffffffff), + this.indicatorColor, + this.indicatorWeight, + this.indicatorWidth, + this.indicatorPadding = EdgeInsets.zero, + this.labelColor, + this.labelStyle, + this.labelPadding = EdgeInsets.zero, + this.unselectedLabelColor, + this.unselectedLabelStyle, + this.dragStartBehavior = DragStartBehavior.start, + this.onTap, + this.tabWidth, + this.hasDivider = false, + this.hasIndex = false, + this.showMore = false, + this.moreWindowText, + this.onMorePop, + this.closeController, + this.themeData, + this.tagSpacing, + this.preLineTagCount, + this.tagHeight, +}) : assert(tabs == null || tabs is List) { + this.themeData ??= BrnTabBarConfig(); + this.themeData = this.themeData!.merge(BrnTabBarConfig( + tabHeight: tabHeight, + indicatorHeight: indicatorWeight, + indicatorWidth: indicatorWidth, + labelStyle: BrnTextStyle.withStyle(labelStyle), + unselectedLabelStyle: BrnTextStyle.withStyle(unselectedLabelStyle), + tagSpacing: tagSpacing, + preLineTagCount: preLineTagCount, + tagHeight: tagHeight, + )); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .tabBarConfig + .merge(this.themeData); +} ``` ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| -------------------- | ------------------------ | ------------------------------------------------------------ | ------------ | ------------------------------------------------------ | -| tabs | List | 组件每个 Tab 的数据集 | 是 | 无 | -| mode | Mode | Tabbar 的模式,默认为等分模式 BrnTabBarBadgeMode.average,切换为 origin 基本为原生的 Tabbar 分配模式 | 否 | BrnTabBarBadgeMode.average | -| isScroll | bool | 是否能滑动(当 tab 数量大于 4 个,默认都是滚动的,再设置此属性无效) | 否 | false | -| tabHeight | double | BrnTabBar 的最小高度 | 否 | 50 | -| padding | EdgeInsetsGeometry | BrnTabBar 的 padding | 否 | EdgeInsets.zero | -| controller | TabController | 组件和 TabBarView 联动控制器 | 否 | 无 | -| backgroundcolor | Color | 组件整体背景色 | 否 | Color(0xffffffff) | -| indicatorColor | Color | 指示器的颜色 | 否 | 无 | -| indicatorWeight | double | 指示器的高度 | 否 | 2 | -| indicatorWidth | double | 指示器的宽度 | 否 | 24 | -| indicatorPadding | EdgeInsetsGeometry | 指示器的 padding | 否 | EdgeInsets.zero | -| labelColor | Color | 选中 Tab 文本的颜色 | 否 | APP 主题色/品牌色 | -| labelStyle | TextStyle | 选中 Tab 文本的样式 | 否 | TextStyle(fontSize: 16, fontWeight: FontWeight.w600) | -| labelPadding | EdgeInsetsGeometry | 选中 Tab 文本的 padding | 否 | EdgeInsets.zero | -| unselectedLabelColor | Color | 未选中 Tab 文本的颜色 | 否 | 纯黑文字 #222222 | -| unselectedLabelStyle | TextStyle | 未选中 Tab 文本的样式 | 否 | TextStyle(fontSize: 16, fontWeight: FontWeight.normal) | -| dragStartBehavior | DragStartBehavior | 处理拖动开始的行为 | 否 | DragStartBehavior.start | -| onTap | TabChanged | 底部按钮之间的分割线 | 否 | 无 | -| tabWidth | double | 组件每个 Tab 的宽度 | 否 | 无 | -| hasDivider | bool | 是否显示 Tab 间分隔线 | 否 | false:不显示 | -| hasIndex | bool | 是否显示 Tab 文本上面角标 | 否 | false:不显示 | -| showMore | bool | 是否展开更多 Tabs | 否 | false:不显示 | -| moreWindowText | String | 展开更多弹框标题 | 否 | 无 | -| onMorePop | VoidCallback | 更多弹框弹出的时候回调 | 否 | 无 | -| closeController | BrnCloseWindowController | 更多弹框关闭控制器 | 否 | 无 | -| tagSpacing | double | tag 间距 | 否 | 12 | -| preLineTagCount | int | 每行 tag 数 | 否 | 4 | -| tagHeight | double | tag 高度 | 否 | 32 | -| themeData | BrnTabBarConfig | tabBar 配置信息,配置详情见 BrnTabBarConfig | 否 | 无 | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| -------------------- | ------------------------- | ------------------------------------------------------------ | ------------ | ------------------------------------------------------ | +| tabs | List | 组件每个 Tab 的数据集 | 是 | 无 | +| mode | BrnTabBarBadgeMode | Tabbar 的模式,默认为等分模式 BrnTabBarBadgeMode.average,切换为 origin 基本为原生的 Tabbar 分配模式 | 否 | BrnTabBarBadgeMode.average | +| isScroll | bool | 是否能滑动(当 tab 数量大于 4 个,默认都是滚动的,再设置此属性无效) | 否 | false | +| tabHeight | double? | BrnTabBar 的最小高度 | 否 | 50 | +| padding | EdgeInsetsGeometry | BrnTabBar 的 padding | 否 | EdgeInsets.zero | +| controller | TabController? | 组件和 TabBarView 联动控制器 | 否 | 无 | +| backgroundcolor | Color | 组件整体背景色 | 否 | Color(0xffffffff) | +| indicatorColor | Color? | 指示器的颜色 | 否 | 无 | +| indicatorWeight | double? | 指示器的高度 | 否 | 2 | +| indicatorWidth | double? | 指示器的宽度 | 否 | 24 | +| indicatorPadding | EdgeInsetsGeometry | 指示器的 padding | 否 | EdgeInsets.zero | +| labelColor | Color? | 选中 Tab 文本的颜色 | 否 | APP 主题色/品牌色 | +| labelStyle | TextStyle? | 选中 Tab 文本的样式 | 否 | TextStyle(fontSize: 16, fontWeight: FontWeight.w600) | +| labelPadding | EdgeInsetsGeometry | 选中 Tab 文本的 padding | 否 | EdgeInsets.zero | +| unselectedLabelColor | Color? | 未选中 Tab 文本的颜色 | 否 | 纯黑文字 #222222 | +| unselectedLabelStyle | TextStyle? | 未选中 Tab 文本的样式 | 否 | TextStyle(fontSize: 16, fontWeight: FontWeight.normal) | +| dragStartBehavior | DragStartBehavior | 处理拖动开始的行为 | 否 | DragStartBehavior.start | +| onTap | BrnTabBarOnTap? | 底部按钮之间的分割线 | 否 | 无 | +| tabWidth | double? | 组件每个 Tab 的宽度 | 否 | 无 | +| hasDivider | bool | 是否显示 Tab 间分隔线 | 否 | false:不显示 | +| hasIndex | bool | 是否显示 Tab 文本上面角标 | 否 | false:不显示 | +| showMore | bool | 是否展开更多 Tabs | 否 | false:不显示 | +| moreWindowText | String? | 展开更多弹框标题 | 否 | 无 | +| onMorePop | VoidCallback? | 更多弹框弹出的时候回调 | 否 | 无 | +| closeController | BrnCloseWindowController? | 更多弹框关闭控制器 | 否 | 无 | +| tagSpacing | double? | tag 间距 | 否 | 12 | +| preLineTagCount | int? | 每行 tag 数 | 否 | 4 | +| tagHeight | double? | tag 高度 | 否 | 32 | +| themeData | BrnTabBarConfig? | tabBar 配置信息,配置详情见 BrnTabBarConfig | 否 | 无 | ## 四、代码演示 diff --git a/docs/components/text/BrnPairInfoTable/BrnPairInfoTable.md b/docs/components/text/BrnPairInfoTable/BrnPairInfoTable.md index e8128caa..c0dbbc63 100644 --- a/docs/components/text/BrnPairInfoTable/BrnPairInfoTable.md +++ b/docs/components/text/BrnPairInfoTable/BrnPairInfoTable.md @@ -22,30 +22,33 @@ group: ### 构造函数 ```dart - BrnPairInfoTable({ - Key key, - @required this.children, - this.isValueAlign = true, - this.expandAtIndex = -1, - this.rowDistance, - this.itemSpacing, - this.isFolded = true, - this.themeData, - this.customKeyWidth, - }); +BrnPairInfoTable({ + Key? key, + required this.children, + this.defaultVerticalAlignment = TableCellVerticalAlignment.baseline, + this.isValueAlign = true, + this.expandAtIndex = -1, + this.rowDistance, + this.itemSpacing, + this.isFolded = true, + this.themeData, + this.customKeyWidth, +}); ``` ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| -------------- | ---------------- | --------------------------------------------------- | ------------ | --------------- | -| children | List | 待展示的文本信息 | 是 | 无 | -| isValueAlign | bool | value 是否对齐 | 否 | 无 | -| expandAtIndex | int | 从第几个位置开始展开收起,-1 表示不需要展开收起功能 | 否 | -1 | -| rowDistance | double | 行与行之间的间距 | 否 | 4 | -| itemSpacing | double | key-value 之间的间距 | 否 | 2 | -| isFolded | true | 初始的展开收起状态 | 否 | bool | -| customKeyWidth | TableColumnWidth | value 的对齐策略 | 否 | key 最大宽度 94 | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| ------------------------ | -------------------------- | ------------------------------------------------------------ | ------------ | --------------- | +| children | List | 待展示的文本信息 | 是 | 无 | +| isValueAlign | bool | value 是否对齐 | 否 | 无 | +| defaultVerticalAlignment | TableCellVerticalAlignment | TableCell 默认垂直对齐方式, 默认值为 [TableCellVerticalAlignment.baseline],当 [BrnInfoModal.valuePart] 为自定义 Widget 时,可设置该参数调整对齐方式,仅在 [isValueAlign] 为 true 时设置才生效 | 否 | | +| expandAtIndex | int | 从第几个位置开始展开收起,-1 表示不需要展开收起功能 | 否 | -1 | +| rowDistance | double? | 行与行之间的间距 | 否 | 4 | +| itemSpacing | double? | key-value 之间的间距 | 否 | 2 | +| isFolded | true | 初始的展开收起状态 | 否 | bool | +| customKeyWidth | TableColumnWidth? | 对齐情况下,自定义的key展示规则,默认是最大的Key展示长度是107,可以参考[_MaxWrapTableWidth]实现自定义的展示规则,指定长度等 | 否 | key 最大宽度 94 | +| themeData | BrnPairInfoTableConfig? | 主题定制属性 | 否 | | ## 四、代码演示 diff --git a/example/lib/sample/components/appraise/appraise_example.dart b/example/lib/sample/components/appraise/appraise_example.dart index 8cb7791d..c2f21523 100644 --- a/example/lib/sample/components/appraise/appraise_example.dart +++ b/example/lib/sample/components/appraise/appraise_example.dart @@ -85,7 +85,7 @@ class _AppraiseExampleState extends State { BrnToast.show('输入的内容为' + input, context); }, iconClickCallback: (index) { - BrnToast.show('选中的评价为${index}', context); + BrnToast.show('选中的评价为$index', context); }, tagSelectCallback: (list) { BrnToast.show('选中的标签为:' + list.toString(), context); diff --git a/example/lib/sample/components/dialog/dialog_entry_page.dart b/example/lib/sample/components/dialog/dialog_entry_page.dart index f53999bf..93abb2db 100644 --- a/example/lib/sample/components/dialog/dialog_entry_page.dart +++ b/example/lib/sample/components/dialog/dialog_entry_page.dart @@ -924,6 +924,7 @@ class DialogEntryPage extends StatelessWidget { submitText: "提交", onSubmitClick: () { BrnToast.show("点击了纯文本弹框", context); + Navigator.of(context).pop(); })); } diff --git a/example/lib/sample/components/navbar/nav_bar_example_page.dart b/example/lib/sample/components/navbar/nav_bar_example_page.dart index d0870d2a..46f5f25c 100644 --- a/example/lib/sample/components/navbar/nav_bar_example_page.dart +++ b/example/lib/sample/components/navbar/nav_bar_example_page.dart @@ -1,8 +1,5 @@ - - import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; class NavBarPage extends StatefulWidget { final int index; @@ -563,7 +560,7 @@ class _NavBarPageState extends State with TickerProviderStateMixin { leadClickCallback: (controller, update) { //controller 是文本控制器,通过controller 可以拿到输入的内容 以及 对输入的内容更改 //update 是setState方法的方法命,update() 就可以刷新输入框 - BrnPopupListWindow.showPopListWindow(context, keyLeading, data: ["aaaa", "bbbbb"]); + BrnPopupListWindow.showPopListWindow(context, keyLeading, data: ["aaaa", "bbbbb"], offset: 10); }, //输入框 文本内容变化的监听 searchBarInputChangeCallback: (input) { diff --git a/example/lib/sample/components/selection/selectionview_customview_example_page.dart b/example/lib/sample/components/selection/selectionview_customview_example_page.dart index e84b04ef..882f6d44 100644 --- a/example/lib/sample/components/selection/selectionview_customview_example_page.dart +++ b/example/lib/sample/components/selection/selectionview_customview_example_page.dart @@ -40,7 +40,7 @@ class _SelectionViewExamplePageState extends State { /// bottomWidgetKey: 已选列表下边操作区域绑定的 GlobalKey,已选列表会自动与操作区域左右对齐,且从操作区域的顶部滑出 void showWithTargetKey({required GlobalKey bottomWidgetKey}) { - RenderBox? renderBox = - bottomWidgetKey.currentContext?.findRenderObject() as RenderBox?; + RenderBox? renderBox; + RenderObject? renderObject = + bottomWidgetKey.currentContext?.findRenderObject(); + if (renderObject != null && renderObject is RenderBox) { + renderBox = renderObject; + } var offset = renderBox?.localToGlobal(Offset.zero); _leftOffset = offset?.dx ?? 0; _maxWidth = renderBox?.size.width ?? MediaQuery.of(context).size.width; @@ -286,21 +289,22 @@ class _BrnActionSheetSelectedItemListState AnimationController alphaAnimationController = AnimationController( duration: const Duration(milliseconds: 200), vsync: this); widget._alphaAnimationController = alphaAnimationController; - Animation yAnimation = Tween(begin: 65.0, end: this.getContentHeight()) - .animate(yAnimationController) - ..addListener(() { - setState(() => {}); - }) - ..addStatusListener((status) { - if (status == AnimationStatus.dismissed) { - widget.onDismiss!(_isClosedByClear); - } - }); - widget._yAnimation = yAnimation as Animation; - Animation alphaAnimation = Tween(begin: 0.0, end: 0.7) + Animation yAnimation = + Tween(begin: 65.0, end: this.getContentHeight()) + .animate(yAnimationController) + ..addListener(() { + setState(() => {}); + }) + ..addStatusListener((status) { + if (status == AnimationStatus.dismissed) { + widget.onDismiss!(_isClosedByClear); + } + }); + widget._yAnimation = yAnimation; + Animation alphaAnimation = Tween(begin: 0.0, end: 0.7) .animate(alphaAnimationController) ..addListener(() {}); - widget._alphaAnimation = alphaAnimation as Animation; + widget._alphaAnimation = alphaAnimation; yAnimationController.forward(); alphaAnimationController.forward(); } diff --git a/lib/src/components/card/bubble_card/brn_bubble_text.dart b/lib/src/components/card/bubble_card/brn_bubble_text.dart index e5161c5b..bacd5bd6 100644 --- a/lib/src/components/card/bubble_card/brn_bubble_text.dart +++ b/lib/src/components/card/bubble_card/brn_bubble_text.dart @@ -33,10 +33,10 @@ class BrnBubbleText extends StatelessWidget { /// 显示的文本 final String text; - /// 最多显示的行数 + ///最多显示的行数 final int? maxLines; - /// 展开收起回调 + ///展开收起回调 final TextExpandedCallback? onExpanded; /// 气泡的圆角 默认是4 @@ -60,7 +60,6 @@ class BrnBubbleText extends StatelessWidget { this.textStyle}) : super(key: key); - @override @override Widget build(BuildContext context) { Image image = BrunoTools.getAssetImageWithColor( diff --git a/lib/src/components/card/content_card/brn_pair_info_table.dart b/lib/src/components/card/content_card/brn_pair_info_table.dart index 2e7b7a4c..c1e10fdd 100644 --- a/lib/src/components/card/content_card/brn_pair_info_table.dart +++ b/lib/src/components/card/content_card/brn_pair_info_table.dart @@ -71,9 +71,15 @@ import 'package:flutter/material.dart'; /// * [BrnFollowPairInfo], key-value紧紧相随的的文本组件 /// class BrnPairInfoTable extends StatefulWidget { + /// 文本信息是否对齐 默认不对齐 final bool isValueAlign; + /// TableCell 默认垂直对齐方式, 默认值为 [TableCellVerticalAlignment.baseline] + /// 当 [BrnInfoModal.valuePart] 为自定义 Widget 时,可设置该参数调整对齐方式,仅在 + /// [isValueAlign] 为 true 时设置才生效 + final TableCellVerticalAlignment defaultVerticalAlignment; + /// 待展示的文本信息集合 final List children; @@ -100,6 +106,7 @@ class BrnPairInfoTable extends StatefulWidget { BrnPairInfoTable({ Key? key, required this.children, + this.defaultVerticalAlignment = TableCellVerticalAlignment.baseline, this.isValueAlign = true, this.expandAtIndex = -1, this.rowDistance, @@ -191,6 +198,7 @@ class _BrnPairInfoTableState extends State { if (widget.isValueAlign) { showWidget = BrnAlignPairInfo( + defaultVerticalAlignment: widget.defaultVerticalAlignment, children: showList, itemSpacing: widget.itemSpacing, rowDistance: widget.rowDistance, @@ -579,7 +587,8 @@ class BrnFollowPairInfo extends StatelessWidget with PairInfoPart { } return Row( mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.start, children: [ Container( constraints: BoxConstraints(maxWidth: keyMax), @@ -599,6 +608,10 @@ class BrnFollowPairInfo extends StatelessWidget with PairInfoPart { } class BrnAlignPairInfo extends StatelessWidget with PairInfoPart { + /// TableCell 默认垂直对齐方式, 默认值为 [TableCellVerticalAlignment.baseline] + /// 当 [BrnInfoModal.valuePart] 为自定义 Widget 时,可设置该参数调整对齐方式 + final TableCellVerticalAlignment defaultVerticalAlignment; + /// 待展示的文本信息集合 final List? children; @@ -617,6 +630,7 @@ class BrnAlignPairInfo extends StatelessWidget with PairInfoPart { BrnAlignPairInfo( {this.children, + this.defaultVerticalAlignment = TableCellVerticalAlignment.baseline, this.rowDistance, this.backgroundColor, this.itemSpacing, @@ -642,7 +656,7 @@ class BrnAlignPairInfo extends StatelessWidget with PairInfoPart { BrnPairInfoTableConfig defaultThemeConfig, double maxWith) { int index = -1; Widget table = Table( - defaultVerticalAlignment: TableCellVerticalAlignment.baseline, + defaultVerticalAlignment: this.defaultVerticalAlignment, textBaseline: TextBaseline.ideographic, columnWidths: { 0: customKeyWidth ?? _MaxWrapTableWidth(maxWith), diff --git a/lib/src/components/charts/broken_line/brn_broken_line.dart b/lib/src/components/charts/broken_line/brn_broken_line.dart index 501f4799..95f5dd8c 100644 --- a/lib/src/components/charts/broken_line/brn_broken_line.dart +++ b/lib/src/components/charts/broken_line/brn_broken_line.dart @@ -95,7 +95,7 @@ class BrnBrokenLine extends StatefulWidget { this.isShowXDialText = false, this.isShowYDialText = false, }) : super(key: key) { - // 设置自定义 X 轴时,检查 x轴的最大、最小刻度范围 + // 设置自定义 X 轴时,检查 x 轴的最大、最小刻度范围 if (xDialValues != null) { assert(xDialMin != null); assert(xDialMax != null); diff --git a/lib/src/components/charts/broken_line/brn_line_painter.dart b/lib/src/components/charts/broken_line/brn_line_painter.dart index be8db97e..5b0f850f 100644 --- a/lib/src/components/charts/broken_line/brn_line_painter.dart +++ b/lib/src/components/charts/broken_line/brn_line_painter.dart @@ -377,8 +377,8 @@ class BrnLinePainter extends BrnBasePainter { void _drawLine(Canvas canvas) { _lineCanvasModels.forEach((element) { //阴影区域 - if (element.shaderColors != null) { - element.shadowPaths.forEach((shadowPathElement) { + if (element.shadowPaths != null && element.shaderColors != null) { + element.shadowPaths!.forEach((shadowPathElement) { var shader = LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, @@ -577,7 +577,7 @@ class LineCanvasModel { final Color pathColor; final double pathWidth; - final List shadowPaths; + final List? shadowPaths; final List? shaderColors; final List? points; diff --git a/lib/src/components/dialog/brn_dialog.dart b/lib/src/components/dialog/brn_dialog.dart index e3fb2adf..be20efcc 100644 --- a/lib/src/components/dialog/brn_dialog.dart +++ b/lib/src/components/dialog/brn_dialog.dart @@ -99,7 +99,6 @@ enum _ButtonType { /// 弹窗由五部分组成:Icon、标题、内容、警示、按钮操作区域。 /// 每一部分都可以显示或者不显示。 /// -///弹窗的样式通过[brnDialogStyle]控制,开发者可以设置每一部分的间距、颜色、字体等一切和样式相关的配置 /// ///有两种使用方式: ///1:系统的showDialog @@ -576,8 +575,6 @@ class BrnDialog extends AlertDialog { /// /// dismiss 点击按钮后是否 消失弹窗 /// -/// dialogStyle 对话框的样式:间距、字体、阴影等 -/// /// barrierDismissible 点击四周的黑色遮罩 是否关闭弹窗 /// /// titleMaxLines 标题的最大行数 @@ -745,4 +742,4 @@ class BrnDialogManager { }, ); } -} +} \ No newline at end of file diff --git a/lib/src/components/dialog/brn_middle_input_diaolg.dart b/lib/src/components/dialog/brn_middle_input_diaolg.dart index 35ae8b3c..6092c097 100644 --- a/lib/src/components/dialog/brn_middle_input_diaolg.dart +++ b/lib/src/components/dialog/brn_middle_input_diaolg.dart @@ -170,4 +170,4 @@ class BrnMiddleInputDialog { if (onCancel != null) onCancel!(); }); } -} +} \ No newline at end of file diff --git a/lib/src/components/dialog/brn_scrollable_text_dialog.dart b/lib/src/components/dialog/brn_scrollable_text_dialog.dart index 292e4a29..9de95c0d 100644 --- a/lib/src/components/dialog/brn_scrollable_text_dialog.dart +++ b/lib/src/components/dialog/brn_scrollable_text_dialog.dart @@ -122,8 +122,10 @@ class BrnScrollableText extends StatelessWidget { children: [ BrnCSS2Text.toTextView(contentText, linksCallback: linksCallback, - defaultStyle: - TextStyle(fontSize: textFontSize, color: textColor)) + defaultStyle: TextStyle( + fontSize: textFontSize, + color: textColor, + fontWeight: FontWeight.normal)) ])))), ), title: title, diff --git a/lib/src/components/form/items/general/brn_multi_choice_input_item.dart b/lib/src/components/form/items/general/brn_multi_choice_input_item.dart index 1c632b54..70fbdb75 100644 --- a/lib/src/components/form/items/general/brn_multi_choice_input_item.dart +++ b/lib/src/components/form/items/general/brn_multi_choice_input_item.dart @@ -5,7 +5,6 @@ import 'package:bruno/src/components/radio/brn_checkbox.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// /// 横向多选录入项 diff --git a/lib/src/components/form/items/general/brn_multi_choice_portrait_input_item.dart b/lib/src/components/form/items/general/brn_multi_choice_portrait_input_item.dart index 8ed2e616..c761ad62 100644 --- a/lib/src/components/form/items/general/brn_multi_choice_portrait_input_item.dart +++ b/lib/src/components/form/items/general/brn_multi_choice_portrait_input_item.dart @@ -6,7 +6,6 @@ import 'package:bruno/src/components/radio/brn_checkbox.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// /// 纵向多选录入项 diff --git a/lib/src/components/form/items/general/brn_quick_select_input_item.dart b/lib/src/components/form/items/general/brn_quick_select_input_item.dart index dd594699..c9baa814 100644 --- a/lib/src/components/form/items/general/brn_quick_select_input_item.dart +++ b/lib/src/components/form/items/general/brn_quick_select_input_item.dart @@ -6,7 +6,6 @@ import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// /// 快速选择类型录入项 diff --git a/lib/src/components/form/items/general/brn_radio_input_item.dart b/lib/src/components/form/items/general/brn_radio_input_item.dart index b13c7eba..3f16018f 100644 --- a/lib/src/components/form/items/general/brn_radio_input_item.dart +++ b/lib/src/components/form/items/general/brn_radio_input_item.dart @@ -9,7 +9,6 @@ import 'package:bruno/src/components/radio/brn_radio_button.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// /// 横向单选录入项 diff --git a/lib/src/components/form/items/general/brn_radio_portrait_input_item.dart b/lib/src/components/form/items/general/brn_radio_portrait_input_item.dart index 3a446f72..2a6c705f 100644 --- a/lib/src/components/form/items/general/brn_radio_portrait_input_item.dart +++ b/lib/src/components/form/items/general/brn_radio_portrait_input_item.dart @@ -1,13 +1,6 @@ - - import 'package:bruno/bruno.dart'; -import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; -import 'package:bruno/src/components/form/base/input_item_interface.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; -import 'package:bruno/src/components/line/brn_line.dart'; -import 'package:bruno/src/theme/brn_theme.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// /// 纵向单选录入项 diff --git a/lib/src/components/form/items/general/brn_ratio_input_item.dart b/lib/src/components/form/items/general/brn_ratio_input_item.dart index 2a5c1293..2284c7e9 100644 --- a/lib/src/components/form/items/general/brn_ratio_input_item.dart +++ b/lib/src/components/form/items/general/brn_ratio_input_item.dart @@ -6,7 +6,6 @@ import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; /// /// 比例输入型录入项 diff --git a/lib/src/components/form/items/general/brn_star_input_item.dart b/lib/src/components/form/items/general/brn_star_input_item.dart index b19cf5ab..8ead2dbd 100644 --- a/lib/src/components/form/items/general/brn_star_input_item.dart +++ b/lib/src/components/form/items/general/brn_star_input_item.dart @@ -8,7 +8,6 @@ import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// /// 评星型录入项 diff --git a/lib/src/components/form/items/general/brn_step_input_item.dart b/lib/src/components/form/items/general/brn_step_input_item.dart index f6c48048..ce7f0ee1 100644 --- a/lib/src/components/form/items/general/brn_step_input_item.dart +++ b/lib/src/components/form/items/general/brn_step_input_item.dart @@ -1,13 +1,7 @@ import 'package:bruno/bruno.dart'; -import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; -import 'package:bruno/src/components/form/base/input_item_interface.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; -import 'package:bruno/src/theme/brn_theme_configurator.dart'; -import 'package:bruno/src/theme/configs/brn_form_config.dart'; -import 'package:bruno/src/utils/brn_tools.dart'; import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// /// 递增/递减型录入项 diff --git a/lib/src/components/form/items/general/brn_text_block_input_item.dart b/lib/src/components/form/items/general/brn_text_block_input_item.dart index 7fbc70b2..0d0d5bf4 100644 --- a/lib/src/components/form/items/general/brn_text_block_input_item.dart +++ b/lib/src/components/form/items/general/brn_text_block_input_item.dart @@ -3,7 +3,6 @@ import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/theme/brn_theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; /// /// 文本块输入型录入项 diff --git a/lib/src/components/form/items/general/brn_text_select_item.dart b/lib/src/components/form/items/general/brn_text_select_item.dart index 1678b5c8..13a9645d 100644 --- a/lib/src/components/form/items/general/brn_text_select_item.dart +++ b/lib/src/components/form/items/general/brn_text_select_item.dart @@ -9,7 +9,6 @@ import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// /// 选择型表单项 diff --git a/lib/src/components/form/items/group/brn_portrait_radio_group.dart b/lib/src/components/form/items/group/brn_portrait_radio_group.dart index 88ecbf44..739ed348 100644 --- a/lib/src/components/form/items/group/brn_portrait_radio_group.dart +++ b/lib/src/components/form/items/group/brn_portrait_radio_group.dart @@ -4,7 +4,6 @@ import 'package:bruno/src/components/radio/brn_radio_button.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// 备选项点击时的回调。[oldStr] 旧的选项,如果初始没有选中项,该参数为null,[newStr] 新选中的选项。 typedef BrnPortraitRadioGroupOnChanged = void Function( diff --git a/lib/src/components/form/items/misc/brn_title_item.dart b/lib/src/components/form/items/misc/brn_title_item.dart index a3d77a21..83bb8e10 100644 --- a/lib/src/components/form/items/misc/brn_title_item.dart +++ b/lib/src/components/form/items/misc/brn_title_item.dart @@ -4,7 +4,6 @@ import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// 标题类型录入项 // ignore: must_be_immutable diff --git a/lib/src/components/form/items/title/brn_base_title_item.dart b/lib/src/components/form/items/title/brn_base_title_item.dart index 90a1ba0a..363d0359 100644 --- a/lib/src/components/form/items/title/brn_base_title_item.dart +++ b/lib/src/components/form/items/title/brn_base_title_item.dart @@ -4,7 +4,6 @@ import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// /// 可组合title类型录入项 diff --git a/lib/src/components/picker/time_picker/brn_date_time_formatter.dart b/lib/src/components/picker/time_picker/brn_date_time_formatter.dart index 18bb9d78..3ec7e4e9 100755 --- a/lib/src/components/picker/time_picker/brn_date_time_formatter.dart +++ b/lib/src/components/picker/time_picker/brn_date_time_formatter.dart @@ -40,7 +40,6 @@ class DateTimeFormatter { case BrnDateTimePickerMode.datetime: return datetimePickerDatetimeFormat; } - return ''; } static String generateDateRangePickerFormat( @@ -54,7 +53,6 @@ class DateTimeFormatter { case BrnDateTimeRangePickerMode.time: return datetimeRangePickerTimeFormat; } - return ''; } /// Check if the date format is for day(contain y、M、d、E) or not. @@ -109,7 +107,7 @@ class DateTimeFormatter { /// Format datetime string static String formatDateTime( int value, String format, DateTimePickerLocale locale) { - if (format == null || format.length == 0) { + if (format.length == 0) { return value.toString(); } diff --git a/lib/src/components/popup/brn_popup_window.dart b/lib/src/components/popup/brn_popup_window.dart index 738be500..3ae42acb 100644 --- a/lib/src/components/popup/brn_popup_window.dart +++ b/lib/src/components/popup/brn_popup_window.dart @@ -133,6 +133,10 @@ class BrnPopupWindow extends StatefulWidget { double? arrowOffset, VoidCallback? dismissCallback, double turnOverFromBottom = 50.0}) { + assert(popKey.currentContext != null && + popKey.currentContext!.findRenderObject() != null); + if (popKey.currentContext == null || + popKey.currentContext!.findRenderObject() == null) return; Navigator.push( context, BrnPopupRoute( @@ -164,7 +168,7 @@ class BrnPopupWindow extends StatefulWidget { class _BrnPopupWindowState extends State { /// targetView的位置 - Rect? _showRect; + Rect _showRect = Rect.zero; /// 屏幕的尺寸 late Size _screenSize; @@ -199,57 +203,50 @@ class _BrnPopupWindowState extends State { _backgroundColor = (widget.backgroundColor ?? Colors.transparent).withAlpha(255); _popDirection = widget.popDirection; - if (this._showRect != null) { - _calculateOffset(this._showRect!); - } + _calculateOffset(); } // 获取targetView的位置 - Rect? _getWidgetGlobalRect(GlobalKey key) { - BuildContext? ctx = key.currentContext; - RenderObject? obj; - if (ctx != null) { - obj = ctx.findRenderObject(); - } - if (obj != null && obj is RenderBox) { - RenderBox renderBox = obj; + Rect _getWidgetGlobalRect(GlobalKey key) { + try { + BuildContext? ctx = key.currentContext; + RenderObject? renderObject = ctx?.findRenderObject(); + RenderBox renderBox = renderObject as RenderBox; var offset = renderBox.localToGlobal(Offset.zero); return Rect.fromLTWH( offset.dx, offset.dy, renderBox.size.width, renderBox.size.height); + } catch (e) { + debugPrint('获取尺寸信息异常'); + return Rect.zero; } - return null; } // 计算popUpWindow显示的位置 - void _calculateOffset(Rect showRect) { - if (showRect.center.dx < _screenSize.width / 2) { + void _calculateOffset() { + if (_showRect.center.dx < _screenSize.width / 2) { // popUpWindow向右侧延伸 _expandedRight = true; - _left = showRect.left; + _left = _showRect.left; } else { // popUpWindow向左侧延伸 _expandedRight = false; - _right = _screenSize.width - showRect.right + widget.spaceMargin; + _right = _screenSize.width - _showRect.right + widget.spaceMargin; } if (_popDirection == BrnPopupDirection.bottom) { // 在targetView下方 - _top = showRect.height + showRect.top + widget.offset; + _top = _showRect.height + _showRect.top + widget.offset; if ((_screenSize.height - _top) < widget.turnOverFromBottom) { _popDirection = BrnPopupDirection.top; - _bottom = _screenSize.height - showRect.top + widget.offset; + _bottom = _screenSize.height - _showRect.top + widget.offset; } } else if (_popDirection == BrnPopupDirection.top) { // 在targetView上方 - _bottom = _screenSize.height - showRect.top + widget.offset; + _bottom = _screenSize.height - _showRect.top + widget.offset; } } @override Widget build(BuildContext context) { - if (this._showRect == null) { - Navigator.pop(context); - return Container(); - } return ExcludeSemantics( excluding: true, child: WillPopScope( @@ -287,7 +284,7 @@ class _BrnPopupWindowState extends State { ? Positioned( left: widget.arrowOffset ?? _left + - (_showRect!.width - _arrowSpacing) / 2 - + (_showRect.width - _arrowSpacing) / 2 - widget.spaceMargin, top: _popDirection == BrnPopupDirection.bottom ? _top - widget.arrowHeight @@ -306,7 +303,7 @@ class _BrnPopupWindowState extends State { : Positioned( right: widget.arrowOffset ?? _right + - (_showRect!.width - _arrowSpacing) / 2 - + (_showRect.width - _arrowSpacing) / 2 - widget.spaceMargin, top: _popDirection == BrnPopupDirection.bottom ? _top - widget.arrowHeight @@ -508,6 +505,10 @@ class BrnPopupListWindow { double maxHeight = 200; double borderRadius = 4; bool hasCloseIcon = true; + assert(popKey.currentContext != null && + popKey.currentContext!.findRenderObject() != null); + if (popKey.currentContext == null || + popKey.currentContext!.findRenderObject() == null) return; Navigator.push( context, BrnPopupRoute( @@ -557,6 +558,11 @@ class BrnPopupListWindow { double offset = 0, BrnPopupListItemClick? onItemClick, VoidCallback? onDismiss}) { + assert(popKey.currentContext != null && + popKey.currentContext!.findRenderObject() != null); + if (popKey.currentContext == null || + popKey.currentContext!.findRenderObject() == null) return; + double arrowHeight = 6.0; double borderRadius = 4; double spaceMargin = 0; diff --git a/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart b/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart index 29b3fea2..f4705a1c 100644 --- a/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart +++ b/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart @@ -1,7 +1,6 @@ import 'dart:async'; -import 'dart:ui'; import 'package:bruno/src/components/tabbar/normal/brn_tab_bar.dart'; import 'package:flutter/gestures.dart'; diff --git a/lib/src/components/selectcity/brn_base_azlistview_page.dart b/lib/src/components/selectcity/brn_base_azlistview_page.dart index 953bf7bc..03d23313 100644 --- a/lib/src/components/selectcity/brn_base_azlistview_page.dart +++ b/lib/src/components/selectcity/brn_base_azlistview_page.dart @@ -48,7 +48,7 @@ abstract class BaseAZListViewPage extends StatefulWidget { } class _BaseAZListViewPageState extends State { - String suspensionTag = ""; + String? suspensionTag = ""; List _dataList = []; late StreamController streamController; diff --git a/lib/src/components/selectcity/brn_index_bar.dart b/lib/src/components/selectcity/brn_index_bar.dart index a802c71d..3db2109e 100644 --- a/lib/src/components/selectcity/brn_index_bar.dart +++ b/lib/src/components/selectcity/brn_index_bar.dart @@ -200,7 +200,7 @@ class _IndexBarState extends State<_IndexBar> { onVerticalDragDown: (DragDownDetails details) { if (_widgetTop == -1 || _widgetTopChange) { _widgetTopChange = false; - RenderBox box = context.findRenderObject() as RenderBox; + RenderBox? box = context.findRenderObject() as RenderBox; Offset topLeftPosition = box.localToGlobal(Offset.zero); _widgetTop = topLeftPosition.dy.toInt(); } diff --git a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart index 0e8422a9..b4cf7ba1 100644 --- a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart +++ b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart @@ -1,7 +1,3 @@ - - -import 'dart:ui' show Color; - import 'package:flutter/material.dart'; /// 简述:[BrnBottomTabBar]中的单个选择按钮组件 diff --git a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart index 40cb9016..9de45647 100644 --- a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart +++ b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart @@ -5,7 +5,6 @@ import 'dart:math' as math; import 'package:bruno/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// 定义一些UI常量,根据UI稿进行填写 const double _kActiveFontSize = 10.0; diff --git a/lib/src/components/tabbar/normal/brn_tab_bar.dart b/lib/src/components/tabbar/normal/brn_tab_bar.dart index 121eb38a..069ef69e 100644 --- a/lib/src/components/tabbar/normal/brn_tab_bar.dart +++ b/lib/src/components/tabbar/normal/brn_tab_bar.dart @@ -1,5 +1,3 @@ -import 'dart:ui'; - import 'package:badges/badges.dart'; import 'package:bruno/src/components/popup/brn_measure_size.dart'; import 'package:bruno/src/components/tabbar/indicator/brn_custom_width_indicator.dart'; @@ -9,7 +7,6 @@ import 'package:bruno/src/theme/brn_theme.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; /// 单个tab选中的回调 /// [state]:当前组件的State对象,[BrnTabBarState] diff --git a/lib/src/theme/configs/brn_common_config.dart b/lib/src/theme/configs/brn_common_config.dart index fa652fff..b43a02f0 100644 --- a/lib/src/theme/configs/brn_common_config.dart +++ b/lib/src/theme/configs/brn_common_config.dart @@ -1,3 +1,5 @@ +import 'dart:core'; + import 'package:bruno/src/theme/base/brn_base_config.dart'; import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; From 066fb544e7867686f8421b8d6832619996d40967 Mon Sep 17 00:00:00 2001 From: Sandy <15143015732@163.com> Date: Mon, 14 Mar 2022 18:39:21 +0800 Subject: [PATCH 12/24] BrnSingleSelectDialog add attribute messageText and messageWidget (#133) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Null safe (#13) * remove useless comments * remove useless dependencies * adapt brn_expandable_text.dart null-safe * upgrade dependencies:collection to stable * migrate constants to null safety * migrate brn_multi_click_util to null safety * migrate font util to null safety * migrate brn_text_style to null safety * migrate brn picker constants to null safety * migrate brn appBar theme to null safety * optimize bruno theme's import (#16) * ♻️ [NNBD] Part 1. Migrate configs (#28) * ♻️ [NNBD] Part 2. Migrate utils (#30) * ♻️ Migrate utils to NNBD * 🎨 Improve the color getter * :art: BrnSearchText (#36) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null (#40) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 🎨 utils-EventBus添加null-safe (#23) * 🎨 utils-EventBus添加null-safe * 🎨 修改theme配置功能及utils/brn_tools工具函数 null-safe * 🎨 EventBus添加null-safe(其他提交请忽略,输入回退) Co-authored-by: 大脸儿 * refactor brn_toast (#33) * refactor brn_toast * refactor brn_toast * 优化修复 EventBus * 优化 EventBus 单例实现 (#43) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * brn_toast time change to seconds (#45) * migrate brn_loading to null safety (#32) * migrate brn_loading to null safety * mv loading content to brnString constants * optimization brn_theme_configurator instance constructor (#47) * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * Migrate BrnStateTag、BrnTagCustom、BrnSelectTag、BrnDeleteTag to null-safe (#46) * [null-safe]: BrnStateTag、BrnTagCustom、BrnSelectTag、BrnDeleteTag 空安全适配 * perf: BrnDeleteTag null-safe * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * reset and migrated package [rating] to null-safety. (#42) * 迁移example ,优化常量命名,增加export (#51) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * 空安全报错修改 (#55) * 空安全报错修改 * 优化sketch教程为视频教程 * Migrated package [selectcity] to null-safety (#56) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * migrate card_title to null safety (#59) * migrate card_title to null-safety * [fix] brn_action_card_title: _sub widget is not null * [optimize] empty widget use SizedBox instead of Container * replace empty widget SizedBox to SizedBox.shrink * Migrated package [radio] to null-safety (#62) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * 1.Migrated package [radio] to null-safety; 2.Modified not-need-nullable param in brn_single_select_city_page.dart; * Migrated tabbar to null-safety * Migrated package [guide] to null-safety (#65) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * 1.Migrated package [radio] to null-safety; 2.Modified not-need-nullable param in brn_single_select_city_page.dart; * Migrated package [guide] to null-safety * 🚀 Use the latest Podfile for the example (#68) * Null safe calendar (#64) * migrate calendar widget to null safety * brn_calendar_view fix _currentStartSelectedDate is not null * brn_calendar_view: simplify borderRadius usage * calendar widget late _displayMode * calendar widget add two constructors with date change * Card Components Null safe adapter (#53) * feat: support fvm * feat: Card components null-safey adpater * refactor: make code simple and clean * refactor: make code simple and clean * Migrated scroll_anchor to null-safety * fix #71 (#77) * fix content_card themeData is not null (#79) * Null safe of all buttons (#20) * icon button 增加null safe * null safe for normal button * null safe for normal button * null safe for button * null safe for all button * merge * rebase * rebase * merge * optimization * GlobalKey is not null * optimization * reset popup window * showButtonPanelPopList Co-authored-by: foreturn * Migrated package [navbar][input] to null-safety (#75) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * 1.Migrated package [radio] to null-safety; 2.Modified not-need-nullable param in brn_single_select_city_page.dart; * Migrated package [guide] to null-safety * Migrated package [navbar][input] to null-safety * Optimized codes in brn_appbar.dart * Restore partial modification * fix:修复迁移tabar问题 * Migrated tabbar & scroll_anchor to null-safety (#66) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * Migrate Selection to null-safe (#54) * [null-safe]: BrnStateTag、BrnTagCustom、BrnSelectTag、BrnDeleteTag 空安全适配 * perf: BrnDeleteTag null-safe * Migrate Selection to null-safe * Migrate Selection to null-safe * perf: ItemEntity name 字段的初始化 * Migrate Selection to null-safe * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * Migrated package [dialog] to null-safety (#81) * reset and migrated package [rating] to null-safety. * Migrated package [selectcity] to null-safety * 修改ISuspensionBean抽象类相关子类的空字段问题。 * Migrated package [noticebar] to null-safety * 1.Migrated package [radio] to null-safety; 2.Modified not-need-nullable param in brn_single_select_city_page.dart; * Migrated package [guide] to null-safety * Migrated package [navbar][input] to null-safety * Optimized codes in brn_appbar.dart * Restore partial modification * Migrated package [dialog] to null-safety * Modified some params's default value or nullable type * migrate brn_horizontal_steps、brn_step_line to null safety (#89) * migrate charts to null safety (#80) * migrate DoughuntChart to null safety * migrate progress bar chart to null safety * update progress bar chart document * migrate progress chart to null safety * migrate radar chart to null safety * migrate funnel chart to null safety * migrate broken line chart to null safety * fix progress bar chart some value is required * fix progress bar chart some value is required * fix brn_line_paint _path is not null * fix brn_funnel_chart properties is not null * fix brn_radar_chart properties is not null * fix brn_line_painter not null values * fix brn_progress_bar_chart error * brn_broken_line some properties is not null value * replace empty Container to SizedBox.shrink * update progress_bar_chart null safety value by hand * update broken_line null safety values by hand * update funnel_chart null safety value by hand * make LineCanvasModel immutable * migrate actionsheet into null-safe (#73) * migrate actionsheet into null-safe * sheet: code review Co-authored-by: yuanjunliang * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate form to null safety (#86) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * migrate popup to null safety (#69) * migrate popup to null safety * fix MeasureSize null safe problems * fix popup migrate to null-safety review problems * migrate gallery to null safety (#90) * migrate gallery to null safety * change the type error * remove @ * change String? to String * fix:修复picker空安全迁移问题 * migrate appraise dir to null safety (#84) * migrate appraise dir to null safety * fix appraise migrate to null-safety review problems * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate picker to null safety (#91) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * fix:修复picker空安全迁移问题 * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate example to null safty * fix:修复部分example warning * fix:修复demo报错问题 * fix:追加未跟踪修复 * fix:优化部分接口可空参数为非空 * Perf:Button Null safe (#93) * perf: Migrate Button Null-Safe * perf:优化 HorizontalStep Null-Safe * fix: null exception when parse json to entity * perf Button Null-Safe, fix NullException perf more layer icon color when item selected * migrate example to null safety (#94) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * fix:修复picker空安全迁移问题 * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate example to null safty * fix:修复部分example warning * fix:修复demo报错问题 * fix:追加未跟踪修复 * fix:优化部分接口可空参数为非空 Co-authored-by: violinday * fix:修复tabar showmore overflow 问题 #98 以及 tabbar 标签颜色默认设置倒置问题 * Fix #98 问题及优化部分代码 (#99) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * fix:修复picker空安全迁移问题 * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate example to null safty * fix:修复部分example warning * fix:修复demo报错问题 * fix:追加未跟踪修复 * fix:优化部分接口可空参数为非空 * fix:修复tabar showmore overflow 问题 #98 以及 tabbar 标签颜色默认设置倒置问题 Co-authored-by: violinday * refactor:优化 BrnInputItemType 常量命名 * refactor:优化枚举值命名 * fix:修改docs目录下form相关常量命名及所有枚举命名 * 优化 BrnInputItemType 常量命名 (#100) * Theme: 优化单例实现,初步优化 BrnAllThemeConfig 属性获取不为 null * refactor:优化theme,暴露非null引用 * theme:去除无用信息及优化部分代码 * theme:增加属性类型 * 优化修复 EventBus * 迁移example ,优化常量命名,增加export * migrate brn_empty_status.dart * 删除 BrnThemeImg * fix:tagConfig merge方法增加判空处理 * fix:revert tagConfig * fix:BrnAbnormalStateWidget空处理 * Migrated tabbar to null-safety * Migrated scroll_anchor to null-safety * fix:修复迁移tabar问题 * migrate form to null safety * fix:修复tabbar报错及selection警告信息 * fix:修复迁移问题 * fix:优化迁移部分问题key和style非空问题 * migrate picker to null safety * fix:修复picker空安全迁移问题 * fix:修复list没指定泛型及if判断错误问题 * fix:migrate dashed line to null safty * migrate example to null safty * fix:修复部分example warning * fix:修复demo报错问题 * fix:追加未跟踪修复 * fix:优化部分接口可空参数为非空 * fix:修复tabar showmore overflow 问题 #98 以及 tabbar 标签颜色默认设置倒置问题 * refactor:优化 BrnInputItemType 常量命名 * refactor:优化枚举值命名 * fix:修改docs目录下form相关常量命名及所有枚举命名 Co-authored-by: violinday * refactor: 更新 changelog * refactor:BrnBubbleText 增加属性 bgColor、textStyle,修复demo actionSheet、gallery、selection、picker错误 * fix:修复changelog 错误,brn_gallery_summary_page.dart 中标题空处理 * fix:修复部分问题 * fix:修复部分问题 * migrate docs to null-safety * feat:changelog 增加 BrnHorizontalStepsManager 改动 * fix:优化changelog * BrnSingleSelectDialog add attribute messageText and messageWidget * update BrnSingleSelectDialog.md * update BrnSingleSelectDialog.md attribute desc Co-authored-by: laiiihz Co-authored-by: LAIIIHZ <35956195+laiiihz@users.noreply.github.com> Co-authored-by: Alex Li Co-authored-by: kalifun <37646342+kalifun@users.noreply.github.com> Co-authored-by: kkkman22 <2594387207@qq.com> Co-authored-by: 大脸儿 Co-authored-by: leftcoding <137387869@qq.com> Co-authored-by: violinday Co-authored-by: jojinshallar Co-authored-by: HappyImp Co-authored-by: Kenneth Co-authored-by: donywan Co-authored-by: foreturn Co-authored-by: Junl <17602153700@163.com> Co-authored-by: yuanjunliang Co-authored-by: Nayuta403 <40540394+Nayuta403@users.noreply.github.com> --- .../BrnSingleSelectDialog.md | 101 ++++++++++-------- .../img/BrnSingleSelectDialog.png | Bin 96728 -> 152197 bytes .../components/dialog/dialog_entry_page.dart | 1 + .../dialog/brn_multi_select_dialog.dart | 8 +- .../components/dialog/brn_single_select.dart | 40 +++++++ 5 files changed, 98 insertions(+), 52 deletions(-) diff --git a/docs/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md b/docs/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md index b6d46bd4..f5212325 100644 --- a/docs/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md +++ b/docs/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md @@ -27,6 +27,8 @@ group: const BrnSingleSelectDialog( {this.isClose: true, this.title: "", + this.messageText, + this.messageWidget, required this.conditions, this.submitText: "提交", this.submitBgColor, @@ -44,6 +46,8 @@ const BrnSingleSelectDialog( | ------------------------ | ----------------------------------- | --------------------------------------------------------- | ------------ | ---------- | | isClose | bool | 用于控制弹窗是否相应电机外部关闭,true 关闭,false 不关闭 | 否 | true | | title | String | 弹窗标题名称 | 否 | "" | +| messageText | String? | 描述文案,优先级较 messageWidget 低,优先使用 messageWidget | 否 | | +| messageWidget | Widget? | 描述 Widget | 否 | | | conditions | List | 备选项数组 | 否 | | | checkedItem | String | 选中的选项名称 | 否 | | | submitText | String | 确定/提交 按钮文案 | 否 | | @@ -60,6 +64,7 @@ const BrnSingleSelectDialog( + ```dart String hintText = "感兴趣待跟进"; int selectedIndex = 0; @@ -75,51 +80,53 @@ String hintText = "感兴趣待跟进"; "vzxczxc" ]; showDialog( - context: context, - builder: (_) => StatefulBuilder( - builder: (context, state) { - return BrnSingleSelectDialog( - isClose: true, - title: '请选择无效客源原因', - conditions: conditions, - checkedItem: conditions[selectedIndex], - submitText: '提交', - isCustomFollowScroll: true, - customWidget: TextField( - //光标颜色 - maxLines: 2, - cursorColor: Color(0xFF0984F9), - //光标圆角弧度 - cursorRadius: Radius.circular(2.0), - style: TextStyle(fontSize: 14, color: Color(0xFF222222)), - maxLengthEnforcement: MaxLengthEnforcement.enforced, - onChanged: (value) {}, - decoration: InputDecoration( - contentPadding: EdgeInsets.all(8.0), - hintText: hintText, - hintStyle: TextStyle(fontSize: 14, color: Color(0xFFCCCCCC)), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(2.0), - borderSide: BorderSide( - width: 0.5, - color: Color(0xFFCCCCCC), - )), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(2.0), - borderSide: BorderSide( - width: 0.5, - color: Color(0xFFCCCCCC), - )), - ), - ), - onItemClick: (BuildContext context, int index) { - hintText = conditions[index]; - selectedIndex = index; - state(() {}); - }, - onSubmitClick: (data) { - BrnToast.show(data, context); - }); - }, - )); + context: context, + builder: (_) => StatefulBuilder( + builder: (context, state) { + return BrnSingleSelectDialog( + isClose: true, + title: '请选择无效客源原因', + messageText: '请您评价该条线索请您评价该条线索请您评价该条线索请您评价该条线索请您评价该条线索', + conditions: conditions, + checkedItem: conditions[selectedIndex], + submitText: '提交', + isCustomFollowScroll: true, + customWidget: TextField( + //光标颜色 + maxLines: 2, + cursorColor: Color(0xFF0984F9), + //光标圆角弧度 + cursorRadius: Radius.circular(2.0), + style: TextStyle(fontSize: 14, color: Color(0xFF222222)), + maxLengthEnforcement: MaxLengthEnforcement.enforced, + onChanged: (value) {}, + decoration: InputDecoration( + contentPadding: EdgeInsets.all(8.0), + hintText: hintText, + hintStyle: + TextStyle(fontSize: 14, color: Color(0xFFCCCCCC)), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(2.0), + borderSide: BorderSide( + width: 0.5, + color: Color(0xFFCCCCCC), + )), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(2.0), + borderSide: BorderSide( + width: 0.5, + color: Color(0xFFCCCCCC), + )), + ), + ), + onItemClick: (BuildContext context, int index) { + hintText = conditions[index]; + selectedIndex = index; + state(() {}); + }, + onSubmitClick: (data) { + BrnToast.show(data!, context); + }); + }, + )); ``` diff --git a/docs/components/dialog/BrnSingleSelectDialog/img/BrnSingleSelectDialog.png b/docs/components/dialog/BrnSingleSelectDialog/img/BrnSingleSelectDialog.png index a727361c66f9a33feb637ffdc6ef3c2dec51ff47..2fa2c4aed95488d5b37124053113d1cfdc5c1964 100644 GIT binary patch literal 152197 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

p(a5n?^L8LFU|E#h+BccRG-gSrDSH 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�n1e>19iZyE_C|7%k5o&bSB!0IT<4LQ?d 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⪼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

  • go~_6Bm#95RRje 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�W7FkCY*Rp}+ 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
    ;qu&?g5hD?*?M5%G+$@6*`=V>3^R9AH7rj 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 { if (!BrunoTools.isEmpty(widget.messageText)) { return Padding( padding: EdgeInsets.only(bottom: 8, left: 20, right: 20), - child: Center( - child: Text( - widget.messageText!, - style: cContentTextStyle, - ), + child: Text( + widget.messageText!, + style: cContentTextStyle, ), ); } diff --git a/lib/src/components/dialog/brn_single_select.dart b/lib/src/components/dialog/brn_single_select.dart index 96d5726b..1f3554e5 100644 --- a/lib/src/components/dialog/brn_single_select.dart +++ b/lib/src/components/dialog/brn_single_select.dart @@ -6,6 +6,8 @@ import 'package:bruno/src/theme/configs/brn_dialog_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; +import 'brn_dialog.dart'; + typedef BrnSingleSelectOnSubmitCallback = Function(String? data); typedef BrnSingleSelectOnItemClickCallback = void Function( BuildContext dialogContext, int index); @@ -18,6 +20,12 @@ class BrnSingleSelectDialog extends Dialog { /// 弹窗标题 final String title; + /// 描述文案,优先级较 messageWidget 低,优先使用 messageWidget + final String? messageText; + + /// 描述widget + final Widget? messageWidget; + /// 时间区间最大值 final List conditions; @@ -48,6 +56,8 @@ class BrnSingleSelectDialog extends Dialog { const BrnSingleSelectDialog( {this.isClose: true, this.title: "", + this.messageText, + this.messageWidget, required this.conditions, this.submitText: "提交", this.submitBgColor, @@ -63,6 +73,8 @@ class BrnSingleSelectDialog extends Dialog { return BrnSingleSelectDialogWidget( isClose: isClose, title: title, + messageText: messageText, + messageWidget: messageWidget, conditions: conditions, submitText: submitText, onSubmitClick: onSubmitClick, @@ -79,6 +91,8 @@ class BrnSingleSelectDialog extends Dialog { class BrnSingleSelectDialogWidget extends StatefulWidget { final bool isClose; final String title; + final String? messageText; + final Widget? messageWidget; final List? conditions; final String submitText; final BrnSingleSelectOnSubmitCallback? onSubmitClick; @@ -97,6 +111,8 @@ class BrnSingleSelectDialogWidget extends StatefulWidget { BrnSingleSelectDialogWidget( {this.isClose = true, this.title = "", + this.messageText, + this.messageWidget, this.conditions, this.submitText = "", this.submitBgColor, @@ -151,6 +167,7 @@ class BrnSingleSelectDialogWidgetState widget.themeData!), ), ), + _generateContentWidget(), Container( constraints: BoxConstraints(maxHeight: 300), child: widget.isCustomFollowScroll @@ -250,6 +267,29 @@ class BrnSingleSelectDialogWidgetState ))); } + /// 内容widget 以 messageWidget 为准, + /// 若无则以 messageText 生成widget 填充, + /// 都没设置则为空 Container + Widget _generateContentWidget() { + if (widget.messageWidget != null) + return Padding( + padding: EdgeInsets.only(bottom: 8, left: 20, right: 20), + child: widget.messageWidget, + ); + + if (!BrunoTools.isEmpty(widget.messageText)) { + return Padding( + padding: EdgeInsets.only(bottom: 8, left: 20, right: 20), + child: Text( + widget.messageText!, + style: cContentTextStyle, + ), + ); + } + return Container(); + } + + Widget _buildItem(BuildContext context, int index) { if (widget.conditions == null) { return Container(); From ed3e898df5e361bb34e3959e6995998505cb970b Mon Sep 17 00:00:00 2001 From: violinday Date: Mon, 28 Mar 2022 20:21:50 +0800 Subject: [PATCH 13/24] Optimize the component logic and fix the problem that the user's `Navigator.push()` operation is invalid (#134) * perf: Optimize `BrnPopupListWindow` `onItemClick` logic to aviod `Navigator.push()` failure by user. * perf: Optimize `BrnPopupListWindow` `onItemClick` logic to aviod `Navigator.push()` failure by user. * perf: Optimize `BrnPopupListWindow` `onItemClick` logic to aviod `Navigator.push()` failure by user. * [feature][2.2.x]: Add a Web Demo entrance; --- .../navbar/nav_bar_example_page.dart | 19 ++- example/web/assets/FontManifest.json | 10 ++ .../assets/fonts/MaterialIcons-Regular.otf | Bin 0 -> 1299300 bytes example/web/favicon.png | Bin 0 -> 436 bytes example/web/icons/icon-192.png | Bin 0 -> 5095 bytes example/web/icons/icon-512.png | Bin 0 -> 25214 bytes example/web/index.html | 10 ++ example/web/main.dart | 7 + example/web/manifest.json | 23 +++ .../button/collection/brn_button_panel.dart | 17 ++- .../components/popup/brn_popup_window.dart | 137 +++++++++--------- 11 files changed, 148 insertions(+), 75 deletions(-) create mode 100644 example/web/assets/FontManifest.json create mode 100644 example/web/assets/fonts/MaterialIcons-Regular.otf create mode 100644 example/web/favicon.png create mode 100644 example/web/icons/icon-192.png create mode 100644 example/web/icons/icon-512.png create mode 100644 example/web/index.html create mode 100644 example/web/main.dart create mode 100644 example/web/manifest.json diff --git a/example/lib/sample/components/navbar/nav_bar_example_page.dart b/example/lib/sample/components/navbar/nav_bar_example_page.dart index 57a696d8..a1f950fd 100644 --- a/example/lib/sample/components/navbar/nav_bar_example_page.dart +++ b/example/lib/sample/components/navbar/nav_bar_example_page.dart @@ -245,7 +245,11 @@ class _NavBarPageState extends State with TickerProviderStateMixin { key: actionKey, iconPressed: () { BrnPopupListWindow.showPopListWindow(context, actionKey, - offset: 10, data: ["aaaa", "bbbbb"]); + offset: 10, data: ["aaaa", "bbbbb"], onItemClick: (index, item){ + BrnDialogManager.showConfirmDialog(context, cancel: 'cancel', confirm: 'confirm', message: 'message'); + }, onDismiss: (){ + BrnToast.show('onDismiss', context); + }); }, ), ); @@ -510,6 +514,12 @@ class _NavBarPageState extends State with TickerProviderStateMixin { context, keyLeading, data: ["aaaa", "bbbbb"], + onItemClick: (index, data) { + BrnDialogManager.showConfirmDialog(context, cancel: 'cancel', confirm: 'confirm', message: 'message'); + }, + onDismiss: (){ + BrnToast.show('onDismiss', context); + }, ); }, //输入框 文本内容变化的监听 @@ -568,7 +578,12 @@ class _NavBarPageState extends State with TickerProviderStateMixin { leadClickCallback: (controller, update) { //controller 是文本控制器,通过controller 可以拿到输入的内容 以及 对输入的内容更改 //update 是setState方法的方法命,update() 就可以刷新输入框 - BrnPopupListWindow.showPopListWindow(context, keyLeading, data: ["aaaa", "bbbbb"], offset: 10); + BrnPopupListWindow.showPopListWindow( + context, + keyLeading, + data: ["aaaa", "bbbbb"], + offset: 10 + ); }, //输入框 文本内容变化的监听 searchBarInputChangeCallback: (input) { diff --git a/example/web/assets/FontManifest.json b/example/web/assets/FontManifest.json new file mode 100644 index 00000000..ac26bd3f --- /dev/null +++ b/example/web/assets/FontManifest.json @@ -0,0 +1,10 @@ +[ + { + "family": "MaterialIcons", + "fonts": [ + { + "asset": "fonts/MaterialIcons-Regular.otf" + } + ] + } +] \ No newline at end of file diff --git a/example/web/assets/fonts/MaterialIcons-Regular.otf b/example/web/assets/fonts/MaterialIcons-Regular.otf new file mode 100644 index 0000000000000000000000000000000000000000..3246ad559eeae0370195978eaed83f1053ee13fd GIT binary patch literal 1299300 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ξEU|ZJ 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 H4-)u)iLm?K literal 0 HcmV?d00001 diff --git a/example/web/favicon.png b/example/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..00158cec0a15c0c7558eacd786178a6cf30566a5 GIT binary patch literal 436 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 JPDHLkV1hUzy1)Pc literal 0 HcmV?d00001 diff --git a/example/web/icons/icon-512.png b/example/web/icons/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..624294c2039f9fb0cc9ab925d7120070143a019d GIT binary patch literal 25214 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 z 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 VitC*hbu7T=%4KWVI}?|<{{!%+e+>Wt literal 0 HcmV?d00001 diff --git a/example/web/index.html b/example/web/index.html new file mode 100644 index 00000000..f32bf8da --- /dev/null +++ b/example/web/index.html @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/example/web/main.dart b/example/web/main.dart new file mode 100644 index 00000000..002f07d0 --- /dev/null +++ b/example/web/main.dart @@ -0,0 +1,7 @@ + +// TODO: change `my_app` to refer to your app package name. +import 'package:example/main.dart' as app; + +main() async { + app.main(); +} \ No newline at end of file diff --git a/example/web/manifest.json b/example/web/manifest.json new file mode 100644 index 00000000..e10777ee --- /dev/null +++ b/example/web/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "Bruno Demo", + "short_name": "Bruno", + "start_url": ".", + "display": "Bruno", + "background_color": "#FFFFFFFF", + "theme_color": "#0175C2", + "description": "Bruno 是基于一整套设计体系的 Flutter 组件库。An enterprise-class package of Flutter components for mobile applications.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/lib/src/components/button/collection/brn_button_panel.dart b/lib/src/components/button/collection/brn_button_panel.dart index 5e26e4e2..3650f2d0 100644 --- a/lib/src/components/button/collection/brn_button_panel.dart +++ b/lib/src/components/button/collection/brn_button_panel.dart @@ -202,17 +202,18 @@ class _BrnButtonPanelState extends State { fontSize: 16)); }, popDirection: widget.popDirection, - onItemClick: (index, item) { + onItemClickInterceptor: (index, item) { // 按钮不可用的时候,点击无响应; + if (_secondaryButtonList[index + 2].isEnable) { + return false; + } else { + return true; + } + }, + onItemClick: (index, item) { if (widget.secondaryButtonOnTap != null) { - if (_secondaryButtonList[index + 2].isEnable) { - widget.secondaryButtonOnTap!(index + 2); - return false; - } else { - return true; - } + widget.secondaryButtonOnTap!(index + 2); } - return false; }); }, ); diff --git a/lib/src/components/popup/brn_popup_window.dart b/lib/src/components/popup/brn_popup_window.dart index 3ae42acb..cd0d94bc 100644 --- a/lib/src/components/popup/brn_popup_window.dart +++ b/lib/src/components/popup/brn_popup_window.dart @@ -66,9 +66,6 @@ class BrnPopupWindow extends StatefulWidget { /// 箭头图标水平方向的绝对偏移量,为 null 时则自动计算 final double? arrowOffset; - /// popUpWindow 消失回调,此回调会在 pop 之后执行 - final VoidCallback? onDismiss; - /// popWindow 距离底部的距离小于此值的时候, /// 自动将 popWindow 在 targetView 上面弹出 final double turnOverFromBottom; @@ -91,7 +88,6 @@ class BrnPopupWindow extends StatefulWidget { this.canWrap = false, this.spaceMargin = 20, this.arrowOffset, - this.onDismiss, this.turnOverFromBottom = 50.0}) : super(key: key); @@ -157,7 +153,6 @@ class BrnPopupWindow extends StatefulWidget { canWrap: canWrap, spaceMargin: spaceMargin, arrowOffset: arrowOffset, - onDismiss: dismissCallback, turnOverFromBottom: turnOverFromBottom, ))); } @@ -254,9 +249,6 @@ class _BrnPopupWindowState extends State { behavior: HitTestBehavior.translucent, onTap: () { Navigator.pop(context); - if (widget.onDismiss != null) { - widget.onDismiss!(); - } }, child: Material( color: Colors.transparent, @@ -270,9 +262,6 @@ class _BrnPopupWindowState extends State { ), ), onWillPop: () { - if (widget.onDismiss != null) { - widget.onDismiss!(); - } return Future.value(true); }), ); @@ -469,7 +458,13 @@ class BrnPopupRoute extends PopupRoute { /// popup 中每个 Item 被点击时的回调, /// [index] Item 的索引 /// [item] Item 内容 -typedef BrnPopupListItemClick = Function(int index, String item); +typedef BrnPopupListItemClick = void Function(int index, String item); + +/// popup 中每个 Item 被点击时,是否拦截点击事件 +/// [index] Item 的索引 +/// [item] Item 内容 +/// 返回 true 则拦截点击事件,不再回调 [onItemClick]。 +typedef BrnPopupListItemClickInterceptor = bool Function(int index, String item); /// popup 用于构造自定义的 Item /// [index] Item 的索引 @@ -484,17 +479,20 @@ class BrnPopupListWindow { /// [popDirection] 箭头的方向 /// [itemBuilder] 自定义 item 构造方法 /// [onItemClick] item 点击回调 - static void showButtonPanelPopList(context, GlobalKey popKey, - {List? data, - BrnPopupDirection popDirection = BrnPopupDirection.bottom, - BrnPopupListItemBuilder? itemBuilder, - BrnPopupListItemClick? onItemClick}) { + /// [onItemClickInterceptor] item 点击拦截回调 + /// [onDismiss] popUpWindow消失回调 + static void showButtonPanelPopList( + context, + GlobalKey popKey, { + List? data, + BrnPopupDirection popDirection = BrnPopupDirection.bottom, + BrnPopupListItemBuilder? itemBuilder, + BrnPopupListItemClick? onItemClick, + BrnPopupListItemClickInterceptor? onItemClickInterceptor, + VoidCallback? onDismiss, + }) { TextStyle textStyle = TextStyle( - color: BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .colorTextBase, - fontSize: 16); + color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, fontSize: 16); double arrowHeight = 6.0; Color borderColor = Color(0xffCCCCCC); Color backgroundColor = Colors.white; @@ -505,10 +503,8 @@ class BrnPopupListWindow { double maxHeight = 200; double borderRadius = 4; bool hasCloseIcon = true; - assert(popKey.currentContext != null && - popKey.currentContext!.findRenderObject() != null); - if (popKey.currentContext == null || - popKey.currentContext!.findRenderObject() == null) return; + assert(popKey.currentContext != null && popKey.currentContext!.findRenderObject() != null); + if (popKey.currentContext == null || popKey.currentContext!.findRenderObject() == null) return; Navigator.push( context, BrnPopupRoute( @@ -522,18 +518,23 @@ class BrnPopupListWindow { offset: offset, widget: BrunoTools.isEmpty(data) ? Container( - constraints: - BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), + constraints: BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), ) : Container( - constraints: - BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), + constraints: BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), child: SingleChildScrollView( child: Container( padding: EdgeInsets.only(top: 6, bottom: 6), child: Column( - children: _getItems(context, minWidth, maxWidth, - itemBuilder, textStyle, data!, onItemClick, null), + children: + _getItems(context, minWidth, maxWidth, itemBuilder, textStyle, data!, + (index, item) { + if (onItemClickInterceptor != null) { + bool isIntercept = onItemClickInterceptor(index, item); + if (isIntercept) return; + } + Navigator.pop(context, {'index': index, 'item': item}); + }), ), ), ), @@ -542,7 +543,14 @@ class BrnPopupListWindow { borderRadius: borderRadius, borderColor: borderColor, spaceMargin: spaceMargin, - ))); + ))).then((result) { + if (onItemClick != null && result != null) { + onItemClick(result['index'], result['item']); + } + if (onDismiss != null) { + onDismiss(); + } + }); } /// 显示Popup List Window @@ -551,17 +559,17 @@ class BrnPopupListWindow { /// [popDirection] 箭头的方向 /// [offset] 距离targetView偏移量 /// [onItemClick] item 点击回调 + /// [onItemClickInterceptor] item 点击拦截回调 /// [onDismiss] popUpWindow消失回调 static void showPopListWindow(context, GlobalKey popKey, {List? data, BrnPopupDirection popDirection = BrnPopupDirection.bottom, double offset = 0, BrnPopupListItemClick? onItemClick, + BrnPopupListItemClickInterceptor? onItemClickInterceptor, VoidCallback? onDismiss}) { - assert(popKey.currentContext != null && - popKey.currentContext!.findRenderObject() != null); - if (popKey.currentContext == null || - popKey.currentContext!.findRenderObject() == null) return; + assert(popKey.currentContext != null && popKey.currentContext!.findRenderObject() != null); + if (popKey.currentContext == null || popKey.currentContext!.findRenderObject() == null) return; double arrowHeight = 6.0; double borderRadius = 4; @@ -570,21 +578,16 @@ class BrnPopupListWindow { double maxWidth = 150; double maxHeight = 200; double? arrowOffset; - Color borderColor = - BrnThemeConfigurator.instance.getConfig().commonConfig.dividerColorBase; + Color borderColor = BrnThemeConfigurator.instance.getConfig().commonConfig.dividerColorBase; Color backgroundColor = Colors.white; TextStyle textStyle = TextStyle( - color: BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .colorTextBase, - fontSize: 14); + color: BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, fontSize: 14); bool hasCloseIcon = true; Navigator.push( - context, - BrnPopupRoute( - child: BrnPopupWindow( + context, + BrnPopupRoute( + child: BrnPopupWindow( context, arrowHeight: arrowHeight, popKey: popKey, @@ -595,18 +598,22 @@ class BrnPopupListWindow { offset: offset, widget: BrunoTools.isEmpty(data) ? Container( - constraints: - BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), + constraints: BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), ) : Container( - constraints: - BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), + constraints: BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight), child: SingleChildScrollView( child: Container( padding: EdgeInsets.only(top: 6, bottom: 6), child: Column( - children: _getItems(context, minWidth, maxWidth, null, - textStyle, data!, onItemClick, onDismiss), + children: _getItems(context, minWidth, maxWidth, null, textStyle, data!, + (index, item) { + if (onItemClickInterceptor != null) { + bool isIntercept = onItemClickInterceptor(index, item); + if (isIntercept) return; + } + Navigator.pop(context, {'index': index, 'item': item}); + }), ), ), ), @@ -615,8 +622,16 @@ class BrnPopupListWindow { borderRadius: borderRadius, borderColor: borderColor, spaceMargin: spaceMargin, - onDismiss: onDismiss, - ))); + ), + ), + ).then((result) { + if (onItemClick != null && result != null) { + onItemClick(result['index'], result['item']); + } + if (onDismiss != null) { + onDismiss(); + } + }); } static List _getItems( @@ -626,8 +641,7 @@ class BrnPopupListWindow { BrnPopupListItemBuilder? itemBuilder, TextStyle textStyle, List data, - BrnPopupListItemClick? onItemClick, - VoidCallback? onDismiss) { + BrnPopupListItemClick onItemClick) { double textMaxWidth = _getMaxWidth(textStyle, data); if (textMaxWidth + 52 < minWidth) { textMaxWidth = minWidth; @@ -639,14 +653,7 @@ class BrnPopupListWindow { return data.map((f) { return GestureDetector( onTap: () { - if (onItemClick != null) { - dynamic isIntercept = onItemClick(data.indexOf(f), f); - if ((isIntercept is bool) && isIntercept) return; - } - Navigator.pop(context); - if (onDismiss != null) { - onDismiss(); - } + onItemClick(data.indexOf(f), f); }, child: Container( width: textMaxWidth, From 049a0134a464e359b7ebd708ef4351c98a8a1b85 Mon Sep 17 00:00:00 2001 From: Sandy <15143015732@163.com> Date: Tue, 29 Mar 2022 20:07:44 +0800 Subject: [PATCH 14/24] Fix the BrnCalendarView status display error (#147) * fix calender show error * fix _currentEndSelectedDate is null error --- .../calendar/brn_calendar_view.dart | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/src/components/calendar/brn_calendar_view.dart b/lib/src/components/calendar/brn_calendar_view.dart index 9fd8beff..119bdb62 100644 --- a/lib/src/components/calendar/brn_calendar_view.dart +++ b/lib/src/components/calendar/brn_calendar_view.dart @@ -613,18 +613,18 @@ class _CustomCalendarViewState extends State { if (date.isAfter(_currentEndSelectedDate!)) { _currentEndSelectedDate = date; } - setState(() { - try { - if (widget.rangeDateChange != null) { - widget.rangeDateChange!(DateTimeRange( - start: _currentStartSelectedDate!, - end: _currentEndSelectedDate!, - )); - } - } catch (_) {} - }); } + setState(() { + if (_currentStartSelectedDate != null && + _currentEndSelectedDate != null && + widget.rangeDateChange != null) { + widget.rangeDateChange!(DateTimeRange( + start: _currentStartSelectedDate!, + end: _currentEndSelectedDate!, + )); + } + }); } String _getChinaWeekName(int weekOfDay) { From a7073818292394ca198d5ad97a01b9cf6fd5240a Mon Sep 17 00:00:00 2001 From: violinday Date: Wed, 30 Mar 2022 10:57:24 +0800 Subject: [PATCH 15/24] =?UTF-8?q?fix=20BrnBottomTabBar=20=E5=BA=95?= =?UTF-8?q?=E9=83=A8=E6=96=87=E5=AD=97=E5=9C=A8=E7=89=B9=E5=AE=9A=E6=83=85?= =?UTF-8?q?=E5=86=B5=E4=B8=8B=E6=97=A0=E6=B3=95=E5=B1=95=E7=A4=BA=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=E3=80=82=20(#145)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [feature][2.2.x]: Add a Web Demo entrance; * [fix][2.2.x]: fix BrnBottomTabBar 底部文字在特定情况下无法展示的问题。 --- .../BrnBottomTabBar/BrnBottomTabBar.md | 4 + .../bottom_tabbar/bottom_tabbar_example.dart | 137 +++-- .../bottom/brn_bottom_tab_bar_item.dart | 14 +- .../bottom/brn_bottom_tab_bar_main.dart | 480 +++++++++--------- 4 files changed, 339 insertions(+), 296 deletions(-) diff --git a/docs/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md b/docs/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md index 3033aeeb..7225d841 100644 --- a/docs/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md +++ b/docs/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md @@ -81,11 +81,15 @@ const BrnBottomTabBarItem({ | icon | Widget | 未选中时的icon | 是 | 无 | | activeIcon | Widget | 选中时的icon | 否 | 无 | | title | Widget? | Tab标题名调 | 否 | 无 | +| selectedTextStyle | TextStyle? | tab 选中文本样式 | 否 | 否 | +| unSelectedTextStyle | TextStyle? | tab 未选中文本样式 | 否 | 否 | | backgroundColor | Color? | 背景色 | 否 | 无 | | badge | Widget? | 未读信息 | 否 | 无 | | badgeNo | String? | 未读信息个数 | 否 | 无 | | maxBadgeNo | int | 未读消息最大个数 | 否 | 99 | + + ## 四、代码演示 ### 效果1 diff --git a/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart b/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart index d916d9a3..764c314d 100644 --- a/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart +++ b/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart @@ -1,5 +1,3 @@ - - import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -25,6 +23,9 @@ class BottomTabbarExampleState extends State /// test3 int _selectedIndexTest3 = 0; + /// test4 + int _selectedIndexTest4 = 0; + /// 未读消息数量 String badgeNo1 = '100'; @@ -76,6 +77,14 @@ class BottomTabbarExampleState extends State }); } + /// test4 + void _onItemSelectedTest4(int index) { + setState(() { + /// 置为当前选中item的索引值 + _selectedIndexTest4 = index; + }); + } + @override Widget build(BuildContext context) { return MaterialApp( @@ -98,32 +107,47 @@ class BottomTabbarExampleState extends State items: [ // 定义每个BottomTabBarItem,子属性请看源码 BrnBottomTabBarItem( - icon: - Image(image: AssetImage("assets/icons/navbar_house.png")), - activeIcon: - Image(image: AssetImage("assets/icons/navbar_house.png")), + icon: Image(image: AssetImage("assets/icons/navbar_house.png")), + activeIcon: Image( + image: AssetImage("assets/icons/navbar_house.png"), + color: Colors.blue, + ), title: Text(titles[0])), BrnBottomTabBarItem( - icon: - Image(image: AssetImage("assets/icons/navbar_house.png")), + icon: Image(image: AssetImage("assets/icons/navbar_house.png")), + activeIcon: Image( + image: AssetImage("assets/icons/navbar_house.png"), + color: Colors.blue, + ), title: Text(titles[1])), BrnBottomTabBarItem( - icon: - Image(image: AssetImage("assets/icons/navbar_house.png")), + icon: Image(image: AssetImage("assets/icons/navbar_house.png")), + activeIcon: Image( + image: AssetImage("assets/icons/navbar_house.png"), + color: Colors.blue, + ), title: Text(titles[2])), BrnBottomTabBarItem( - icon: - Image(image: AssetImage("assets/icons/navbar_house.png")), - activeIcon: - Image(image: AssetImage("assets/icons/navbar_house.png")), + icon: Image(image: AssetImage("assets/icons/navbar_house.png")), + activeIcon: Image( + image: AssetImage("assets/icons/navbar_house.png"), + color: Colors.blue, + ), title: Text(titles[3])), BrnBottomTabBarItem( - icon: - Image(image: AssetImage("assets/icons/navbar_house.png")), - title: Text(titles[4])), + icon: Image(image: AssetImage("assets/icons/navbar_house.png")), + activeIcon: Image( + image: AssetImage("assets/icons/navbar_house.png"), + color: Colors.blue, + ), + title: Text(titles[4]), + ), BrnBottomTabBarItem( - icon: - Image(image: AssetImage("assets/icons/navbar_house.png")), + icon: Image(image: AssetImage("assets/icons/navbar_house.png")), + activeIcon: Image( + image: AssetImage("assets/icons/navbar_house.png"), + color: Colors.blue, + ), title: Text(titles[5])), ], ), @@ -138,66 +162,69 @@ class BottomTabbarExampleState extends State currentIndex: _selectedIndexTest1, onTap: _onItemSelectedTest1, items: [ - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text(titles[0])), + BrnBottomTabBarItem(icon: Icon(icons[0]), title: Text(titles[0])), ], ), Padding( padding: const EdgeInsets.all(12.0), - child: Text('极限条件测试2,有8个item'), + child: Text('有 2 个 item'), ), BrnBottomTabBar( fixedColor: Colors.blue, currentIndex: _selectedIndexTest2, onTap: _onItemSelectedTest2, items: [ - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text(titles[0])), - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text(titles[0])), - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text(titles[0])), - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text(titles[0])), - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text(titles[0])), - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text(titles[0])), - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text(titles[0])), - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text(titles[0])), + BrnBottomTabBarItem(icon: Icon(icons[0]), title: Text(titles[0])), + BrnBottomTabBarItem(icon: Icon(icons[0]), title: Text(titles[0])), ], ), Padding( padding: const EdgeInsets.all(12.0), - child: Text('极限条件测试3,text比较长的情况'), + child: Text('极限条件测试2,有8个item'), ), BrnBottomTabBar( fixedColor: Colors.blue, currentIndex: _selectedIndexTest3, onTap: _onItemSelectedTest3, + items: _getTabBarItems(count: 8), + ), + Padding( + padding: const EdgeInsets.all(12.0), + child: Text('极限条件测试3,text比较长的情况'), + ), + BrnBottomTabBar( + fixedColor: Colors.blue, + currentIndex: _selectedIndexTest4, + onTap: _onItemSelectedTest4, items: [ - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text("1111111111")), - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text("2222222222")), - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text("3333333333")), - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text("4444444444")), - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text("5555555555")), - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text("6666666666")), - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text("7777777777")), - BrnBottomTabBarItem( - icon: Icon(icons[0]), title: Text("8888888888")), + BrnBottomTabBarItem(icon: Icon(icons[0]), title: Text("1111111111")), + BrnBottomTabBarItem(icon: Icon(icons[0]), title: Text("2222222222")), + BrnBottomTabBarItem(icon: Icon(icons[0]), title: Text("3333333333")), + BrnBottomTabBarItem(icon: Icon(icons[0]), title: Text("4444444444")), + BrnBottomTabBarItem(icon: Icon(icons[0]), title: Text("5555555555")), + BrnBottomTabBarItem(icon: Icon(icons[0]), title: Text("6666666666")), + BrnBottomTabBarItem(icon: Icon(icons[0]), title: Text("7777777777")), + BrnBottomTabBarItem(icon: Icon(icons[0]), title: Text("8888888888")), ], ), ], )), ); } + + List _getTabBarItems({int count = 1}) { + return List.generate( + count, + (index) => BrnBottomTabBarItem( + icon: Icon( + icons[0], + color: Colors.grey, + ), + title: Text(titles[0]), + activeIcon: Icon( + icons[0], + color: Colors.blue, + ), + )); + } } diff --git a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart index 98d6ebd1..2ce74ff9 100644 --- a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart +++ b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart @@ -5,23 +5,31 @@ import 'package:flutter/material.dart'; /// 特别注意:Tab的右上角小红点可能不符合UI规范,可以使用BrnBadge小红点组件 class BrnBottomTabBarItem { const BrnBottomTabBarItem({ - required this.icon, this.title, + required this.icon, Widget? activeIcon, + this.selectedTextStyle, + this.unSelectedTextStyle, this.backgroundColor, this.badge, this.badgeNo, this.maxBadgeNo = 99, }) : activeIcon = activeIcon ?? icon; + /// Tab标题名 + final Widget? title; + /// 未选中时的icon final Widget icon; /// 选中时的icon final Widget activeIcon; - /// Tab标题名 - final Widget? title; + /// tab 选中文本样式 + final TextStyle? selectedTextStyle; + + /// tab 未选中文本样式 + final TextStyle? unSelectedTextStyle; /// 背景色 final Color? backgroundColor; diff --git a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart index 2f4675e2..70776a9e 100644 --- a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart +++ b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart @@ -3,7 +3,9 @@ import 'dart:collection' show Queue; import 'dart:math' as math; +import 'package:bruno/bruno.dart'; import 'package:bruno/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart'; +import 'package:bruno/src/theme/configs/brn_all_config.dart'; import 'package:flutter/material.dart'; /// 定义一些UI常量,根据UI稿进行填写 @@ -79,246 +81,9 @@ class BrnBottomTabBar extends StatefulWidget { _BottomTabBarState createState() => _BottomTabBarState(); } -/// 表示底部导航栏中的单个tile,它的目的是进入一个伸缩页面 -class _BottomNavigationTile extends StatelessWidget { - const _BottomNavigationTile( - this.type, - this.item, - this.animation, - this.iconSize, { - this.onTap, - this.colorTween, - this.flex, - this.selected = false, - this.indexLabel, - this.isAnimation = true, - this.isInkResponse = true, - this.badgeColor, - }); - - final BrnBottomTabBarDisplayType type; - final BrnBottomTabBarItem item; - final Animation animation; - final double iconSize; - final VoidCallback? onTap; - final ColorTween? colorTween; - final double? flex; - final bool selected; - final String? indexLabel; - final bool isAnimation; - final bool isInkResponse; - final Color? badgeColor; - - /// 构建icon - Widget _buildIcon() { - double? tweenStart; - Color? iconColor; - switch (type) { - case BrnBottomTabBarDisplayType.fixed: - tweenStart = 8.0; - iconColor = colorTween?.evaluate(animation); - break; - case BrnBottomTabBarDisplayType.shifting: - tweenStart = 16.0; - iconColor = Colors.blue; - break; - } - return Align( - alignment: Alignment.topCenter, - heightFactor: 1.0, - child: Container( - margin: EdgeInsets.only( - top: isAnimation - ? Tween( - begin: tweenStart, - end: _kTopMargin, - ).evaluate(animation) - : _kTopMargin, - ), - child: IconTheme( - data: IconThemeData( - color: iconColor, - size: iconSize, - ), - child: selected ? item.activeIcon : item.icon, - ), - ), - ); - } - - /// 构建固定Label - /// 修改icon与text间距在这里修改 - Widget _buildFixedLabel() { - double scale = isAnimation - ? Tween( - begin: _kInactiveFontSize / _kActiveFontSize, - end: 1.0, - ).evaluate(animation) - : 1.0; - return Align( - alignment: Alignment.bottomCenter, - heightFactor: 1.0, - child: Container( - margin: const EdgeInsets.only( - bottom: _kBottomMargin, top: _kMiddleInterval), - child: DefaultTextStyle.merge( - style: TextStyle( - fontSize: _kActiveFontSize, - color: colorTween?.evaluate(animation), - ), - - /// 使用矩阵变化控制字体大小 - child: Transform( - transform: Matrix4.diagonal3Values( - scale, - scale, - scale, - ), - alignment: Alignment.bottomCenter, - child: item.title, - ), - ), - ), - ); - } - - /// 构建可变Label - Widget _buildShiftingLabel() { - return Align( - alignment: Alignment.bottomCenter, - heightFactor: 1.0, - child: Container( - margin: EdgeInsets.only( - bottom: Tween( - /// 在规范中,他们只是删除了非活动项目的标签,并指定了16dp的底部边距, - /// 我们不想移除标签因为我们想淡入淡出它,所以这修改了底部边距来考虑到这一点。 - begin: 2.0, - end: _kBottomMargin, - ).evaluate(animation), - ), - child: FadeTransition( - alwaysIncludeSemantics: true, - opacity: animation, - child: DefaultTextStyle.merge( - style: const TextStyle( - fontSize: _kActiveFontSize, - color: Colors.blue, - ), - child: item.title!, - ), - ), - ), - ); - } - - /// 构建未读消息弹窗 - Widget? _buildBadge() { - if (item.badge == null && (item.badgeNo == null || item.badgeNo!.isEmpty)) { - return Container(); - } - if (item.badge != null) { - return item.badge; - } - return Container( - width: 24, - padding: EdgeInsets.fromLTRB(0, 2, 0, 2), - alignment: Alignment.center, - decoration: BoxDecoration( - color: badgeColor, - shape: BoxShape.rectangle, - borderRadius: BorderRadius.all(Radius.circular(10))), - child: Text( - /// 设置未读数 > item.maxBadgeNo 则报加+ 默认 99 - _getUnReadText(), - style: TextStyle(fontSize: 10, color: Colors.white), - ), - ); - } - - String _getUnReadText() { - int _badgeNo = 0; - try { - if (item.badgeNo != null) { - _badgeNo = int.parse(item.badgeNo!); - } - } catch (e) { - debugPrint('badgeNo has FormatException'); - } - return '${_badgeNo > item.maxBadgeNo ? '${item.maxBadgeNo}+' : _badgeNo}'; - } - - /// 构建底字体缩放动画 - /// label: 传入的文字组件 - Widget _buildInkWidget(Widget? label) { - if (isInkResponse) { - return InkResponse( - onTap: onTap, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, - children: [ - _buildIcon(), - label!, - ], - ), - ); - } - return GestureDetector( - onTap: onTap, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, - children: [ - _buildIcon(), - label!, - ], - )); - } - - @override - Widget build(BuildContext context) { - /// 为了在动画过程中使用flex容器来增长平铺块,我们 - /// 需要将flex分配中的更改划分为更小的块 - /// 制作流畅的动画。我们通过将flex值相乘来实现这一点 - /// (这是一个整数)乘以一个大数。 - late int size; - Widget? label; - switch (type) { - case BrnBottomTabBarDisplayType.fixed: - size = 1; - label = _buildFixedLabel(); - break; - case BrnBottomTabBarDisplayType.shifting: - size = (flex! * 1000.0).round(); - label = _buildShiftingLabel(); - break; - } - - return Expanded( - flex: size, - child: Semantics( - container: true, - header: true, - selected: selected, - child: Stack( - children: [ - Positioned(right: 4, top: 4, child: _buildBadge()!), - _buildInkWidget(label), - Semantics( - label: indexLabel, - ) - ], - ), - ), - ); - } -} /// 底部导航栏中状态控制类 -class _BottomTabBarState extends State - with TickerProviderStateMixin { +class _BottomTabBarState extends State with TickerProviderStateMixin { List _controllers = []; late List _animations; @@ -582,6 +347,244 @@ class _BottomTabBarState extends State } } + +/// 表示底部导航栏中的单个tile,它的目的是进入一个伸缩页面 +class _BottomNavigationTile extends StatelessWidget { + + const _BottomNavigationTile( + this.type, + this.item, + this.animation, + this.iconSize, { + this.onTap, + this.colorTween, + this.flex, + this.selected = false, + this.indexLabel, + this.isAnimation = true, + this.isInkResponse = true, + this.badgeColor, + }); + + final BrnBottomTabBarDisplayType type; + final BrnBottomTabBarItem item; + final Animation animation; + final double iconSize; + final VoidCallback? onTap; + final ColorTween? colorTween; + final double? flex; + final bool selected; + final String? indexLabel; + final bool isAnimation; + final bool isInkResponse; + final Color? badgeColor; + + @override + Widget build(BuildContext context) { + /// 为了在动画过程中使用flex容器来增长平铺块,我们 + /// 需要将flex分配中的更改划分为更小的块 + /// 制作流畅的动画。我们通过将flex值相乘来实现这一点 + /// (这是一个整数)乘以一个大数。 + late int size; + Widget? label; + switch (type) { + case BrnBottomTabBarDisplayType.fixed: + size = 1; + label = _buildFixedLabel(); + break; + case BrnBottomTabBarDisplayType.shifting: + size = (flex! * 1000.0).round(); + label = _buildShiftingLabel(); + break; + } + + return Expanded( + flex: size, + child: Semantics( + container: true, + header: true, + selected: selected, + child: Stack( + children: [ + Positioned(right: 4, top: 4, child: _buildBadge()!), + _buildInkWidget(label), + Semantics( + label: indexLabel, + ) + ], + ), + ), + ); + } + + + /// 构建icon + Widget _buildIcon() { + double? tweenStart; + Color? iconColor; + switch (type) { + case BrnBottomTabBarDisplayType.fixed: + tweenStart = 8.0; + iconColor = colorTween?.evaluate(animation); + break; + case BrnBottomTabBarDisplayType.shifting: + tweenStart = 16.0; + iconColor = Colors.blue; + break; + } + return Align( + alignment: Alignment.topCenter, + heightFactor: 1.0, + child: Container( + margin: EdgeInsets.only( + top: isAnimation + ? Tween( + begin: tweenStart, + end: _kTopMargin, + ).evaluate(animation) + : _kTopMargin, + ), + child: IconTheme( + data: IconThemeData( + color: iconColor, + size: iconSize, + ), + child: selected ? item.activeIcon : item.icon, + ), + ), + ); + } + + /// 构建固定Label + /// 修改icon与text间距在这里修改 + Widget _buildFixedLabel() { + double scale = isAnimation + ? Tween( + begin: _kInactiveFontSize / _kActiveFontSize, + end: 1.0, + ).evaluate(animation) + : 1.0; + return Align( + alignment: Alignment.bottomCenter, + heightFactor: 1.0, + child: Container( + margin: const EdgeInsets.only( + bottom: _kBottomMargin, top: _kMiddleInterval), + child: DefaultTextStyle.merge( + style: TextStyle( + fontSize: _kActiveFontSize, + color: colorTween?.evaluate(animation), + ), + + /// 使用矩阵变化控制字体大小 + child: Transform( + transform: Matrix4.diagonal3Values( + scale, + scale, + scale, + ), + alignment: Alignment.bottomCenter, + child: item.title, + ), + ), + ), + ); + } + + /// 构建可变Label + Widget _buildShiftingLabel() { + return Align( + alignment: Alignment.bottomCenter, + heightFactor: 1.0, + child: Container( + margin: EdgeInsets.only( + bottom: Tween( + /// 在规范中,他们只是删除了非活动项目的标签,并指定了16dp的底部边距, + /// 我们不想移除标签因为我们想淡入淡出它,所以这修改了底部边距来考虑到这一点。 + begin: 2.0, + end: _kBottomMargin, + ).evaluate(animation), + ), + child: DefaultTextStyle.merge( + style: TextStyle( + fontSize: _kActiveFontSize, + color: selected ? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary + : BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase, + ).merge(selected ? item.selectedTextStyle : item.unSelectedTextStyle), + child: item.title!, + ), + ), + ); + } + + /// 构建未读消息弹窗 + Widget? _buildBadge() { + if (item.badge == null && (item.badgeNo == null || item.badgeNo!.isEmpty)) { + return Container(); + } + if (item.badge != null) { + return item.badge; + } + return Container( + width: 24, + padding: EdgeInsets.fromLTRB(0, 2, 0, 2), + alignment: Alignment.center, + decoration: BoxDecoration( + color: badgeColor, + shape: BoxShape.rectangle, + borderRadius: BorderRadius.all(Radius.circular(10))), + child: Text( + /// 设置未读数 > item.maxBadgeNo 则报加+ 默认 99 + _getUnReadText(), + style: TextStyle(fontSize: 10, color: Colors.white), + ), + ); + } + + String _getUnReadText() { + int _badgeNo = 0; + try { + if (item.badgeNo != null) { + _badgeNo = int.parse(item.badgeNo!); + } + } catch (e) { + debugPrint('badgeNo has FormatException'); + } + return '${_badgeNo > item.maxBadgeNo ? '${item.maxBadgeNo}+' : _badgeNo}'; + } + + /// 构建底字体缩放动画 + /// label: 传入的文字组件 + Widget _buildInkWidget(Widget? label) { + if (isInkResponse) { + return InkResponse( + onTap: onTap, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + _buildIcon(), + label!, + ], + ), + ); + } + return GestureDetector( + onTap: onTap, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + _buildIcon(), + label!, + ], + )); + } +} + + /// 简介:TabBarItem点击飞溅动画私有类 /// 功能:实现点击飞溅动画 class _Circle { @@ -633,6 +636,7 @@ class _Circle { } } + /// 绘制动画色彩飞溅的圆圈 class _RadialPainter extends CustomPainter { _RadialPainter({ From b5c7a685576bc6fbd2a4e3b4955b77193c3f2e52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E8=84=B8=E5=84=BF?= Date: Thu, 31 Mar 2022 10:12:56 +0800 Subject: [PATCH 16/24] fix some document bug (#148) --- .../BrnSelectedListActionSheet.md | 2 +- .../appraise/BrnAppraise/BrnAppraise.md | 2 +- .../BrnAppraiseBottomPicker.md | 6 +- .../BrnBottomButtonPanel.md | 4 +- .../charts/BrnBrokenLine/BrnBrokenLine.md | 84 +++++++++---------- .../BrnDoughnutChart/BrnDoughnutChart.md | 2 +- docs/components/dialog/BrnDialog/BrnDialog.md | 8 +- .../BrnMiddleInputDialog.md | 4 +- .../BrnMultiSelectDialog.md | 2 +- .../BrnGalleryDetailPage.md | 2 +- .../BrnGallerySummaryPage.md | 2 +- .../BrnBigGhostButton/BrnBigGhostButton.md | 10 +-- .../BrnBigMainButton/BrnBigMainButton.md | 10 +-- .../BrnBigOutlineButton.md | 12 +-- .../BrnSmallMainButton/BrnSmallMainButton.md | 14 ++-- .../BrnSmallOutlineButton.md | 23 ++--- .../notification/BrnNoticeBar/BrnNoticeBar.md | 61 +++++++------- .../BrnNoticeBarWithButton.md | 69 ++++++++------- .../BrnMultiColumnPicker.md | 11 +-- .../BrnMultiSelectListPicker.md | 19 +++-- .../radio/BrnRadioButton/BrnRadioButton.md | 29 +++---- .../ratingBar/BrnRatingStar/BrnRatingStar.md | 6 +- .../search/BrnSearchText/BrnSearchText.md | 84 ++++++++++--------- .../BrnSelectionView/BrnSelectionView.md | 4 +- .../shadowCard/BrnShadowCard/BrnShadowCard.md | 24 +++--- .../BrnHorizontalSteps/BrnHorizontalSteps.md | 21 +++-- .../stepBar/BrnStepLine/BrnStepLine.md | 36 ++++---- .../tag/BrnDeleteTag/BrnDeleteTag.md | 38 +++++---- .../tag/BrnSelectTag/BrnSelectTag.md | 71 ++++++++++------ .../components/tag/BrnStateTag/BrnStateTag.md | 19 ++--- .../tag/BrnTagCustom/BrnTagCustom.md | 31 +++---- .../BrnEnhanceNumberCard.md | 21 ++--- .../BrnExpandableText/BrnExpandableText.md | 30 +++---- .../text/BrnRichInfoGrid/BrnRichInfoGrid.md | 19 +++-- .../BrnActionCardTitle/BrnActionCardTitle.md | 23 +++-- .../BrnCommonCardTitle/BrnCommonCardTitle.md | 48 +++++------ .../BrnSubSwitchTitle/BrnSubSwitchTitle.md | 20 ++--- .../title/BrnSwitchTitle/BrnSwitchTitle.md | 12 +-- 38 files changed, 461 insertions(+), 422 deletions(-) diff --git a/docs/components/actionsheet/BrnSelectedListActionSheet/BrnSelectedListActionSheet.md b/docs/components/actionsheet/BrnSelectedListActionSheet/BrnSelectedListActionSheet.md index 9af650b9..a0304672 100644 --- a/docs/components/actionsheet/BrnSelectedListActionSheet/BrnSelectedListActionSheet.md +++ b/docs/components/actionsheet/BrnSelectedListActionSheet/BrnSelectedListActionSheet.md @@ -21,7 +21,7 @@ group: ### 交互规则 -1. 通用的已选列表弹窗。包括顶部工具条和中间的数据列表两部分,不包括底部的按钮交互区域,底部的按钮Demo中使用的是 [BrnBottomButtonPanel](../../buttonPanel/BrnButtonPanel/BrnBottomButtonPanel.md)。整体布局通过`OverlayEntry` 实现,将控制列表的控制功能和已选列表视图独立开来,一来可以更加方便的控制列表,二来可以充分自定义控制列表的功能区域。 +1. 通用的已选列表弹窗。包括顶部工具条和中间的数据列表两部分,不包括底部的按钮交互区域,底部的按钮Demo中使用的是 [BrnBottomButtonPanel](../widgets/brn-button-panel)。整体布局通过`OverlayEntry` 实现,将控制列表的控制功能和已选列表视图独立开来,一来可以更加方便的控制列表,二来可以充分自定义控制列表的功能区域。 2. 工具条:包括关闭弹窗和清空按钮。 3. 数据列表中每一行,从左至右依次是`icon`(高50,宽45)、文本和移除按钮。 4. 最小行高50,如果是自定义每行视图,则高度自动撑开。 diff --git a/docs/components/appraise/BrnAppraise/BrnAppraise.md b/docs/components/appraise/BrnAppraise/BrnAppraise.md index 899564bd..c0ad9aa4 100644 --- a/docs/components/appraise/BrnAppraise/BrnAppraise.md +++ b/docs/components/appraise/BrnAppraise/BrnAppraise.md @@ -22,7 +22,7 @@ group: ### 交互规则 1. BrnAppraise:评价组件,支持表情包和五角星两种,可使用在页面和弹窗里。 -2. [BrnAppraiseBottomPicker](../brn-appraise-bottom-picker/brn-appraise-bottom-picker):评价组件底部弹窗,对 BrnAppraise 做了一层 picker 的封装,参数与 BrnAppraise 完全一致。 +2. [BrnAppraiseBottomPicker](../widgets/brn-appraise-bottom-picker):评价组件底部弹窗,对 BrnAppraise 做了一层 picker 的封装,参数与 BrnAppraise 完全一致。 ### 使用规范 diff --git a/docs/components/appraise/BrnAppraiseBottomPicker/BrnAppraiseBottomPicker.md b/docs/components/appraise/BrnAppraiseBottomPicker/BrnAppraiseBottomPicker.md index 15a0d259..ccec6891 100644 --- a/docs/components/appraise/BrnAppraiseBottomPicker/BrnAppraiseBottomPicker.md +++ b/docs/components/appraise/BrnAppraiseBottomPicker/BrnAppraiseBottomPicker.md @@ -7,7 +7,7 @@ group: # BrnAppraiseBottomPicker -以 picker 样式展现的评价组件。具体参数和 [BrnAppraise](../brn-appraise/brn-appraise) 一样。 +以 picker 样式展现的评价组件。具体参数和 [BrnAppraise](../widgets/brn-appraise) 一样。 ## 一、效果总览 ![](./img/BrnAppraiseBottomPickerIntro.png) @@ -16,7 +16,7 @@ group: ### 适用场景 -需要收集用户评价和反馈的业务场景,并以弹窗形式展示。页面交互规则和使用规范参见 [BrnAppraise](../brn-appraise/brn-appraise)。 +需要收集用户评价和反馈的业务场景,并以弹窗形式展示。页面交互规则和使用规范参见 [BrnAppraise](../widgets/brn-appraise)。 ## 三、构造函数及参数说明 @@ -47,7 +47,7 @@ BrnAppraiseBottomPicker({ | tags | `List?` | 供选择的标签数据 | 否 | 无 | | inputHintText | String | 输入框的提示文字 | 否 | '' | | onConfirm | `void Function(int index, List selectedTags, String input)?` | 点击提交时的回调,其中index是选中的表情或者五角星的index,selectedTags是选中的标签,input是输入框的内容 | 否 | 无 | -| config | BrnAppraiseConfig | 配置类,具体参见 [BrnAppraise](../brn-appraise/brn-appraise) | 否 | BrnAppraiseConfig() | +| config | BrnAppraiseConfig | 配置类,具体参见 [BrnAppraise](../widgets/brn-appraise) | 否 | BrnAppraiseConfig() | ### 四、代码演示 diff --git a/docs/components/bottomButtonPanel/BrnBottomButtonPanel/BrnBottomButtonPanel.md b/docs/components/bottomButtonPanel/BrnBottomButtonPanel/BrnBottomButtonPanel.md index 232526b3..c5f266e9 100644 --- a/docs/components/bottomButtonPanel/BrnBottomButtonPanel/BrnBottomButtonPanel.md +++ b/docs/components/bottomButtonPanel/BrnBottomButtonPanel/BrnBottomButtonPanel.md @@ -59,8 +59,8 @@ const BrnBottomButtonPanel( | 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | | --- | --- | --- | --- | --- | -| mainButtonName | String | 主按钮的显示文案 | 否 | 无 | -| mainButtonOnTap | VoidCallback | 主按钮的点击回调 | 否 | 无 | +| mainButtonName | String | 主按钮的显示文案 | 是 | 无 | +| mainButtonOnTap | VoidCallback | 主按钮的点击回调 | 是 | 无 | | secondaryButtonName | String? | 次按钮显示文案 | 否 | 无 | | secondaryButtonOnTap | VoidCallback? | 次按钮的点击回调 | 否 | 无 | | iconButtonList | List? | icon按钮的集合 | 否 | 无 | diff --git a/docs/components/charts/BrnBrokenLine/BrnBrokenLine.md b/docs/components/charts/BrnBrokenLine/BrnBrokenLine.md index c34e53e9..1206b72e 100644 --- a/docs/components/charts/BrnBrokenLine/BrnBrokenLine.md +++ b/docs/components/charts/BrnBrokenLine/BrnBrokenLine.md @@ -30,37 +30,37 @@ group: ```dart BrnBrokenLine({ - Key? key, - required this.size, - required this.lines, - this.contentPadding = const EdgeInsets.only(left: 10, right: 10), - this.backgroundColor, - this.xyDialLineWidth = 2, - this.xDialColor, - this.yDialColor, - this.yHintLineOffset = 20.0, - this.showPointDashLine = true, - this.dialWidth = 4, - this.xDialMin, - this.xDialMax, - this.xDialValues, - required this.yDialMin, - required this.yDialMax, - this.yDialValues, - this.isShowXHintLine = true, - this.isShowYHintLine = false, - this.isHintLineSolid = true, - this.hintLineColor, - this.isTipWindowAutoDismiss = true, - this.isShowXDialText = false, - this.isShowYDialText = false, - }) : super(key: key) { - // 设置自定义 X 轴时,检查 x轴的最大、最小刻度范围 - if (xDialValues != null) { - assert(xDialMin != null); - assert(xDialMax != null); - } + Key? key, + required this.size, + required this.lines, + this.contentPadding = const EdgeInsets.only(left: 10, right: 10), + this.backgroundColor, + this.xyDialLineWidth = 2, + this.xDialColor, + this.yDialColor, + this.yHintLineOffset = 20.0, + this.showPointDashLine = true, + this.dialWidth = 4, + this.xDialMin, + this.xDialMax, + this.xDialValues, + required this.yDialMin, + required this.yDialMax, + this.yDialValues, + this.isShowXHintLine = true, + this.isShowYHintLine = false, + this.isHintLineSolid = true, + this.hintLineColor, + this.isTipWindowAutoDismiss = true, + this.isShowXDialText = false, + this.isShowYDialText = false, +}) : super(key: key) { + // 设置自定义 X 轴时,检查 x轴的最大、最小刻度范围 + if (xDialValues != null) { + assert(xDialMin != null); + assert(xDialMax != null); } +} ``` ### 参数说明: @@ -77,19 +77,19 @@ BrnBrokenLine({ | yHintLineOffset | double | Y 轴辅助线向右偏移量,默认 20(X 轴刻度线也会跟随该偏移量向右偏移) | 否 | 20.0 | | | showPointDashLine | bool | 是否展示数据点选中时的辅助线 | 否 | true | | | dialWidth | double | Y 轴刻度的宽度,和 X 轴刻度的高度 | 否 | 4 | | -| xDialMin | double | X 轴展示范围最小值 | 否 | | | -| xDialMax | double | X 轴展示范围最大值 | 否 | | | +| xDialMin | double? | X 轴展示范围最小值 | 否 | | | +| xDialMax | double? | X 轴展示范围最大值 | 否 | | | | yDialMin | double | Y 轴展示范围最小值 | 是 | | | | yDialMax | double | Y 轴展示范围最大值 | 是 | | | -| xDialValues | `List` | X 轴刻度数据 | 否 | | | -| yDialValues | `List`? | Y 轴刻度数据 | 否 | | | -| isShowXHintLine | bool | 是否展示 X 轴辅助线 | | true | | -| isShowYHintLine | bool | 是否展示 Y 轴辅助线 | | false | | -| isHintLineSolid | bool | 辅助线是否为虚线 | | true | | -| hintLineColor | Color? | 辅助线颜色 | | | | -| isTipWindowAutoDismiss | bool | 点击弹出的 tip 提示框,是否自动消失 | | true | | -| isShowXDialText | bool | 是否展示 X 坐标刻度文案 | | false | | -| isShowYDialText | bool | 是否展示 Y 坐标刻度文案 | | false | | +| xDialValues | `List?` | X 轴刻度数据 | 否 | | | +| yDialValues | `List?` | Y 轴刻度数据 | 否 | | | +| isShowXHintLine | bool | 是否展示 X 轴辅助线 | 否 | true | | +| isShowYHintLine | bool | 是否展示 Y 轴辅助线 | 否 | false | | +| isHintLineSolid | bool | 辅助线是否为虚线 | 否 | true | | +| hintLineColor | Color? | 辅助线颜色 | 否 | | | +| isTipWindowAutoDismiss | bool | 点击弹出的 tip 提示框,是否自动消失 | 否 | true | | +| isShowXDialText | bool | 是否展示 X 坐标刻度文案 | 否 | false | | +| isShowYDialText | bool | 是否展示 Y 坐标刻度文案 | 否 | false | | ### 其他数据结构 @@ -121,7 +121,7 @@ class BrnPointData { #### BrnLineTouchData 每个点的点击行为配置数据 -``` +```dart class BrnLineTouchData { /// 用于临时存储要展示 tip 内容在坐标的位置 double? x, y; diff --git a/docs/components/charts/BrnDoughnutChart/BrnDoughnutChart.md b/docs/components/charts/BrnDoughnutChart/BrnDoughnutChart.md index 69f0ae97..42fc8e87 100644 --- a/docs/components/charts/BrnDoughnutChart/BrnDoughnutChart.md +++ b/docs/components/charts/BrnDoughnutChart/BrnDoughnutChart.md @@ -47,7 +47,7 @@ BrnDoughnutChart( | width | double | 宽 | 否 | 0 | | height | double | 高 | 否 | 0 | | padding | EdgeInsetsGeometry | 内边距 | 否 | EdgeInsets.zero | -| ringWidth | double | 圆环宽度 | 否 | 50 | +| ringWidth | int | 圆环宽度 | 否 | 50 | | data | `List` | 饼图数据 | 是 | | | fontSize | double | 选中时展示文字大小 | 否 | 12 | | fontColor | Color | 选中时展示文字颜色 | 否 | Colors.white | diff --git a/docs/components/dialog/BrnDialog/BrnDialog.md b/docs/components/dialog/BrnDialog/BrnDialog.md index 4a272260..8e4e380c 100644 --- a/docs/components/dialog/BrnDialog/BrnDialog.md +++ b/docs/components/dialog/BrnDialog/BrnDialog.md @@ -62,11 +62,11 @@ BrnDialog({ | titleText | String? | 对话框的标题文案 | 否 | 无 | | messageText | String? | 对话框中间的显示文本 | 否 | 无 | | warningText | String? | 对话框的警示文案文本 | 否 | 无 | -| actionsText | List? | 对话框底部的按钮 | 否 | 无 | +| actionsText | `List?` | 对话框底部的按钮 | 否 | 无 | | titleWidget | Widget? | 自定义widget的标题 | 否 | 无 | | contentWidget | Widget? | 自定义widget的内容 | 否 | 无 | | warningWidget | Widget? | 自定义widget的警示内容 | 否 | 无 | -| actionsWidget | List? | 对话框底部的自定义widget按钮 | 否 | 无 | +| actionsWidget | `List?` | 对话框底部的自定义widget按钮 | 否 | 无 | | indexedActionCallback | DialogIndexedActionClickCallback? | 对话框底部的点击回调 | 否 | 无 | | divider | Divider | 底部按钮的水平和上面内容的水平分割线 | 否 | 高1像素的L1分割线 | | verticalDivider | VerticalDivider | 底部按钮之间的分割线 | 否 | 宽1像素的L1分割线 | @@ -130,7 +130,7 @@ BrnDialog({ | **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | | context | BuildContext | 用于显示弹窗的上下文 | 是 | 五 | -| actions | List | 对话框底部的按钮 | 否 | 无 | +| actions | `List` | 对话框底部的按钮 | 否 | 无 | | showIcon | bool | 是否显示icon | 否 | false | | iconWidget | Image? | 头部显示的icon 默认为alert | 否 | 主题色alert | | title | String? | 对话框的标题文案 | 否 | 无 | @@ -139,7 +139,7 @@ BrnDialog({ | messageWidget | Widget? | 自定义widget的内容 | 否 | 无 | | warning | String? | 对话框的警示文案文本 | 否 | 无 | | warningWidget | Widget? | 自定义widget的警示内容 | 否 | 无 | -| actionsWidget | List? | 对话框底部的自定义widget按钮 | 否 | 无 | +| actionsWidget |` List?` | 对话框底部的自定义widget按钮 | 否 | 无 | | indexedActionClickCallback | DialogIndexedActionClickCallback? | 对话按钮点击的回调 | 否 | 无 | | titleMaxLines | int | 标题最大行数 | 否 | 3 | | barrierDismissible | bool | 点击对话框遮罩是否消失对话框 | 否 | true 关闭 | diff --git a/docs/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md b/docs/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md index a8ace15f..9dd40a66 100644 --- a/docs/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md +++ b/docs/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md @@ -16,7 +16,7 @@ group: ## 二、描述 1. 带输入框的Dialog,在BrnDialogManager 基础上封装了输入框功能。 -2. 更进一步的细节定制,可使用 [BrnDialog](../brn-dialog/brn-dialog) 实现 +2. 更进一步的细节定制,可使用 [BrnDialog](../widgets/brn-dialog) 实现 ## 三、构造方法及参数说明 @@ -57,7 +57,7 @@ const BrnMiddleInputDialog( | inputEditingController | TextEditingController? | 输入控制器。如果有初始状态的填充文字,可以通过 [inputEditingController] 设置 | 否 | | | cancelText | String | 取消文案 | 否 | 取消 | | confirmText | String | 确定文案 | 否 | 确定 | -| inputFormatters | List? | 键盘操作按钮类型,可参见系统的 TextField.textInputAction | 否 | TextInputAction.newline | +| inputFormatters | `List?` | 键盘操作按钮类型,可参见系统的 TextField.textInputAction | 否 | TextInputAction.newline | | textInputAction | `TextInputAction` | 用于控制输入的内容范围比如只能输入数字可以填写:`FilteringTextInputFormatter.digitsOnly` | 否 | 无 | | onConfirm | void Function(String value)? | 确定回调,返回输入的值 | 否 | | | onCancel | VoidCallback | 取消回调 | 否 | | diff --git a/docs/components/dialog/BrnMultiSelectDialog/BrnMultiSelectDialog.md b/docs/components/dialog/BrnMultiSelectDialog/BrnMultiSelectDialog.md index 4d035372..8cb174f1 100644 --- a/docs/components/dialog/BrnMultiSelectDialog/BrnMultiSelectDialog.md +++ b/docs/components/dialog/BrnMultiSelectDialog/BrnMultiSelectDialog.md @@ -17,7 +17,7 @@ group: ### 适用场景 -多选列表,适用于从页面中部弹出的情况,属于 Dialog。 相似组件有 [BrnMultiSelectListPicker](../../picker/brn-multi-select-list-picker/brn-multi-select-list-picker), 从页面中部弹出。 +多选列表,适用于从页面中部弹出的情况,属于 Dialog。 相似组件有 [BrnMultiSelectListPicker](../widgets/brn-multi-select-list-picker), 从页面中部弹出。 ## 三、构造函数及参数说明 diff --git a/docs/components/gallery/BrnGalleryDetailPage/BrnGalleryDetailPage.md b/docs/components/gallery/BrnGalleryDetailPage/BrnGalleryDetailPage.md index 04860117..0b2cf4b8 100644 --- a/docs/components/gallery/BrnGalleryDetailPage/BrnGalleryDetailPage.md +++ b/docs/components/gallery/BrnGalleryDetailPage/BrnGalleryDetailPage.md @@ -9,7 +9,7 @@ group: 查看大图交互模式-详情页。 -关联组件: [BrnGallerySummaryPage](../brn-gallery-summary-page/brn-gallery-summary-page.md) +关联组件: [BrnGallerySummaryPage](../widgets/brn-gallery-summary-page) ## 一、效果总览 diff --git a/docs/components/gallery/BrnGallerySummaryPage/BrnGallerySummaryPage.md b/docs/components/gallery/BrnGallerySummaryPage/BrnGallerySummaryPage.md index d49ded54..e7b44047 100644 --- a/docs/components/gallery/BrnGallerySummaryPage/BrnGallerySummaryPage.md +++ b/docs/components/gallery/BrnGallerySummaryPage/BrnGallerySummaryPage.md @@ -10,7 +10,7 @@ group: 查看大图交互模式-列表页 -相关组件 [BrnGalleryDetailPage](../brn-gallery-detail-page/brn-gallery-detail-page) +相关组件 [BrnGalleryDetailPage](../widgets/brn-gallery-detail-page) ## 一、效果总览 diff --git a/docs/components/normalButton/BrnBigGhostButton/BrnBigGhostButton.md b/docs/components/normalButton/BrnBigGhostButton/BrnBigGhostButton.md index 4b4df7f8..a5f9a937 100644 --- a/docs/components/normalButton/BrnBigGhostButton/BrnBigGhostButton.md +++ b/docs/components/normalButton/BrnBigGhostButton/BrnBigGhostButton.md @@ -38,11 +38,11 @@ const BrnBigGhostButton({ | **参数名** | **参数类型** | 描述 | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | | title | String | 按钮显示文案 | 否 | 确认 | -| onTap | VoidCallback | 点击的回调 | 否 | 无 | -| bgColor | Color | 按钮的背景色 | 否 | 主题色为5透明度的颜色 | -| width | double | 按钮的宽度 | 否 | double.infinity | -| titleColor | Color | 按钮的文字颜色 | 否 | 主题色 | -| themeData | BrnButtonConfig | button主题定制 | 否 | 无 | +| onTap | VoidCallback? | 点击的回调 | 否 | 无 | +| bgColor | Color? | 按钮的背景色 | 否 | 主题色为5透明度的颜色 | +| width | double? | 按钮的宽度 | 否 | double.infinity | +| titleColor | Color? | 按钮的文字颜色 | 否 | 主题色 | +| themeData | BrnButtonConfig? | button主题定制 | 否 | 无 | diff --git a/docs/components/normalButton/BrnBigMainButton/BrnBigMainButton.md b/docs/components/normalButton/BrnBigMainButton/BrnBigMainButton.md index 7b4c1b70..c5e7b70f 100644 --- a/docs/components/normalButton/BrnBigMainButton/BrnBigMainButton.md +++ b/docs/components/normalButton/BrnBigMainButton/BrnBigMainButton.md @@ -39,12 +39,12 @@ const BrnBigMainButton({ | **参数名** | **参数类型** | 描述 | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| title | String | 按钮显示文案 | 否 | 确认 | -| onTap | VoidCallback | 点击的回调 | 否 | 无 | +| title | String | 按钮显示文案 | 否 | `'确认'` | +| onTap | VoidCallback? | 点击的回调 | 否 | 无 | | isEnable | bool | 按钮是否可用 | 否 | false | -| bgColor | Color | 按钮的背景色 | 否 | 主题色 | -| width | double | 按钮的宽度 | 否 | double.infinity | -| themeData | BrnButtonConfig | 按钮主题配置 | 否 | 无 | +| bgColor | Color? | 按钮的背景色 | 否 | 主题色 | +| width | double? | 按钮的宽度 | 否 | double.infinity | +| themeData | BrnButtonConfig? | 按钮主题配置 | 否 | 无 | diff --git a/docs/components/normalButton/BrnBigOutlineButton/BrnBigOutlineButton.md b/docs/components/normalButton/BrnBigOutlineButton/BrnBigOutlineButton.md index 3c33346b..95488697 100644 --- a/docs/components/normalButton/BrnBigOutlineButton/BrnBigOutlineButton.md +++ b/docs/components/normalButton/BrnBigOutlineButton/BrnBigOutlineButton.md @@ -39,13 +39,13 @@ const BrnBigOutlineButton({ | **参数名** | **参数类型** | 描述 | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| title | String | 按钮显示文案 | 否 | 确认 | -| onTap | VoidCallback | 点击的回调 | 否 | 无 | +| title | String | 按钮显示文案 | 否 | '确认' | +| onTap | VoidCallback? | 点击的回调 | 否 | 无 | | isEnable | bool | 按钮是否可用 | 否 | True | -| lineColor | Color | 边框颜色 | 否 | 主题色 | -| textColor | Color | 按钮文本颜色 | 否 | 黑色 | -| width | double | 按钮的宽度 | 否 | double.infinity | -| themeData | BrnButtonConfig | 按钮主题配置 | 否 | 无 | +| lineColor | Color? | 边框颜色 | 否 | 主题色 | +| textColor | Color? | 按钮文本颜色 | 否 | 黑色 | +| width | double? | 按钮的宽度 | 否 | double.infinity | +| themeData | BrnButtonConfig? | 按钮主题配置 | 否 | 无 | ## 四、效果及代码演示 diff --git a/docs/components/normalButton/BrnSmallMainButton/BrnSmallMainButton.md b/docs/components/normalButton/BrnSmallMainButton/BrnSmallMainButton.md index 208a5334..5978b472 100644 --- a/docs/components/normalButton/BrnSmallMainButton/BrnSmallMainButton.md +++ b/docs/components/normalButton/BrnSmallMainButton/BrnSmallMainButton.md @@ -43,16 +43,16 @@ const BrnSmallMainButton({ | 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | | ---------- | --------------- | -------------- | -------- | --------------- | -| title | String | 按钮显示文案 | 否 | 确认 | -| onTap | VoidCallback | 点击的回调 | 否 | 无 | +| title | String | 按钮显示文案 | 否 | '确认' | +| onTap | VoidCallback? | 点击的回调 | 否 | 无 | | isEnable | bool | 按钮是否可用 | 否 | True | -| bgColor | Color | 按钮的背景色 | 否 | 主题色 | -| width | double | 按钮的宽度 | 否 | double.infinity | +| bgColor | Color? | 按钮的背景色 | 否 | 主题色 | +| width | double? | 按钮的宽度 | 否 | double.infinity | | textColor | Color | 文本的颜色 | 否 | 白色 | | fontWeight | FontWeight | 文本的粗细 | 否 | bold | -| fontSize | double | 文字的大小 | 否 | 14 | -| radius | double | 按钮的圆角 | 否 | 4 | -| maxWidth | double | 按钮的最大宽度 | 否 | null | +| fontSize | double? | 文字的大小 | 否 | 14 | +| radius | double? | 按钮的圆角 | 否 | 4 | +| maxWidth | double? | 按钮的最大宽度 | 否 | null | | themeData | BrnButtonConfig? | 按钮主题配置 | 否 | 无 | ## 四、代码演示 diff --git a/docs/components/normalButton/BrnSmallOutlineButton/BrnSmallOutlineButton.md b/docs/components/normalButton/BrnSmallOutlineButton/BrnSmallOutlineButton.md index 83c3bcdd..1984ee8e 100644 --- a/docs/components/normalButton/BrnSmallOutlineButton/BrnSmallOutlineButton.md +++ b/docs/components/normalButton/BrnSmallOutlineButton/BrnSmallOutlineButton.md @@ -40,17 +40,18 @@ const BrnSmallOutlineButton({ ### 参数说明 -| 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | -| ---------- | ------------ | ------------ | -------- | --------------- | -| title | String | 按钮显示文案 | 否 | 确认 | -| onTap | VoidCallback | 点击的回调 | 否 | 无 | -| isEnable | bool | 按钮是否可用 | 否 | true | -| lineColor | Color | 边框的背景色 | 否 | 主题色 | -| width | double | 按钮的宽度 | 否 | 无 | -| textColor | Color | 文本的颜色 | 否 | 白色 | -| fontWeight | FontWeight | 文本的粗细 | 否 | FontWeight.w600 | -| fontSize | double | 文字的大小 | 否 | 14 | -| radius | double | 按钮的圆角 | 否 | 无 | +| 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | +| ---------- | ---------------- | ------------ | -------- | --------------- | +| title | String | 按钮显示文案 | 否 | '确认' | +| onTap | VoidCallback? | 点击的回调 | 否 | 无 | +| isEnable | bool | 按钮是否可用 | 否 | true | +| lineColor | Color? | 边框的背景色 | 否 | 主题色 | +| width | double? | 按钮的宽度 | 否 | 无 | +| textColor | Color? | 文本的颜色 | 否 | 白色 | +| fontWeight | FontWeight | 文本的粗细 | 否 | FontWeight.w600 | +| fontSize | double | 文字的大小 | 否 | 14 | +| radius | double? | 按钮的圆角 | 否 | 无 | +| themeData | BrnButtonConfig? | 主题定制属性 | 否 | 无 | ## 四、代码演示 diff --git a/docs/components/notification/BrnNoticeBar/BrnNoticeBar.md b/docs/components/notification/BrnNoticeBar/BrnNoticeBar.md index 09520f97..b7ba9671 100644 --- a/docs/components/notification/BrnNoticeBar/BrnNoticeBar.md +++ b/docs/components/notification/BrnNoticeBar/BrnNoticeBar.md @@ -35,41 +35,40 @@ group: ```dart const BrnNoticeBar( - {Key key, - this.leftWidget, - this.showLeftIcon = true, - @required this.content, - this.textColor, - this.backgroundColor, - this.rightWidget, - this.showRightIcon = true, - this.noticeStyle, - this.onNoticeTap, - this.onRightIconTap, - this.marquee = false, - this.padding, - this.minHeight = 36}) - : assert(content != null), - super(key: key); + {Key? key, + this.leftWidget, + this.showLeftIcon = true, + required this.content, + this.textColor, + this.backgroundColor, + this.rightWidget, + this.showRightIcon = true, + this.noticeStyle, + this.onNoticeTap, + this.onRightIconTap, + this.marquee = false, + this.padding, + this.minHeight = 36}) + : super(key: key); ``` ### 参数说明 -| 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | -| --------------- | ------------ | ------------------------------------------------------------------------------------------------------------ | -------- | ----------------------------- | -| noticeStyle | NoticeStyle | 样式,取 NoticeStyles 里面的值 | 否 | NoticeStyles.runningWithArrow | -| content | String | 通知具体内容 | 是 | 无 | -| textColor | Color | 文案的颜色 | 否 | 随 defaultStyle 改变 | -| backgroundColor | Color | 通知栏的背景颜色 | 否 | 随 defaultStyle 改变 | -| leftWidget | Widget | 左侧图标区域自定义视图 | 否 | 无 | -| showLeftIcon | bool | 是否显示左侧图标 | 否 | true | -| rightWidget | Widget | 右侧图标区域自定义视图 | 否 | 无 | -| showRightIcon | bool | 是否显示右侧图标 | 否 | true | -| onNoticeTap | VoidCallback | 点击通知回调 | 否 | 无 | -| onRightIconTap | VoidCallback | 点击右侧图标回掉 | 否 | 无 | -| marquee | bool | 跑马灯 | 否 | false | -| minHeight | double | 最小高度。leftWidget、rightWidget 都为空时,限制的最小高度。可以通过该属性控制组件高度,内容会自动垂直居中。 | 否 | 36 | -| padding | EdgeInsets | 内容的内边距 | 否 | 无 | +| 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | +| --------------- | ------------- | ------------------------------------------------------------ | -------- | ----------------------------- | +| noticeStyle | NoticeStyle? | 样式,取 NoticeStyles 里面的值 | 否 | NoticeStyles.runningWithArrow | +| content | String | 通知具体内容 | 是 | 无 | +| textColor | Color? | 文案的颜色 | 否 | 随 defaultStyle 改变 | +| backgroundColor | Color? | 通知栏的背景颜色 | 否 | 随 defaultStyle 改变 | +| leftWidget | Widget? | 左侧图标区域自定义视图 | 否 | 无 | +| showLeftIcon | bool | 是否显示左侧图标 | 否 | true | +| rightWidget | Widget? | 右侧图标区域自定义视图 | 否 | 无 | +| showRightIcon | bool | 是否显示右侧图标 | 否 | true | +| onNoticeTap | VoidCallback? | 点击通知回调 | 否 | 无 | +| onRightIconTap | VoidCallback? | 点击右侧图标回掉 | 否 | 无 | +| marquee | bool | 跑马灯 | 否 | false | +| minHeight | double | 最小高度。leftWidget、rightWidget 都为空时,限制的最小高度。可以通过该属性控制组件高度,内容会自动垂直居中。 | 否 | 36 | +| padding | EdgeInsets? | 内容的内边距 | 否 | 无 | ### 其他参数说明 diff --git a/docs/components/notification/BrnNoticeBarWithButton/BrnNoticeBarWithButton.md b/docs/components/notification/BrnNoticeBarWithButton/BrnNoticeBarWithButton.md index 3cce9b45..a673433e 100644 --- a/docs/components/notification/BrnNoticeBarWithButton/BrnNoticeBarWithButton.md +++ b/docs/components/notification/BrnNoticeBarWithButton/BrnNoticeBarWithButton.md @@ -34,45 +34,44 @@ group: ```dart const BrnNoticeBarWithButton( - {Key key, - @required this.contentStr, - this.bgColor, - this.contentTextColor, - this.leftTagTxt, - this.leftTagBgColor, - this.leftTagTxtColor, - this.rightBtnBorderColor, - this.rightBtnTxt, - this.rightBtnTxtColor, - this.onRightBtnTap, - this.marquee = false, - this.leftWidget, - this.rightWidget, - this.padding, - this.minHeight = 54}) - : assert(contentStr != null), - super(key: key); + {Key? key, + required this.content, + this.backgroundColor, + this.contentTextColor, + this.leftTagText, + this.leftTagBackgroundColor, + this.leftTagTextColor, + this.rightButtonBorderColor, + this.rightButtonText, + this.rightButtonTextColor, + this.onRightButtonTap, + this.marquee = false, + this.leftWidget, + this.rightWidget, + this.padding, + this.minHeight = 54}) + : super(key: key); ``` ### 参数说明 -| 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | -| ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------------ | -------- | ----------------- | -| content | String | 通知的具体内容 | 是 | 无 | -| backgroundColor | Color | 通知的背景颜色 | 否 | Color(0x14FA5741) | -| contentTextColor | Color | 通知的文字颜色 | 否 | Color(0xFF333333) | -| leftTagText | String | 左边标签的文案,为空或者 null 时不显示标签视图 | 否 | 无 | -| leftTagTextColor | Color | 左边标签文字的颜色 | 否 | Colors.white | -| leftTagBackgroundColor | Color | 标签背景的颜色 | 否 | Color(0xFFFA5741) | -| leftWidget | Widget | 自定义左侧控件 | 否 | 无 | -| rightButtonText | String | 右侧按钮的文案,为空时不显示按钮 | 否 | | -| rightButtonTextColor | Color | 右侧按钮文字颜色 | 否 | Color(0xFFFA5741) | -| rightButtonBorderColor | Color | 右侧按钮边框颜色 | 否 | Color(0xFFFA5741) | -| rightWidget | Widget | 自定义右侧控件 | 否 | | -| marquee | bool | 通知文案是否以跑马灯效果展示 | 否 | false | -| onRightButtonTap | VoidCallback | 右侧按钮的点击回调 | 否 | | -| minHeight | double | 最小高度。leftWidget、rightWidget 都为空时,限制的最小高度。可以通过该属性控制组件高度,内容会自动垂直居中。 | 否 | 54 | -| padding | EdgeInsets | 内容的内边距 | 否 | 无 | +| 参数名 | 参数类型 | 描述 | 是否必填 | 默认值 | +| ---------------------- | ------------- | ------------------------------------------------------------ | -------- | ----------------- | +| content | String | 通知的具体内容 | 是 | 无 | +| backgroundColor | Color? | 通知的背景颜色 | 否 | Color(0x14FA5741) | +| contentTextColor | Color? | 通知的文字颜色 | 否 | Color(0xFF333333) | +| leftTagText | String? | 左边标签的文案,为空或者 null 时不显示标签视图 | 否 | 无 | +| leftTagTextColor | Color? | 左边标签文字的颜色 | 否 | Colors.white | +| leftTagBackgroundColor | Color? | 标签背景的颜色 | 否 | Color(0xFFFA5741) | +| leftWidget | Widget? | 自定义左侧控件 | 否 | 无 | +| rightButtonText | String? | 右侧按钮的文案,为空时不显示按钮 | 否 | | +| rightButtonTextColor | Color? | 右侧按钮文字颜色 | 否 | Color(0xFFFA5741) | +| rightButtonBorderColor | Color? | 右侧按钮边框颜色 | 否 | Color(0xFFFA5741) | +| rightWidget | Widget? | 自定义右侧控件 | 否 | | +| marquee | bool | 通知文案是否以跑马灯效果展示 | 否 | false | +| onRightButtonTap | VoidCallback? | 右侧按钮的点击回调 | 否 | | +| minHeight | double | 最小高度。leftWidget、rightWidget 都为空时,限制的最小高度。可以通过该属性控制组件高度,内容会自动垂直居中。 | 否 | 54 | +| padding | EdgeInsets? | 内容的内边距 | 否 | 无 | ## 四、代码演示 diff --git a/docs/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md b/docs/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md index b674bbc6..990b8f6b 100644 --- a/docs/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md +++ b/docs/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md @@ -45,12 +45,13 @@ BrnMultiColumnPicker( | entity | BrnPickerEntity | 筛选数据源 | 是 | | | maxHeight | double | Picker 展示最大高度 | 否 | 280.0 | | showSelectedCount | bool | 展示选中的条目的个数 | 否 | false | -| onConfirm | BrnOnPickerConfirm | 选择数据后回调函数 | 否 | null | -| onEntityTap | BrnOnEntityTap | 选择项目后回调函数 | 否 | null | +| onConfirm | `void BrnOnPickerConfirm(Map> results,int? firstIndex, int? secondIndex, int? thirdIndex)?` | 选择数据后回调函数 | 否 | null | +| onEntityTap | `void BrnOnEntityTap(int columnIndex, int rowIndex, BrnPickerEntity entity)?` | 选择项目后回调函数 | 否 | null | | pickerTitleConfig | BrnPickerTitleConfig | Picker 标题数据配置 | 否 | BrnPickerTitleConfig.Default | | isIncludeUnLimit | bool | 当选中”不限“的时候,返回的 reslut 结果是否包含 “不限” 选项,“不限” 选项 value 字段不能为空,上一级 key 字段不能为空 | 否 | false | -| canSelectEntryInterceptor | bool BrnOnSelectEntityInterceptor( int listIndex, int index, BrnPickerEntity entity) | 当前选项是否可以被选中:返回 true 可以被选中 false 不可以被选中 | 否 | | -| defaultFocusedIndexes | `List` | 初始化时的选中选项 | 否 | | +| canSelectEntryInterceptor | `bool BrnOnSelectEntityInterceptor( int listIndex, int index, BrnPickerEntity entity)?` | 当前选项是否可以被选中:返回 true 可以被选中 false 不可以被选中 | 否 | | +| defaultFocusedIndexes | `List?` | 初始化时的选中选项 | 否 | | +| themeData | BrnPickerConfig? | 主题定制,只有 Picker Title 部分样式生效 | 否 | | ### 其它数据结构 @@ -88,7 +89,7 @@ class BrnPickerEntity { ### 效果1: -[示例数据 list_picker.json](../../../example/assets/list_picker.json) +[示例数据 list_picker.json](https://bruno.ke.com/widgets/picker/brn-multi-column-picker/list_picker.json) image-20211115110957518 diff --git a/docs/components/picker/BrnMultiSelectListPicker/BrnMultiSelectListPicker.md b/docs/components/picker/BrnMultiSelectListPicker/BrnMultiSelectListPicker.md index c14b2de8..428c861f 100644 --- a/docs/components/picker/BrnMultiSelectListPicker/BrnMultiSelectListPicker.md +++ b/docs/components/picker/BrnMultiSelectListPicker/BrnMultiSelectListPicker.md @@ -11,9 +11,9 @@ group: 相似组件有: -[BrnMultiSelectTagsPicker](../brn-multi-select-tags-picker/brn-multi-select-tags-picker)从底部弹出的 Tag 样式多选。 +[BrnMultiSelectTagsPicker](../widgets/brn-multi-select-tags-picker)从底部弹出的 Tag 样式多选。 -[BrnMultiSelectDialog](../../dialog/brn-multi-select-dialog/brn-multi-select-dialog) 从页面中部弹出多选弹窗。 +[BrnMultiSelectDialog](../widgets/brn-multi-select-dialog) 从页面中部弹出多选弹窗。 ## 一、效果总览 @@ -44,13 +44,14 @@ BrnMultiSelectListPicker({ ### 参数说明 -| 参数名 | 参数类型 | 作用 | 是否必填 | 默认值 | -| ----------------- | ------------------------------------------------------------ | --------------------------------------------- | -------- | ---------------------------- | -| items | `List` | 数据源 | 是 | | -| pickerTitleConfig | BrnPickerTitleConfig | 设置 Picker 主题 | 否 | BrnPickerTitleConfig.Default | -| onSubmit | `BrnMultiSelectListPickerSubmit = bool Function(List checkedItems)`? | 点击【完成】时回调给外部选中的数据 | 否 | | -| onItemClick | BrnMultiSelectListPickerItemClick = void Function(BuildContext context, int index)? | Item 被点击的回调 | 否 | | -| isDismissible | bool | 是否可电机外部关闭弹窗,true 点击外部关闭弹窗 | 否 | true | +| 参数名 | 参数类型 | 作用 | 是否必填 | 默认值 | +| ----------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- | ---------------------------- | +| items | `List` | 数据源 | 是 | | +| pickerTitleConfig | BrnPickerTitleConfig | 设置 Picker 主题 | 否 | BrnPickerTitleConfig.Default | +| onSubmit | `BrnMultiSelectListPickerSubmit = bool Function(List checkedItems)?` | 点击【完成】时回调给外部选中的数据 | 否 | | +| onItemClick | `BrnMultiSelectListPickerItemClick = void Function(BuildContext context, int index)?` | Item 被点击的回调 | 否 | | +| isDismissible | bool | 是否可电机外部关闭弹窗,true 点击外部关闭弹窗。只在`show`方法里才有 | 否 | true | +| onCancel | VoidCallback? | 点击取消时的回调 | 否 | | ### 其它数据结构 diff --git a/docs/components/radio/BrnRadioButton/BrnRadioButton.md b/docs/components/radio/BrnRadioButton/BrnRadioButton.md index a27d1482..545cb373 100644 --- a/docs/components/radio/BrnRadioButton/BrnRadioButton.md +++ b/docs/components/radio/BrnRadioButton/BrnRadioButton.md @@ -29,18 +29,18 @@ group: ### 构造函数 ```dart -const BrnRadioButton({ - Key key, - @required this.radioIndex, - @required this.onValueChangedAtIndex, - this.disable = false, - this.isSelected = false, - this.iconPadding, - this.child, - this.childOnRight = true, - this.mainAxisAlignment = MainAxisAlignment.start, - this.mainAxisSize = MainAxisSize.min, -}); +const BrnRadioButton( + {Key? key, + required this.radioIndex, + required this.onValueChangedAtIndex, + this.disable = false, + this.isSelected = false, + this.iconPadding, + this.child, + this.childOnRight = true, + this.mainAxisAlignment = MainAxisAlignment.start, + this.mainAxisSize = MainAxisSize.min, + this.behavior = HitTestBehavior.translucent}); ``` ### 参数说明 @@ -50,11 +50,12 @@ const BrnRadioButton({ | onValueChangedAtIndex | void Function(int, bool) | radio选中状态发生变化产生的回调,int 为 选项的index,bool 为选项的选中状态,true表示选中,false未选中 | 是 | 无 | | isSelected | bool | 初始选中状态 | 否 | false | | disable | bool | 选项是否禁用 | 否 | false | -| child | widget | 除了 icon 部分的自定义视图 | 否 | 无 | -| iconPadding | EdgeInsets | 选择图标的padding | 否 | EdgeInsets.all(5) | +| child | widget? | 除了 icon 部分的自定义视图 | 否 | 无 | +| iconPadding | EdgeInsets? | 选择图标的padding | 否 | EdgeInsets.all(5) | | childOnRight | bool | widget在是否在选择 icon 的右边,false 就在左边 | 否 | true | | mainAxisAlignment | MainAxisAlignment | child 视图和 icon 在row布局里面的alignment | 否 | MainAxisAlignment.start | | mainAxisSize | MainAxisSize | child 视图和 icon 在row布局里面的mainAxisSize | 否 | MainAxisSize.min | +| behavior | HitTestBehavior | 默认值HitTestBehavior.translucent,控制widget.onRadioItemClick触发的点击范围 | 否 | HitTestBehavior.translucent | ## 四、代码演示 diff --git a/docs/components/ratingBar/BrnRatingStar/BrnRatingStar.md b/docs/components/ratingBar/BrnRatingStar/BrnRatingStar.md index bcda80f2..6251c6e4 100644 --- a/docs/components/ratingBar/BrnRatingStar/BrnRatingStar.md +++ b/docs/components/ratingBar/BrnRatingStar/BrnRatingStar.md @@ -25,7 +25,7 @@ group: ```dart const BrnRatingStar({ - Key key, + Key? key, this.count = DEFAULT_COUNT, this.selectedCount = 0, this.space = DEFAULT_SPACE, @@ -41,9 +41,9 @@ const BrnRatingStar({ | count | int | 星星总数 | 否 | 5 | | selectedCount | int | 初始选中的个数 | 否 | 0 | | space | double | 星星间距 | 否 | 1.0 | -| onSelected | ValueChanged | 点击回调,设置了才能支持点击选中操作 | 否 | | +| onSelected | `ValueChanged?` | 点击回调,设置了才能支持点击选中操作 | 否 | | | canRatingZero | bool | 是否可评 0 颗星,即第一颗星是否支持反选,默认不可评 0 星 | 否 | false | -| starBuilder | BrnRatingStarBuilder | 单颗星星视图的自定义构造器 | 否 | | +| starBuilder | BrnRatingStarBuilder? | 单颗星星视图的自定义构造器 | 否 | | ## 四、代码演示 diff --git a/docs/components/search/BrnSearchText/BrnSearchText.md b/docs/components/search/BrnSearchText/BrnSearchText.md index 3854f892..ad21dc85 100644 --- a/docs/components/search/BrnSearchText/BrnSearchText.md +++ b/docs/components/search/BrnSearchText/BrnSearchText.md @@ -36,31 +36,33 @@ group: ```dart -BrnSearchText( - {Key key, - this.searchController, - this.maxLines = 1, - this.maxLength, - this.hintText, - this.hintStyle, - this.textStyle, - this.prefixIcon, - this.onTextChange, - this.onTextCommit, - this.onActionTap, - this.maxHeight = 60, - this.innerPadding = const EdgeInsets.only(top: 10, bottom: 10, left: 20, right: 20), - this.outSideColor = Colors.white, - this.innerColor = const Color(0xfff8f8f8), - this.normalBorder, - this.activeBorder, - this.borderRadius = const BorderRadius.all(const Radius.circular(6.0)), - this.controller, - this.focusNode, - this.autoFocus = false, - this.textInputAction, - this.onTextClear, - this.action}) +const BrnSearchText({ + Key? key, + this.searchController, + this.controller, + this.maxLines = 1, + this.maxLength, + this.hintText, + this.hintStyle, + this.textStyle, + this.prefixIcon, + this.onTextChange, + this.onTextCommit, + this.onTextClear, + this.onActionTap, + this.action, + this.maxHeight = 60, + this.innerPadding = + const EdgeInsets.only(top: 10, bottom: 10, left: 20, right: 20), + this.outSideColor = Colors.white, + this.innerColor = const Color(0xfff8f8f8), + this.normalBorder, + this.activeBorder, + this.borderRadius = const BorderRadius.all(const Radius.circular(6.0)), + this.focusNode, + this.autoFocus = false, + this.textInputAction, +}) : super(key: key); ``` @@ -68,29 +70,29 @@ BrnSearchText( | **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| searchController | BrnSearchTextController | 用于控制 clear Icon 和右侧 Action 的显示与隐藏。等其他复杂的操作。 | 否 | 无 | -| controller | TextEditingController | 控制输入框行为和相应监听 | 否 | 无 | +| searchController | BrnSearchTextController? | 用于控制 clear Icon 和右侧 Action 的显示与隐藏。等其他复杂的操作。 | 否 | 无 | +| controller | TextEditingController? | 控制输入框行为和相应监听 | 否 | 无 | | maxLines | int | 允许输入的最大行数 | 否 | 1 | -| maxLength | int | 允许输入的最大长度 | 否 | 无 | -| hintText | String | 输入提示语,默认为"请输入搜索内容" | 否 | "请输入搜索内容" | -| hintStyle | TextStyle | 输入提示语的样式 | 否 | TextStyle(fontSize: 16,height: 1, textBaseline: TextBaseline.alphabetic,color: Color(0xff999999),) | -| textStyle | TextStyle | 输入文本的样式 | 否 | TextStyle(textBaseline: TextBaseline.alphabetic,color: BrunoColor.instance.F0Color, fontSize: 16) | -| prefixIcon | Widget | 输入框前置的图标 | 否 | 默认为搜索图标 | -| onTextChange | BrnOnSearchTextChange | 搜索框输入内容改变时候的回调函数,str为输入内容 | 否 | 无 | -| onTextCommit | BrnOnCommit | 输入内容点击搜索后的回调,content为输入内容 | 否 | 无 | -| onTextClear | ClearTapIntercept | 拦截取消的事件。
    1、返回值为true,表明用户想要拦截,则不会走默认的清除行为
    2、如果返回值为false,表明用户不想要拦截,在执行了用户的行为之后,还会走默认的行为 | 否 | 无 | -| onActionTap | VoidCallback | 右侧 action 区域点击的回调 | 否 | 无 | -| action | widget | 右侧操作 widget | 否 | 无 | +| maxLength | int? | 允许输入的最大长度 | 否 | 无 | +| hintText | String? | 输入提示语,默认为"请输入搜索内容" | 否 | "请输入搜索内容" | +| hintStyle | TextStyle? | 输入提示语的样式 | 否 | TextStyle(fontSize: 16,height: 1, textBaseline: TextBaseline.alphabetic,color: Color(0xff999999),) | +| textStyle | TextStyle? | 输入文本的样式 | 否 | TextStyle(textBaseline: TextBaseline.alphabetic,color: BrunoColor.instance.F0Color, fontSize: 16) | +| prefixIcon | Widget? | 输入框前置的图标 | 否 | 默认为搜索图标 | +| onTextChange | `BrnOnSearchTextChange=void Function(String content)?` | 搜索框输入内容改变时候的回调函数,str为输入内容 | 否 | 无 | +| onTextCommit | `BrnOnCommit=void Function(String content)?` | 输入内容点击搜索后的回调,content为输入内容 | 否 | 无 | +| onTextClear | `BrnOnTextClear = bool Function()?` | 拦截取消的事件。
    1、返回值为true,表明用户想要拦截,则不会走默认的清除行为
    2、如果返回值为false,表明用户不想要拦截,在执行了用户的行为之后,还会走默认的行为 | 否 | 无 | +| onActionTap | VoidCallback? | 右侧 action 区域点击的回调 | 否 | 无 | +| action | widget? | 右侧操作 widget | 否 | 无 | | maxHeight | double | 搜索框的最大高 | 否 | 60 | | innerPadding | EdgeInsets | 文本内容与边框的边距,设置该字段会导致显示区域变小。 | 否 | EdgeInsets.only(top: 10, bottom: 10, left: 20, right: 20) | | outSideColor | Color | 包裹搜索框的容器背景色 | 否 | 白色 | | innerColor | Color | 搜索框内部的颜色 | 否 | Color(0xfff8f8f8) | -| normalBorder | BoxBorder | 一般状态边框 | 否 | Border.all(width: 1.0, color: widget.innerColor) | -| activeBorder | BoxBorder | 激活状态边框 | 否 | Border.all(width: 1.0, color: widget.innerColor) | +| normalBorder | BoxBorder? | 一般状态边框 | 否 | Border.all(width: 1.0, color: widget.innerColor) | +| activeBorder | BoxBorder? | 激活状态边框 | 否 | Border.all(width: 1.0, color: widget.innerColor) | | borderRadius | BorderRadius | 边框圆角 | 否 | BorderRadius.all(const Radius.circular(6.0)) | -| focusNode | FocusNode | 管理焦点 | 否 | 无 | +| focusNode | FocusNode? | 管理焦点 | 否 | 无 | | autofocus | bool | 是否自动获取焦点 | 否 | false | -| textInputAction | TextInputAction | 用于控制键盘动作 | 否 | 无 | +| textInputAction | TextInputAction? | 用于控制键盘动作 | 否 | 无 | diff --git a/docs/components/selection/BrnSelectionView/BrnSelectionView.md b/docs/components/selection/BrnSelectionView/BrnSelectionView.md index b6938eb8..67a1119c 100644 --- a/docs/components/selection/BrnSelectionView/BrnSelectionView.md +++ b/docs/components/selection/BrnSelectionView/BrnSelectionView.md @@ -9,9 +9,9 @@ group: 用于筛选数据 -相关组件 [BrnFlatSelectionWidget](../brn-flat-selection/brn-flat-selection) +相关组件 [BrnFlatSelectionWidget](../widgets/brn-flat-selection) -相关组件 [BrnSimpleSelection](../brn-simple-selection/brn-simple-selection) +相关组件 [BrnSimpleSelection](../widgets/brn-simple-selection) ## 一、效果总览 diff --git a/docs/components/shadowCard/BrnShadowCard/BrnShadowCard.md b/docs/components/shadowCard/BrnShadowCard/BrnShadowCard.md index 3a04a84a..bcf9d133 100644 --- a/docs/components/shadowCard/BrnShadowCard/BrnShadowCard.md +++ b/docs/components/shadowCard/BrnShadowCard/BrnShadowCard.md @@ -25,30 +25,30 @@ group: ```dart BrnShadowCard( - {@required this.child, - this.color, - this.shadowColor, - this.padding, - this.circular = 4.0, - this.blurRadius = 5.0, - this.spreadRadius = 0, - this.offset = Offset.zero, - this.borderWidth = 0.5}); + {required this.child, + this.color = const Color(0xfffafafa), + this.shadowColor = const Color(0xffeeeeee), + this.padding = const EdgeInsets.all(0), + this.circular = 4.0, + this.blurRadius = 5.0, + this.spreadRadius = 0, + this.offset = Offset.zero, + this.borderWidth = 0.5}); ``` ### 参数说明 | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | ------------ | ------------------ | ----------------- | ------------ | ----------------- | -| color | Color | 背景色 | 否 | | +| color | Color | 背景色 | 否 | Color(0xfffafafa) | | shadowColor | Color | 阴影颜色 | 否 | Color(0xffeeeeee) | | offset | Offset | 阴影 xy 轴偏移量 | 否 | 0 | -| padding | EdgeInsetsGeometry | 内边距 | 否 | | +| padding | EdgeInsetsGeometry | 内边距 | 否 | EdgeInsets.all(0) | | circular | double | 圆角大小 | 否 | 4.0 | | blurRadius | double | 阴影模糊程度 | 否 | 5.0 | | spreadRadius | double | 阴影扩散程度 | 否 | 0 | | borderWidth | double | 边框宽度 | 否 | 0.5 | -| child | Widget | 需要填充的 widget | 否 | 无 | +| child | Widget | 需要填充的 widget | 是 | 无 | ## 三、代码演示 diff --git a/docs/components/stepBar/BrnHorizontalSteps/BrnHorizontalSteps.md b/docs/components/stepBar/BrnHorizontalSteps/BrnHorizontalSteps.md index 9a6380ec..e5d627da 100644 --- a/docs/components/stepBar/BrnHorizontalSteps/BrnHorizontalSteps.md +++ b/docs/components/stepBar/BrnHorizontalSteps/BrnHorizontalSteps.md @@ -34,12 +34,19 @@ group: ### 构造函数 ```dart -BrnHorizontalSteps({this.steps, this.controller, this.doingIcon, this.completedIcon}); +const BrnHorizontalSteps({ + Key? key, + required this.steps, + this.controller, + this.doingIcon, + this.completedIcon, + }) : assert(steps.length < 6), + super(key: key); ``` ### 参数说明 -#### BrnHorizontalStepsManager方法说明 +#### BrnStepsController 方法说明 | **方法名** | **参数** | **描述** | | --- | --- | --- | @@ -63,11 +70,11 @@ BrnHorizontalSteps({this.steps, this.controller, this.doingIcon, this.completedI | 参数名称 | 参数类型 | 描述 | | --- | --- | --- | -| stepContentText | String | 步骤显示的文案 | -| stepContent | Widget | 步骤自定义视图,如果stepContentText同时存在,此属性优先级更高 | -| doingIcon | Widget | 步骤正在进行时的图标自定义视图 | -| completedIcon | Widget | 步骤完成时的图标自定义视图 | -| state | BrunoStepState | indexed/doing/complete未进行/正在进行/已完成 | +| stepContentText | String? | 步骤显示的文案 | +| stepContent | Widget? | 步骤自定义视图,如果stepContentText同时存在,此属性优先级更高 | +| doingIcon | Widget? | 步骤正在进行时的图标自定义视图 | +| completedIcon | Widget? | 步骤完成时的图标自定义视图 | +| state | BrunoStepState? | indexed/doing/complete未进行/正在进行/已完成 | ## 四、代码演示 diff --git a/docs/components/stepBar/BrnStepLine/BrnStepLine.md b/docs/components/stepBar/BrnStepLine/BrnStepLine.md index 87efcc01..3f98843a 100644 --- a/docs/components/stepBar/BrnStepLine/BrnStepLine.md +++ b/docs/components/stepBar/BrnStepLine/BrnStepLine.md @@ -32,9 +32,9 @@ group: ### 构造函数 ```dart -BrnStepLine({ - Key key, - @required this.contentWidget, +const BrnStepLine({ + Key? key, + required this.contentWidget, this.isGrey = false, this.lineColor, this.lineWidth = 2, @@ -46,25 +46,25 @@ BrnStepLine({ this.normalColor, this.highlightColor, this.iconWidget, -}) +}) : super(key: key); ``` ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| ------------------ | ------------------------ | -------------------------------------- | ------------ | ----------------- | -| contentWidget | Widget | 右侧显示的 widget | 是 | 无 | -| isGrey | bool | 是否整体是灰色:线条和 Icon, | 否 | false | -| lineColor | Color 或者 `List` | 边框线的颜色,如果是数组则分段展示线条 | 否 | 主题色 | -| lineWidth | double | 线的宽度 | 否 | 2 | -| iconTopPadding | double | icon 距离所在 Item 项顶部的 padding | 否 | 0 | -| isDashLine | bool | 是否是虚线模式 | 否 | false | -| dashLength | double | 小虚线短的长度 | 否 | 4 | -| dashSpace | double | 小虚线段之间的间隔 | 否 | 4 | -| contentLeftPadding | double | contentWidget 距离左侧的 padding | 否 | 12 | -| normalColor | Color | 普通状态(isGrey=true)的颜色 | 否 | Color(0xffeeeeee) | -| highlightColor | Color | 高亮状态(isGrey=false)的颜色 | 否 | 主题色 | -| iconWidget | Widget | 自定义 icon 的 widget | 否 | 无 | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| ------------------ | ------------ | ------------------------------------------------------------ | ------------ | ----------------- | +| contentWidget | Widget | 右侧显示的 widget | 是 | 无 | +| isGrey | bool | 是否整体是灰色:线条和 Icon | 否 | false | +| lineColor | dynamic | Color 或者 `List`,边框线的颜色,如果是数组则分段展示线条 | 否 | 主题色 | +| lineWidth | double | 线的宽度 | 否 | 2 | +| iconTopPadding | double | icon 距离所在 Item 项顶部的 padding | 否 | 0 | +| isDashLine | bool | 是否是虚线模式 | 否 | false | +| dashLength | double | 小虚线短的长度 | 否 | 4 | +| dashSpace | double | 小虚线段之间的间隔 | 否 | 4 | +| contentLeftPadding | double | contentWidget 距离左侧的 padding | 否 | 12 | +| normalColor | Color? | 普通状态(isGrey=true)的颜色 | 否 | Color(0xffeeeeee) | +| highlightColor | Color? | 高亮状态(isGrey=false)的颜色 | 否 | 主题色 | +| iconWidget | Widget? | 自定义 icon 的 widget | 否 | 无 | ## 四、代码演示 diff --git a/docs/components/tag/BrnDeleteTag/BrnDeleteTag.md b/docs/components/tag/BrnDeleteTag/BrnDeleteTag.md index 4afc378e..8527c202 100644 --- a/docs/components/tag/BrnDeleteTag/BrnDeleteTag.md +++ b/docs/components/tag/BrnDeleteTag/BrnDeleteTag.md @@ -34,7 +34,7 @@ group: ```dart BrnDeleteTag( - {Key key, + {Key? key, this.tags, this.controller, this.onTagDelete, @@ -46,8 +46,17 @@ BrnDeleteTag( this.deleteIconColor, this.deleteIconSize, this.softWrap = true, - this.padding, + this.padding = const EdgeInsets.fromLTRB(20, 0, 20, 0), this.themeData}) + : super(key: key) { + themeData ??= BrnTagConfig(); + themeData = themeData!.merge(BrnTagConfig( + tagBackgroundColor: this.backgroundColor, + tagTextStyle: BrnTextStyle.withStyle(tagTextStyle))); + themeData = BrnThemeConfigurator.instance + .getConfig(configId: themeData!.configId) + .tagConfig + .merge(this.themeData); ``` @@ -56,18 +65,19 @@ BrnDeleteTag( | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| tags | List | 展示的标签列表 | 是 | | -| controller | BrnDeleteTagController | 标签控制器,用于主动添加标签,如果只需要删除标签并进行回调可以不传控制器 | 否 | | -| onTagDelete | Function(List, String, int) | 点击删除某个标签后将现有的所有标签,删除的标签内容,删除的标签index回传 | 否 | | -| verticalSpacing | double | 垂直方向的间距 | 否 | 10 | -| horizontalSpacing | double | 水平方向的间距 | 否 | 10,softWrap false 时 12 | -| tagTextStyle | TextStyle | 标签的字体样式 | 否 | | -| shape | ShapeBorder | 标签的圆角 | 否 | | -| backgroundColor | Color | 标签背景色 | 否 | | -| deleteIconSize | Size | 设置删除 Icon的大小 | 否 | 默认值为内置删除 icon 的图片大小。 | -| deleteIconColor | Color | 删除图标的颜色 | 否 | | +| tags | `List?` | 展示的标签列表 | 是 | | +| controller | BrnDeleteTagController? | 标签控制器,用于主动添加标签,如果只需要删除标签并进行回调可以不传控制器 | 否 | | +| onTagDelete | `Function(List, String?, int)?` | 点击删除某个标签后将现有的所有标签,删除的标签内容,删除的标签index回传 | 否 | | +| verticalSpacing | double? | 垂直方向的间距 | 否 | 10 | +| horizontalSpacing | double? | 水平方向的间距 | 否 | 10,softWrap false 时 12 | +| tagTextStyle | TextStyle? | 标签的字体样式 | 否 | | +| shape | OutlinedBorder? | 标签的圆角 | 否 | | +| backgroundColor | Color? | 标签背景色 | 否 | | +| deleteIconSize | Size? | 设置删除 Icon的大小 | 否 | 默认值为内置删除 icon 的图片大小。 | +| deleteIconColor | Color? | 删除图标的颜色 | 否 | | | softWrap | bool | 是否为流式布局true流式,false横向滑动 | 否 | true | | padding | EdgeInsets | 内容边距 | 否 | EdgeInsets.fromLTRB(20, 0, 20, 0) | +| themeData; | BrnTagConfig? | 主题配置信息,包含标签背景色、文本颜色等字段 | 否 | | ### BrnDeleteTagController @@ -75,8 +85,8 @@ BrnDeleteTag( | 方法名 | **参数类型** | **作用** | | --- | --- | --- | -| setTags | List | 设置标签 | -| addTags | List | 将标签集合添加到现有的标签集合中 | +| setTags | `List` | 设置标签 | +| addTags | `List` | 将标签集合添加到现有的标签集合中 | | addTag | String | 添加一个标签 | | clear | Function | 清空标签 | | deleteForIndex | int | 删除某个index底下tag | diff --git a/docs/components/tag/BrnSelectTag/BrnSelectTag.md b/docs/components/tag/BrnSelectTag/BrnSelectTag.md index f9ecccee..8ffca7df 100644 --- a/docs/components/tag/BrnSelectTag/BrnSelectTag.md +++ b/docs/components/tag/BrnSelectTag/BrnSelectTag.md @@ -36,24 +36,40 @@ group: ```dart BrnSelectTag({ - Key key, - @required this.tags, - this.onSelect, - this.spacing = 12, - this.verticalSpacing = 10, - this.tagTextStyle, - this.selectedTagTextStyle, - this.tagBackgroundColor, - this.selectedTagBackgroundColor, - this.tagWidth, - this.tagHeight, - this.isSingleSelect = true, - this.initTagState, - this.softWrap = true, - this.alignment = Alignment.centerLeft, - this.fixWidthMode = true, - this.themeData, - }) + Key? key, + required this.tags, + this.onSelect, + this.spacing = 12, + this.verticalSpacing = 10, + this.tagTextStyle, + this.selectedTagTextStyle, + this.tagBackgroundColor, + this.selectedTagBackgroundColor, + this.tagWidth, + this.tagHeight, + this.isSingleSelect = true, + this.initTagState, + this.softWrap = true, + this.alignment = Alignment.centerLeft, + this.fixWidthMode = true, + this.themeData, +}) : super(key: key) { + if (isSingleSelect == true) { + assert(initTagState == null || (initTagState!.length <= 1)); + } + this.themeData ??= BrnTagConfig(); + this.themeData = this.themeData!.merge(BrnTagConfig( + tagBackgroundColor: this.tagBackgroundColor, + tagTextStyle: BrnTextStyle.withStyle(this.tagTextStyle), + selectTagTextStyle: BrnTextStyle.withStyle(this.selectedTagTextStyle), + tagWidth: this.tagWidth, + tagHeight: this.tagHeight, + selectedTagBackgroundColor: this.selectedTagBackgroundColor)); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .tagConfig + .merge(this.themeData); +} ``` @@ -62,21 +78,22 @@ BrnSelectTag({ | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| tags | List | 展示的标签列表 | 是 | | -| onSelect | void Function(List) | 点击标签的回调, | 否 | | +| tags | `List` | 展示的标签列表 | 是 | | +| onSelect | `void Function(List)?` | 点击标签的回调, | 否 | | | spacing | double | 水平间距 | 否 | 12 | | verticalSpacing | double | 垂直间距 | 否 | 10 | -| tagTextStyle | TextStyle | 普通标签的样式 | 否 | | -| selectedTagTextStyle | TextStyle | 选中的标签样式 | 否 | | -| tagBackgroundColor | Color | 普通标签背景色 | 否 | F0Color | -| selectedTagBackgroundColor | Color | 选中的标签背景色 | 否 | B0Color | -| tagWidth | double | 标签宽度 | 否 | 75 | -| tagHeight | double | 标签高度 | 否 | 34 | +| tagTextStyle | TextStyle? | 普通标签的样式 | 否 | | +| selectedTagTextStyle | TextStyle? | 选中的标签样式 | 否 | | +| tagBackgroundColor | Color? | 普通标签背景色 | 否 | F0Color | +| selectedTagBackgroundColor | Color? | 选中的标签背景色 | 否 | B0Color | +| tagWidth | double? | 标签宽度 | 否 | 75 | +| tagHeight | double? | 标签高度 | 否 | 34 | | isSingleSelect | bool | 是否是单选 | 否 | true | -| initTagState | List | 初始选中的标签状态 | 否 | | +| initTagState | `List?` | 初始选中的标签状态 | 否 | | | softWrap | bool | 是否为流式布局,true流式,false横向滑动 | 否 | true | | aligment | Alignment | 对齐模式,默认为靠左 | 否 | Alignment.centerLeft | | fixWidthMode | bool | 是否为宽度固定模式,true宽度固定,false宽度自适应 | 否 | true | +| themeData | BrnTagConfig? | 主题定制属性 | 否 | | diff --git a/docs/components/tag/BrnStateTag/BrnStateTag.md b/docs/components/tag/BrnStateTag/BrnStateTag.md index 5a563544..a1ac1c18 100644 --- a/docs/components/tag/BrnStateTag/BrnStateTag.md +++ b/docs/components/tag/BrnStateTag/BrnStateTag.md @@ -24,14 +24,13 @@ group: ### 构造函数 ```dart - BrnStateTag( - {Key key, - this.tagText, - this.backgroundColor, - this.textColor, - this.tagState = TagState.waiting}) - : super(key: key) - +const BrnStateTag({ + Key? key, + required this.tagText, + this.tagState = TagState.waiting, + this.backgroundColor, + this.textColor, + }) : super(key: key); ``` ### 参数说明 @@ -40,8 +39,8 @@ group: | --------------- | ------------ | ------------------ | ------------ | ------------------ | | tagText | String | 标签显示文本 | 是 | | | tagState | TagState | 标签状态 | 否 | TagState.waiting | -| backgroundColor | Color | 自定义标签背景颜色 | 否 | 0xFFFAAD14 10%透明 | -| textColor | Color | 自定义标签文字颜色 | 否 | 0xFFFAAD14 | +| backgroundColor | Color? | 自定义标签背景颜色 | 否 | 0xFFFAAD14 10%透明 | +| textColor | Color? | 自定义标签文字颜色 | 否 | 0xFFFAAD14 | 其中 TagState 为枚举,共 5 种状态: diff --git a/docs/components/tag/BrnTagCustom/BrnTagCustom.md b/docs/components/tag/BrnTagCustom/BrnTagCustom.md index 36e7e37e..0dbae402 100644 --- a/docs/components/tag/BrnTagCustom/BrnTagCustom.md +++ b/docs/components/tag/BrnTagCustom/BrnTagCustom.md @@ -24,19 +24,19 @@ group: ### 构造函数 ```dart - BrnTagCustom({ - Key key, - this.tagText, - this.textColor, - this.backgroundColor, - this.tagBorderRadius, - this.textPadding, - this.border, - this.fontSize = 11, - this.fontWeight = FontWeight.normal, - this.maxWidth = double.infinity, - }) : super(key: key); - +BrnTagCustom({ + Key? key, + required this.tagText, + this.textColor, + this.backgroundColor, + this.tagBorderRadius = const BorderRadius.all(Radius.circular(2)), + this.textPadding = + const EdgeInsets.only(bottom: 0.5, left: 3, right: 3, top: 0), + this.border, + this.fontSize = 11, + this.fontWeight = FontWeight.normal, + this.maxWidth = double.infinity, +}) : super(key: key); ``` ### 参数说明 @@ -44,13 +44,14 @@ group: | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --------------- | ------------ | ------------------ | ------------ | ---------------------------------- | | tagText | String | 标签显示文本 | 是 | | -| backgroundColor | Color | 标签背景色 | 否 | 主题色 | -| textColor | Color | 文本颜色 | 否 | F4Color | +| backgroundColor | Color? | 标签背景色 | 否 | 主题色 | +| textColor | Color? | 文本颜色 | 否 | F4Color | | tagBorderRadius | BorderRadius | 标签圆角 | 否 | 圆角为 2 | | textPadding | EdgetInsets | 标签文字的 padding | 否 | EdgeInsets.symmetric(horizontal:2) | | fontSize | double | 标签文字的大小 | 否 | 11 | | fontWeight | FontWeight | 文字的粗细 | 否 | FontWeight.normal | | maxWidth | Double | 标签高度 | 否 | double.infinity | +| border | Border? | 标签边框 | 否 | 无 | ## 四、代码演示 diff --git a/docs/components/text/BrnEnhanceNumberCard/BrnEnhanceNumberCard.md b/docs/components/text/BrnEnhanceNumberCard/BrnEnhanceNumberCard.md index 507a2666..3554fab2 100644 --- a/docs/components/text/BrnEnhanceNumberCard/BrnEnhanceNumberCard.md +++ b/docs/components/text/BrnEnhanceNumberCard/BrnEnhanceNumberCard.md @@ -34,9 +34,9 @@ group: ### 构造函数 -``` +```dart BrnEnhanceNumberCard({ - Key key, + Key? key, this.itemChildren, this.rowCount = 3, this.runningSpace, @@ -45,19 +45,20 @@ BrnEnhanceNumberCard({ this.backgroundColor = Colors.white, this.itemTextAlign = TextAlign.left, this.themeData, -}) +}) : super(key: key); ``` ### 参数说明 | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| itemChildren | List | 待展示的信息 | 否 | 无 | +| itemChildren | `List?` | 待展示的信息 | 否 | 无 | | rowCount | int | 每行展示的item的数量 | 否 | 3 | -| runningSpace | double | 如果超过一行,则展示行间距则 | 否 | 16 | -| itemRunningSpace | double | Item的上半部分和下半部分的间距 | 否 | 8 | +| runningSpace | double? | 如果超过一行,则展示行间距则 | 否 | 16 | +| itemRunningSpace | double? | Item的上半部分和下半部分的间距 | 否 | 8 | | padding | EdgeInsets | 元件左右侧的边距 | 否 | EdgeInsets.only(left: 20, right: 20) | | backgroundColor | Color | 背景色 默认为白色 | 否 | Colors.white | | itemTextAlign | TextAlign | 文本内容对齐方式 | 否 | TextAlign.left | +| themeData | BrnEnhanceNumberCardConfig? | 主题定制属性 | 否 | 无 | @@ -67,7 +68,7 @@ BrnEnhanceNumberCard({ ![image-20211031143416320](./img/BrnEnhanceNumberCardDemo1.png) -``` +```dart BrnMetaNumberInfoWidget( itemChildren: [ BrnMetaNumberInfoItemModel( @@ -104,7 +105,7 @@ BrnEnhanceNumberCard( -``` +```dart BrnMetaNumberInfoWidget( rowCount: 2, itemChildren: [ @@ -126,7 +127,7 @@ BrnMetaNumberInfoWidget( ![image-20211031144401720](./img/BrnEnhanceNumberCardDemo4.png) -``` +```dart BrnEnhanceNumberCard( rowCount: 3, itemChildren: [ @@ -157,7 +158,7 @@ BrnEnhanceNumberCard( ### 效果5:其他展示效果 ![image-20211031144549311](./img/BrnEnhanceNumberCardDemo5.png) -``` +```dart BrnEnhanceNumberCard( rowCount: 3, itemChildren: [ diff --git a/docs/components/text/BrnExpandableText/BrnExpandableText.md b/docs/components/text/BrnExpandableText/BrnExpandableText.md index 621062a6..82ffb9a0 100644 --- a/docs/components/text/BrnExpandableText/BrnExpandableText.md +++ b/docs/components/text/BrnExpandableText/BrnExpandableText.md @@ -24,25 +24,25 @@ group: ### 构造函数 ```dart -BrnExpandableText( - {Key key, - @required this.text, - this.maxLines = 1000000, - this.textStyle, - this.onExpanded, - this.color}) - : super(key: key) +const BrnExpandableText( + {Key? key, + required this.text, + this.maxLines = 1000000, + this.textStyle, + this.onExpanded, + this.color}) + : super(key: key); ``` ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| ---------- | ------------------- | ---------------- | ------------ | --------------- | -| text | String | 待显示的文案 | 是 | | -| maxLines | int | 最大可展示的行数 | 否 | 1000000 | -| textStyle | TextStyle | 文本显示的样式 | 否 | 14 号的 F0 字体 | -| onExpanded | void Function(bool) | 展开收起的回调 | 否 | 无 | -| color | Colors | 背景色 | 否 | 白色 | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| ---------- | ---------------------- | ---------------- | ------------ | --------------- | +| text | String | 待显示的文案 | 是 | | +| maxLines | int? | 最大可展示的行数 | 否 | 1000000 | +| textStyle | TextStyle? | 文本显示的样式 | 否 | 14 号的 F0 字体 | +| onExpanded | `void Function(bool)?` | 展开收起的回调 | 否 | 无 | +| color | Colors? | 背景色 | 否 | 白色 | ## 四、代码演示 diff --git a/docs/components/text/BrnRichInfoGrid/BrnRichInfoGrid.md b/docs/components/text/BrnRichInfoGrid/BrnRichInfoGrid.md index 70044c2d..7053cd34 100644 --- a/docs/components/text/BrnRichInfoGrid/BrnRichInfoGrid.md +++ b/docs/components/text/BrnRichInfoGrid/BrnRichInfoGrid.md @@ -27,7 +27,7 @@ group: ```dart BrnRichInfoGrid({ - Key key, + Key? key, this.pairInfoList, this.padding, this.rowSpace, @@ -40,14 +40,15 @@ BrnRichInfoGrid({ ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| -------------- | ------------------ | ----------------- | ------------ | ---------------- | -| pairInfoList | List | 待展示的文本信息 | 是 | 无 | -| padding | EdgeInsetsGeometry | 字体大小 | 否 | 无 | -| rowSpace | double | 纵向间距 | 否 | 4 | -| space | double | 横向间距 | 否 | 2 | -| itemHeight | double | item 的高度 | 否 | 和文字相关的行高 | -| crossAxisCount | int | GridView 分为几列 | 否 | 2 | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| -------------- | -------------------------- | ----------------- | ------------ | ---------------- | +| pairInfoList | `List?` | 待展示的文本信息 | 是 | 无 | +| padding | EdgeInsetsGeometry? | 字体大小 | 否 | 无 | +| rowSpace | double? | 纵向间距 | 否 | 4 | +| space | double? | 横向间距 | 否 | 2 | +| itemHeight | double? | item 的高度 | 否 | 和文字相关的行高 | +| crossAxisCount | int | GridView 分为几列 | 否 | 2 | +| themeData | BrnPairRichInfoGridConfig? | 主题定制属性 | 否 | 无 | ## 四、代码演示 diff --git a/docs/components/title/BrnActionCardTitle/BrnActionCardTitle.md b/docs/components/title/BrnActionCardTitle/BrnActionCardTitle.md index 77801099..249073ef 100644 --- a/docs/components/title/BrnActionCardTitle/BrnActionCardTitle.md +++ b/docs/components/title/BrnActionCardTitle/BrnActionCardTitle.md @@ -25,27 +25,26 @@ group: ```dart BrnActionCardTitle({ - Key key, - @required this.title, + Key? key, + required this.title, this.accessoryText, this.onTap, this.subTitle, this.subTitleWidget, this.themeData, - }) : assert(null != title), - super(key: key); + }) : super(key: key); ``` ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| -------------- | ------------------ | ----------------------------------- | ------------ | ---------- | -| title | String | 标题文本 | 是 | | -| subTitle | String | 标题右侧的小文字 | 否 | | -| subTitleWidget | Widget | 标题右侧的显示 widget | 否 | | -| accessoryText | String | 箭头左边的文字 | 否 | | -| onTap | VoidCallback | 整个标题点击的事件 | 否 | | -| themeData | BrnCardTitleConfig | 标题主题配置详见 BrnCardTitleConfig | 否 | | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| -------------- | ------------------- | ----------------------------------- | ------------ | ---------- | +| title | String | 标题文本 | 是 | | +| subTitle | String? | 标题右侧的小文字 | 否 | | +| subTitleWidget | Widget? | 标题右侧的显示 widget | 否 | | +| accessoryText | String? | 箭头左边的文字 | 否 | | +| onTap | VoidCallback? | 整个标题点击的事件 | 否 | | +| themeData | BrnCardTitleConfig? | 标题主题配置详见 BrnCardTitleConfig | 否 | | ## 四、代码演示 diff --git a/docs/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md b/docs/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md index 4fb48c77..3b4f7453 100644 --- a/docs/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md +++ b/docs/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md @@ -25,34 +25,34 @@ group: ```dart BrnCommonCardTitle( - {Key key, - @required this.title, - this.accessoryText, - this.accessoryWidget, - this.onTap, - this.subTitleWidget, - this.detailTextString, - this.detailColor, - this.alignment, - this.padding, - this.themeData}) - : super(key: key); + {Key? key, + required this.title, + this.accessoryText, + this.accessoryWidget, + this.onTap, + this.subTitleWidget, + this.detailTextString, + this.detailColor, + this.alignment, + this.padding, + this.themeData}) + : super(key: key); ``` ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| ---------------- | -------------------- | ----------------------------------- | ------------ | ----------------- | -| title | String | 标题文本 | 是 | | -| subTitleWidget | Widget | 标题右侧的显示 widget | 否 | | -| accessoryText | String | 最右侧的文字 | 否 | | -| accessoryWidget | Widget | 最右侧的 widget | 否 | | -| onTap | VoidCallback | 整个标题点击的事件 | 否 | | -| detailTextString | String | 标题下面的文字 | 否 | | -| detailColor | Color | 标题下方文字颜色 | 否 | Color(0xFF222222) | -| alignment | PlaceholderAlignment | title 的流式文本的对齐方式 | 否 | | -| padding | EdgeInsetsGeometry | 内容的间距 | 否 | | -| themeData | BrnCardTitleConfig | 标题配置,详情见 BrnCardTitleConfig | 否 | | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| ---------------- | --------------------- | ----------------------------------- | ------------ | ----------------- | +| title | String | 标题文本 | 是 | | +| subTitleWidget | Widget? | 标题右侧的显示 widget | 否 | | +| accessoryText | String? | 最右侧的文字 | 否 | | +| accessoryWidget | Widget? | 最右侧的 widget | 否 | | +| onTap | VoidCallback? | 整个标题点击的事件 | 否 | | +| detailTextString | String? | 标题下面的文字 | 否 | | +| detailColor | Color? | 标题下方文字颜色 | 否 | Color(0xFF222222) | +| alignment | PlaceholderAlignment? | title 的流式文本的对齐方式 | 否 | | +| padding | EdgeInsetsGeometry? | 内容的间距 | 否 | | +| themeData | BrnCardTitleConfig? | 标题配置,详情见 BrnCardTitleConfig | 否 | | ## 四、代码演示 diff --git a/docs/components/title/BrnSubSwitchTitle/BrnSubSwitchTitle.md b/docs/components/title/BrnSubSwitchTitle/BrnSubSwitchTitle.md index 3db295b2..46857066 100644 --- a/docs/components/title/BrnSubSwitchTitle/BrnSubSwitchTitle.md +++ b/docs/components/title/BrnSubSwitchTitle/BrnSubSwitchTitle.md @@ -31,13 +31,13 @@ group: ```dart const BrnSubSwitchTitle({ - Key key, - @required this.nameList, - this.defaultSelectIndex = 0, - this.onSelect, - this.padding, - this.controller, -}) : super(key: key); + Key? key, + required this.nameList, + this.defaultSelectIndex = 0, + this.onSelect, + this.padding, + this.controller, + }) : super(key: key); ``` ### 参数说明 @@ -45,9 +45,9 @@ const BrnSubSwitchTitle({ | --- | --- | --- | --- | --- | | nameList | `List` | 标题的文案列表 | 是 | 无 | | defaultSelectIndex | int | 默认选中的 index | 否 | 0 | -| onSelect | void Function(int index) | 选择指定标题的回调 | 否 | 无 | -| padding | EdgeInsets | 二级标题的padding | 否 | EdgeInsets.only(right: 20) | -| controller | TabController | 控制tab切换,默认不需要传递 | 否 | 无 | +| onSelect | `void Function(int index)?` | 选择指定标题的回调 | 否 | 无 | +| padding | EdgeInsets? | 二级标题的padding | 否 | EdgeInsets.only(right: 20) | +| controller | TabController? | 控制tab切换,默认不需要传递 | 否 | 无 | ## 四、代码演示 diff --git a/docs/components/title/BrnSwitchTitle/BrnSwitchTitle.md b/docs/components/title/BrnSwitchTitle/BrnSwitchTitle.md index ff0ae874..22b5b092 100644 --- a/docs/components/title/BrnSwitchTitle/BrnSwitchTitle.md +++ b/docs/components/title/BrnSwitchTitle/BrnSwitchTitle.md @@ -31,8 +31,8 @@ group: ```dart const BrnSwitchTitle( - {Key key, - @required this.nameList, + {Key? key, + required this.nameList, this.defaultSelectIndex = 0, this.onSelect, this.indicatorWeight = 2.0, @@ -49,13 +49,13 @@ const BrnSwitchTitle( | --- | --- | --- | --- | --- | | nameList | `List` | 标题的文案列表 | 是 | 无 | | defaultSelectIndex | int | 默认选中的 index | 否 | 0 | -| onSelect | void Function(int index) | 标题选中时的回调 | 否 | 无 | -| controller | TabController | 控制tab切换,默认不需要传递 | 否 | 无 | +| onSelect | `void Function(int index)?` | 标题选中时的回调 | 否 | 无 | +| controller | TabController? | 控制tab切换,默认不需要传递 | 否 | 无 | | padding | EdgeInsets | 标题的 padding | 否 | 默认 `EdgeInsets.fromLTRB(0, 14, 20, 14)` | | indicatorWeight | double | 下划线的高度 | 否 | 默认是 2 | | indicatorWidth | double | 下划线的宽度。indicatorWidth 要大于等于 indicatorWeight。 | 否 | 默认是 24 | -| selectedTextStyle | TextStyle | 标题选中时的样式 | 否 | `TextStyle(fontWeight: FontWeight.w600,fontSize: 18)` | -| unselectedTextStyle | TextStyle | 标题未选中时的样式 | 否 | `TextStyle(fontWeight: FontWeight.w600,fontSize: 18)` | +| selectedTextStyle | TextStyle? | 标题选中时的样式 | 否 | `TextStyle(fontWeight: FontWeight.w600,fontSize: 18)` | +| unselectedTextStyle | TextStyle? | 标题未选中时的样式 | 否 | `TextStyle(fontWeight: FontWeight.w600,fontSize: 18)` | ## 四、代码演示 From 962db20163fa4f0afdb563c52682a26e3fd5228e Mon Sep 17 00:00:00 2001 From: violinday Date: Thu, 31 Mar 2022 10:17:44 +0800 Subject: [PATCH 17/24] =?UTF-8?q?[fix][2.2.x]:=20=20fix=20BrnToast=20textS?= =?UTF-8?q?tyle=20=E9=BB=98=E8=AE=A4=E5=80=BC=E4=B8=A2=E5=A4=B1=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20(#150)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [fix][2.2.x]: fix BrnToast textStyle 默认值丢失的问题 * [fix][2.2.x]: fix BrnToast textStyle 默认值丢失的问题 --- lib/src/components/toast/brn_toast.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/components/toast/brn_toast.dart b/lib/src/components/toast/brn_toast.dart index 78b5468f..d9a314d9 100644 --- a/lib/src/components/toast/brn_toast.dart +++ b/lib/src/components/toast/brn_toast.dart @@ -55,7 +55,7 @@ class BrnToast { BuildContext context, { Duration? duration, Color? background, - TextStyle? textStyle, + TextStyle textStyle = const TextStyle(fontSize: 16, color: Colors.white), double? radius, Image? preIcon, double? verticalOffset, From 8f3e2bd0b68234c020750ec934c61acea3154af4 Mon Sep 17 00:00:00 2001 From: violinday Date: Thu, 31 Mar 2022 10:33:53 +0800 Subject: [PATCH 18/24] =?UTF-8?q?fix=EF=BC=9A=E4=BC=98=E5=8C=96=20Demo=20A?= =?UTF-8?q?ppBar=20=E6=A0=B7=E5=BC=8F=EF=BC=8C=E4=BD=BF=E7=94=A8=20BrnAppB?= =?UTF-8?q?ar=20=E5=B1=95=E7=A4=BA=E3=80=82=20(#151)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/lib/main.dart | 2 +- .../components/selection/flat_selection_five_tags_example.dart | 2 +- .../components/selection/flat_selection_four_tags_example.dart | 2 +- .../components/selection/flat_selection_three_tags_example.dart | 2 +- example/lib/sample/home/home.dart | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index dff77517..af9a7870 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -13,7 +13,7 @@ class MyApp extends StatelessWidget { return MaterialApp( title: 'Flutter Example', theme: ThemeData( - primarySwatch: Colors.orange, + primarySwatch: Colors.blue, ), home: HomePage(), ); diff --git a/example/lib/sample/components/selection/flat_selection_five_tags_example.dart b/example/lib/sample/components/selection/flat_selection_five_tags_example.dart index ff1b2424..40295e5f 100644 --- a/example/lib/sample/components/selection/flat_selection_five_tags_example.dart +++ b/example/lib/sample/components/selection/flat_selection_five_tags_example.dart @@ -41,7 +41,7 @@ class _SelectionViewExamplePageState @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text(widget._title)), + appBar: BrnAppBar(title: Text(widget._title)), body: SingleChildScrollView( child: Column( children: [ diff --git a/example/lib/sample/components/selection/flat_selection_four_tags_example.dart b/example/lib/sample/components/selection/flat_selection_four_tags_example.dart index 807a7112..8cb13f47 100644 --- a/example/lib/sample/components/selection/flat_selection_four_tags_example.dart +++ b/example/lib/sample/components/selection/flat_selection_four_tags_example.dart @@ -41,7 +41,7 @@ class _SelectionViewExamplePageState @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text(widget._title)), + appBar:BrnAppBar(title: Text(widget._title)), body: SingleChildScrollView( child: Column( children: [ diff --git a/example/lib/sample/components/selection/flat_selection_three_tags_example.dart b/example/lib/sample/components/selection/flat_selection_three_tags_example.dart index c45ecfdb..31849c32 100644 --- a/example/lib/sample/components/selection/flat_selection_three_tags_example.dart +++ b/example/lib/sample/components/selection/flat_selection_three_tags_example.dart @@ -41,7 +41,7 @@ class _SelectionViewExamplePageState @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text(widget._title)), + appBar: BrnAppBar(title: Text(widget._title)), body: SingleChildScrollView( child: Column( children: [ diff --git a/example/lib/sample/home/home.dart b/example/lib/sample/home/home.dart index cf745500..5e5b2132 100644 --- a/example/lib/sample/home/home.dart +++ b/example/lib/sample/home/home.dart @@ -11,7 +11,7 @@ class HomePage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: BrnAppBar( - title: Text("UI组件"), + title: 'UI组件', leading: null, automaticallyImplyLeading: false, ), From f9bee7c8038fdd5cf2c74172cf25b5cb83c505b2 Mon Sep 17 00:00:00 2001 From: Sandy <15143015732@163.com> Date: Thu, 31 Mar 2022 10:40:04 +0800 Subject: [PATCH 19/24] fix set BrnTextSelectFormItem's titlePaddingLg doesn't work (#152) --- .../form/items/general/brn_text_select_item.dart | 12 +++++------- lib/src/components/form/utils/brn_form_util.dart | 14 -------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/lib/src/components/form/items/general/brn_text_select_item.dart b/lib/src/components/form/items/general/brn_text_select_item.dart index 262d6c55..975bfac4 100644 --- a/lib/src/components/form/items/general/brn_text_select_item.dart +++ b/lib/src/components/form/items/general/brn_text_select_item.dart @@ -157,8 +157,7 @@ class BrnTextSelectFormItemState extends State { Widget build(BuildContext context) { return Container( color: Colors.white, - padding: BrnFormUtil.computeItemEdgeInsets2( - widget.prefixIconType, widget.isRequire), + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -202,8 +201,8 @@ class BrnTextSelectFormItemState extends State { children: [ Flexible( child: Container( - padding: BrnFormUtil.computeEdgeInsets2( - widget.prefixIconType, widget.isRequire), + padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, + widget.isRequire, widget.themeData!), child: Row( children: [ BrnFormUtil.buildPrefixIcon( @@ -243,7 +242,6 @@ class BrnTextSelectFormItemState extends State { BrnFormUtil.notifyTap(context, widget.onTap); }, child: Container( - padding: EdgeInsets.only(top: 14), child: Row( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.start, @@ -319,8 +317,8 @@ class BrnTextSelectFormItemState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - padding: BrnFormUtil.computeEdgeInsets2( - widget.prefixIconType, widget.isRequire), + padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, + widget.isRequire, widget.themeData!), child: Row( children: [ BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, diff --git a/lib/src/components/form/utils/brn_form_util.dart b/lib/src/components/form/utils/brn_form_util.dart index 4dc2166e..d1b9b0f3 100644 --- a/lib/src/components/form/utils/brn_form_util.dart +++ b/lib/src/components/form/utils/brn_form_util.dart @@ -157,20 +157,6 @@ class BrnFormUtil { return BrunoTools.getAssetImage(BrnAsset.iconQuestion); } - /// 设置录入项总的padding, 不包括顶部和底部padding - static EdgeInsets computeItemEdgeInsets2(String type, bool isRequire) { - return EdgeInsets.fromLTRB(0, 0, 20, 14); - } - - /// 设置内容行padding, 包括顶部和底部padding - static EdgeInsets computeEdgeInsets2(String type, bool isRequire) { - if (isRequire && type == BrnPrefixIconType.normal) { - return EdgeInsets.only(left: 10, top: 14); - } - - return EdgeInsets.only(left: 20, top: 14); - } - static EdgeInsets computeErrorEdgeInsets(String type, bool isRequire) { return EdgeInsets.only( left: 20, From 46a3abe6a5a1e349274941fc0ab492ef67d0bff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E8=84=B8=E5=84=BF?= Date: Fri, 1 Apr 2022 11:23:18 +0800 Subject: [PATCH 20/24] fix broken line demo so short;update doc (#153) --- .../BrnBottomTabBar/BrnBottomTabBar.md | 18 ++++++++++-------- .../charts/line/brn_broken_line_example.dart | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md b/docs/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md index 7225d841..10c268e4 100644 --- a/docs/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md +++ b/docs/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md @@ -64,14 +64,16 @@ BrnBottomTabBar({ ```dart const BrnBottomTabBarItem({ - required this.icon, - this.title, - Widget? activeIcon, - this.backgroundColor, - this.badge, - this.badgeNo, - this.maxBadgeNo = 99, -}) : activeIcon = activeIcon ?? icon; + this.title, + required this.icon, + Widget? activeIcon, + this.selectedTextStyle, + this.unSelectedTextStyle, + this.backgroundColor, + this.badge, + this.badgeNo, + this.maxBadgeNo = 99, +}) : activeIcon = activeIcon ?? icon; ``` diff --git a/example/lib/sample/components/charts/line/brn_broken_line_example.dart b/example/lib/sample/components/charts/line/brn_broken_line_example.dart index cbb7929f..7a5759e0 100644 --- a/example/lib/sample/components/charts/line/brn_broken_line_example.dart +++ b/example/lib/sample/components/charts/line/brn_broken_line_example.dart @@ -77,7 +77,7 @@ class _BrokenLineExampleState extends State { lineColor: Colors.green, ) ], - size: Size(MediaQuery.of(context).size.width * 1 - 100 * 2, + size: Size(MediaQuery.of(context).size.width, MediaQuery.of(context).size.height / 5 * 1.6 - 20 * 2), isShowXHintLine: true, xDialValues: _getXDialValuesForExample1(brokenData), From ab7db0631dabc6d8e971fcec2b35cec26977c723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E8=84=B8=E5=84=BF?= Date: Fri, 1 Apr 2022 13:13:06 +0800 Subject: [PATCH 21/24] fix checkbox doc (#154) --- .../checkbox/BrnCheckbox/BrnCheckbox.md | 10 +++++----- .../BrnCheckbox/img/BrnRadioItemDemo1.png | Bin 5719 -> 0 bytes .../BrnCheckbox/img/BrnRadioItemDemo2.png | Bin 3666 -> 0 bytes .../BrnCheckbox/img/BrnRadioItemIntro.png | Bin 47715 -> 0 bytes .../BrnMultiDataPicker/BrnMultiDataPicker.md | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 docs/components/checkbox/BrnCheckbox/img/BrnRadioItemDemo1.png delete mode 100644 docs/components/checkbox/BrnCheckbox/img/BrnRadioItemDemo2.png delete mode 100644 docs/components/checkbox/BrnCheckbox/img/BrnRadioItemIntro.png diff --git a/docs/components/checkbox/BrnCheckbox/BrnCheckbox.md b/docs/components/checkbox/BrnCheckbox/BrnCheckbox.md index 8e355ccd..e9699d85 100644 --- a/docs/components/checkbox/BrnCheckbox/BrnCheckbox.md +++ b/docs/components/checkbox/BrnCheckbox/BrnCheckbox.md @@ -1,17 +1,17 @@ --- -title: BrnRadioItem +title: BrnCheckbox group: title: Radio order: 25 --- -# BrnRadioItem +# BrnCheckbox 多项选择 ## 一、效果总览 - + ## 二、描述 @@ -60,7 +60,7 @@ const BrnCheckbox({ ### 效果1:多选+选项居右+不可用状态 -![](./img/BrnRadioItemDemo1.png) +![](./img/BrnCheckboxDemo1.png) ```dart Container( height: 130, @@ -93,7 +93,7 @@ Container( ### 效果2:自定义视图 -![](./img/BrnRadioItemDemo2.png) +![](./img/BrnCheckboxDemo2.png) ```dart BrnCheckbox( radioIndex: 10, diff --git a/docs/components/checkbox/BrnCheckbox/img/BrnRadioItemDemo1.png b/docs/components/checkbox/BrnCheckbox/img/BrnRadioItemDemo1.png deleted file mode 100644 index 2d20284db8bf3c209e2d7d21bfe3cf2a1da33c76..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5719 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
    %pVWamTAgX>h>p(GQaeQyW@rZ$N+|)_G88JL zhDgdolRzLq5|Th5ug&h>-Fy4}`^eqh>~2EcWYS^Ju)8x zwsWIGCcoLse_qg_)#*2TTXOuDut39jOQ-Md5CBas13OO}c>kCOHP-=&tRZs{Fy?j{ z>+=-!vrC;;mK@mgED#p}TaJ72dcGI#>hKd>QVEnmM}C19OJ=F~Ie{Q|0}gCM74)`9 zxOTzQX-mqfK<*eT3QuV;yq#!y$Odj3VL|;RZ}@nzzlht@vs5@V11*>RDNa(N8zHDS z*6-0a6TBzdZ;AXaCIH?z?7_Pqd!V~xtMgnp@W(%EaJUWpYJmzV`u<~2(1~9pn>px_ zF&12CHgLE)8~}#P9HaD+ASveGvQ5HM6RmimSx4Qqa4zC$phqK|D#kxQ)rS0m9vmcp z@d@{}dbS-~KXbuz!@R*xhd;(}yP>kxH_zJnDHz``ys#>w&NmM@0o_1et`!eubR3@h zS|zO7*8=To_`x%GmAI>@0627B$L~J!z|cBYB>ITE_jxd3u!PmQA(rp>){aNe@K4N2 z!9D5zWoGpPE;@kkjkUJj%YcAK_cXUT=9!sxjOnYu9pdXIf_U9Dd)qzYV&VV^c{?2N zT=x&mo?t=QWe>cK2G$*J#r6fMI7*;7E4{F!%UD9kZTWFuL47L`B^k zJGPzHFf>KN+5#tTFm1XW1~LXI_d?KcEdwV${*` z_Iz$M97jIAUGWwb0Nac7PB}lgAcH{NxX+6f(-f!)Uijct3BNqyLTOcWG;Ur%V+mpc z)8j7{I#G2lJW2%D>iZ;U-dox`?5kNr6b$bzQB#Vg#09E6~saCiq znV~e)5ShKi2vhcc+6vjOK+7=G(Q{L5I7lZI22SMVMjhoP;St4MH&404D*|e=+$Q6#uccrZdBB9*sjJpJHN8|;2A=3)oY=(d;VLE( z&>2iQFBZCeE}u6-#Y0&ZY%Ve93Ex=P{M8Ns{psY;6Q6zubJIKpf4W1$hylQ8hW}-M z(9l$2hR@*AX!9Y1Z;tMK zv1U;TBwECb53(-Li_zN5ibw%M|KyQ8!Hu+ZfJ_OVFp(hY7bq!(+smrN$oA66`v1wJ zPJHlnJ1Xg2Nx46aIa8OXVXwqLXUZn)S!2Mg8N%fs2ch^OD?i4^s?FtQ+LItk3C)9&~wKuksv z`*@rwppccoFjgRo@3P|~I#DMr2#SatXTQ+Uk6~Mgm&{+tc{+R+%fn-=-)FFN-Nf+j zCErkbOX1Om0Lo$2F^^8~!xLXbU6qU=l1lCnBX#%`bitb$69bc57-^rK%cf35#BFBC zkL7$3_P%wu0&B!QiCXW(f$RVdkMW9t@Lgo(sigl;k~fGPEy^vm6KzW2q`7z7@ZtPa ze9C7RPw#2L(%mgcXYKy`2YX}komO(7_&dtvN&e|X3*J3rrVPFZ|7cvKwAJJc^(lOS>}-bf-j^&#!v!C>aa#RP14cr!#WTy$W6?Pv{B} z=2*pgyg4)KQZbMY3W^}C>q**vaM+2Oau0s&XvIo4c*Zl=iZZK$^R%)ZEHZPI!)4)5d2nq?R?=Y&ooMXigkND>f>hygQV5?@?usB1- zPmZ}z#}MD(*0F4g#YgmtMYDmN5)k)my*&mEzn^K=$Xq-t}0O$h@Zd{r6oB}kF`J&06o?<-LtSH0J_J{ kJyuH+06o?<-LtU&0)2{&!s5u<7ytkO07*qoM6N<$f+)e~{r~^~ diff --git a/docs/components/checkbox/BrnCheckbox/img/BrnRadioItemIntro.png b/docs/components/checkbox/BrnCheckbox/img/BrnRadioItemIntro.png deleted file mode 100644 index 633d0a5abcae815696345d5293bbb69939088f24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47715 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

    Lz%L5sfvmMDZZEka4h_ zvq!?T&P7J?S<%MMoexd|o_oOggD*TgCm7_AjokQ}eAt+3%9<%E!hL+j(cqBaN#T%R zG5FUa3{UpIxD@<*IK+R^5#ZoLE#Z*M{K=Z76F}M(<%p)sXG2mhUnU@~ zc$%Bka)5Tyoxz)Y8@Ocng7_lmdqou5OR!yL9sMcIBpmX^_H6@jLl(E~-ee0d*o(*>wPI-j1plE(QiV%F{->3H z05cha?589w$lLV)HZS{W2IYT6NE$5T%H-DAOcieakI;WWZY=k|I{I%(qamXBQKo_1 z$c+E1!7HKuzir}aawElAFq74P;Qd#>{v|2SA|LDjQn{8oM$&jWTe17U8pcS{+WuRS ze^p4rdbPkPiYHqH3F3b%{C|_YTIT;LlS~o$Kir<*wr3I%_=}HU~KklzH4GKCY@xxkLU3_i3krrDicT&L?q`LExj!DEiEgQbw@->-*V5bJXb26 z_2Y3jzV#W7X{ilOB!CKNv=yC7c`WAQYu8iAyv^$GM_kgOt&7laZVY5T_UmoS3QFtNjW)|V zV3zN`Bn*s47+MoSS*4tb8+%F8qd1!a2MS>($2X{x4(~cLbc+z<6EAP6e z&36iU8g|c!gw7YZSDSr`mTO(CKQz@X`(wVM)e>`3H5_6$%5n7r&sz<7+Xf=b6ma|D0^H z->{p=64^)>aH~XN_y1cnNKqDO*&H6yJ(lx^6hXDqZx!c<7$k?;e3N-S*x9l&s+i zl~P~{!0%k#C@sW3qwbTt(ct1_X&!^?5h8m+_R z_Wk83n{`&q!%5xbf}rfD5HSzvKKh1Z>)l)7zkxWy#m|RBv9#mc(IR?``gzxsWt25G zV)#)WHlo0Hs~t}_D@U4>nL^s;o@TiyD;@0*N0H7Hc=9cT@Z135A~s$OL9=Kx>^FQ+ zs`mi_n|Acwa>&w~%bc>`&sjwQXSd6Bi~lk5VA;w;<`D6{`L`!Ph; zxBv9HKAPh`xoo!MZ!eBW`4X|34HDmY0-E!yZUFYA9_%$Nk{OJ8!#E3Z%>6 z1+^jNt$bM+Al->zEA2k~QxMU>subsxjt`Jdso!@kAyPrhKoYafFM4>w*FAVi?tCnW zLs@dTKp;cqKZuRUuB=-3eR+cT2HY*MXp{M;1@7SbvgfLhO4%>1w>i}PiG*u@mk$=| z3g|fRc(9|F9tzISz+>N=P4z~Cqu#zFH%aGrDUGYkla5|E|9;@-Yq!?%U4t_wvT5VF z^YY%ip{dpF{98FP9(pD$*5?TEDPKrl_Ge9RsH~dW?MDwTrR&z^>mC#1JJMywR=n!y zWDb+PvpP_O@HA)}9(pJ9T!d-DC9iqhM)4Nxp3U&;Jr?8=-K>jsWJnFW% zY*Z+j9r5aHu}M*4y7o8kkb_D1xZjSR=mBd5uIW^d1w9LEbez>>lQ% zz^`_t+wVPB^49wqIEVIv=IM!hrf$`QRuz^@$56=i{bAQEb~cr~5k{Kmk(m{PJ8PBlBZ`ZPMu3B z&&Fjo=TSWC#ZQ2zchH+MVdQX`-8R1 zt7FKU)lbhL!9%suTHOfz^yh5;D3`?79r+M zmtOs%RXXCri5RfB3~1UZ*BNw2U1Wn&LLb-;5V$ev*YTAl8>y;TipbL!k?H`sT(=gs z52QL2RrS7m*mY5)K-D>Ek6j9xXX{gaSc{;mnmY~Dv<#caxU1#}owE(};+WXN_plzA z5ILe|GZ`U+x~r*T3XnKb}lwTuyIb=>MNf$_rXz8Mr z3*;JlaDgs~5vN4A-XfXQ$;wyzK5kPUoBNM-xq!QmnZx=Sih=Ac>-)UkJjBTEfs>JO z+gk5Slw$~q6Yu{<`|6kuFlQ*Bw$q|PM|R-GKH)O7oPFqSM)`f1z5OdS`RPr%6tCg# zrl`KsV!ONU*JR5K^u00TQY;H&Q*`tP0EDS zKUwNUuy5ZGkSEOmx{S~I=0z`mVY+dVjo1@8tB5s7go z7|TPZ$buSX@wm5F(*i6W50!mO9f>f$Ie!-sEN7T$MI0`j`f-Cfr|E4ZB7+6G2o?_qTXrs1BdvqO z7zr>u(4^3<_tmT0pG3+BK_xq1=bGA3{+mG&;dOp}O{+9v=cIHz#?C)ep#fR*$c=sK zx@3SL{?Wp!=k2j&oT&?!jRi4YqT&JAf(F8)wH9wb~5|hk45~Ae3|$_fG4t? zEr-;}7LXyrNAq5d^0H_(ay;QtSpH^S;cePAD1bBi>RKD#SL6JJ!>LsizpuQom)6@O66!??&Wi#) z0kAOLh4~q#Wb1{r*|ad|VDKBFhz%Rx+O__gtg-vbX>#>P(vzE{@!S4<&I)m)1;Xh~ z1uUs<{cOj*Z^%DT_xp34WXz}m80PIx(#vmZYHX->G=CP5!EFttlUF)Oq1a&RY_xKv zzUL~>08#*Q{3O6)<}pqQ>Fqbb^ds-BV4@?x{7^v+R{fH0Q7=6DmL>Z?%MLO0N?k6F z^sv+~@hs7jdURlP?oQZz)koo8d@LyM5QfKu!!|Q3O0bVM18%3{Bgl3hbc=wq z*$nK?`*HhHmRnlV%MoJ*(ops(rG2WR%i`pU**EV7P`sFFt8eNI^2gZ|MO2p@$saaA z8pBHk5y?lq0iS7rmpj9xV=?q4P5R(h*VdE@|1jNVwzR z#6;?ZIq~2%X9HnAm+#3?;7)p0=9}xIcL6C6rWdvwNtppqLne?QRu8p~YmrJ84!G)^m5smv!kCgJ#pQYwxXtw_l39S|458zxy#2B#+X z`C(y#SIxnGh-oP)#i%Gg)krtw{pj=l0_0&m9&uu>#6p8Ah(m?r^RZ5G*kB62YDkxZ zHn+ajpGZ6ma4bbY0zWrlQ8~y{F8$K$yj_3gqropR#{pCv0JFy^W{sddW!i$oW*p@Q z3$H>7pTi5JBG3%Y_RuJI)Q(wNoC zRg%Key62ST)cmbVX@!~(7N`TS*eaBC_uP7(ma(f?bX`E{&1c_YoyR>ry3F?Rn(NUQ zHk-8|&732k;6Aa$8Wt8#Xnnw^F*4pxr`j_Y`ndL07) zFoQEw72yCabyPJH89=si4jub9RE>4Q?h+XQ+dZ~?(GCvR9qPQP zfxyt`i#cPeIIrwB-C3&Zwa7o$hpsmx_oW-_C}M(UAGhdemdN@>;{0)+4x}d&4eC1i z@lJp42oK^%JO1&!WfloFE~M~hVV}l1N|-Z8d0k*dE?FLERm?Usm$eV4P$7S&r15xT zNxFY|PfWPDA4vFz*KPCSQMw2qeb|xLRj*2?wOmQe6%d#64Y#?us0I`4O`~KPR%Sp9 z2+H)wiY0VmvI67~TKn=2bh?vqVQ@)_)>+Dd|;L+c4 zGed*~em!vW3_W{YiN~okPhv6`?RBc|5xrVua+K$P z-IUZ>BkF2J+$$t^J|A~h-dG5l|7b@m*UH5U>=mv4#IJ&I#^!rJdSt_gJt@z}!o_pT z=MNN5Z|UA%uISw)NxkH z->fD=o$(H#xXU;6(4caQZKKJNUL~(BJkCRL4ckaTXW$afC+@Yg1JuO^M0f+^-Q%ya z0?|Sq<;!XT;igIBy8_D>51flmr=1q^w@0_%`Oe6pYIM=4NG*&pT^JZA@ar_CV@ zzWLQ8wg3~Z*d{M9sBBlheF6%(77%Lj@Cm_7n?YgXk|9_-VEORI>ohU+w0DN~gMaF& zB7iv(ILU&eA0uvTsCfkJ;fS0=pe2XH^MH}#=RxrnCu@$@~b7U6Ke?;1^@IK>%B z(g$MrSoY=}yG9|8@7uK>&q>%K!R~{1F-=Xj*FfFQE4Q$cdC6xba-f*^>t1?kWarIz z&s8JGTg}aKB^a%xbG~%pe0bL{deUif6v0N@q=9J?=JZed)M#mz&2|iQo6F3Hsq}f^ zO?rFYAC6cw*z<<2Cfs+h<0=hv+poZu(=Gw6T~w7r@~)h1qX`qVLa@wrn5k=b@8&)+ zAD%gvTTl@Xx+s7;gB~%BmXH^>qJR!&%j`J*Y;cUZ(j`wG*Fp~5^W($!bn0_vN8Ilk zI{w4Zd7fUXm6%QKe#bgxS@yi3zm+ma63SnnYI;c^3zI;(9>isH)88}b83FI{8tVi%GhCdrJgJ7H40v>? zcqHg`Q^p?>iMX+K`Zv6T;yX=iM^0mke30|v+59bdjCEhy=d7O>7wP46IlHFbmt{!sguo0pQ)c_m)HcXGfj5!OUPP8TY;-oi!@e|?#R^Wl+l zV_sU1unrDqzQ`kbwMC=83N3fvzvYNOT?GXAY5krI@L$fm@mi=_TXXG}z|a{O zVRo>-FDnMrUdH0m!McLE5_4^Kv_?FfmRpUlwo+?V?k;!bT?WFxSum*{iGt?%^nI#< z`Y*r>-8G^zB9ft>H?{KzZcjZSOOBmyP1uhLX9sF0w+w9x^@S?uzw+~BVvq0#l6e{H z50o@kBR^qU6W6&k=Cnh)1|sdvWwrX=zy~&Tc|N#4BuDKZr;+p*LK7FCON0vSh|99< zRrb9dSBnt6ZqQVp&~l!udrX)^Z9|2E1Wn1OrC~cYfv4Ke=GR_fI5tTeTp>}GnxsVo z0_}5YAMg%ByIQD7QGSb=izdCuUpS6s5T<LQ>`lw4-enl=^L*7+xSFlzr{Phc=KHzw*?wMoO*;B&LzdW6WWx@d(yjn zWK$Ia&d2@$%PNK-ET4~D+_)J~Llpc{4R16(#2}1#sjjHQAAwm?w&cBznDVVC|@1XJ~ z(TQ0Tur#iLa3MkONbW<%viu1M{P9#Lll@ z$lTh5nnK(IO8)B*-LgE31l4r-Ge6#dm*T_hCr#HG2zckgs&9u>RN}GVz z#^ukq(v&WyeV@5=m2N79vl_H~59~b$@I5pr7k3FBaix7eD87r^f~1PK#eTY(A(NS} z5G0#k=<;tEWcK-d-;_%m$x&}hP%~{?t z-Smjk>3HJ)pvnP7$~m#^JZI-*jg;8H!yYcBRQ*{W)NwXDIt@yy^S;qvUW9itc9Kt} z6S7f7ZNF~sD5T^pnl!{bu51^y@zDa=QnQo!EU34>TO$n&l3<_Wqn?;eHRd#KMD5Mq z^~P+xqL*>f)Wdn!@P%q{$={eMT|yba21|YL5CKEcGLZnWglIp5h91m0gQohCW{*g} z_rRn8R&xUBgX}2m?%c+LvGt*E>kRx#!GYK9WS?~0SOS7uP7$}@hRG6o9O9z7rsdn& zi`#daTbi{yP0y(e=e4vNQn3%g909_7bT1)>i&i=vl_Xbx1S@9qp9LrNwug#|uu z&zaj4rXlex(y;Ts!LCf}rX7b_N~2rM>y2!G@gZI6Gr#HQUM4C(jCQV5dm?px>tbE! zy)rV;d%D}O5BoLVXC<~nHs7rIr9zo(4$q`l4$iC96Z)gsw+00$wn`lEMZm6!=;6k~ z#n?8wmV3f=u#4R@1dB$%8=h=mJCeX>!!GQMW0i(@frHg21bSn8TDATdl$HtcH)*=_ zz~pNEA=uDAN6vlK3X=i@S_-lPqOUOS}@Mq50K5%Cj3JvdSp&?DDKs{%t z!lL2wgL#aEee^|m*sDm@YV#)*%i@aa3hNfppom2qNIDu%;nfQ7rH}3ngFC-6!r!+a z*o01}=lBCAXpe9|DP;<3^@m7&XB(_4PbBv6wqJq7A!X6_j}5wc@O={tqW$a0QB{Ao zKz8Ra0Vrxmu09ySTy|g};G4xJGan946h&s5Sj@qyxUw;~e0Dr-4+y-}ea-n}+?v~- z@1#7S9Bl_5fUOhvmeCsNd2TA}T3Kjtu-cWzDUD1tunOxL%T0M3{~Xb9s{#_G?G)(A zsp;|i;@`iaX)fy@xNTiV9*mHXxCz23#E?z~vu7LeyLJq*&JLYA8B&b7OcfLoMHl+T zmb+}P%|BMO%ZJ!3$=>o;}_~6a`Z#7Vo z2Fm9`iZXQbNsw-U$)m?jNsG-P9=bWpkkeN{-R8hFhI4v&xB1??x`BRd$%$T@0RftF zCA7Y+RXz;QvOw=LdjZvZBAFGt}rwHFw9y9usP}~Y))LQ+~(Zvwm(W(n*KA$l< z4u>6LP2P@PUA;lJ=h}!tB|F6f;7a)TuUe4N6f&>pVmhn0i+6n?wIrSd4|{ z4TI@i726W$gVcm?W!NmGplugYOxq$0Ck0-h7P88H_Suy~`@4b>j z!YyKA=TSr#OJ>`36;oBE?mruC>=)y!ZJ0mn(2I;O>L;3X55u|-lX1alnCVUWa%f@L zCIJe}8#8t7WC&UM8GZV(I?TfcR_dg@s7$DC81RrzUwxN2JUC=KlO8LKB06>;T6zKr zK#1=bnwgkVeJY~bLLnD?=Imw=uk@lZ)Sm(n-=(jCT4*lrj80|lpP+)#bf5`=emq1Yyr z@1G7CqhMg~P;PYhBXceopN$k>%U$r>$Ke=dk?zkn4D1Xgb(zA z%)eU-%O%J~BvsvF4Edd*rtvZ*jjQjsDW$68toTevYf|zB)8}ZBK_{`k4raa1hgrB$ zN!dd<8lgKji8D*)Y8UfvfzIDTy4=9*x?xo>n#`SN)e+3qJxzZmG^VIle(OJbhZ`Ulbg57W{h|j8%Z>kXqx0YL{gupSy&-(M?DsI1xm1!MtN|kBa5RG49p1Ks+E~d40i|G3 zbsV$Z>~KX6Ge(e83sgGIIA=18_(siVR<8GgLZVz_6)Qc(8yowW)^y)w93tA&ZQDQZ z*;_p~>QV?SO-^;(q>p!rWzj-z=q-uT#Lp%Y+9hE_zpEjkW5kHg0pIIaCcWG3*4n$g zmu{jy>NlMZyj?qb;Fm)_6H=gwP(an12!nr^LxmxAT+JgAJrzX;V#!u>gK=;59*&Eg zY&Bx@vH&}m*7CAPQg`!{>dTc}8|L1y^7C`WB*HQ|&Lma&2X{2#n}Vgu-cB1<$0t(e z*(0fcMlf*Pfag7?`i2`}kvT1~s$b4vmoqo}niFs{y|$a}E15fmt!6*_T@8qnWpr@n zQ8k&6&zXqQJ_4bMf>Lt9665@IJA^C zOu%xk0C~&(-lXXpi!9-=&GQ!H5_DI{;i8@{XOTVPqM>Ohg>J?Wm_snKt=hr-KFWo= zaj8$Q=iD1QziiZWT4lC`@)W7~ge~on{Of?&*l&aHvM+Y8M&eX?C*FdYa6VDZ?saG; zW}U2jr)MVIltlm7@MVx9jbw8GdFMxpBd&1FKXm#94{N&$J)IryRWxmsBC1eu@p`QC z$nOK`0^g@gdlP+qBpk0W;dk}l(&cqb`q@ngs5R$PBt`MkXqi9|Jl{TH`B2D8q10$B-fbAGEu6vej% zJrlnj3Eftbc(WY)(p&msXTEZ%43J@k`yM(awl*zwOB-7z3_l|m)iG!1E(N5M_E87% z8t}&vmFe&FBnNKP6+Ip2YX5X{6*?I$*W=q=CMciVg{a17aoLetZ#0r}&JBjJ>O;QU zqF@_xU5+g&d{~(@yKX;*(9{I-ajQY7aaseSxkJXg*iY)M2ft6{!HTY{gk7%-yK-+~ zMjgF}uJ>NjusFqDzcsHutMtQ->S&Oo1dr)*kikSp#m_GCVPo^@s!N=i6_-$9Ah9yc zYU%B6l&)v>{ndVFRXp3R&a6^=IdOcYw3V!>fF8$K%>HUa_mDkx-$sU^u{S~*q^1tq z&*gF1`??Tv$5lWWFspvUhq7pwpc(UM(uM`q?GW=Jp-{q)cX1YvVF+PYf9!%s6TBo9 z<+xz}oYwD#+9((sEy0<6Kz$L+rTUVckBKVD=pwhp-YbUn@tA+DzTfe8V_8=3&rTsD zCxb-YBlMzdibX)>7oV$niAGOe8D754k|+R+R{FcaQHN3qP!L_F2rVfZ_5M#@3pYCA z9$8;ahYM>eTY~E0D>Y-ENcQ67iD?S+#aPt+^_!u|SSQaTDX9vKVl}rml2 zZjVFeXfI%lM)maIMIld`AENdgkr;P9hYcqLR&5T|NK5seG7E{VIK7rYptlXXxmW6t z@Io}s+HT=~&OQ`-W-o%BogO?)wVI_z#XF5)J$!lT7Emw2{n|Np*@4b&kXS_S^u*H- z;n`(l(hi25wc0bKLLHg612R0uENz^J*TlK=GETtl$I%wI;|i-Ui724lNb?Vo!45$rc4C(Mau?yS%fxb_q|%_D)A*+I+U6I{XIPc5 z%JbZ9+5BH1%~2+si;MPqdkt_Kiu0T@s*-dz5m4gR!cF6i={ArO^oBlYNG_11^E)~8 zhb4QSD&->`wgztDo1%da`t6Pll^0Xv`tdvYfTy@@qCPM)>_ZW&zb~<_*X|KhW4He= z#Y3Xg5^%kNMYKOjnRU%yjkFz!Pjh8LXT4EM9oA$;Wc)K+GDQ0$vAxo%Duq*G?Gdqx zZ{Cfo17I=FhFo}5;&vL1lWVk>;9T9)-eh%EjWbM}H(k#6R+k8uPPT}n_{R2A3jlRUG5#xDSk8iVxytsM> z0)ah>0VR?}T^bL|pY=a{sOxBbKFaZTyHgiCa^3sy(@!>YU-n{CIFNDFSoSc)g;PVNh!^N#oKv37LTo@siM?F?1HaHF|GHTo|d#yRoXDjZ;abPIq89nq# zqN%k>xJqV`o8RGCbt&>D_{vu^-XBMYNG^8LM*roSfu=MaJ~#JeXqv}OE-jt@=A7Qj zWb){ByMq0}9oy`JtMW8s`h{b{(}nU{7bJavbhU0BI0F9D(s7$I`}1dD)bq}6)~BjA zn4E6Lbm4_IF!7*t4Le##p>f@PJL>1>T+=*Yxw@5dO#4*w)1bT9X7UP;RJ(^B2#EsF zFsi>#Tjoz4irDZ2PqHWbr>PAhMo!n>n#QY_&9>;0+-v9Uf0b z7LJ!Ng!gq^53?A!o`)js)u4F6bBARI)sEuuDq3X!0FlgeonCC<6%T2oF?|kTSp6qq zT=@xc|V45(HqBH@8_)| ztW6hcv0;vYx>z6WBa;s7>{H*VlMbXUVAGZmU;a{`r@u^jN!q>yTEf(+AJ0n7vM%dI zHo5FE>zNon>F?Ahb3naMFsIbTCt4g1%@DjAP7L*VjZZV4WKR03+OEghVRPb$&pDKF zV%$Q*tBvjSq$Xvre);e~(I3m#MEnmRXlU6DByTl*yh-HxMf=aH_G0$=(KL#yN8#hI zgV)0cdEJcqk4{E^B%jpY2;7O4k5fK8WSJ z^J#y<>RCM|k_+fD;$(5`NAU0yuo{ne2*?(O!njLuVxM*5kN-h}w;@ksGI)n&(Z|Qn z;$b(+)X7slSLKA8f@Ru8*k=o#=+ua7sL}x$k=s~dJTz6G^ni#BjcZ{^64%T%KkGcv zdV5zm_1Y2aN!eG3b(c?(!N~&o!R`3m(ImA zQr7oAa@k$sjjw6s)sRz4bvyt7m9eI(ZD-_?I@fR$V`dGW&x%W} zNQhxQ5BEU|H%jw0Y2<4*3>X;4|FpTgYmy#YyWZJ#F9Si>_D9YHB)Il`&ED+e-A?^> zWb2Tn+qn0Q@AW6tt_V;#Cm@LyxLchVtNhg|!+8Iorv%y<#mc_8h;2GtzC-DVh>Y&j+UsxEYGWDl~HM19ag!fTnerl)H;(B~%b<&A0QH4unwZ*+f+Z=>Yu zW8ZnXF0KD_NG9h@JLzp3lKLIh70|h7BvJDsE&4emvV>TE#5w+))k8m|v8ER!DUrIM z4%u8wteG<3y`~iEbv1{z#E{%Bm&%5^fi+nSvM%dg8b5aht&K)#^3fTOWYPKMIX=Ne z1sbA#wD?4^W0q=aGJLL@K2JQ$<22q)ytL1@{oNyTVLo+` zQ#}9l`1*VdCK19touREyTZoHPsxrU40j=I(nSw&n9UeOy$_-%L1^(ALr>lYSO!NJ^ zGNv6ZtQg7#XQ;(UX_V-U%fNKz5BqRxx6x;SPxygDA1w1M;xNJ@@XDwczkDgXrQtI| z)}~QG36G0I-nP++fx&u!#(6s$PzEJUjC0egR`A(~?e)aJyv{^(+7i2RRxW;64`Fne z6BLPf!}ygZOYd%8aR*HjJL@n%#HiwyZez4 zpF_9pRXok0irGA-qDGfYu)6R7AY+(1Iip)X4RAtQ+4*#8f6QBR#4c>MYt|wX*$Lqk zZ1hPmPnSC(OVT~rJv_2f=(93aNH|kAW@owakH2(gSot{cK-s1*Tj<$ljymjq*1Uh@ zt`%kx^S#D1JBiA{$8M+K^S>e+l*e^^BxGvYub;jmOCe@n?Gx(|v~|EP%l0zdHcCc^ z(o?kv7>ApOx!yZ402+3svDK@Ii1A2U2gbR_@aI04&Xq-PenBlG4yd{*Ruk@zkx zBs9Pvf1&2T+>oIauaM+N8R!S%+E+oTHj>7~7&hNGU*+B|n3Sd~|!ADz{BB6H7v zGoF8XeCnIG4*oMIJ9Ic(R5r(DWwM!Pj{Fz`^UK!@jG8+s->s^8 z%?BI)^gUsryAM-(-eay94}vwMt)Y?zv8!pRrC)+)_f>5Z@pi<>Wd@p^Hs10%1=_v+ zZoaaY^3vezBnCGP=B4pXhvF^A!Ts?%p!`4Vy=7QbUEBDLFu>3=q97riqI60Q9U>y# z9ny$2L#NV`f*_%QbR%6-(%qdycf)^=*L`2la~$vc`Tg?#Ke7+j?6vkf*IH+--|4u7h>~BmRmVa6Iq7JjH+W42<4fM9lx$4=H;zTWO47hR`;TN#qwL4D_zB88t7d{^T7WuU!iwvwnQ z&v1ddJZC$+@&(lEO@*2fox0SmjL4D(7+MrLC#!y~<}JF9nQ?3XMKut7LvSIJ6~ivS zRSj4rq(Ah#1NVBA-qM z{DGIYy25&#Ue+O$f<(I6Lq{?-_1MnVc?VNsIdA6Fnp6Br7ffZtCZf}bg1xU=ai;UP98ap z)|I4~iZldLQ89Ebo55)DvjLj4+2zQhG_k33*~amCsk{u8kbLzigQ3iA|6IEGa73h@ zkiezGg@5G0bXR17aaX>6`cxbWjt(zFu6u|K-;f4{d$&m<>hroU0}0}MSC#Nl*57Ry z_%e7Td-~}bF*iCEkJl~(X+9hNPlJx_GS}R zWr8(93~v2}F833~bPMlP0$#lykQLKE4Z}|vT`;w_o@Bj@=y3>kq`Wcwo*P*0zSi zFY2eWET-q$7hBSRNeRDDKEAp?_ke?-4}3?;`PwPx#G?yd2d?1gRYaKthPgO>p}6M9 zku-NT51j6f*<;>a4zDKKm{df>O+cAbExh*AwlbcQGt~F0ejRIp*3LWEt_p6_gkpIg zAqe|PJC;^y+0UwYP$_P2O+N=v^2UtWDxEyggS)gBBuAp6+>BlVKCH3DnqN1@C?Y41 z#6+()R}ib{U|WX&E|c!WGG#ZM+16ZO)>f)XENz>GNr$H*C(`(fPvO`KmjiKP=jr#C>1vco zH3Rrd-^lA6nuG1GBENq4Y!J^J;ENt<^VIta_VmPfg^-ZYnG$+iD4u%X2svTX5uQ^a zi1i;VrS&Q9z?d(|%jLT=AnO`BcgW<^qo864qGcldoWw}slZnV^#5|Iw$4Q+MeSX4M z@Du?K$9x=u6Kk}OYqMEozgaXF`lEb|*;ZS2{+q{<2Th4xSO>cv+Y=#A#1!Yn^mnU( z#5T@o0nXPUZDL}$sxaS?^|<^1kxSL%3&JRkGXIj3mmNkQ*qa3)T=ZO=rXArb-@tnO zxemUG#kxgT$t}N!%gPOn0vI+JoxcVTkcT%zT71!nsK)Z)C2uUe)_uuSV;4`@nNgEo zZc#zN!3PPowHQO+h;=auZESsTz*3! zPU!rnt(*3NdM)V7pj?{fPYbpaBC1N3RCf@UsOV_*v~9c;$|gfgk`T-<0t>~K>}sW` z;f%34xDb4IrC3reFGgwWSR-9!ePTv?#beVkEaI6^%YXUG;5JIAgv>TD$YU%=bdk2k zn&p=|Nq9iCS!MH+_lh${S+9>KQAvtQXZUpq1oxH$F9t&jY2Qp^+Fzw!p1eA4385UF z5}5*5b6~SPAz@=5^yy(@YaW);JIS(`R2^k$^5#=F%->&hthvc}X(D}{T>{e)h6g{^ zN|9f%rqoOPa)L&J&<-cBD%e$z-H9+(>H01=gfq~@eyqvp^@siH_r++FBNK6Y)*nA3GDGi7kYc}LXR4$rZ zBd{4+EML7E0L#d68_LPNR>9tw-KBAFO>Rm3?5wD7CUD+d=Nugh8nl1t2{~BIX_|!O5FA&r`n+w# z6PaGuE|_i>_1AwqeoPSScse~MuWwuonNh8NDelTkIEl6S0mi+v1~Z57!ZYslZ7TH0 z%x!)Yh!5ht8zRc4zmgW!i~yr%&CBk^WU!_<8BrHM#<>6=Q4F{nU_7mb6LHpB)bK-? zJO*VJyl&*`rb7p*1vx}c%<6ArBicH&NXVKZjLx`o^?6(HyVdYJjy%0`^%^7til!f^ zm`uPr+UQ<>hN(|ZcpZ(t5N&E@EzqSQ?Mf8ZMW#Fd24`4z4tfm-H|5MVxNv)I_5S(- z)vT6mGu)=Yuq0nX!NrbD8d=?>b%wF}Sz*D(%=XNC7I^1g%^0 zC4yK^WDWHE_IvTxH>DFlG3Msh$ND?WvA(%%>CadUP&38Mq?*fJYMx~&et1LK;1a)$ zTJmypHsvI~4{quf-f0e@Zke$n5a`0VMC7FNQawR@ipS-p9S{%mrf|Nw_)a-d1>!jF z|MDZ37@oOnBdzc3;+zw5mAMbv)a)}PX#4S`+NLF`GIrT9PRvRz#I981BLzY^SpR5S zG+#R1Yxph?MnYIOELZh`DX-Cf&PgiAEhh`!NsUGH~i9ZL!dt zQ=ButmXX4aKd$Yd^gHU=uEdb=&2yE3RI4Rxkc6AqWCQ@V)8oSu{ zTLt>(A##O9>WjhEK}M_QX_WYW&WhYmL`|Y#hA2;R{VSW7d$CMz{Xex?oUeWsHP=V2 zRdgZ@GS!40AdK+2Q(NBF#@Qi`6;K3Q(ZT(!sY%I?7)=%e{rXCilZU0!+S1 zzbt@zRBsK{+g=8AO%^-+cB!Z42PfHezS&<_DLe}5H%vDoYmXlD5}GbPSVCh3tD+tP zp`p`Ck_RlP??i`pDQ3PKtm=KVedk&596<@1OOmRHM#<;q70~_;F3ai%LN~u+>1tYU z?`~b%%Eu&*^t}#$Yj?P1TJv?=AyKa5L zoD#cGgGh`2RJ!hQsoqnW9b`*IdX+FIZ;CI!YKe(^GWUu1nkdtvmsW4b%?1~0xo`_L zd3KVl#G1ZlsMGOB_0suEw%+tkZ52M?s@(w3kWi)zx?pU@OlVM`I?43)jO=Id80Q+@ z^y4;Oe|0*VqjGQ{HHR;iq~aN$?g0nnI>>lJhgUKH;(mI^{VVk(kG+691 ziZ0Y`x*-_n`NFakSUbF|?a7NqwqsMbw#-$)eMoiMIT+!7SVWzjz>W7^oJsdqI_`}k;*Sdgk%fvXk3wuJL7 zc$F7w{V~$E)-~m4)B(U;)&u>m!7M z>4L?UI!Vq=KyB(Ned?{GfV!A?(T!i?VWH9#c0;AX(`gT} z;*S(vnyxp<1R#@NF@gfsxa`Wk^U;iQQ&rBR*~|+tY@_i4exodh_tt_OrT2G8b4*d5 z;4TGHRI%XMwETWwY_XG?GZhD?l*O=+#tfh=731DnIMDoU0qZG9Xj^HnNH+N}o={Z2 z>HWiXb+>QAIe|RzWkrfUx#}Y1LgYCHfr`kLcPZy4K3f#@gb|lt&sGA=Z+;FxPYzIL z@PFfZ#u{>F(Rr|iai9;6Gvh)SIi-ExcET693VNE9hn-eJL{}&@nDMF7kaqGnEw5RD zal6fIBM21GM@wXWRf;vZg4z=IwUoq`(Ni-e%u5em0Vo&AeS=VQ|CB08hlr}PWvCSsKOq`7H;Cv9qDrQhg2LoGh2YdGw-h7_l9btaY`tw^Ug zKYAx-9?k3B?5e5Hdgm84=yUb9nRjULe2#lJ(yFQT)AQO^N&PB9eq8IO7|JRy46QEd z&H2Kng^d^A@oWOwj`@<}Op0R<`_i5bJ=64r*8vXC)3crrdKBKwJ6ODpn!Q#>iEbz1EBWsG2gqneQynd*V)^q9+=MjGHdX4Zhiy&k1bAg zQjwkv;-l$Yd#%^Ut(XqPeKQRp%YmYC zp<;#*O|-rXTyek`S|;arz{Yn5L6?*64=L|UjaQ@iBBH8&zP``frBM52Ibgg7{3&X} zz5Te?s9Akd41)K1*i}-(7mWJ?oKc0|n(?{pDimJI^4g#&Wr>E2m{s?=vrPePtT(p& zaW-v|^Gu!+2qT{ZHEVSU#}oE^GM`r#wQ^ubEd8fSa^3HQ`sQb=wUl&L9K2}N{4@t( zPFcdT8-n`-0-j0mo}OTS58fd`N{I4gtzoDp2_tGv_QDA@S!Ha-yu_Mguqfp>#fI(+ znAl0aNb=T1><}VYBN*q)mG1orS>y>sb!~$0>Wvtky`2@KNKrQqaV^HULQ4iqIyvWJ zFJsWGUE2IWih@pbxOW)&=f_btU$^obrg_3`IJW|N;|MAX9V8uqYaE0y;MSM73f8=M zyQ$`{Z2^6`5* zv^cJ{P+W%=ykG1i>%F5-1N5#T6bdURs}2GfYz#-3tGzc}?=3wmnh<)lCNus;S=;AR zmD-J)D{%A=$6r@$9l!W!skqxN3H7H(8K_she1YCZQ#4Llu9L4O60+wvU~H-rcEHP*Ta(u=`+piHR^C%pIy#l8JxnfAQ=ogeIeBugjD zg_dlHEfk~!wVZlAp-z-+aP6bKz9a9=kx#XR-Y5muOwf7dz8G#QYe_ z+wp?Eu1TfuYG)K4Ft*b$pmjY-HN?cM*_|A^A9`IaQY&>Z)(Pv_aUG)6H|Ejet^JvP zcV#rvac1Tu+Yz?1+oPP=TcRd6vl7vECFk=xZcL64{Z=fEW9)a?i>Z5qm;B+(EYH+& z3T$X3OU5nQdJu)Mx+xleE3eP!_7h_yVO|SaX*HOFyIABE3YXDYUPIpFfjMyHE=L1z zI1H0N#O9o{kQFrkdmOlUr;{06Qowl&f{gL9`zu{J}Ur=f>HT9d4Pj ztH2!IbFx!oB50H?|Mz)1HbxdrM^68uZ!MQejwB`1yW|01_Z%zA56?V{cP{3gQAASc zotBpd+cG5Y=AA}=4*>~Jclc66o%&HV^C><{`-P3G$#AU5)TuT)Ti;@oG27xhFy?l7 zQy(XSZqN;PeGbn?>0nU9Ms<;L!gTzf3yY1@9HUySRVa~pG3eAq9Ok6G)C&DQB+p9Y zOG|J-!rL;NG%;a{DfgC9phGkn5xl!6T*uNsz1|>DbZSjj@bi|~tDDpDz*3z+M%Km!$i_xj>NVPM1w$LJG}h)5%e`ed7|gwB(f_;te^_)|5`7uo6f+ne`=CoVgLM1qbVPeSmV`x7@A32tvW zW!~^)dDr(=2%HAV%8O3*Y$`=zo+K{Z(TbYy9c*u`UUhHjs|3$}-yDfAj~n<< z)3_9mZ=-%+y5Od};nYOeB&057xGYHXAj_NCrsKARM3ToQI3np+r@6?&r(bcS3+6u`$>+P2_M?1S#L@XDqa{BD;&1=3wJe zLDNns?~}4_+^>{^Cz{98*2QDq$iVG>{+oe$VfyHVcy8tn<2cF>kyS%2Njc>nC!)h9 z^;kmBpb?WX%@=0T^v&zrjPR;kLf=*)0sJ{^vwF*T4Q*w@J>dl z@bVN&U6S$SbT$nx`SH0$rMWqIl@s@bA(n;Urp=%W=Gc40WW4PgovZ9}7^~wGa_k&F zgSYA=fgeBPVrI-aN?tb8G_tMRI3*=AIim8$Ca>YifA|)4mh?i$ZxFvfW&|HoAlIvD zd-XSG)8eM!u)pDuT$Av}#_gPK$W19pB@9#kuz-(Th}@r+*e+6hBXK zba|fA7gsfC=2=Qye5`MEKRD2mR;1T3K3hN5i2jJz;iH6}LLr)ngK55z1>(^`xP)_b zUyi17jnnn(@?S#60Rl67SNQlYR-`8Gw#Gr_jYj1s>I|q`B`ciM(n@Ua0sP{|jja0|hToSANUw z{a+BPux4F=QPumKwu$~A1a$)bH_#WhNR(lT8F0S(7e37_4x)*wXp~? zK3)?OVO{sOU}+Ke)w#u{Qam1?7e4kslk54kj**xufUM$Fo)Jf)hJ8C)srie4SaV1% zB~H)gQn`|P?JqcvT^?Am;Sc-bDs8~v+0UOp_r3G*I? z96i1qqPUl;6&>?lD05dRH`$0Z2S80+fwV`f0)HuXW1+y#GB#0Jbc7UXH0f$8~yy;NvhX=sjPhQu(*}T=2X1{=-a2pS? zj<>9Xguetl&upAdd&W9G{z+8}d)KcVh7p^gH8Sy|M;?c!!eSr|!|!8!g1}m0rfPy5 zl7P1erHz(cfx3#Ri;|;49SUWspnUf81+W_cs|8TDu30idg}~je3-F10*Q*B73O(YJ zLQYM*OW@Z3c2CD=C6Os|f%h3xznm=SDOOfiBE|?{A`itg@k3t16FWLPwm(Y3g;Z8M ze|A?dc+aF>?!0mW7)$0O9f~{#LbbmH-K&3jZrHt$Nsm}5mjq#nM@K#tRG%rc*iX|Y zIC{AIllUn8FSbve1n{7$YlRdlInTWF+3BotK2|?&!K75>JnZ9J;4W^wvML7xei+Kp zAls*YJ74fIko!~y4u2dQfLZ9!OHaBnkY1cm zyO4VQV?0ckib&-==h@+8{W~Y8gVKP$$X&soH*Ad;nd5%4;ZafXCMJE>Jm^puML`)A zKa4k;O0pyCTi9np9wpmXcc1?<7oW)h8~d~U=F@N9J7bdELfG!>qg>7sIWkO0;FMma z+fHex)ne5%LmspT?i+KiUuk7{?fH+vH<7^jno6|~TXEP% z$8b1D9S5>Lmpyb^-HegfMBGIVAIy*8x<4&CpVuL%ine_PO#fI2Qu-z=w$)8wQ)##? z57a5VWOyMsQ7RBnVDmh#>GIX-_UZAN?F`G%!6aHs$v|6!lE`H?hR=I1QSTeKcxV(X zRd{)_sxmqr;F%%1E;`Dr-V$k!);V?duWx>qN%_pEq+SMNG;J%^>WUjONxe2(3-I!w zayYy0TG_7iDJJTG4yZNI_;lEpr zj2|%BGJYQ8mxExc2Qaz&$CJ{+t3pt%CG~N+;02=Z_cWl3iIjJ zWj0q!@!Ed9?LuszZ<3lEE zlzTMh+UELU)Y+*50+vv)JV>$>7N6*Sd93|cA!B&}=wd7x#BW2~p<<*v3Xs6!cq;Gw z=s=hKw%gh=s!-3Nc(nk4+16k1=prb@+P_qW)LYw%Af%Jgzdj!GfrvU81f?alV5L(j zZd=D(wq13orC5AbBjI&_<2i$A;A?gAf&!uY+2cM!nKVng`I;#&_};d>DugERcUByM z=#9hr992VE?LrLck@s17x|&clQ$BN%g*yFf|LDNi7)Mvk65=oD zx<6XmczKqxuH;l2CIQ>njcmV7qa7t+AfwM!j z^MpTp^ufeX&Wf=1lS`CZ?y&7Kg>^zh3?e5@s24lrTYnt+v!)j>)XeMNt-k+yJ2L|z z6JI+&o@6m&3sOT3lsY)~XN!6r9T`GHYBq#MazLmdiJGUpkYeAcwe7xJIbqe%70MTm z;W)UN_B)1zyugr3F7nks+Y}LUn@UL2?)2!$3RW2qQt?TCfKA3EYfXFn zN{nvbNN(!YCSqLv;zUmrq-*+*Bs5R~lF)E+^2{zLxn3AgozyDaLa?x%j7Pb`6 z@3sStdI-V4ri`nMHF8={oAaDji`+_Y^*Hf0eD$bosW0s@J(W|@;44%oK7Jj?5}GA#zG%#DU+JCl66mN1ZaZ)l z%E4P=?v>SVaqst_ds&KnD)c?6ul+>=aZc*RkFleqbyfOlWAlz)6I@DEcQF=QD~lXS zHsE}XuQsZ^!W#-~7Sx+o9h2vJ4tGigO-d;k$j0T-KiJEMUm~Kx{d_3alSS>|4=SR;1 zE3+is$(O>Fc{EAdRRX89)Orm{V&?_Sx7#d|j4J;u`Nw{`Lz;hu=M&1?rOh8yX#Pzo zI~vdY%eE=%+zR|{+;oTO>Gz`In@WDB8e~k47@6dz*J;C}iQhR=(VPYuRQC+nD(LU8 zhN?jWTM<|SrB+L%!~SmVe`<~IWmc7aDj56cTz+o={HRLdljB4q*WGzFpI@;}LRf)+ zzcmXKx#^T@yv;#}hQr~WgZeKM#(HYf;ktX7kHwyK<==c zD4!b>_+$RE((m;Ze|j)cml9d$8xAiw(lsud?r-<=af>-b9hcqU&z;tK#^m4ovr`G3 zg;9|$_?*M_V5L7FHj%@4>GEmj)j#$!&9ME-xdVV=_l1|cFAhJY2#@TqZfY#bf`l~OeqrGQYf?KoXgPOWG)MYd~ie-IJDYBTUpH9xU&7vuebnxNG{w*E1VLr#Hq`vMEJ;;A}5 z$jC>ueY^8E5Wr3v*y`UM{^=`S>3lXMCJRA{V)Hs9R(xyPYTR%Gx+ZhwDb1oE zIiD-2!_vI3w!RQMX5^^h?Gycj-ENkb0+x#WZt`e88){d}*BMtt_&m#RblnHKV&^2v z7dOXjJp=j!W4Abf%43ywJ5Kzi-c460sV^My6u6-YN(I!VabLFRdf-*IU1$Vh_5ax(Rgv4{XqsGuIRv5# z1(mz8ZF;Ok@O^QechA9alWdi5GXQvb7`iP_S|EdS$NUnDQHDE>6XBHPqM89!O?(fd zUIQ1K(eoe0s)3?d>UUU9p0J48&hg(eBD%L30$bBPt3NIkx4n#}ZC{hT{8ZBUCq1HC zwA~6b)(E}h$J=}+wuY0pwieN0MYG=NS$mptTZxSS5AlXPcyOnFDe*3m&ERJ~Nsdx_ zQ9h*U?zDIt5dbGqrw7@!Xe>HYJxOHKv+Gw%V`E#j%y$$;V)Fgh6V~-E{4B*J?)2QF^YNVhn z9fQrO;(1GxCeQy&U3?%gb@8KQc?t#~(0jTzK^7risA=Dw4?un#Rm1V*vH>|OrA=Cf zku!Z_9~}eRWZh6cm_239bI@yaQ$2chIrFR`O6rO^*E>aO0e(LBGhlz!tzsF9pJ`+e zq=r|kaAtb(O6FR~MjxJE&_hM3ZnXTBQe8CjRa5PM^`NK7EvX^oZPQ2JF>DqL3j2!{ zOaJOlJXt@wT%2jt`gjlv`I+1Wnw2^;1fQ-A-u;WL87{-UbA6E1?iYCSM~BVjE@t3o zJLTO$NNwII+ndcNokO%TDYuwsuJYVmQMQ}mnu7yM*1{O#ycHAJGB>!cua|CO|1qV+ zk){-);PmG+ajGXX3x;Yajt4mS6Esr?@64Lnq;~pBG+L?I9xj!J-q$jRN(7JreREet5sJ22LCEOQ3m2(=yHB3(9hBCsu)C{^m$0Uki8=V}XV!asHFe{C6qFha=~6RxmHc z;OBUJa6CSG85R1W*4EVz@4xE9%^SdqxX6g^_Za6!RTrn}tM-7p|K}L?fKi=W79^(i zyRfpL%CROqo_~Z?p7Wph{jw+1{*5O$_CIuf!!;y*eC<@u>fdqz1tiF&mt52v{4Xq@ zg#bCX#Y%6p{vNtW#j+2nPV{{+|OP3J$W}I4;m`{FR2e#9t*3S&<+fX|={rFy<-$+s+)>&b*eB?62$~D+&|{A%|Qq zA{X&*JDvcb9nVPoRP?_?{{Q|{8LsrGF#jFiSZMR;sH)Tb-7UaiBIC8Otd-Fna6)#S z64~|i#{L8b)IY%}u}esVyf7{K@Z_YXFmI&24R5%;X4Tc-nhgL84EW#KM!CL+eviYN zN8{8!X&FOTY5Ku3*`>9a9OHoFqPnx=F!?e51O&=LfmD?Zcaavv?%D2@O>)=?%}Tg?Cb%^h#_im#Yey2dV@qlrQEsfyTd(JI?A#|TS=Tp zcZE`ZIDbGyfBC|QNb6rfY&%LQ)tLtgmnoe{J=>f8H8NZ4oF9uTiPr7QH)j%06Q|0c z{?d!0PLNmP70p1x3mx+-!#Ftf=oqP`MiKepnH{(aFK3N0SSx|nVPeg--nSl3r--qK zgS@<$_&derEAuq|O8`9o3mKnX+;z%!fffoOE_xT>t(#appEQZ$0sL)Wu--SkPdL(p zsIxuw2r%D2pU>E+n`+c*Bx!o=`@5+BxzvVH4;7)S-NHM&`C2WG(brMJ<`iMCL@~l- zsE5>T-#6>u|6Z!A51mgKp0`~SU z>I)rSKEVCs`K{0Y2Jnzg036m|<`YGF^aFRK&7eOl8b#dc-dFFOuE%%RJK64Qrka{W zwcN!vqlqCI`%U+au@T@}Wp00aFZ(cQz4aul4uHh}{N=8-hIY@o+pOymO3VVkg1 zkcY&A^7AK(crE%<^ZuOsF92}qFMwl$7kEq3J5lk&IoAaqpc~%DfTuLEd7?iR{TJXl zp-l+q&+cz+`61bDOLrDqAL>K=R+D+7(E(DQeAgC@}1k_u%6CdRIRZy0bV_I&&} zn8x(rJlP!hG)_ISFWzwpZ%VMODwJWDSx@Zwx1C+VRqtn0 zo?mn9RRxN{Ph?mN>NWjB$B1pevi+ugY-@XNW%GR31}lVD6Ww0{lGto3lI+fg+=MVu zk3B=ihJr`mKc%7)!;kf_&*hup%atCm;R)z^O4{KO;`4{T1_qLAQe@>NK z*waILw1*skQ~%H9Tla8Its|Uy|BbyeRGLXCaWPi?dQElNMq8lRfr01<8nq+Q1-h1L zXQk6dKMxW=FO2yvELr6Jw|Q{xVXp7|9#&Ox!bW}y^ypRh--}C(R)xeCaokqiEPT{m^JXjjB`|yVmVu+zLp-|`9{B(}uYMb^j z0kRMQ*D-JypaBz?pOyahkH7C?Iq>#%0G`OhgoQAlq)6wVEq~? zoud?3b?XOHg*~hGjsf*_AVqI&zN*ZFYVz{NO-q^IZLt}5it1jS*}@>Cx#)SOfA64$ z(-c}+v5+^1!a}*L(hH0DwZ)bIF1iOXVy1sfE1ce+pO#gxiXEpk-76jgfbwx61f>0` zI=2;s&5S0r^R@`Ti>M4L*(Q8BiuP%D#`V$LlC6xLU=f&amo#TV#o)lk?;lkDJ=9P1 z#4!gng|VlO=$15}_auw{ucPRc3i6=ml_nK$mdN{6*<;cBV^L?bl|O7v1uWR8iDK7) z{y#=_19;cQe3^W)^!?W&w)qerLs4$Wb?nvNmX(4ktkE`{ z*$lEMv9y-8>xbAtC}Afrhd|rAw{A}tfw;emc zRB8qA!Q0$jbc&A45O})mzoS%sG)Js}Ylw!HH2;Esxar}yw-d%@eHLG)u^F$0Mz`u- zLRr$6B0=WJQ+^C-p^VM>Y^!?$aQ`->dib@jXC;c0E3y-df_V~j1*H3rm&;(G=BPc$ ze~Q$|%hwHVmWkDZ4R>==&hRD&N-YNVl9Q{NKR)57WkXbEmcnPwuH06WRR*{R;>H5z zzK5p|&p!idRjjAjBeIggU;J|yFM;R*cY4}o#k?nAgCKq?KyX&yZM<%ZR=!Uo^~!Q8 zZ1p;uvQV?nUfmGAcR%i7Ddrv!I(|jZ8|wSA5ThP&#m9$^rtc=WIyM`Xu2O|!^vbu} zS0(s1{n|+Z>q!(Ve}z6b&0_ZSF6?c_8=wA+)B)8+kvfnMWzioZ@M}Ot{dyPQ;r10e zBSf+aaikN_`Ov=BpyAAZPnSJxd>MDjmhvFLxsyON+BBRN04!ti?MV- zLGY5lqvKEUn~&kZ23%w#4zDf}0^i}+#;WjT=r^dVzqRAJzuUjpH}iP)?RC`49bs7H z=Hr)nBW$)poR@$*igb0;LiAdTUKV+8VSE6kAhMnI>8{uLSJ!-8(S-;#g3Dkz7`Jhy zY|7I3r#|+w;BJW`yl=xmIK|3XMdEf_G>s&c(}p4SHW z=89>$3f-~0qi@!w4CzLKRga(#O*^sCrVt4rd-oXB{O3KBvmYyJD7u}atfI;CDMCZr zC>}e@lr4=_ZlwD(?k!y`wh?^EQlhZ+KFOk#O2`;+C@EX?%`y=PlV-v&NW$1kdVZ@I zqDaO!rjaPqChs?kvF#cci7LoNNbTlZds7VAu|hUi`6 zz}~5dx|kt^C`u!mC}a#P$`+&|DIq4MziIj%jpLg&-9$7l=GPUA`disx!+PuUqFSIj z1bQ-!(shU;0CgK=p4QPI@urG>(5A`bAJCW~nwj)h#MzJ{Zog1S)`u=CxwJE3VT}^e ziRE8~5@|z)f%@6&j_BiJgk{%CoiBZ8484PZ3>E%+nrNKKy@+R6llZmN^6I3U)=E+Z zN#GLv{pHXBL=M;cKvQb^Td?$IUaAYV0=}foSJbLA%L#G0#_l7AHq93H8@P3W>a;^kE0tYobJcCXCq0araR~oK{;l`hu*MmbdAC zVPPWTOIN`5y^p8sndw-}R~#=DwKu(}c$VUsVpbXBLNiu%S;1MyA!S~N^x7L`p3pF5qAkySv!d*NS*<@}(Oo-Is=kXg%4b_OdWZ{mC%jjud6Rm5 z*@`B)q8bn9mFcoEH%ghs(IZ3e}!a|4FVx-~?jwWS7 zhxYlXtzYoWBzZ#dGusIp8yG{uYdJZ_*q1sJkmA-3(g!0H(+zsqM(lcaACqQQCt00r zGhboFRbo0eb$#6W$)&`Q(~gnR+;K3PIg-3~I6unWTS7#m9`it(!kox;OD3$>9aUe*U zT5Ce=jT_HsMH>)~wq9+m?9W*j9Et+!JMl!tS96`kg$7GzmkP?v$lUePTM%PO zM+V0J>fTOD*jUl;%5mY+lp3x=Ol>%7KVw-n!NnYSD>sh3ZD;C!1H1jmYJ1NmRuHn<>jDG3-tK{@?;6U1hw8`CkwwA`7` zJ#W6|H)!c<#wbj4?-FVr{&kO^@SzGg4==3nmCVyNC(~($`N$_h@QFM;cpkmmoh>bw z=9Cnd#Cnzyza8rVyFzri&be#Av&>dTiQh;OnyRqQ+rZZ6tqw`^y266KG~z73fZFOP z`O!fe^GI!f<~;Qe33X^v+!@N*OqBXcRM``I<*ajXwLLBxN|X6fb~x>K;gx)L`-hQ2 z9`CD9Y&Rc|{9>{^^J6N|MV}ndI%r2!l}7*u{U$yjO0@yj+Pj>n)cDgf?W=s5Wtt~l zF-kpEbDfA_mBylvi%_;<+=tGuK~&DBwi3k>A^1E>H#cFm_EL{Y>6^t&-P96FAk@^- z1-FAgerKQ0x%$lUwV|r|FJ6tR2pD}!3k4a8yB$b)df^#>6GOFgS)lAhEmwEgt-|)# zM|oYr-W8vJr%jJxa7dAq; zCzL>!uk3q=SNz4m=rXI1lv=y6O9@HrZ}!Pfx8`|g_1{Ivil@B70>_{zqukR{0B$tV z(Ms|kf|D-kij=m;j$D)$gfB`)Hq-A;a!94z0H3ur8Ih4Tn*XXvMCgRJlzJ$k3SXHE zwC2?&6D3W%$0Ip7P22QCPcPkiw~T3O25^{LgqoIkP*mW<3?m;XjoFB*q;zu74^p`& ztRo5%U-Rf2TX_O!#dn`q>4sBhJV9j-Tr##byF`BPr=Yi%C;gh)jGx3%m}$k74yj*4 z3iHsEL(UgOM^mr%RF6Mgwr;B^iH?OwI9KheCk%=WBW6t6c-k4RTc6DUHN5F0Wg-&? zDhNqAmzLCYDEZ239_7uXqg@g*Wa2-3u#_q~AH762^zEs??^BT)X)nu9-v+C)XCsfK zG}67!6Z$$SeRM?&q~mtj><2AXNbY2s;;C)C&I1>z@rhC1kjN7q!nEmqMErKSAhwXa#rMKYYv$tP1nH-fwC;)Gm+>bD`1pKe@~% zZLiHwvR%0#4jpom00G?rxlQzvIJF72g2yi;0fMa?I;D!be735{giChZC=Np_y z*y;kunFDF0L-9x0x*(Tfk4of#Xs?L{6qW1q7S1-0q!<{_d*)I2Q(nopV7yN*A2-gS`R4B zn@cILuIdZEsINiuGoPH?&NCftsiZ(@2xBQ^giY3SX56-~U(n@s z*ynyS8Y0i>7}e{vO=#g&%nTlrL^GB5$P*geABq zETJ_*Z0KY5>ZUvht3N4gif+8ssUn`rv$gNxN7_;web`DpHqVNmzjrDMujZSTC?Yhg za{#?g>T;sb@NRve9L)BE^JHIqyDzNOH>cV>9)|w!6ccM1(J?8X|Gk_>38rH!riW=kVa?y^afQcmjkULNGJzS zQ6j6s&)fGeXcYcb`lPU~?;__#3OO${lT)L^5V5PYJ1LCFM5*Mi)5A_mdt^#St#qsX z2qZ`T(b8(SeF}ld%{Q;DQ^~N`Hielj+p#f_+*}lxUxgGUgt;{z^?NAf)AMw<<*;Y? z1x_`3#%*!Ir_?kg-XWpxcb6L}rQ$a~OqZ<-cYce%9$^pcvgj1GM)II)``d3J{E=Sk zDP=T|C9z>yUk}JQ>e#Lh3DZ9{Ys(Ka#Lz;OZ3}F|tG-vrWxt?T^Ha7VtfncO`OFJqtr@eq4O zWJ2=+t7Y%mwW6%7r_H@4mwqTNl;zW`KltfN>RfW5G&hwXjmhzPP(yzneCQ+c-aoX3 z9bNq5;54mnKMxw5ynCQ_J%lMDKukTzOJ*CB;U&n-C}Ut=zQEcP=frE~-Q0fCJ$9I1 zsW|zir&hPhijsLm^@>xKM(PYDIgI5-!Vp5jlj!I;idiLLY4c35z$J@KVasP6>E4fr z8A@D+Al7L+dnRA8gf)MpS+w6Yof2Y^L|f^?l@pMMnNvTzsZ87bQg(bB?;52z6nOR$ z>vUcI=HpYC;vXB<1xAuN?&)xw`d{U1x~nAKABjSznPf~u>3Y=|Z<3~>X5ynfJ_!d$ zeU)t=Beh*(Q^qhEdZY}Vx|E&T`O`U=ottkH5gJEZe}RZd>XVf2F6o!;FqUEX!-#t8 z2Pji_PjXJmLZD(lY=^(HJ>)Rpi>`XK{I0Rg`h79D@z8q3SurT@Yb|>v7&EMS(RH+{hI-g`y6(w{2*^E0xb z+9+UvdnTzb{*6wdA+=z?r&l{}|Lx--9N3jUP_Ece|M&GzG=V3$JA)RT|Bh{sHd;LE z`iTY3e_!9+OcO0`Vi+PK_&3)K85sIN3C!PIC%?{rMj;ErAOfDC37$+H{yjzSbkHf^7nzi`(|E%4I%DQb~2p`iAMhO6Wq5alAZQTStuLtJ$cwa5&x) zWhfUu8j{uww;_MWYdfv_8-1wM{dk>pjEW!d?1wcQ0yjf$B!ISLo4gc&Xo`_(9hGXKE7yd^G%BVXOm4a83bon)%Y2H8|f{RNWU`%)WMtPu42Z zv#9JhVzPo6N){=Hzi-%07m=jPy5c=8mV+5ik7eLVs5#h>&W(mgM!xxPkZAprf3nJU=0!F!oK6z(xf`T63(MJ0m3>c;NCQ%H?O&(z zEC240AP^pfkg+gx+r65%Wcb*etRNW}GHWY`6a%@5RMzvyo4~1>JiO# zpMk&+$rCxfWl6YJKU}+8C-yrTy@H08^;(hm53JiGT^VZ zY`os9vs&sG+_%}QS&7`rS!Mq;*?52Vf7<)bXgJ@mU1Y*&F{5{8^pYqML@%QS5hc+( zAwh)bH5kkghD41ZN|ZzwJ%~PuAbPJ6Q6hR9CFdFc_xF3xI_s=;KAtbHkF(4?_wzja z-uK?ub?v=R@mOykK!;^CZ8bJAu``u{{0@IluEY+sI`?1r)lOF0YgGGg%@s**h-Ljw z{N(_J!Z_j5i&E{Z?1$MyaVzazv3;0#aXZxdlcGkeQe^#)&sVxux%Bh(l)ImyIe(t; z!ZwpN7gbRpL!N$126=HhmHIE8>fpF^Hz7p{i%t@YsHhL$MR`GtJJ4V|%=sfX8hi_nt(cw{hVO=K7zOJCZ6Ae;Wnpb z2a^GT_50gitM~Q*q*v#aSbH3+0&(%_riJV-kd$ZeW%=deuG>X?|3xkIb4_a)%Px-)Oa%2b4-ob22kJPqKv1U0%C5o~<)uc0L?9%c;FWHPbTh z)WI?6&p6-+?8dQCY|Yq<>=3(%EnV+(i|4`jjAX!VD^ucUK!W{bDp&-SL48--DG2ma`GsBC@L z;4~oLx4JU8vY&o)w2n(7USev$v!7j-PcO@LF64AG;2apb_UKRJMwuWS{8l?vL|5+s zq5;k(Krgcr!|vGKvG?+NR_!v*<{iNQ^~OPwuHEzRPm^rOrcpM+BR(vu-jXR@IaYVX zYT8?{QM5jbOle~*CmMkJDPh4!R~Z*~IiC{{T&L1PC>!Niw6ZBHbs`Jr@t_8t9NNR{ z`vHL1Z4S_F+(E+WL090CZgv5Y-;451a~Y@Wyy=4j3={)?JI6VHI$6oMFIVI;OLBTN z7wG;Bm{>`>J7)>%bgqf^(#yU*`$i$S;3Nl3s`4-wp-SdN4;34k@jjY8*d#w##tWz2 zfF|4*1q#J`Bx_Y7?d{o3+9&hphrYL%?E};t)Ogj8KNBa0FGmESDcZk!LE3ULt_sHs z5q)_W1v59n^3r#_DtT;QIEfH!DK4psXE9QGHt>y`!UuiL(`uPa&!(IV4540~D0M(Wt;_mzZQ&*iuUL3(y#S(2oQ97X2;W zKEsW-mbr1dgj|iA|)|` zt30r>RKub4*L8eNSQ|c29|DpJo`;EKgI71GAl07hXriWF2P_A&HxoZl!deL{!ic5Q_DD$`Uec@A=dQiR`n)@VREB; zak?5r&nsXLSZlOq{K!GKpE*eO4ogU z$;QoBsjJgz7<^ySP(d)7_GHoGT6RHyx5>7H&}Rr7xQRnji4ccLvE3=!zsXiXagt z&dK!%dM%N}MFznDCV)rC*Z$#;)y=HtimX88)jERK7&}>!#di^6*W^6kR^IKD4{?qL z@0y#(&+!7SI9oKQ=q>BZN9g*#>**(Ms69soKveZ>ADFar1o25sq|-AyQoUFmpw_uj zA9JyGg=69IizX&5(+Yc2QQ%nu$Tuys5SbJ61~HK)SefSPm^?}oLIyS%QKIc&CebHr zZ%>MRX3B&pyB3zCU~shW8qfhvmxaqC{~QcgR-UWzyJpZc$F3QJsq(cnQ6C{U5%H^$ zKF7MQ5PDE&06ga)z2G=YyRgaqy6ud?J)=0Z?Ui_rs~JX_Q-rG>1C&B(Bc6V3q0 zZSb7;ZG&kNM|e$dXH6ITBsekW$w6JvBkvl6g&&M9C5YAsy?5oU6pZE-nd#~<+CNF5xWxLtGi<5d%p(m?<^>&9Lbc3!#UvG1^0Bm$Xy)& zz{@Vp)$Vw`T5zTbw8-8p+Ds?4?N7;bg}5MS1>5ef#q!_G=&P4BPOooGuy=d*o-^>G zE@iFYlbNzO2!C!%Tj`Q#Rv(m9j%BXL z#9&@IvK)-w>E6IO2qUihrFc}jYh5BH*7%gv`p0e2X4o~mU}c_-;;hp-O>TGbH0GU$ z(E};5CMef5by5$gA%kr!Cwkoa2Xi1BbQsE0=3lAeC6F$HWU=^Y*Vj;gic&1F_%ygwO6UI8uO>+}5wdW6TqDR0CicdpUhfKC{(aW4 z*H^nMSmNM*O+^hZ&0FT(VyrR);aN}rLt2>=oExn>*&sf9cPe?mw?T4xvYG$KCl;+h z7-Nm&@5b4OQn*A(yoxOZc*Wl^dUKl|AelEaus%+K_Vy2@c!3k$6*!ZXIgfaP+)(Ni zG&VkgvAlc$C-Xj2x^xzt69y@_SVL$c?j#+l$L6^g``LHlFc1nPxtOhB`1ZZ*V=?*9 zBnJhCFw+)|tdJ=khzp)#gm`71N0g=!9%NZP`7i~2VNnGe-A7()uWDZ z2*{N8*4O9(8QCyuf`S{LbeHzF70h@8@HKuCfI2FJ*Uv%H$m$28sNnu5&pT$E2N_1S{w$iB~l+ua^Lv$MFl(K{mU|0LL^zQdk^#Wdy4U+(VD`Z+F}&h z4m1(d)EmMqMfRoo$LJJ9r5EX}JbFT!hg#iE-UiPzI5?mqd1J8kK__?UoD{@+Fr&Xu zsb~8i;|)|3cx=Md6~c2Y;2BzG-J53MJNrtVpQEhclsUTeQ0K6-=Wn41~CuJWRDr2lb_j?pTgu!CLS(!Koo&7!D7lz8|+l;fFZ zPNf-F_9mcrKgegJF@sX6hQe2IGOB9i&S~#T(>3I4Fscb`xzjv>+QC*9^1ni zS)kapG6com*~Y1%2;i!4_VqtGJVuIgL;k(W+@Q%`e1Mys&BrY_Sgldiscx<5`4O_0 zQl$}HMC@sV!6r<+7#OFK!%GU|Doh;iI8QgcOWfK9HcJA`j@UUMMo*y*Q+O&EZb5=6sOAk2wM zFCbUNB4MvN*Et_Aw(O$5ciXt$Inxi7+`VsQj-bk|&FYArF6rZZBFqdFYr5C`c>Rdp zPSy0#m6^9PFRtNb)pU&XNmJ`-Q@pdF9kxdD!L!j!e|em$=+()+Z1*sl${O0~o720p zuCZ|7AbDMKp8VLp*5^{=Ucv@MyJOc*UH!wroP36qE!uXK1>UrXHlgxQ28A~gYKy6s zSBpwq5UQu>nf>R*1WSZpDm5tl8r4U@dR}c_s8s-P4_2mIe1FrpimG$%W?`YVTin&+ z0&Ntk5SSFCZE4S?;YG};Fbh@oflT@r7gRgfe`yuMhRW%5+CR%#fi%rY6KRp`9 zd|9*qogkAf-SEivuzFQ7bb)_JW&3lM-%_vV@9JAta3RS;C0TxX6Vm4pbkI`Lk>JYDp3vN=7M z9P}QA`bCL88XqlO)rN$eUKk8aF4O!z=D}FAi44nUN~s?6ZRmk(oUJXHqPk&l^=-6U zx2g@Jq7S%avfH-!!l@YmHCORe+x}cyzQ#?6k`;=a5PoZ!7Ice2>#8YS{x&N8xGYSCw^)|_Mu@jBd#Wx*?CvibJ2gZ%8pTJk4 z?88disZqU+bar8yoDw#4DnNbgwA0DG*Sq&!X%pM~??DCg@*F9@)%H)zZ(qLU2s~)j z#`vpci)ZN-I!v;%Z&WNCwk}O&3+-uGZzzjfv>g_F)_O8nR-TDlwg%sCHem_3V0b+N zNlt{DReW!p<=4RI(zijvOW9y#$`2}qf08vSdbBZ)TKL?n>EzDk45JKtiI*Y~UjghX zLacwX7hz)xwz!q-`GtPVxS&uS1u^a92eCroL(0N#H=q<5sgYO|7+b~q1xV`Q-+l2u ztO=$aO%pb%q14$m?!w0_GhO2gisCnPGJC(7=&V*UkMd>=iG6xmhuMawWf$W752c|d z5=79-G=B&FvPgY>%134PNxk-fTc;q#!{YXDs#AgAzXZ!azvfJ+{B|o$o<;W`5d42z z?mtMmE|6ta@>V$I{rfc=Jg6+%eLFB6*f5u$mXP8-80gSd0=VT%Se}src-a))(oQ1( z;^MdPnegk+S#kd|1OL2+-;V!T5O9q1;=>M_iR!_BP;eVj;QC^WKi)Lsdj(v6ItIdL zr$m90um8FJ|NY)n>~(Dh)c?JHn-Xw+n-|Xx#s68P2@U?FBmI3zsa)QQC?jxv#upy_ zR{t*2B^;G=25pa@8gb;F)@ly!3P@AJ>j3%7dY(0@mKY(NR&a>m{pQ|AU$0 zgMkC7g2_CfXaT}0%FD;+(gMKp@{PQ=scANU%Ot`msi?;7FB0({2~QPlguWmti&lOf zkGhWSb4N-8Ef>&F9USr#_tpXyL)B~;)3IQkA2VB;{Vu}xcb?X>dv7$GA~i?)@NXVC z&?S@pF1TOxR)pY^<(X_i33H<#j6W1Hvaz{IKAABY9PU29CkBB| zA1-Dn3Q-60^~O*^8%BRz_O-v^UJo_ivl()$#V0As_B{Hb|74vJe$PwwZktq`Q5LXN zGQ7y^!=goNrt;$|XQXfq7q#0<&+N2%K+#+c;EIC$GnkF}pgrB@IsmMG_^Us&j*fX4 zIThs_Bm8CGEFqn1|GGg zrpb86o zPuK%ib7bP+Rbi{7arhPtCyUV>udk3?Ga{rh6siu>B1n6f_(SWB;!UmO1pO$~$@y03 z{3igd?_=|w(Z6~(sno%2{f_eIeoMaG0y6ti3uPL^K<1kbkw_W^9p`aao`y64v~x!hB;G5SGUOQdEDyoXh zY_h&1xGC$9#ss?O(!a4Pg;VOX(95oeYeN^=So5?-;fxB zCFLpbG4Pzr@)5$U3PJTJyS*Yp`k0hcEX0G$A$;jvbxZ13fA)tXG_61`9L@rmU_ho7 zjJD*L(iukn(B!71*5aSg$z@o*cNzy4;Q-)9Lh4Ww7(o$_UR5h*xv>Wv=R9tTyi+*kC5K-*+%Pyi>3C?hV|dZsUzZ8ew4T; ziaarf^Bd=ri>3jRqmPB|{krKW9V8aqs(8LXELalHp*R4oPVs{*@{$aaZkMT z>Im$HP7S{{#fdHflpg^J>(CpI&^!?_|HM4Vuo?R>tT8D+KgCa$C%yA3$>&iT^vi4%rJXwrFT=+ zZyK?)WUlwhL5_Is#s!`;|BG2vIv{|dMNJ3<(`!XXl^~ox?!j1~gOac1mW|+ISXIas z+YiwrH>_I>u&%je#D+Xrzq56}n-+6(kYuHO_%+P|4_|*8L<*RZDV>HDpV7tM+34Gi zE{ZuVFh`M18j*XnDTb>BBEc%&nX7{w!LX;`YhS#*(a9YgtWOlq_p9MqR?b<0hYc%( zLn1%RQ|pvlPFt!K)PR-%^M9KUQ*8#V)1}RI$g14QDeI&8&0ds7rZ`%MI&StfY~Zts zx2<^2e*Q<@Mf1_iZeglHFwS%PK}7>kG{nKPW2Q08TL^(({-|{Axi_)CUK>G z{M%C~{hqv5&#?T$53L#hd?6ljIFYiAU)O`CGic-@My8WIJF!?ZTD%`B3x&Ujqx~#| zkI>wbRskpPm~;I1oiLKVbZz2Bx#X%D>M@!PO%n|!U6>1MStLc1>kY{owACzxX_lJV zc3gifWIDROWg^7kQin*1k8Qi9^BJDOL}Rh2To54?Du5)eI#5UR6RNa|`R6?${waq* zYZ4Ht;^J8}Bp-MR85wJZ@-}qQNbaVpGD7$@_5IfjOgDBmzw}#ij0Gb(;q324-j(Fb z5kl=caL`(W9e^lFa#!m`xp1i&nM&U&k){^j%%@DG_C840b&EdtnT*UL8T2)G_;~)v zevY1HQMJi63ooYl3j}O=q1}&dD_rV8Yp-Jfr>zjmvZ@MApNGy3m)yen}1pFO9At01qY|7oQ-hA9!H37 zK!SVJ%?X6tzvafN%P!V=U|NKyfbuoKe6xTcQGI|yO-7u72s^!z$q{rptB)OY!9#8$w55>+7ZAt6(BWGZoI0p9HR!YgrckC- z274zu(K3I!WDEkCry1wXgdoiM4m%O(z8)vUH;`TKhboBpvbNu4$D@s#_~_ne!l@VV?8@e$kn%jZF^e}EERBmxKycap z5DrIvuh2?4mngA6KKY?oo*&|U_L%3uMD)>Ygl<_$o{|^#wcF+mz8$pljwOw06Z}Rl zMbI^6nx1zbd6?}markavF}%a_xGN;*Xo2L&sWQ7faJ=S+cVfBnJ*bCBEXuw~=l?X) zZ{U$vt|#ibd}GGc-$Y>voEh}WiM0|GwfVSVprSW^`@>%M6O+hUd?xHrA(yE zFNpV9<|%9+b^QXQeHjH(pAO(dP?e5m2(xk#t}Y?}lfXN?*4n-0Y^0ZejETOdx4mXV}+%X(71lj&JJnAYUPD;JFcm z(z2#y&NTUifz3H)p)#S7ge7=Vcc4E$Xv4`{cu$spFS2TT~;vb~Vuj zbatWZfcpA&KvB_EPd>@_$NaI1Twfv3NFRA`_tcL}xjB|&HRc9FRf{sV;)ZW#3_`*b z@1__#12u9|8H#5>U6vs)oDp%^CU3^_aP%0>LH^NYvGA{!c1`8yf)F!TvPPdKv2Mld zZ;bJN*BXLFskgo`!ugXEL2oM|5~IHQBP77l!;T&fB^`_`EFa2C%$_s3`*TVhjH3C8 z_2HQKCpQdlwcH*`5BZ)&t4}drN(jA=l9JPjHi=lgHM%`8MPb(?5ubO6u=^-*+DCOE zGbG@a8`pBXvA=fhCD%{NH+6GCA8L=j3W-P+=q&Y?Z_32pE+@M3MhccWoZ2;EsWW+v z*wNyw{FB%S`+V2Lmn!@jE{l)AGAlLp=);sCF9i=iv8qxW>)K54sn+uN1)t`X%vVHp zq|E6nBGtiUr>-Wa9zg#Isna8jE_s|?%M{JJWe2~! z<@Mx#r`gfCB6Tq3&t(=zGp8~Hc6$rYEV+osv!2xZFLp7!ZpD3QeNV2mH52^H;y!~< zGf)e${f>kB#ZtW>a-LqAN8x_3Ks#^iMS~ia_>}jPVvw((Gmx;E^BHyPU)P2<7>QMgZ|*R+f|^`w2tb z_JbE)@2B`=gmvP)x#8ToOp0&Lb85HPGpd&Bq#n8o^G-p-i|5|pR9UR7Yqm)Ke&P+> z-ia7?Us|1hmnZ48x?_Tc5F%jcAt{T4mUHKlZb)w~duN>FDEVO9n2w5Z z3U+}dCkJD75DX}6GAb)8r|M1+>X4)G=hq`u9FQFA+B;1bt4ka{ytAS+P-a|>*``mW z_9Gc6BQS={nPPwY$o*HM2=w`P-P;gKI1Tc-UIh)&nE0pNuR`~oJF}?2(y-=&!PfFB zs@zwKO`pM_H~v&#kFhN$BkBmDo08wghBflG!*$XVprbZ=mQV_fkg02y!3W2-xTx&~ z5^7&B-N&KaWmf#55PID5tufUtHo+J3Bf$zKUn=IKJMS(BC>!OzK{^+W)9;W7w`b)o zPv{O|4yDU7nTuajzlwb-AB%?*Ffia4?jh!$P3Is)Jb@PQ1#XCdkpq}et2`pq7dsu$ z79~Y_AUmL!s?mP*MOpMJ7q`(-yIc5+MlNbM21KX zLq0fDWs#9r#COi1psKltW?vibE@*-%0~KV;gMD~%QEUgLS5L};)^{u0iyhvAnyr&i zM^Y8u7>GpR*%D1)E_bY!@-A+GS20R5sjI>=K;t?n%7^=W&__zG&u$xw-)w;56JS@U zT1%S0f+573r+|v9%#gIj$@8P!rn~S`yOc5{NdV9Wz$rjPRccm=kdIg*bG|#EAJZ?@ zC?Q!JwKwN$Tzp|N$Z;c>ZA^RZoTh~YG7XsKnj<;g$v8fVkun5Gk?6Dq^2Mji*hHCN z709RKrC9GDq6*qUP)aoJQZgp;cURRh9%^vH{_l>!0m|9EY*%xQ*KUglMmgf76v*<1xe%gS(@g5p1%&oxVJ zx4lGS!t$X<+9J&(XS=Db!iK!588-_DMx3Jxj{t3M@-dpw0rMG5C2Ne*o2tYKe^WhvcfG>DRG9j}+tfwy__15GOzUx%$YVrAf~|(B+iL@; zZlyYcwo85!ouwH36!FNAd+G66jroo}`AF zazWO*(t9B+PcDXv2%dlEyEWakA}L%s$k*NptwUdlS`5h z0W?4?+|)>rXdfGZXtkL1VQIqOnKrGK`)?bDGBVS-6aZIHkb{W!*T;~Kl1Nue4-__)YTrK52Er1ywQaTUyeq+8x; zE*=v5aJ%o8x1#_^{dmQ9Uw^)Y&BNmH)V--k`{~8yi1}3+Z3V{-?wNr$Jp-3sXe`jI40I{3#7Yjs( z7aB-P-hdOrzrP`Yku)^Wql+pSt8eTJH$~KT1-BlHxt&n6Ms?M43QH z!PZ_m>gojuA{JK~mJDs#z(142tQQMUua7?&ZfN`pRosI<-H&zK(3W&(FID-v^)7!X z`H?=&fr~@lZ=WgJ;LoX&QHvQ|)=#ty;T_(Seh4PX{b9yJZ2i@mvqW$SIk0a_Vr?zv zGnFhf%@Cj4wSFO=7hl!#Qc}0VrhOM3g%d5+(RR`!j77RR47pLuGkngdh(VPRa@`!$8}|6IHCeSw_VbudzVqa9_?of#@phPBgwq1uuj&&9yY}YKR{rUm z6?zWBd^mCQ>C6660eJMgS?t8R3^eqEx{}UDBAf z`GfvG#fj938c93ewmD({4W@9~21Y@>pOVnwGF*_A^Hfcsaqs~hp-91IH zG>Tkpl27AZc;@uGH&%ezh+T~B-)=WOeKOrz^WZ;q3>pAAf(ccBQ9a+3bWyGWS`sjs z4=-7o_*356pE&I>apUIRr@d^YXvXs%h#@gK9rOCQK;%Z&kb5Se{7|8`jwng|a}Rol zyrdDbCuC4?p-O07-n3h%lY^WWeLB}x6%nTHbf}2D>iUzhBmL)t&P55l#8@8BE@UxA zdF5I|l}aKsU&4e@TtxO&D5~C=PCXFx23;S Y(rkU1_e*ZY699i&YIhN3DmLN&3*_yMxBvhE diff --git a/docs/components/picker/BrnMultiDataPicker/BrnMultiDataPicker.md b/docs/components/picker/BrnMultiDataPicker/BrnMultiDataPicker.md index 5e7c7d61..8c2b62eb 100644 --- a/docs/components/picker/BrnMultiDataPicker/BrnMultiDataPicker.md +++ b/docs/components/picker/BrnMultiDataPicker/BrnMultiDataPicker.md @@ -5,7 +5,7 @@ group: order: 23 --- -# BrnMultiDataPicker +# BrnMultiDataPicker 适用于单列或者多列数据选择的情况 From b317ec9675a24b2207e6172491848380e6d226cb Mon Sep 17 00:00:00 2001 From: violinday Date: Fri, 1 Apr 2022 13:13:44 +0800 Subject: [PATCH 22/24] =?UTF-8?q?fix=EF=BC=9A=E4=BC=98=E5=8C=96=20Demo=20A?= =?UTF-8?q?ppBar=20=E6=A0=B7=E5=BC=8F=EF=BC=8C=E4=BD=BF=E7=94=A8=20BrnAppB?= =?UTF-8?q?ar=20=E5=B1=95=E7=A4=BA=E3=80=82=20(#155)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/lib/main.dart | 2 +- .../components/selection/flat_selection_five_tags_example.dart | 2 +- .../components/selection/flat_selection_four_tags_example.dart | 2 +- .../components/selection/flat_selection_three_tags_example.dart | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index af9a7870..f1993428 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -13,7 +13,7 @@ class MyApp extends StatelessWidget { return MaterialApp( title: 'Flutter Example', theme: ThemeData( - primarySwatch: Colors.blue, + primarySwatch: Colors.grey, ), home: HomePage(), ); diff --git a/example/lib/sample/components/selection/flat_selection_five_tags_example.dart b/example/lib/sample/components/selection/flat_selection_five_tags_example.dart index 40295e5f..68b12f1e 100644 --- a/example/lib/sample/components/selection/flat_selection_five_tags_example.dart +++ b/example/lib/sample/components/selection/flat_selection_five_tags_example.dart @@ -41,7 +41,7 @@ class _SelectionViewExamplePageState @override Widget build(BuildContext context) { return Scaffold( - appBar: BrnAppBar(title: Text(widget._title)), + appBar: BrnAppBar(title: widget._title), body: SingleChildScrollView( child: Column( children: [ diff --git a/example/lib/sample/components/selection/flat_selection_four_tags_example.dart b/example/lib/sample/components/selection/flat_selection_four_tags_example.dart index 8cb13f47..b657ea1f 100644 --- a/example/lib/sample/components/selection/flat_selection_four_tags_example.dart +++ b/example/lib/sample/components/selection/flat_selection_four_tags_example.dart @@ -41,7 +41,7 @@ class _SelectionViewExamplePageState @override Widget build(BuildContext context) { return Scaffold( - appBar:BrnAppBar(title: Text(widget._title)), + appBar:BrnAppBar(title: widget._title), body: SingleChildScrollView( child: Column( children: [ diff --git a/example/lib/sample/components/selection/flat_selection_three_tags_example.dart b/example/lib/sample/components/selection/flat_selection_three_tags_example.dart index 31849c32..5639b8ef 100644 --- a/example/lib/sample/components/selection/flat_selection_three_tags_example.dart +++ b/example/lib/sample/components/selection/flat_selection_three_tags_example.dart @@ -41,7 +41,7 @@ class _SelectionViewExamplePageState @override Widget build(BuildContext context) { return Scaffold( - appBar: BrnAppBar(title: Text(widget._title)), + appBar: BrnAppBar(title: widget._title), body: SingleChildScrollView( child: Column( children: [ From f98b0523c77e1472f730447ca3cd4c2e727a9b30 Mon Sep 17 00:00:00 2001 From: violinday Date: Fri, 1 Apr 2022 17:30:57 +0800 Subject: [PATCH 23/24] =?UTF-8?q?[opt][2.2.x]:=20=201=E3=80=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20BrnPopupListWindow=20=20onItemClick=20=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E9=97=AE=E9=A2=98=EF=BC=9B2=E3=80=81changeLog?= =?UTF-8?q?=EF=BC=9B=203=E3=80=81=E4=BC=98=E5=8C=96=20Demo=20(#157)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 17 ++++++++-- .../tips/BrnPopupWindow/BrnPopupWindow.md | 2 ++ .../bottom_tabbar/bottom_tabbar_example.dart | 3 ++ .../button/brn_text_button_panel_example.dart | 4 ++- .../navbar/nav_bar_example_page.dart | 6 +++- .../button/collection/brn_button_panel.dart | 17 +++++----- .../collection/brn_text_button_panel.dart | 2 ++ .../components/popup/brn_popup_window.dart | 31 ++++++------------- 8 files changed, 46 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7459db8..4bf45da8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ -## [2.1.0-nullsafety.0] - 2022-3-10 + + +## [2.1.0-nullsafety] - 2022-4-1 + ### Changed #### base @@ -6,9 +9,9 @@ - **Breaking change**: Sound null safety support, thanks to @leftcoding #39#33 @donywan #20 @laiiihz #80#64#59#32#14 @kalifun #36 @jojinshallar #81#75#65#62#56#42 @junlandroid #73 @Kenneth #53 @HappyImp #55 @kkkman22 #23 @AlexV525 #30 - **Breaking change**: Refer to the dart language specification to optimized constant and enum naming. - Replace DIN Font with Bebas Font . -- Add build test thank to **AlexV525**. #### components + - **Breaking change**: remove BrnHorizontalStepsManager and put function forwardStep() backStep() into BrnStepsController thanks to leftcoding. - **Breaking change**: remove BrnDialogStyle and replace with BrnDialogConfig. - BrnCalendarView: add BrnCalendarView.single() and BrnCalendarView.range() constructor and had its argument startEndDateChange removed. @@ -17,17 +20,25 @@ - BrnScrollableTextDialog: remove Navigator.pop(context) in onSubmit() and hand it over to external processing (user). - BrnBubbleText: add attribute bgColor and textStyle. - BrnPairInfoTable: add attribute defaultVerticalAlignment. -- BrnDialog: remove BrnDialogStyle and replace with BrnDialogConfig. +- BrnSingleSelectDialog : add attribute messageText and messageWidget. + ### Fixed - Fix example error [#71](https://github.com/LianjiaTech/bruno/issues/71) thanks to **leftcoding** fixing this issue. + - Fix BrnPickerTitleConfig titleContent setting is invalid [#70](https://github.com/LianjiaTech/bruno/issues/70). + - Optimize BrnPopupWindow onItemClick logic [#57 ](https://github.com/LianjiaTech/bruno/issues/57) . + - Fix BrnDialog is obscured by keyboard [#7](https://github.com/LianjiaTech/bruno/issues/7) . +- Fix BrnTextSelectFormItem set titlePaddingLg doesn't work [#108](https://github.com/LianjiaTech/bruno/issues/108). + +- Fix the bottom text of BrnBottomTabBar cannot be displayed in some cases [#141](https://github.com/LianjiaTech/bruno/issues/141). + Thanks again to **leftcoding**, **jojinshallar**, **laiiihz**, **donywan**, **kalifun**, **junlandroid**, **Kenneth**, **HappyImp**, **kkkman22** , **a1017480401** and **Alex**. diff --git a/docs/components/tips/BrnPopupWindow/BrnPopupWindow.md b/docs/components/tips/BrnPopupWindow/BrnPopupWindow.md index 45938484..0313b8a1 100644 --- a/docs/components/tips/BrnPopupWindow/BrnPopupWindow.md +++ b/docs/components/tips/BrnPopupWindow/BrnPopupWindow.md @@ -124,10 +124,12 @@ RaisedButton( ![image-20211028170442805](./img/BrnPopupWindowDemo3.png) +注意:onItemClick 必须返回 true 或 false 决定是否拦截点击事件, 如果为 true 拦截事件,则内部不再走 pop 消失逻辑。 ```dart BrnPopupListWindow.showPopListWindow(context, _leftKeylist0, data: ['选项一', '选项二', '选项三'], onItemClick: (index, item) { BrnToast.show(item, context); + return false; }, hasCloseIcon: true); ``` diff --git a/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart b/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart index 764c314d..80473add 100644 --- a/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart +++ b/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart @@ -91,6 +91,9 @@ class BottomTabbarExampleState extends State home: Scaffold( appBar: BrnAppBar( title: 'BottomTabBar', + backLeadCallback: (){ + Navigator.pop(context); + }, ), /// 首先定义一个BottomTabBar容器 diff --git a/example/lib/sample/components/button/brn_text_button_panel_example.dart b/example/lib/sample/components/button/brn_text_button_panel_example.dart index 50cf4e80..388bf47c 100644 --- a/example/lib/sample/components/button/brn_text_button_panel_example.dart +++ b/example/lib/sample/components/button/brn_text_button_panel_example.dart @@ -104,7 +104,9 @@ class BrnTextButtonPanelExample extends StatelessWidget { nameList: ['操作1', '操作2', '操作3', '操作4', '操作5', '操作6'], popDirection: BrnPopupDirection.top, onTap: (index) { - BrnToast.show('第$index个操作', context); + BrnDialogManager.showSingleButtonDialog(context, message: 'index $index clicked!', label: 'OK', onTap: (){ + Navigator.pop(context); + }); }, ), Text( diff --git a/example/lib/sample/components/navbar/nav_bar_example_page.dart b/example/lib/sample/components/navbar/nav_bar_example_page.dart index a1f950fd..1f7e0cdd 100644 --- a/example/lib/sample/components/navbar/nav_bar_example_page.dart +++ b/example/lib/sample/components/navbar/nav_bar_example_page.dart @@ -246,7 +246,10 @@ class _NavBarPageState extends State with TickerProviderStateMixin { iconPressed: () { BrnPopupListWindow.showPopListWindow(context, actionKey, offset: 10, data: ["aaaa", "bbbbb"], onItemClick: (index, item){ - BrnDialogManager.showConfirmDialog(context, cancel: 'cancel', confirm: 'confirm', message: 'message'); + BrnDialogManager.showConfirmDialog(context, cancel: 'cancel', confirm: 'confirm', message: 'message', onCancel: (){ + Navigator.pop(context); + }); + return true; }, onDismiss: (){ BrnToast.show('onDismiss', context); }); @@ -516,6 +519,7 @@ class _NavBarPageState extends State with TickerProviderStateMixin { data: ["aaaa", "bbbbb"], onItemClick: (index, data) { BrnDialogManager.showConfirmDialog(context, cancel: 'cancel', confirm: 'confirm', message: 'message'); + return true; }, onDismiss: (){ BrnToast.show('onDismiss', context); diff --git a/lib/src/components/button/collection/brn_button_panel.dart b/lib/src/components/button/collection/brn_button_panel.dart index 3650f2d0..5e26e4e2 100644 --- a/lib/src/components/button/collection/brn_button_panel.dart +++ b/lib/src/components/button/collection/brn_button_panel.dart @@ -202,18 +202,17 @@ class _BrnButtonPanelState extends State { fontSize: 16)); }, popDirection: widget.popDirection, - onItemClickInterceptor: (index, item) { - // 按钮不可用的时候,点击无响应; - if (_secondaryButtonList[index + 2].isEnable) { - return false; - } else { - return true; - } - }, onItemClick: (index, item) { + // 按钮不可用的时候,点击无响应; if (widget.secondaryButtonOnTap != null) { - widget.secondaryButtonOnTap!(index + 2); + if (_secondaryButtonList[index + 2].isEnable) { + widget.secondaryButtonOnTap!(index + 2); + return false; + } else { + return true; + } } + return false; }); }, ); diff --git a/lib/src/components/button/collection/brn_text_button_panel.dart b/lib/src/components/button/collection/brn_text_button_panel.dart index 93e2f582..74b3d6a6 100644 --- a/lib/src/components/button/collection/brn_text_button_panel.dart +++ b/lib/src/components/button/collection/brn_text_button_panel.dart @@ -156,9 +156,11 @@ class _BrnTextButtonPanelState extends State { offset: 10, popDirection: widget.popDirection, data: list, onItemClick: (index, item) { + Navigator.pop(context); if (widget.onTap != null) { widget.onTap!(index + 3); } + return true; }, onDismiss: () { setState(() { _isExpanded = false; diff --git a/lib/src/components/popup/brn_popup_window.dart b/lib/src/components/popup/brn_popup_window.dart index cd0d94bc..4d39d410 100644 --- a/lib/src/components/popup/brn_popup_window.dart +++ b/lib/src/components/popup/brn_popup_window.dart @@ -455,16 +455,11 @@ class BrnPopupRoute extends PopupRoute { Duration get transitionDuration => _duration; } -/// popup 中每个 Item 被点击时的回调, +/// popup 中每个 Item 被点击时的回调,并决定是否拦截点击事件 /// [index] Item 的索引 /// [item] Item 内容 -typedef BrnPopupListItemClick = void Function(int index, String item); - -/// popup 中每个 Item 被点击时,是否拦截点击事件 -/// [index] Item 的索引 -/// [item] Item 内容 -/// 返回 true 则拦截点击事件,不再回调 [onItemClick]。 -typedef BrnPopupListItemClickInterceptor = bool Function(int index, String item); +/// 返回 true 则拦截点击事件,不再走 pop 逻辑 +typedef BrnPopupListItemClick = bool Function(int index, String item); /// popup 用于构造自定义的 Item /// [index] Item 的索引 @@ -488,7 +483,6 @@ class BrnPopupListWindow { BrnPopupDirection popDirection = BrnPopupDirection.bottom, BrnPopupListItemBuilder? itemBuilder, BrnPopupListItemClick? onItemClick, - BrnPopupListItemClickInterceptor? onItemClickInterceptor, VoidCallback? onDismiss, }) { TextStyle textStyle = TextStyle( @@ -529,8 +523,8 @@ class BrnPopupListWindow { children: _getItems(context, minWidth, maxWidth, itemBuilder, textStyle, data!, (index, item) { - if (onItemClickInterceptor != null) { - bool isIntercept = onItemClickInterceptor(index, item); + if (onItemClick != null) { + bool isIntercept = onItemClick(index, item); if (isIntercept) return; } Navigator.pop(context, {'index': index, 'item': item}); @@ -544,9 +538,6 @@ class BrnPopupListWindow { borderColor: borderColor, spaceMargin: spaceMargin, ))).then((result) { - if (onItemClick != null && result != null) { - onItemClick(result['index'], result['item']); - } if (onDismiss != null) { onDismiss(); } @@ -566,7 +557,6 @@ class BrnPopupListWindow { BrnPopupDirection popDirection = BrnPopupDirection.bottom, double offset = 0, BrnPopupListItemClick? onItemClick, - BrnPopupListItemClickInterceptor? onItemClickInterceptor, VoidCallback? onDismiss}) { assert(popKey.currentContext != null && popKey.currentContext!.findRenderObject() != null); if (popKey.currentContext == null || popKey.currentContext!.findRenderObject() == null) return; @@ -608,11 +598,11 @@ class BrnPopupListWindow { child: Column( children: _getItems(context, minWidth, maxWidth, null, textStyle, data!, (index, item) { - if (onItemClickInterceptor != null) { - bool isIntercept = onItemClickInterceptor(index, item); + if (onItemClick != null) { + bool isIntercept = onItemClick(index, item); if (isIntercept) return; } - Navigator.pop(context, {'index': index, 'item': item}); + Navigator.pop(context); }), ), ), @@ -625,9 +615,6 @@ class BrnPopupListWindow { ), ), ).then((result) { - if (onItemClick != null && result != null) { - onItemClick(result['index'], result['item']); - } if (onDismiss != null) { onDismiss(); } @@ -641,7 +628,7 @@ class BrnPopupListWindow { BrnPopupListItemBuilder? itemBuilder, TextStyle textStyle, List data, - BrnPopupListItemClick onItemClick) { + void Function(int index, String item) onItemClick) { double textMaxWidth = _getMaxWidth(textStyle, data); if (textMaxWidth + 52 < minWidth) { textMaxWidth = minWidth; From db6aff0f4abc1939c76778e1aaa7382e6bd715a9 Mon Sep 17 00:00:00 2001 From: violinday Date: Fri, 1 Apr 2022 17:56:14 +0800 Subject: [PATCH 24/24] =?UTF-8?q?opt=EF=BC=9Achange=20the=20docs=20dir=20t?= =?UTF-8?q?o=20doc=20(#159)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- {docs => doc}/FAQ.md | 0 {docs => doc}/bruno.md | 0 .../BrnAbnormalStateWidget.md | 0 .../BrnAbnormalStateWidget/img/empty_state_1.png | Bin .../BrnAbnormalStateWidget/img/empty_state_2.png | Bin .../BrnAbnormalStateWidget/img/empty_state_3.png | Bin .../BrnAbnormalStateWidget/img/empty_state_4.png | Bin .../BrnAbnormalStateWidget/img/empty_state_5.png | Bin .../img/empty_state_intro.png | Bin .../BrnCommonActionSheet/BrnCommonActionSheet.md | 0 .../img/brn_action_sheet_common_widget_1.png | Bin .../img/brn_action_sheet_common_widget_2.png | Bin .../img/brn_action_sheet_common_widget_3.png | Bin .../img/brn_action_sheet_common_widget_4.png | Bin .../BrnSelectedListActionSheet.md | 0 .../img/BrnSelectedListActionSheetDemo1.png | Bin .../img/BrnSelectedListActionSheetDemo2.png | Bin .../img/BrnSelectedListActionSheetDemo3.png | Bin .../BrnShareActionSheet/BrnShareActionSheet.md | 0 .../BrnShareActionSheet/img/actionSheet_share_1.png | Bin .../BrnShareActionSheet/img/actionSheet_share_2.png | Bin .../BrnShareActionSheet/img/actionSheet_share_3.png | Bin .../BrnShareActionSheet/img/actionSheet_share_4.png | Bin .../components/anchor/BrnAnchorTab/BrnAnchorTab.md | 0 .../anchor/BrnAnchorTab/img/anchorTab.gif | Bin .../components/appbar/BrnAppBar/BrnAppBar.md | 0 .../appbar/BrnAppBar/img/BrnAppBarIntro.png | Bin .../BrnAppBar/img/appbar_doubleright_icon.png | Bin .../components/appbar/BrnAppBar/img/appbar_down.png | Bin .../appbar/BrnAppBar/img/appbar_left_icon.png | Bin .../appbar/BrnAppBar/img/appbar_leftright_icon.png | Bin .../appbar/BrnAppBar/img/appbar_srolltitle.png | Bin .../appbar/BrnAppBar/img/appbar_three_tab.png | Bin .../components/appbar/BrnAppBar/img/more_icon.png | Bin .../appbar/BrnSearchAppbar/BrnSearchAppbar.md | 0 .../BrnSearchAppbar/img/BrnSearchAppbarDemo1.png | Bin .../BrnSearchAppbar/img/BrnSearchAppbarDemo2.png | Bin .../BrnSearchAppbar/img/BrnSearchAppbarIntro.png | Bin .../components/appraise/BrnAppraise/BrnAppraise.md | 0 .../appraise/BrnAppraise/img/BrnAppraiseDemo1.png | Bin .../appraise/BrnAppraise/img/BrnAppraiseDemo2.png | Bin .../appraise/BrnAppraise/img/BrnAppraiseDemo2_1.png | Bin .../BrnAppraise/img/BrnAppraiseDemoIntro.png | Bin .../BrnAppraiseBottomPicker.md | 0 .../img/BrnAppraiseBottomPickerDemo1.png | Bin .../img/BrnAppraiseBottomPickerDemo2.png | Bin .../img/BrnAppraiseBottomPickerDemo3.png | Bin .../img/BrnAppraiseBottomPickerIntro.png | Bin .../img/brn_appraise_picker.png | Bin .../BrnBottomButtonPanel/BrnBottomButtonPanel.md | 0 .../BrnBottomButtonPanel/img/disable_and_enable.png | Bin .../BrnBottomButtonPanel/img/disable_main.png | Bin .../BrnBottomButtonPanel/img/pannel_1.png | Bin .../BrnBottomButtonPanel/img/pannel_2.png | Bin .../BrnBottomButtonPanel/img/pannel_3.png | Bin .../BrnBottomButtonPanel/img/pannel_4.png | Bin .../BrnBottomButtonPanel/img/pannel_5.png | Bin .../BrnBottomButtonPanel/img/pannel_6.png | Bin .../BrnMultipleBottomButton.md | 0 .../img/BrnMultipleBottomButtonDemo1.png | Bin .../img/BrnMultipleBottomButtonDemo2.png | Bin .../img/BrnMultipleBottomButtonDemo3.png | Bin .../img/BrnMultipleBottomButtonDemo4.png | Bin .../img/BrnMultipleBottomButtonIntro.png | Bin .../bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md | 0 .../BrnBottomTabBar/img/BrnBottomTabBar.png | Bin .../bubble/BrnBubbleText/BrnBubbleText.md | 0 .../BrnBubbleText/img/bubbleTextCollapsed.png | Bin .../bubble/BrnBubbleText/img/bubbleTextExpaned.png | Bin .../bubble/BrnInsertInfo/BrnInsertInfo.md | 0 .../bubble/BrnInsertInfo/img/insert_info.png | Bin .../buttonPanel/BrnButtonPanel/BrnButtonPanel.md | 0 .../BrnButtonPanel/img/BrnButtonPanelDemo1.png | Bin .../BrnButtonPanel/img/BrnButtonPanelDemo2.png | Bin .../BrnButtonPanel/img/BrnButtonPanelDemo3.png | Bin .../BrnButtonPanel/img/BrnButtonPanelDemo4.png | Bin .../BrnButtonPanel/img/BrnButtonPanelDemo5.png | Bin .../BrnButtonPanel/img/BrnButtonPanelDemo6.png | Bin .../BrnButtonPanel/img/BrnButtonPanelIntro.png | Bin .../BrnTextButtonPanel/BrnTextButtonPanel.md | 0 .../img/BrnTextButtonPanelDemo1.png | Bin .../img/BrnTextButtonPanelDemo2.png | Bin .../img/BrnTextButtonPanelDemo3.png | Bin .../img/BrnTextButtonPanelDemo4.png | Bin .../img/BrnTextButtonPanelDemo5.png | Bin .../img/BrnTextButtonPanelIntro.png | Bin .../calendar/BrnCalendarView/BrnCalendarView.md | 0 .../BrnCalendarView/img/BrnCalendarViewDemo1.png | Bin .../BrnCalendarView/img/BrnCalendarViewDemo2.png | Bin .../BrnCalendarView/img/BrnCalendarViewDemo3.png | Bin .../BrnCalendarView/img/BrnCalendarViewDemo4.png | Bin .../BrnCalendarView/img/BrnCalendarViewDemo5.png | Bin .../BrnCalendarView/img/BrnCalendarViewDemo6.png | Bin .../BrnCalendarView/img/BrnCalendarViewIntro1.png | Bin .../BrnCalendarView/img/BrnCalendarViewIntro2.png | Bin .../BrnCalendarView/img/BrnCalendarViewIntro3.png | Bin .../BrnCalendarView/img/BrnCalendarViewIntro4.png | Bin .../BrnCalendarView/img/BrnCalendarViewIntro5.png | Bin .../charts/BrnBrokenLine/BrnBrokenLine.md | 0 .../charts/BrnBrokenLine/img/BrnBrokenLineDemo1.png | Bin .../charts/BrnBrokenLine/img/BrnBrokenLineDemo2.png | Bin .../charts/BrnBrokenLine/img/BrnBrokenLineIntro.png | Bin .../charts/BrnDoughnutChart/BrnDoughnutChart.md | 0 .../BrnDoughnutChart/img/BrnDoughnutChartDemo1.png | Bin .../BrnDoughnutChart/img/BrnDoughnutChartIntro.png | Bin .../charts/BrnFunnelChart/BrnFunnelChart.md | 0 .../charts/BrnFunnelChart/img/BrnFunnelChart1.png | Bin .../charts/BrnFunnelChart/img/BrnFunnelChart2.png | Bin .../charts/BrnFunnelChart/img/BrnFunnelChart3.png | Bin .../BrnFunnelChart/img/BrnFunnelChartIntro.png | Bin .../BrnProgressBarChart/BrnProgressBarChart.md | 0 .../img/BrnProgressBarChartDemo1.png | Bin .../img/BrnProgressBarChartDemo2.png | Bin .../img/BrnProgressBarChartIntro1.png | Bin .../img/BrnProgressBarChartIntro2.png | Bin .../charts/BrnProgressChart/BrnProgressChart.md | 0 .../BrnProgressChart/img/BrnProgressChartDemo1.png | Bin .../BrnProgressChart/img/BrnProgressChartIntro.png | Bin .../charts/BrnRadarChart/BrnRadarChart.md | 0 .../charts/BrnRadarChart/img/BrnRadarChartDemo1.png | Bin .../charts/BrnRadarChart/img/BrnRadarChartDemo2.png | Bin .../charts/BrnRadarChart/img/BrnRadarChartIntro.png | Bin .../components/checkbox/BrnCheckbox/BrnCheckbox.md | 0 .../BrnSingleSelectCityPage.md | 0 .../img/BrnSingleSelectCityPageDemo1.png | Bin .../img/BrnSingleSelectCityPageIntro.png | Bin .../dashedLine/BrnDashedLine/BrnDashedLine.md | 0 .../BrnDashedLine/img/BrnDashedLineDemo1.png | Bin .../BrnDashedLine/img/BrnDashedLineDemo2.png | Bin .../BrnDashedLine/img/BrnDashedLineDemo3.png | Bin .../BrnDashedLine/img/BrnDashedLineIntro.png | Bin .../components/dialog/BrnDialog/BrnDialog.md | 0 .../dialog/BrnDialog/img/common_dialog_2.png | Bin .../dialog/BrnDialog/img/common_dialog_3.png | Bin .../dialog/BrnDialog/img/common_dialog_4.png | Bin .../dialog/BrnDialog/img/common_dialog_5.png | Bin .../dialog/BrnDialog/img/common_dialog_6.png | Bin .../dialog/BrnDialog/img/common_dialog_7.png | Bin .../dialog/BrnDialog/img/common_dialog_8.png | Bin .../dialog/BrnDialog/img/common_dialog_9.png | Bin .../dialog/BrnDialog/img/common_diloag_0.png | Bin .../dialog/BrnDialog/img/common_diloag_1.png | Bin .../BrnEnhanceOperationDialog.md | 0 .../img/BrnEnhanceOperationDialogDemo1.png | Bin .../img/BrnEnhanceOperationDialogDemo2.png | Bin .../img/BrnEnhanceOperationDialogIntro1.png | Bin .../img/dialog_two_vertical_button_1.png | Bin .../dialog/BrnLoadingDialog/BrnLoadingDialog.md | 0 .../BrnLoadingDialog/img/BrnLoadingDialogIntro.png | Bin .../BrnMiddleInputDialog/BrnMiddleInputDialog.md | 0 .../img/BrnMiddleInputDialogIntro1.png | Bin .../img/BrnMiddleInputDialogIntro2.png | Bin .../BrnMiddleInputDialog/img/middleinoutdialog.png | Bin .../BrnMultiSelectDialog/BrnMultiSelectDialog.md | 0 .../img/BrnMultiSelectDialogDemo1.png | Bin .../img/BrnMultiSelectDialogDemo2.png | Bin .../img/BrnMultiSelectDialogDemo3.png | Bin .../img/BrnMultiSelectDialogIntro.png | Bin .../BrnScrollableTextDialog.md | 0 .../img/BrnScrollableTextDialogDemo1.png | Bin .../img/BrnScrollableTextDialogDemo2.png | Bin .../img/BrnScrollableTextDialogDemo3.png | Bin .../img/BrnScrollableTextDialogDemo4.png | Bin .../dialog/BrnShareDialog/BrnShareDialog.md | 0 .../BrnShareDialog/img/BrnShareDialogDemo1.png | Bin .../BrnShareDialog/img/BrnShareDialogDemo2.png | Bin .../BrnSingleSelectDialog/BrnSingleSelectDialog.md | 0 .../img/BrnSingleSelectDialog.png | Bin .../components/form/BrnAddLabel/BrnAddLabel.md | 0 .../form/BrnAddLabel/img/BrnAddLabelDemo1.png | Bin .../form/BrnAddLabel/img/BrnAddLabelIntro.png | Bin .../components/form/BrnBaseTitle/BrnBaseTitle.md | 0 .../form/BrnBaseTitle/img/BrnBaseTitleDemo1.png | Bin .../form/BrnBaseTitle/img/BrnBaseTitleDemo2.png | Bin .../form/BrnBaseTitle/img/BrnBaseTitleIntro.png | Bin .../form/BrnExpandFormGroup/BrnExpandFormGroup.md | 0 .../img/BrnExpandFormGroupDemo1.png | Bin .../img/BrnExpandFormGroupDemo2.png | Bin .../img/BrnExpandFormGroupDemo3.png | Bin .../img/BrnExpandFormGroupIntro.png | Bin .../form/BrnExpandableGroup/BrnExpandableGroup.md | 0 .../img/BrnExpandableGroupIntro1.gif | Bin .../img/BrnExpandableGroupIntro2.png | Bin .../BrnMultiChoiceInputFormItem.md | 0 .../img/BrnMultiChoiceInputFormItemDemo1.png | Bin .../img/BrnMultiChoiceInputFormItemDemo2.png | Bin .../img/BrnMultiChoiceInputFormItemIntro.png | Bin .../BrnMultiChoicePortraitInputFormItem.md | 0 .../BrnMultiChoicePortraitInputFormItemDemo1.png | Bin .../BrnMultiChoicePortraitInputFormItemDemo2.png | Bin .../BrnMultiChoicePortraitInputFormItemIntro.png | Bin .../form/BrnNormalFormGroup/BrnNormalFormGroup.md | 0 .../img/BrnNormalFormGroupDemo1.png | Bin .../img/BrnNormalFormGroupDemo2.png | Bin .../img/BrnNormalFormGroupIntro.png | Bin .../BrnPortraitRadioGroup/BrnPortraitRadioGroup.md | 0 .../img/BrnPortraitRadioGroupDemo1.png | Bin .../img/BrnPortraitRadioGroupDemo2.png | Bin .../BrnRadioInputFormItem/BrnRadioInputFormItem.md | 0 .../img/BrnRadioInputFormItemDemo1.png | Bin .../img/BrnRadioInputFormItemDemo2.png | Bin .../img/BrnRadioInputFormItemDemo3.png | Bin .../img/BrnRadioInputFormItemDemo4.png | Bin .../img/BrnRadioInputFormItemIntro.png | Bin .../BrnRadioPortraitInputFormItem.md | 0 .../img/BrnRadioPortraitInputFormItemDemo1.png | Bin .../img/BrnRadioPortraitInputFormItemDemo2.png | Bin .../img/BrnRadioPortraitInputFormItemIntro.png | Bin .../BrnRangeInputFormItem/BrnRangeInputFormItem.md | 0 .../img/BrnRangeInputFormItemDemo1.png | Bin .../img/BrnRangeInputFormItemDemo2.png | Bin .../img/BrnRangeInputFormItemIntro.png | Bin .../BrnRatioInputFormItem/BrnRatioInputFormItem.md | 0 .../img/BrnRatioInputFormItemDemo1.png | Bin .../img/BrnRatioInputFormItemDemo2.png | Bin .../img/BrnRatioInputFormItemIntro.png | Bin .../form/BrnSelectAllTitle/BrnSelectAllTitle.md | 0 .../img/BrnSelectAllTitleDemo1.png | Bin .../img/BrnSelectAllTitleDemo2.png | Bin .../img/BrnSelectAllTitleIntro.png | Bin .../form/BrnStarsFormItem/BrnStarsFormItem.md | 0 .../BrnStarsFormItem/img/BrnStarsFormItemDemo1.png | Bin .../BrnStarsFormItem/img/BrnStarsFormItemDemo2.png | Bin .../BrnStarsFormItem/img/BrnStarsFormItemIntro.png | Bin .../BrnStepInputFormItem/BrnStepInputFormItem.md | 0 .../img/BrnStepInputFormItemDemo1.png | Bin .../img/BrnStepInputFormItemDemo2.png | Bin .../img/BrnStepInputFormItemIntro.png | Bin .../BrnTextBlockInputFormItem.md | 0 .../img/BrnTextBlockInputFormItemDemo1.png | Bin .../img/BrnTextBlockInputFormItemDemo2.png | Bin .../img/BrnTextBlockInputFormItemDemo3.png | Bin .../img/BrnTextBlockInputFormItemDemo4.png | Bin .../img/BrnTextBlockInputFormItemIntro.png | Bin .../BrnTextInputFormItem/BrnTextInputFormItem.md | 0 .../img/BrnTextInputFormItemDemo1.png | Bin .../img/BrnTextInputFormItemDemo2.png | Bin .../img/BrnTextInputFormItemDemo3.png | Bin .../img/BrnTextInputFormItemDemo4.png | Bin .../img/BrnTextInputFormItemIntro.png | Bin .../BrnTextQuickSelectFormItem.md | 0 .../img/BrnTextQuickSelectFormItemDemo1.png | Bin .../img/BrnTextQuickSelectFormItemDemo2.png | Bin .../img/BrnTextQuickSelectFormItemIntro.png | Bin .../BrnTextSelectFormItem/BrnTextSelectFormItem.md | 0 .../img/BrnTextSelectFormItemDemo1.png | Bin .../img/BrnTextSelectFormItemDemo2.png | Bin .../img/BrnTextSelectFormItemDemo3.png | Bin .../img/BrnTextSelectFormItemDemo4.png | Bin .../img/BrnTextSelectFormItemIntro.png | Bin .../form/BrnTitleFormItem/BrnTitleFormItem.md | 0 .../BrnTitleFormItem/img/BrnTitleFormItemDemo1.png | Bin .../BrnTitleFormItem/img/BrnTitleFormItemDemo2.png | Bin .../BrnTitleFormItem/img/BrnTitleFormItemDemo3.png | Bin .../BrnTitleFormItem/img/BrnTitleFormItemIntro.png | Bin .../BrnTitleSelectInputFormItem.md | 0 .../img/BrnTitleSelectInputFormItemDemo1.png | Bin .../img/BrnTitleSelectInputFormItemDemo2.png | Bin .../img/BrnTitleSelectInputFormItemIntro.png | Bin .../BrnGalleryDetailPage/BrnGalleryDetailPage.md | 0 .../img/BrnGalleryDetailPageDemo1.jpg | Bin .../img/BrnGalleryDetailPageDemo3.gif | Bin .../img/BrnGalleryDetailPageIntro.png | Bin .../img/image-20211101121347565.png | Bin .../BrnGallerySummaryPage/BrnGallerySummaryPage.md | 0 .../img/BrnGallerySummaryPageDemo.png | Bin .../img/BrnGallerySummaryPageIntro.png | Bin {docs => doc}/components/guide/BrnGuide/BrnGuide.md | 0 .../guide/BrnGuide/img/BrnGuideForceDemo.gif | Bin .../guide/BrnGuide/img/BrnGuideIntroForceGuide.png | Bin .../guide/BrnGuide/img/BrnGuideIntroSoftGuide.png | Bin .../guide/BrnGuide/img/BrnGuideSoftDemo.gif | Bin .../iconButton/BrnIconButton/BrnIconButton.md | 0 .../BrnIconButton/img/BrnIconButtonIntro.png | Bin .../BrnVerticalIconButton/BrnVerticalIconButton.md | 0 .../img/BrnVerticalIconButtonIntro.png | Bin .../components/input/BrnInputText/BrnInputText.md | 0 .../BrnInputText/img/BrnInputTextDemoEmpty.png | Bin .../input/BrnInputText/img/BrnInputTextDemoFull.png | Bin .../input/BrnInputText/img/BrnInputTextIntro.png | Bin .../loading/BrnPageLoading/BrnPageLoading.md | 0 .../BrnPageLoading/img/BrnPageLoadingDemo1.png | Bin .../BrnPageLoading/img/BrnPageLoadingDemo2.png | Bin .../BrnBigGhostButton/BrnBigGhostButton.md | 0 .../BrnBigGhostButton/img/BrnBigGhostButtonDemo.png | Bin .../BrnBigMainButton/BrnBigMainButton.md | 0 .../BrnBigMainButton/img/BrnBigMainButton.png | Bin .../img/BrnBigMainButtonDisabled.png | Bin .../BrnBigOutlineButton/BrnBigOutlineButton.md | 0 .../BrnBigOutlineButton/img/BrnBigOutlineButton.png | Bin .../img/BrnBigOutlineButtonDisabled.png | Bin .../BrnSmallMainButton/BrnSmallMainButton.md | 0 .../BrnSmallMainButton/img/BrnSmallMainButton.png | Bin .../img/BrnSmallMainButtonDisabled.png | Bin .../BrnSmallOutlineButton/BrnSmallOutlineButton.md | 0 .../img/BrnSmallOutlineButton.png | Bin .../img/BrnSmallOutlineButtonDisabled.png | Bin .../notification/BrnNoticeBar/BrnNoticeBar.md | 0 .../BrnNoticeBar/img/BrnNoticeBarDemo1.png | Bin .../BrnNoticeBar/img/BrnNoticeBarDemo2.png | Bin .../BrnNoticeBar/img/BrnNoticeBarDemo3.png | Bin .../BrnNoticeBar/img/BrnNoticeBarDemo4.gif | Bin .../BrnNoticeBar/img/BrnNoticeBarIntro1.png | Bin .../BrnNoticeBar/img/BrnNoticeBarIntro2.png | Bin .../BrnNoticeBarWithButton.md | 0 .../img/BrnNoticeBarWithButtonDemo1.png | Bin .../img/BrnNoticeBarWithButtonDemo2.png | Bin .../img/BrnNoticeBarWithButtonDemo3.gif | Bin .../img/BrnNoticeBarWithButtonIntro.png | Bin .../picker/BrnBottomPicker/BrnBottomPicker.md | 0 .../BrnBottomPicker/img/BrnBottomPickerDemo1.png | Bin .../BrnBottomPicker/img/BrnBottomPickerDemo2.png | Bin .../BrnBottomWritePicker/BrnBottomWritePicker.md | 0 .../img/BrnBottomWritePicker.png | Bin .../picker/BrnDatePicker/BrnDatePicker.md | 0 .../picker/BrnDatePicker/img/BrnDatePickerTime.png | Bin .../picker/BrnDatePicker/img/BrnDatePickerYMD.png | Bin .../BrnDatePicker/img/BrnDatePickerYMDHMS.png | Bin .../picker/BrnDateRangePicker/BrnDateRangePicker.md | 0 .../BrnDateRangePicker/img/BrnDateRangePicker1.png | Bin .../BrnDateRangePicker/img/BrnDateRangePicker2.png | Bin .../BrnDateRangePicker/img/BrnDateRangePicker3.png | Bin .../img/BrnDateRangePickerDemo1.png | Bin .../img/BrnDateRangePickerDemo2.png | Bin .../img/BrnDateRangePickerDemo3.png | Bin .../BrnMultiColumnPicker/BrnMultiColumnPicker.md | 0 .../img/BrnMultiColumnPickerDemo.png | Bin .../img/BrnMultiColumnPickerIntro.png | Bin .../picker/BrnMultiDataPicker/BrnMultiDataPicker.md | 0 .../img/BrnMultiDataPickerDemo1.png | Bin .../img/BrnMultiDataPickerDemo2.png | Bin .../img/BrnMultiDataPickerDemo3.png | Bin .../img/BrnMultiDataPickerDemo4.png | Bin .../img/BrnMultiDataPickerIntro.png | Bin .../BrnMultiSelectListPicker.md | 0 .../img/BrnMultiSelectListPicker.png | Bin .../BrnMultiSelectTagsPicker.md | 0 .../img/BrnMultiSelectTagsPickerIntro.png | Bin .../BrnSelectTagsWithInputPicker.md | 0 .../img/BrnSelectTagsWithInputPicker1.png | Bin .../radio/BrnRadioButton/BrnRadioButton.md | 0 .../BrnRadioButton/img/BrnRadioButtonIntro.png | Bin .../radio/BrnRadioButton/img/BrnRadioItemDemo1.png | Bin .../radio/BrnRadioButton/img/BrnRadioItemDemo3.png | Bin .../ratingBar/BrnRatingStar/BrnRatingStar.md | 0 .../BrnRatingStar/img/BrnRatingStarDEmo4.png | Bin .../BrnRatingStar/img/BrnRatingStarDemo1.png | Bin .../BrnRatingStar/img/BrnRatingStarDemo2.png | Bin .../BrnRatingStar/img/BrnRatingStarDemo3.png | Bin .../BrnRatingStar/img/BrnRatingStarIntro.png | Bin .../search/BrnSearchText/BrnSearchText.md | 0 .../search/BrnSearchText/img/1620980916893bbbbb.gif | Bin .../search/BrnSearchText/img/1620981018721ccccc.gif | Bin .../search/BrnSearchText/img/BrnSearchTextDemo1.gif | Bin .../search/BrnSearchText/img/BrnSearchTextDemo2.png | Bin .../search/BrnSearchText/img/BrnSearchTextIntro.png | Bin .../selection/BrnFlatSelection/BrnFlatSelection.md | 0 .../BrnFlatSelection/img/BrnFlatSelectionDemo1.png | Bin .../BrnFlatSelection/img/BrnFlatSelectionDemo2.png | Bin .../BrnFlatSelection/img/BrnFlatSelectionIntro.png | Bin .../selection/BrnSelectionView/BrnSelectionView.md | 0 .../BrnSelectionView/img/BrnSelectionViewDemo1.png | Bin .../BrnSelectionView/img/BrnSelectionViewDemo2.png | Bin .../BrnSelectionView/img/BrnSelectionViewDemo4.gif | Bin .../BrnSelectionView/img/BrnSelectionViewDemo5.png | Bin .../BrnSelectionView/img/BrnSelectionViewIntro.png | Bin .../BrnSelectionView/img/BrnSelectionViewIntro2.png | Bin .../BrnSelectionView/img/BrnSelectionViewIntro3.png | Bin .../img/BrnSelectionViewMorePage.png | Bin .../img/BrnSelectionViewMorePage2.png | Bin .../img/image-20211030160608171.png | Bin .../img/image-20211101155937783.png | Bin .../BrnSimpleSelection/BrnSimpleSelection.md | 0 .../img/simple_selection_checkbox.png | Bin .../img/simple_selection_radio.png | Bin .../shadowCard/BrnShadowCard/BrnShadowCard.md | 0 .../BrnShadowCard/img/BrnShadowCardIntro.png | Bin .../BrnShadowCard/img/BrnShadowCardIntroDemo1.png | Bin .../BrnHorizontalSteps/BrnHorizontalSteps.md | 0 .../img/BrnMetaHorizontalSteps1.jpg | Bin .../img/BrnMetaHorizontalSteps2.jpg | Bin .../img/BrnMetaHorizontalSteps3.jpg | Bin .../img/BrnMetaHorizontalSteps4.jpg | Bin .../img/BrnMetaHorizontalSteps5.png | Bin .../components/stepBar/BrnStepLine/BrnStepLine.md | 0 .../stepBar/BrnStepLine/img/BrnStepLine1.png | Bin .../stepBar/BrnStepLine/img/BrnStepLine2.png | Bin .../stepBar/BrnStepLine/img/BrnStepLine3.png | Bin .../stepBar/BrnStepLine/img/BrnStepLine4.png | Bin .../components/tabbar/BrnTabBar/BrnTabBar.md | 0 .../tabbar/BrnTabBar/img/BrnTabBarDemo1.png | Bin .../tabbar/BrnTabBar/img/BrnTabBarDemo2.png | Bin .../tabbar/BrnTabBar/img/BrnTabBarDemo3.png | Bin .../tabbar/BrnTabBar/img/BrnTabBarDemo4.png | Bin .../tabbar/BrnTabBar/img/BrnTabBarDemo5.png | Bin .../tabbar/BrnTabBar/img/BrnTabBarDemo6.png | Bin .../tabbar/BrnTabBar/img/BrnTabBarIntro.png | Bin .../components/tag/BrnDeleteTag/BrnDeleteTag.md | 0 .../tag/BrnDeleteTag/img/BrnDeleteTagDemo1.png | Bin .../tag/BrnDeleteTag/img/BrnDeleteTagDemo2.png | Bin .../tag/BrnDeleteTag/img/BrnDeleteTagIntro.png | Bin .../components/tag/BrnSelectTag/BrnSelectTag.md | 0 .../tag/BrnSelectTag/img/BrnSelectTagDemo1.png | Bin .../tag/BrnSelectTag/img/BrnSelectTagDemo2.png | Bin .../tag/BrnSelectTag/img/BrnSelectTagDemo3.png | Bin .../tag/BrnSelectTag/img/BrnSelectTagDemo4.png | Bin .../tag/BrnSelectTag/img/BrnSelectTagDemo5.png | Bin .../tag/BrnSelectTag/img/BrnSelectTagIntro.png | Bin .../components/tag/BrnStateTag/BrnStateTag.md | 0 .../tag/BrnStateTag/img/BrnMetaStateTagIntro.png | Bin .../tag/BrnStateTag/img/BrnMetaStateTagSucceed.png | Bin .../tag/BrnStateTag/img/BrnStateTagFailure.png | Bin .../components/tag/BrnTagCustom/BrnTagCustom.md | 0 .../tag/BrnTagCustom/img/BrnTagCustomDemo1.png | Bin .../tag/BrnTagCustom/img/BrnTagCustomDemo2.png | Bin .../tag/BrnTagCustom/img/BrnTagCustomDemo3.png | Bin .../BrnEnhanceNumberCard/BrnEnhanceNumberCard.md | 0 .../img/BrnEnhanceNumberCardDemo1.png | Bin .../img/BrnEnhanceNumberCardDemo2.png | Bin .../img/BrnEnhanceNumberCardDemo3.png | Bin .../img/BrnEnhanceNumberCardDemo4.png | Bin .../img/BrnEnhanceNumberCardDemo5.png | Bin .../img/BrnEnhanceNumberCardIntro.png | Bin .../img/BrnEnhanceNumberCardIntro1.png | Bin .../text/BrnExpandableText/BrnExpandableText.md | 0 .../img/BrnExpandableTextIntro1.png | Bin .../img/BrnExpandableTextIntro2.png | Bin .../text/BrnPairInfoTable/BrnPairInfoTable.md | 0 .../BrnPairInfoTable/img/BrnPairInfoTableDemo3.png | Bin .../BrnPairInfoTable/img/BrnPairInfoTableDemo4.png | Bin .../BrnPairInfoTable/img/BrnPairInfoTableDemo5.png | Bin .../BrnPairInfoTable/img/BrnPairInfoTableIntro1.png | Bin .../BrnPairInfoTable/img/BrnPairInfoTableIntro2.png | Bin .../BrnPairInfoTable/img/BrnPairInfoTableIntro3.png | Bin .../text/BrnRichInfoGrid/BrnRichInfoGrid.md | 0 .../BrnRichInfoGrid/img/BrnRichInfoGridDemo1.png | Bin .../BrnRichInfoGrid/img/BrnRichInfoGridDemo2.png | Bin .../tips/BrnPopupWindow/BrnPopupWindow.md | 0 .../tips/BrnPopupWindow/img/BrnPopupWindowDemo1.png | Bin .../tips/BrnPopupWindow/img/BrnPopupWindowDemo2.png | Bin .../tips/BrnPopupWindow/img/BrnPopupWindowDemo3.png | Bin .../tips/BrnPopupWindow/img/BrnPopupWindowIntro.png | Bin .../title/BrnActionCardTitle/BrnActionCardTitle.md | 0 .../img/BrnActionCardTitleDemo.png | Bin .../title/BrnCommonCardTitle/BrnCommonCardTitle.md | 0 .../img/BrnCommonCardTitleDemo1.png | Bin .../img/BrnCommonCardTitleDemo2.png | Bin .../img/BrnCommonCardTitleDemo3.png | Bin .../img/BrnCommonCardTitleIntro.png | Bin .../title/BrnSubSwitchTitle/BrnSubSwitchTitle.md | 0 .../img/BrnSubSwitchTitleDemo1.png | Bin .../img/BrnSubSwitchTitleDemo2.gif | Bin .../title/BrnSwitchTitle/BrnSwitchTitle.md | 0 .../BrnSwitchTitle/img/BrnSwitchTitleDemo1.png | Bin .../BrnSwitchTitle/img/BrnSwitchTitleDemo2.gif | Bin {docs => doc}/components/toast/BrnToast/BrnToast.md | 0 .../toast/BrnToast/img/brn_toast_fail.png | Bin .../toast/BrnToast/img/brn_toast_intro.png | Bin .../toast/BrnToast/img/brn_toast_normal.png | Bin .../toast/BrnToast/img/brn_toast_success.png | Bin {docs => doc}/contribution.md | 0 {docs => doc}/sketch.md | 0 {docs => doc}/start.md | 0 {docs => doc}/theme.md | 0 464 files changed, 0 insertions(+), 0 deletions(-) rename {docs => doc}/FAQ.md (100%) rename {docs => doc}/bruno.md (100%) rename {docs => doc}/components/abnormalCard/BrnAbnormalStateWidget/BrnAbnormalStateWidget.md (100%) rename {docs => doc}/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_1.png (100%) rename {docs => doc}/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_2.png (100%) rename {docs => doc}/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_3.png (100%) rename {docs => doc}/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_4.png (100%) rename {docs => doc}/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_5.png (100%) rename {docs => doc}/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_intro.png (100%) rename {docs => doc}/components/actionsheet/BrnCommonActionSheet/BrnCommonActionSheet.md (100%) rename {docs => doc}/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_1.png (100%) rename {docs => doc}/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_2.png (100%) rename {docs => doc}/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_3.png (100%) rename {docs => doc}/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_4.png (100%) rename {docs => doc}/components/actionsheet/BrnSelectedListActionSheet/BrnSelectedListActionSheet.md (100%) rename {docs => doc}/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo1.png (100%) rename {docs => doc}/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo2.png (100%) rename {docs => doc}/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo3.png (100%) rename {docs => doc}/components/actionsheet/BrnShareActionSheet/BrnShareActionSheet.md (100%) rename {docs => doc}/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_1.png (100%) rename {docs => doc}/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_2.png (100%) rename {docs => doc}/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_3.png (100%) rename {docs => doc}/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_4.png (100%) rename {docs => doc}/components/anchor/BrnAnchorTab/BrnAnchorTab.md (100%) rename {docs => doc}/components/anchor/BrnAnchorTab/img/anchorTab.gif (100%) rename {docs => doc}/components/appbar/BrnAppBar/BrnAppBar.md (100%) rename {docs => doc}/components/appbar/BrnAppBar/img/BrnAppBarIntro.png (100%) rename {docs => doc}/components/appbar/BrnAppBar/img/appbar_doubleright_icon.png (100%) rename {docs => doc}/components/appbar/BrnAppBar/img/appbar_down.png (100%) rename {docs => doc}/components/appbar/BrnAppBar/img/appbar_left_icon.png (100%) rename {docs => doc}/components/appbar/BrnAppBar/img/appbar_leftright_icon.png (100%) rename {docs => doc}/components/appbar/BrnAppBar/img/appbar_srolltitle.png (100%) rename {docs => doc}/components/appbar/BrnAppBar/img/appbar_three_tab.png (100%) rename {docs => doc}/components/appbar/BrnAppBar/img/more_icon.png (100%) rename {docs => doc}/components/appbar/BrnSearchAppbar/BrnSearchAppbar.md (100%) rename {docs => doc}/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarDemo1.png (100%) rename {docs => doc}/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarDemo2.png (100%) rename {docs => doc}/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarIntro.png (100%) rename {docs => doc}/components/appraise/BrnAppraise/BrnAppraise.md (100%) rename {docs => doc}/components/appraise/BrnAppraise/img/BrnAppraiseDemo1.png (100%) rename {docs => doc}/components/appraise/BrnAppraise/img/BrnAppraiseDemo2.png (100%) rename {docs => doc}/components/appraise/BrnAppraise/img/BrnAppraiseDemo2_1.png (100%) rename {docs => doc}/components/appraise/BrnAppraise/img/BrnAppraiseDemoIntro.png (100%) rename {docs => doc}/components/appraise/BrnAppraiseBottomPicker/BrnAppraiseBottomPicker.md (100%) rename {docs => doc}/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo1.png (100%) rename {docs => doc}/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo2.png (100%) rename {docs => doc}/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo3.png (100%) rename {docs => doc}/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerIntro.png (100%) rename {docs => doc}/components/appraise/BrnAppraiseBottomPicker/img/brn_appraise_picker.png (100%) rename {docs => doc}/components/bottomButtonPanel/BrnBottomButtonPanel/BrnBottomButtonPanel.md (100%) rename {docs => doc}/components/bottomButtonPanel/BrnBottomButtonPanel/img/disable_and_enable.png (100%) rename {docs => doc}/components/bottomButtonPanel/BrnBottomButtonPanel/img/disable_main.png (100%) rename {docs => doc}/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_1.png (100%) rename {docs => doc}/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_2.png (100%) rename {docs => doc}/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_3.png (100%) rename {docs => doc}/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_4.png (100%) rename {docs => doc}/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_5.png (100%) rename {docs => doc}/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_6.png (100%) rename {docs => doc}/components/bottomButtonPanel/BrnMultipleBottomButton/BrnMultipleBottomButton.md (100%) rename {docs => doc}/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo1.png (100%) rename {docs => doc}/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo2.png (100%) rename {docs => doc}/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo3.png (100%) rename {docs => doc}/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo4.png (100%) rename {docs => doc}/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonIntro.png (100%) rename {docs => doc}/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md (100%) rename {docs => doc}/components/bottomTabBar/BrnBottomTabBar/img/BrnBottomTabBar.png (100%) rename {docs => doc}/components/bubble/BrnBubbleText/BrnBubbleText.md (100%) rename {docs => doc}/components/bubble/BrnBubbleText/img/bubbleTextCollapsed.png (100%) rename {docs => doc}/components/bubble/BrnBubbleText/img/bubbleTextExpaned.png (100%) rename {docs => doc}/components/bubble/BrnInsertInfo/BrnInsertInfo.md (100%) rename {docs => doc}/components/bubble/BrnInsertInfo/img/insert_info.png (100%) rename {docs => doc}/components/buttonPanel/BrnButtonPanel/BrnButtonPanel.md (100%) rename {docs => doc}/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo1.png (100%) rename {docs => doc}/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo2.png (100%) rename {docs => doc}/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo3.png (100%) rename {docs => doc}/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo4.png (100%) rename {docs => doc}/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo5.png (100%) rename {docs => doc}/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo6.png (100%) rename {docs => doc}/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelIntro.png (100%) rename {docs => doc}/components/buttonPanel/BrnTextButtonPanel/BrnTextButtonPanel.md (100%) rename {docs => doc}/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo1.png (100%) rename {docs => doc}/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo2.png (100%) rename {docs => doc}/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo3.png (100%) rename {docs => doc}/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo4.png (100%) rename {docs => doc}/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo5.png (100%) rename {docs => doc}/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelIntro.png (100%) rename {docs => doc}/components/calendar/BrnCalendarView/BrnCalendarView.md (100%) rename {docs => doc}/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo1.png (100%) rename {docs => doc}/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo2.png (100%) rename {docs => doc}/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo3.png (100%) rename {docs => doc}/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo4.png (100%) rename {docs => doc}/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo5.png (100%) rename {docs => doc}/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo6.png (100%) rename {docs => doc}/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro1.png (100%) rename {docs => doc}/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro2.png (100%) rename {docs => doc}/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro3.png (100%) rename {docs => doc}/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro4.png (100%) rename {docs => doc}/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro5.png (100%) rename {docs => doc}/components/charts/BrnBrokenLine/BrnBrokenLine.md (100%) rename {docs => doc}/components/charts/BrnBrokenLine/img/BrnBrokenLineDemo1.png (100%) rename {docs => doc}/components/charts/BrnBrokenLine/img/BrnBrokenLineDemo2.png (100%) rename {docs => doc}/components/charts/BrnBrokenLine/img/BrnBrokenLineIntro.png (100%) rename {docs => doc}/components/charts/BrnDoughnutChart/BrnDoughnutChart.md (100%) rename {docs => doc}/components/charts/BrnDoughnutChart/img/BrnDoughnutChartDemo1.png (100%) rename {docs => doc}/components/charts/BrnDoughnutChart/img/BrnDoughnutChartIntro.png (100%) rename {docs => doc}/components/charts/BrnFunnelChart/BrnFunnelChart.md (100%) rename {docs => doc}/components/charts/BrnFunnelChart/img/BrnFunnelChart1.png (100%) rename {docs => doc}/components/charts/BrnFunnelChart/img/BrnFunnelChart2.png (100%) rename {docs => doc}/components/charts/BrnFunnelChart/img/BrnFunnelChart3.png (100%) rename {docs => doc}/components/charts/BrnFunnelChart/img/BrnFunnelChartIntro.png (100%) rename {docs => doc}/components/charts/BrnProgressBarChart/BrnProgressBarChart.md (100%) rename {docs => doc}/components/charts/BrnProgressBarChart/img/BrnProgressBarChartDemo1.png (100%) rename {docs => doc}/components/charts/BrnProgressBarChart/img/BrnProgressBarChartDemo2.png (100%) rename {docs => doc}/components/charts/BrnProgressBarChart/img/BrnProgressBarChartIntro1.png (100%) rename {docs => doc}/components/charts/BrnProgressBarChart/img/BrnProgressBarChartIntro2.png (100%) rename {docs => doc}/components/charts/BrnProgressChart/BrnProgressChart.md (100%) rename {docs => doc}/components/charts/BrnProgressChart/img/BrnProgressChartDemo1.png (100%) rename {docs => doc}/components/charts/BrnProgressChart/img/BrnProgressChartIntro.png (100%) rename {docs => doc}/components/charts/BrnRadarChart/BrnRadarChart.md (100%) rename {docs => doc}/components/charts/BrnRadarChart/img/BrnRadarChartDemo1.png (100%) rename {docs => doc}/components/charts/BrnRadarChart/img/BrnRadarChartDemo2.png (100%) rename {docs => doc}/components/charts/BrnRadarChart/img/BrnRadarChartIntro.png (100%) rename {docs => doc}/components/checkbox/BrnCheckbox/BrnCheckbox.md (100%) rename {docs => doc}/components/citySelection/BrnSingleSelectCityPage/BrnSingleSelectCityPage.md (100%) rename {docs => doc}/components/citySelection/BrnSingleSelectCityPage/img/BrnSingleSelectCityPageDemo1.png (100%) rename {docs => doc}/components/citySelection/BrnSingleSelectCityPage/img/BrnSingleSelectCityPageIntro.png (100%) rename {docs => doc}/components/dashedLine/BrnDashedLine/BrnDashedLine.md (100%) rename {docs => doc}/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo1.png (100%) rename {docs => doc}/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo2.png (100%) rename {docs => doc}/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo3.png (100%) rename {docs => doc}/components/dashedLine/BrnDashedLine/img/BrnDashedLineIntro.png (100%) rename {docs => doc}/components/dialog/BrnDialog/BrnDialog.md (100%) rename {docs => doc}/components/dialog/BrnDialog/img/common_dialog_2.png (100%) rename {docs => doc}/components/dialog/BrnDialog/img/common_dialog_3.png (100%) rename {docs => doc}/components/dialog/BrnDialog/img/common_dialog_4.png (100%) rename {docs => doc}/components/dialog/BrnDialog/img/common_dialog_5.png (100%) rename {docs => doc}/components/dialog/BrnDialog/img/common_dialog_6.png (100%) rename {docs => doc}/components/dialog/BrnDialog/img/common_dialog_7.png (100%) rename {docs => doc}/components/dialog/BrnDialog/img/common_dialog_8.png (100%) rename {docs => doc}/components/dialog/BrnDialog/img/common_dialog_9.png (100%) rename {docs => doc}/components/dialog/BrnDialog/img/common_diloag_0.png (100%) rename {docs => doc}/components/dialog/BrnDialog/img/common_diloag_1.png (100%) rename {docs => doc}/components/dialog/BrnEnhanceOperationDialog/BrnEnhanceOperationDialog.md (100%) rename {docs => doc}/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogDemo1.png (100%) rename {docs => doc}/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogDemo2.png (100%) rename {docs => doc}/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogIntro1.png (100%) rename {docs => doc}/components/dialog/BrnEnhanceOperationDialog/img/dialog_two_vertical_button_1.png (100%) rename {docs => doc}/components/dialog/BrnLoadingDialog/BrnLoadingDialog.md (100%) rename {docs => doc}/components/dialog/BrnLoadingDialog/img/BrnLoadingDialogIntro.png (100%) rename {docs => doc}/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md (100%) rename {docs => doc}/components/dialog/BrnMiddleInputDialog/img/BrnMiddleInputDialogIntro1.png (100%) rename {docs => doc}/components/dialog/BrnMiddleInputDialog/img/BrnMiddleInputDialogIntro2.png (100%) rename {docs => doc}/components/dialog/BrnMiddleInputDialog/img/middleinoutdialog.png (100%) rename {docs => doc}/components/dialog/BrnMultiSelectDialog/BrnMultiSelectDialog.md (100%) rename {docs => doc}/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo1.png (100%) rename {docs => doc}/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo2.png (100%) rename {docs => doc}/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo3.png (100%) rename {docs => doc}/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogIntro.png (100%) rename {docs => doc}/components/dialog/BrnScrollableTextDialog/BrnScrollableTextDialog.md (100%) rename {docs => doc}/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo1.png (100%) rename {docs => doc}/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo2.png (100%) rename {docs => doc}/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo3.png (100%) rename {docs => doc}/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo4.png (100%) rename {docs => doc}/components/dialog/BrnShareDialog/BrnShareDialog.md (100%) rename {docs => doc}/components/dialog/BrnShareDialog/img/BrnShareDialogDemo1.png (100%) rename {docs => doc}/components/dialog/BrnShareDialog/img/BrnShareDialogDemo2.png (100%) rename {docs => doc}/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md (100%) rename {docs => doc}/components/dialog/BrnSingleSelectDialog/img/BrnSingleSelectDialog.png (100%) rename {docs => doc}/components/form/BrnAddLabel/BrnAddLabel.md (100%) rename {docs => doc}/components/form/BrnAddLabel/img/BrnAddLabelDemo1.png (100%) rename {docs => doc}/components/form/BrnAddLabel/img/BrnAddLabelIntro.png (100%) rename {docs => doc}/components/form/BrnBaseTitle/BrnBaseTitle.md (100%) rename {docs => doc}/components/form/BrnBaseTitle/img/BrnBaseTitleDemo1.png (100%) rename {docs => doc}/components/form/BrnBaseTitle/img/BrnBaseTitleDemo2.png (100%) rename {docs => doc}/components/form/BrnBaseTitle/img/BrnBaseTitleIntro.png (100%) rename {docs => doc}/components/form/BrnExpandFormGroup/BrnExpandFormGroup.md (100%) rename {docs => doc}/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo1.png (100%) rename {docs => doc}/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo2.png (100%) rename {docs => doc}/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo3.png (100%) rename {docs => doc}/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupIntro.png (100%) rename {docs => doc}/components/form/BrnExpandableGroup/BrnExpandableGroup.md (100%) rename {docs => doc}/components/form/BrnExpandableGroup/img/BrnExpandableGroupIntro1.gif (100%) rename {docs => doc}/components/form/BrnExpandableGroup/img/BrnExpandableGroupIntro2.png (100%) rename {docs => doc}/components/form/BrnMultiChoiceInputFormItem/BrnMultiChoiceInputFormItem.md (100%) rename {docs => doc}/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemDemo1.png (100%) rename {docs => doc}/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemDemo2.png (100%) rename {docs => doc}/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemIntro.png (100%) rename {docs => doc}/components/form/BrnMultiChoicePortraitInputFormItem/BrnMultiChoicePortraitInputFormItem.md (100%) rename {docs => doc}/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemDemo1.png (100%) rename {docs => doc}/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemDemo2.png (100%) rename {docs => doc}/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemIntro.png (100%) rename {docs => doc}/components/form/BrnNormalFormGroup/BrnNormalFormGroup.md (100%) rename {docs => doc}/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupDemo1.png (100%) rename {docs => doc}/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupDemo2.png (100%) rename {docs => doc}/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupIntro.png (100%) rename {docs => doc}/components/form/BrnPortraitRadioGroup/BrnPortraitRadioGroup.md (100%) rename {docs => doc}/components/form/BrnPortraitRadioGroup/img/BrnPortraitRadioGroupDemo1.png (100%) rename {docs => doc}/components/form/BrnPortraitRadioGroup/img/BrnPortraitRadioGroupDemo2.png (100%) rename {docs => doc}/components/form/BrnRadioInputFormItem/BrnRadioInputFormItem.md (100%) rename {docs => doc}/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo1.png (100%) rename {docs => doc}/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo2.png (100%) rename {docs => doc}/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo3.png (100%) rename {docs => doc}/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo4.png (100%) rename {docs => doc}/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemIntro.png (100%) rename {docs => doc}/components/form/BrnRadioPortraitInputFormItem/BrnRadioPortraitInputFormItem.md (100%) rename {docs => doc}/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemDemo1.png (100%) rename {docs => doc}/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemDemo2.png (100%) rename {docs => doc}/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemIntro.png (100%) rename {docs => doc}/components/form/BrnRangeInputFormItem/BrnRangeInputFormItem.md (100%) rename {docs => doc}/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemDemo1.png (100%) rename {docs => doc}/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemDemo2.png (100%) rename {docs => doc}/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemIntro.png (100%) rename {docs => doc}/components/form/BrnRatioInputFormItem/BrnRatioInputFormItem.md (100%) rename {docs => doc}/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemDemo1.png (100%) rename {docs => doc}/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemDemo2.png (100%) rename {docs => doc}/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemIntro.png (100%) rename {docs => doc}/components/form/BrnSelectAllTitle/BrnSelectAllTitle.md (100%) rename {docs => doc}/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleDemo1.png (100%) rename {docs => doc}/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleDemo2.png (100%) rename {docs => doc}/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleIntro.png (100%) rename {docs => doc}/components/form/BrnStarsFormItem/BrnStarsFormItem.md (100%) rename {docs => doc}/components/form/BrnStarsFormItem/img/BrnStarsFormItemDemo1.png (100%) rename {docs => doc}/components/form/BrnStarsFormItem/img/BrnStarsFormItemDemo2.png (100%) rename {docs => doc}/components/form/BrnStarsFormItem/img/BrnStarsFormItemIntro.png (100%) rename {docs => doc}/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md (100%) rename {docs => doc}/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemDemo1.png (100%) rename {docs => doc}/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemDemo2.png (100%) rename {docs => doc}/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemIntro.png (100%) rename {docs => doc}/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md (100%) rename {docs => doc}/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo1.png (100%) rename {docs => doc}/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo2.png (100%) rename {docs => doc}/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo3.png (100%) rename {docs => doc}/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo4.png (100%) rename {docs => doc}/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemIntro.png (100%) rename {docs => doc}/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md (100%) rename {docs => doc}/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo1.png (100%) rename {docs => doc}/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo2.png (100%) rename {docs => doc}/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo3.png (100%) rename {docs => doc}/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo4.png (100%) rename {docs => doc}/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemIntro.png (100%) rename {docs => doc}/components/form/BrnTextQuickSelectFormItem/BrnTextQuickSelectFormItem.md (100%) rename {docs => doc}/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemDemo1.png (100%) rename {docs => doc}/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemDemo2.png (100%) rename {docs => doc}/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemIntro.png (100%) rename {docs => doc}/components/form/BrnTextSelectFormItem/BrnTextSelectFormItem.md (100%) rename {docs => doc}/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo1.png (100%) rename {docs => doc}/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo2.png (100%) rename {docs => doc}/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo3.png (100%) rename {docs => doc}/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo4.png (100%) rename {docs => doc}/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemIntro.png (100%) rename {docs => doc}/components/form/BrnTitleFormItem/BrnTitleFormItem.md (100%) rename {docs => doc}/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo1.png (100%) rename {docs => doc}/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo2.png (100%) rename {docs => doc}/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo3.png (100%) rename {docs => doc}/components/form/BrnTitleFormItem/img/BrnTitleFormItemIntro.png (100%) rename {docs => doc}/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md (100%) rename {docs => doc}/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemDemo1.png (100%) rename {docs => doc}/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemDemo2.png (100%) rename {docs => doc}/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemIntro.png (100%) rename {docs => doc}/components/gallery/BrnGalleryDetailPage/BrnGalleryDetailPage.md (100%) rename {docs => doc}/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageDemo1.jpg (100%) rename {docs => doc}/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageDemo3.gif (100%) rename {docs => doc}/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageIntro.png (100%) rename {docs => doc}/components/gallery/BrnGalleryDetailPage/img/image-20211101121347565.png (100%) rename {docs => doc}/components/gallery/BrnGallerySummaryPage/BrnGallerySummaryPage.md (100%) rename {docs => doc}/components/gallery/BrnGallerySummaryPage/img/BrnGallerySummaryPageDemo.png (100%) rename {docs => doc}/components/gallery/BrnGallerySummaryPage/img/BrnGallerySummaryPageIntro.png (100%) rename {docs => doc}/components/guide/BrnGuide/BrnGuide.md (100%) rename {docs => doc}/components/guide/BrnGuide/img/BrnGuideForceDemo.gif (100%) rename {docs => doc}/components/guide/BrnGuide/img/BrnGuideIntroForceGuide.png (100%) rename {docs => doc}/components/guide/BrnGuide/img/BrnGuideIntroSoftGuide.png (100%) rename {docs => doc}/components/guide/BrnGuide/img/BrnGuideSoftDemo.gif (100%) rename {docs => doc}/components/iconButton/BrnIconButton/BrnIconButton.md (100%) rename {docs => doc}/components/iconButton/BrnIconButton/img/BrnIconButtonIntro.png (100%) rename {docs => doc}/components/iconButton/BrnVerticalIconButton/BrnVerticalIconButton.md (100%) rename {docs => doc}/components/iconButton/BrnVerticalIconButton/img/BrnVerticalIconButtonIntro.png (100%) rename {docs => doc}/components/input/BrnInputText/BrnInputText.md (100%) rename {docs => doc}/components/input/BrnInputText/img/BrnInputTextDemoEmpty.png (100%) rename {docs => doc}/components/input/BrnInputText/img/BrnInputTextDemoFull.png (100%) rename {docs => doc}/components/input/BrnInputText/img/BrnInputTextIntro.png (100%) rename {docs => doc}/components/loading/BrnPageLoading/BrnPageLoading.md (100%) rename {docs => doc}/components/loading/BrnPageLoading/img/BrnPageLoadingDemo1.png (100%) rename {docs => doc}/components/loading/BrnPageLoading/img/BrnPageLoadingDemo2.png (100%) rename {docs => doc}/components/normalButton/BrnBigGhostButton/BrnBigGhostButton.md (100%) rename {docs => doc}/components/normalButton/BrnBigGhostButton/img/BrnBigGhostButtonDemo.png (100%) rename {docs => doc}/components/normalButton/BrnBigMainButton/BrnBigMainButton.md (100%) rename {docs => doc}/components/normalButton/BrnBigMainButton/img/BrnBigMainButton.png (100%) rename {docs => doc}/components/normalButton/BrnBigMainButton/img/BrnBigMainButtonDisabled.png (100%) rename {docs => doc}/components/normalButton/BrnBigOutlineButton/BrnBigOutlineButton.md (100%) rename {docs => doc}/components/normalButton/BrnBigOutlineButton/img/BrnBigOutlineButton.png (100%) rename {docs => doc}/components/normalButton/BrnBigOutlineButton/img/BrnBigOutlineButtonDisabled.png (100%) rename {docs => doc}/components/normalButton/BrnSmallMainButton/BrnSmallMainButton.md (100%) rename {docs => doc}/components/normalButton/BrnSmallMainButton/img/BrnSmallMainButton.png (100%) rename {docs => doc}/components/normalButton/BrnSmallMainButton/img/BrnSmallMainButtonDisabled.png (100%) rename {docs => doc}/components/normalButton/BrnSmallOutlineButton/BrnSmallOutlineButton.md (100%) rename {docs => doc}/components/normalButton/BrnSmallOutlineButton/img/BrnSmallOutlineButton.png (100%) rename {docs => doc}/components/normalButton/BrnSmallOutlineButton/img/BrnSmallOutlineButtonDisabled.png (100%) rename {docs => doc}/components/notification/BrnNoticeBar/BrnNoticeBar.md (100%) rename {docs => doc}/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo1.png (100%) rename {docs => doc}/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo2.png (100%) rename {docs => doc}/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo3.png (100%) rename {docs => doc}/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo4.gif (100%) rename {docs => doc}/components/notification/BrnNoticeBar/img/BrnNoticeBarIntro1.png (100%) rename {docs => doc}/components/notification/BrnNoticeBar/img/BrnNoticeBarIntro2.png (100%) rename {docs => doc}/components/notification/BrnNoticeBarWithButton/BrnNoticeBarWithButton.md (100%) rename {docs => doc}/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo1.png (100%) rename {docs => doc}/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo2.png (100%) rename {docs => doc}/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo3.gif (100%) rename {docs => doc}/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonIntro.png (100%) rename {docs => doc}/components/picker/BrnBottomPicker/BrnBottomPicker.md (100%) rename {docs => doc}/components/picker/BrnBottomPicker/img/BrnBottomPickerDemo1.png (100%) rename {docs => doc}/components/picker/BrnBottomPicker/img/BrnBottomPickerDemo2.png (100%) rename {docs => doc}/components/picker/BrnBottomWritePicker/BrnBottomWritePicker.md (100%) rename {docs => doc}/components/picker/BrnBottomWritePicker/img/BrnBottomWritePicker.png (100%) rename {docs => doc}/components/picker/BrnDatePicker/BrnDatePicker.md (100%) rename {docs => doc}/components/picker/BrnDatePicker/img/BrnDatePickerTime.png (100%) rename {docs => doc}/components/picker/BrnDatePicker/img/BrnDatePickerYMD.png (100%) rename {docs => doc}/components/picker/BrnDatePicker/img/BrnDatePickerYMDHMS.png (100%) rename {docs => doc}/components/picker/BrnDateRangePicker/BrnDateRangePicker.md (100%) rename {docs => doc}/components/picker/BrnDateRangePicker/img/BrnDateRangePicker1.png (100%) rename {docs => doc}/components/picker/BrnDateRangePicker/img/BrnDateRangePicker2.png (100%) rename {docs => doc}/components/picker/BrnDateRangePicker/img/BrnDateRangePicker3.png (100%) rename {docs => doc}/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo1.png (100%) rename {docs => doc}/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo2.png (100%) rename {docs => doc}/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo3.png (100%) rename {docs => doc}/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md (100%) rename {docs => doc}/components/picker/BrnMultiColumnPicker/img/BrnMultiColumnPickerDemo.png (100%) rename {docs => doc}/components/picker/BrnMultiColumnPicker/img/BrnMultiColumnPickerIntro.png (100%) rename {docs => doc}/components/picker/BrnMultiDataPicker/BrnMultiDataPicker.md (100%) rename {docs => doc}/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo1.png (100%) rename {docs => doc}/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo2.png (100%) rename {docs => doc}/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo3.png (100%) rename {docs => doc}/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo4.png (100%) rename {docs => doc}/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerIntro.png (100%) rename {docs => doc}/components/picker/BrnMultiSelectListPicker/BrnMultiSelectListPicker.md (100%) rename {docs => doc}/components/picker/BrnMultiSelectListPicker/img/BrnMultiSelectListPicker.png (100%) rename {docs => doc}/components/picker/BrnMultiSelectTagsPicker/BrnMultiSelectTagsPicker.md (100%) rename {docs => doc}/components/picker/BrnMultiSelectTagsPicker/img/BrnMultiSelectTagsPickerIntro.png (100%) rename {docs => doc}/components/picker/BrnSelectTagsWithInputPicker/BrnSelectTagsWithInputPicker.md (100%) rename {docs => doc}/components/picker/BrnSelectTagsWithInputPicker/img/BrnSelectTagsWithInputPicker1.png (100%) rename {docs => doc}/components/radio/BrnRadioButton/BrnRadioButton.md (100%) rename {docs => doc}/components/radio/BrnRadioButton/img/BrnRadioButtonIntro.png (100%) rename {docs => doc}/components/radio/BrnRadioButton/img/BrnRadioItemDemo1.png (100%) rename {docs => doc}/components/radio/BrnRadioButton/img/BrnRadioItemDemo3.png (100%) rename {docs => doc}/components/ratingBar/BrnRatingStar/BrnRatingStar.md (100%) rename {docs => doc}/components/ratingBar/BrnRatingStar/img/BrnRatingStarDEmo4.png (100%) rename {docs => doc}/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo1.png (100%) rename {docs => doc}/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo2.png (100%) rename {docs => doc}/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo3.png (100%) rename {docs => doc}/components/ratingBar/BrnRatingStar/img/BrnRatingStarIntro.png (100%) rename {docs => doc}/components/search/BrnSearchText/BrnSearchText.md (100%) rename {docs => doc}/components/search/BrnSearchText/img/1620980916893bbbbb.gif (100%) rename {docs => doc}/components/search/BrnSearchText/img/1620981018721ccccc.gif (100%) rename {docs => doc}/components/search/BrnSearchText/img/BrnSearchTextDemo1.gif (100%) rename {docs => doc}/components/search/BrnSearchText/img/BrnSearchTextDemo2.png (100%) rename {docs => doc}/components/search/BrnSearchText/img/BrnSearchTextIntro.png (100%) rename {docs => doc}/components/selection/BrnFlatSelection/BrnFlatSelection.md (100%) rename {docs => doc}/components/selection/BrnFlatSelection/img/BrnFlatSelectionDemo1.png (100%) rename {docs => doc}/components/selection/BrnFlatSelection/img/BrnFlatSelectionDemo2.png (100%) rename {docs => doc}/components/selection/BrnFlatSelection/img/BrnFlatSelectionIntro.png (100%) rename {docs => doc}/components/selection/BrnSelectionView/BrnSelectionView.md (100%) rename {docs => doc}/components/selection/BrnSelectionView/img/BrnSelectionViewDemo1.png (100%) rename {docs => doc}/components/selection/BrnSelectionView/img/BrnSelectionViewDemo2.png (100%) rename {docs => doc}/components/selection/BrnSelectionView/img/BrnSelectionViewDemo4.gif (100%) rename {docs => doc}/components/selection/BrnSelectionView/img/BrnSelectionViewDemo5.png (100%) rename {docs => doc}/components/selection/BrnSelectionView/img/BrnSelectionViewIntro.png (100%) rename {docs => doc}/components/selection/BrnSelectionView/img/BrnSelectionViewIntro2.png (100%) rename {docs => doc}/components/selection/BrnSelectionView/img/BrnSelectionViewIntro3.png (100%) rename {docs => doc}/components/selection/BrnSelectionView/img/BrnSelectionViewMorePage.png (100%) rename {docs => doc}/components/selection/BrnSelectionView/img/BrnSelectionViewMorePage2.png (100%) rename {docs => doc}/components/selection/BrnSelectionView/img/image-20211030160608171.png (100%) rename {docs => doc}/components/selection/BrnSelectionView/img/image-20211101155937783.png (100%) rename {docs => doc}/components/selection/BrnSimpleSelection/BrnSimpleSelection.md (100%) rename {docs => doc}/components/selection/BrnSimpleSelection/img/simple_selection_checkbox.png (100%) rename {docs => doc}/components/selection/BrnSimpleSelection/img/simple_selection_radio.png (100%) rename {docs => doc}/components/shadowCard/BrnShadowCard/BrnShadowCard.md (100%) rename {docs => doc}/components/shadowCard/BrnShadowCard/img/BrnShadowCardIntro.png (100%) rename {docs => doc}/components/shadowCard/BrnShadowCard/img/BrnShadowCardIntroDemo1.png (100%) rename {docs => doc}/components/stepBar/BrnHorizontalSteps/BrnHorizontalSteps.md (100%) rename {docs => doc}/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps1.jpg (100%) rename {docs => doc}/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps2.jpg (100%) rename {docs => doc}/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps3.jpg (100%) rename {docs => doc}/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps4.jpg (100%) rename {docs => doc}/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps5.png (100%) rename {docs => doc}/components/stepBar/BrnStepLine/BrnStepLine.md (100%) rename {docs => doc}/components/stepBar/BrnStepLine/img/BrnStepLine1.png (100%) rename {docs => doc}/components/stepBar/BrnStepLine/img/BrnStepLine2.png (100%) rename {docs => doc}/components/stepBar/BrnStepLine/img/BrnStepLine3.png (100%) rename {docs => doc}/components/stepBar/BrnStepLine/img/BrnStepLine4.png (100%) rename {docs => doc}/components/tabbar/BrnTabBar/BrnTabBar.md (100%) rename {docs => doc}/components/tabbar/BrnTabBar/img/BrnTabBarDemo1.png (100%) rename {docs => doc}/components/tabbar/BrnTabBar/img/BrnTabBarDemo2.png (100%) rename {docs => doc}/components/tabbar/BrnTabBar/img/BrnTabBarDemo3.png (100%) rename {docs => doc}/components/tabbar/BrnTabBar/img/BrnTabBarDemo4.png (100%) rename {docs => doc}/components/tabbar/BrnTabBar/img/BrnTabBarDemo5.png (100%) rename {docs => doc}/components/tabbar/BrnTabBar/img/BrnTabBarDemo6.png (100%) rename {docs => doc}/components/tabbar/BrnTabBar/img/BrnTabBarIntro.png (100%) rename {docs => doc}/components/tag/BrnDeleteTag/BrnDeleteTag.md (100%) rename {docs => doc}/components/tag/BrnDeleteTag/img/BrnDeleteTagDemo1.png (100%) rename {docs => doc}/components/tag/BrnDeleteTag/img/BrnDeleteTagDemo2.png (100%) rename {docs => doc}/components/tag/BrnDeleteTag/img/BrnDeleteTagIntro.png (100%) rename {docs => doc}/components/tag/BrnSelectTag/BrnSelectTag.md (100%) rename {docs => doc}/components/tag/BrnSelectTag/img/BrnSelectTagDemo1.png (100%) rename {docs => doc}/components/tag/BrnSelectTag/img/BrnSelectTagDemo2.png (100%) rename {docs => doc}/components/tag/BrnSelectTag/img/BrnSelectTagDemo3.png (100%) rename {docs => doc}/components/tag/BrnSelectTag/img/BrnSelectTagDemo4.png (100%) rename {docs => doc}/components/tag/BrnSelectTag/img/BrnSelectTagDemo5.png (100%) rename {docs => doc}/components/tag/BrnSelectTag/img/BrnSelectTagIntro.png (100%) rename {docs => doc}/components/tag/BrnStateTag/BrnStateTag.md (100%) rename {docs => doc}/components/tag/BrnStateTag/img/BrnMetaStateTagIntro.png (100%) rename {docs => doc}/components/tag/BrnStateTag/img/BrnMetaStateTagSucceed.png (100%) rename {docs => doc}/components/tag/BrnStateTag/img/BrnStateTagFailure.png (100%) rename {docs => doc}/components/tag/BrnTagCustom/BrnTagCustom.md (100%) rename {docs => doc}/components/tag/BrnTagCustom/img/BrnTagCustomDemo1.png (100%) rename {docs => doc}/components/tag/BrnTagCustom/img/BrnTagCustomDemo2.png (100%) rename {docs => doc}/components/tag/BrnTagCustom/img/BrnTagCustomDemo3.png (100%) rename {docs => doc}/components/text/BrnEnhanceNumberCard/BrnEnhanceNumberCard.md (100%) rename {docs => doc}/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo1.png (100%) rename {docs => doc}/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo2.png (100%) rename {docs => doc}/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo3.png (100%) rename {docs => doc}/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo4.png (100%) rename {docs => doc}/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo5.png (100%) rename {docs => doc}/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardIntro.png (100%) rename {docs => doc}/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardIntro1.png (100%) rename {docs => doc}/components/text/BrnExpandableText/BrnExpandableText.md (100%) rename {docs => doc}/components/text/BrnExpandableText/img/BrnExpandableTextIntro1.png (100%) rename {docs => doc}/components/text/BrnExpandableText/img/BrnExpandableTextIntro2.png (100%) rename {docs => doc}/components/text/BrnPairInfoTable/BrnPairInfoTable.md (100%) rename {docs => doc}/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo3.png (100%) rename {docs => doc}/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo4.png (100%) rename {docs => doc}/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo5.png (100%) rename {docs => doc}/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro1.png (100%) rename {docs => doc}/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro2.png (100%) rename {docs => doc}/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro3.png (100%) rename {docs => doc}/components/text/BrnRichInfoGrid/BrnRichInfoGrid.md (100%) rename {docs => doc}/components/text/BrnRichInfoGrid/img/BrnRichInfoGridDemo1.png (100%) rename {docs => doc}/components/text/BrnRichInfoGrid/img/BrnRichInfoGridDemo2.png (100%) rename {docs => doc}/components/tips/BrnPopupWindow/BrnPopupWindow.md (100%) rename {docs => doc}/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo1.png (100%) rename {docs => doc}/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo2.png (100%) rename {docs => doc}/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo3.png (100%) rename {docs => doc}/components/tips/BrnPopupWindow/img/BrnPopupWindowIntro.png (100%) rename {docs => doc}/components/title/BrnActionCardTitle/BrnActionCardTitle.md (100%) rename {docs => doc}/components/title/BrnActionCardTitle/img/BrnActionCardTitleDemo.png (100%) rename {docs => doc}/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md (100%) rename {docs => doc}/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo1.png (100%) rename {docs => doc}/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo2.png (100%) rename {docs => doc}/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo3.png (100%) rename {docs => doc}/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleIntro.png (100%) rename {docs => doc}/components/title/BrnSubSwitchTitle/BrnSubSwitchTitle.md (100%) rename {docs => doc}/components/title/BrnSubSwitchTitle/img/BrnSubSwitchTitleDemo1.png (100%) rename {docs => doc}/components/title/BrnSubSwitchTitle/img/BrnSubSwitchTitleDemo2.gif (100%) rename {docs => doc}/components/title/BrnSwitchTitle/BrnSwitchTitle.md (100%) rename {docs => doc}/components/title/BrnSwitchTitle/img/BrnSwitchTitleDemo1.png (100%) rename {docs => doc}/components/title/BrnSwitchTitle/img/BrnSwitchTitleDemo2.gif (100%) rename {docs => doc}/components/toast/BrnToast/BrnToast.md (100%) rename {docs => doc}/components/toast/BrnToast/img/brn_toast_fail.png (100%) rename {docs => doc}/components/toast/BrnToast/img/brn_toast_intro.png (100%) rename {docs => doc}/components/toast/BrnToast/img/brn_toast_normal.png (100%) rename {docs => doc}/components/toast/BrnToast/img/brn_toast_success.png (100%) rename {docs => doc}/contribution.md (100%) rename {docs => doc}/sketch.md (100%) rename {docs => doc}/start.md (100%) rename {docs => doc}/theme.md (100%) diff --git a/docs/FAQ.md b/doc/FAQ.md similarity index 100% rename from docs/FAQ.md rename to doc/FAQ.md diff --git a/docs/bruno.md b/doc/bruno.md similarity index 100% rename from docs/bruno.md rename to doc/bruno.md diff --git a/docs/components/abnormalCard/BrnAbnormalStateWidget/BrnAbnormalStateWidget.md b/doc/components/abnormalCard/BrnAbnormalStateWidget/BrnAbnormalStateWidget.md similarity index 100% rename from docs/components/abnormalCard/BrnAbnormalStateWidget/BrnAbnormalStateWidget.md rename to doc/components/abnormalCard/BrnAbnormalStateWidget/BrnAbnormalStateWidget.md diff --git a/docs/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_1.png b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_1.png similarity index 100% rename from docs/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_1.png rename to doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_1.png diff --git a/docs/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_2.png b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_2.png similarity index 100% rename from docs/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_2.png rename to doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_2.png diff --git a/docs/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_3.png b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_3.png similarity index 100% rename from docs/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_3.png rename to doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_3.png diff --git a/docs/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_4.png b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_4.png similarity index 100% rename from docs/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_4.png rename to doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_4.png diff --git a/docs/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_5.png b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_5.png similarity index 100% rename from docs/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_5.png rename to doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_5.png diff --git a/docs/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_intro.png b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_intro.png similarity index 100% rename from docs/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_intro.png rename to doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_intro.png diff --git a/docs/components/actionsheet/BrnCommonActionSheet/BrnCommonActionSheet.md b/doc/components/actionsheet/BrnCommonActionSheet/BrnCommonActionSheet.md similarity index 100% rename from docs/components/actionsheet/BrnCommonActionSheet/BrnCommonActionSheet.md rename to doc/components/actionsheet/BrnCommonActionSheet/BrnCommonActionSheet.md diff --git a/docs/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_1.png b/doc/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_1.png similarity index 100% rename from docs/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_1.png rename to doc/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_1.png diff --git a/docs/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_2.png b/doc/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_2.png similarity index 100% rename from docs/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_2.png rename to doc/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_2.png diff --git a/docs/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_3.png b/doc/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_3.png similarity index 100% rename from docs/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_3.png rename to doc/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_3.png diff --git a/docs/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_4.png b/doc/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_4.png similarity index 100% rename from docs/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_4.png rename to doc/components/actionsheet/BrnCommonActionSheet/img/brn_action_sheet_common_widget_4.png diff --git a/docs/components/actionsheet/BrnSelectedListActionSheet/BrnSelectedListActionSheet.md b/doc/components/actionsheet/BrnSelectedListActionSheet/BrnSelectedListActionSheet.md similarity index 100% rename from docs/components/actionsheet/BrnSelectedListActionSheet/BrnSelectedListActionSheet.md rename to doc/components/actionsheet/BrnSelectedListActionSheet/BrnSelectedListActionSheet.md diff --git a/docs/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo1.png b/doc/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo1.png similarity index 100% rename from docs/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo1.png rename to doc/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo1.png diff --git a/docs/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo2.png b/doc/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo2.png similarity index 100% rename from docs/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo2.png rename to doc/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo2.png diff --git a/docs/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo3.png b/doc/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo3.png similarity index 100% rename from docs/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo3.png rename to doc/components/actionsheet/BrnSelectedListActionSheet/img/BrnSelectedListActionSheetDemo3.png diff --git a/docs/components/actionsheet/BrnShareActionSheet/BrnShareActionSheet.md b/doc/components/actionsheet/BrnShareActionSheet/BrnShareActionSheet.md similarity index 100% rename from docs/components/actionsheet/BrnShareActionSheet/BrnShareActionSheet.md rename to doc/components/actionsheet/BrnShareActionSheet/BrnShareActionSheet.md diff --git a/docs/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_1.png b/doc/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_1.png similarity index 100% rename from docs/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_1.png rename to doc/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_1.png diff --git a/docs/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_2.png b/doc/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_2.png similarity index 100% rename from docs/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_2.png rename to doc/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_2.png diff --git a/docs/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_3.png b/doc/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_3.png similarity index 100% rename from docs/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_3.png rename to doc/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_3.png diff --git a/docs/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_4.png b/doc/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_4.png similarity index 100% rename from docs/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_4.png rename to doc/components/actionsheet/BrnShareActionSheet/img/actionSheet_share_4.png diff --git a/docs/components/anchor/BrnAnchorTab/BrnAnchorTab.md b/doc/components/anchor/BrnAnchorTab/BrnAnchorTab.md similarity index 100% rename from docs/components/anchor/BrnAnchorTab/BrnAnchorTab.md rename to doc/components/anchor/BrnAnchorTab/BrnAnchorTab.md diff --git a/docs/components/anchor/BrnAnchorTab/img/anchorTab.gif b/doc/components/anchor/BrnAnchorTab/img/anchorTab.gif similarity index 100% rename from docs/components/anchor/BrnAnchorTab/img/anchorTab.gif rename to doc/components/anchor/BrnAnchorTab/img/anchorTab.gif diff --git a/docs/components/appbar/BrnAppBar/BrnAppBar.md b/doc/components/appbar/BrnAppBar/BrnAppBar.md similarity index 100% rename from docs/components/appbar/BrnAppBar/BrnAppBar.md rename to doc/components/appbar/BrnAppBar/BrnAppBar.md diff --git a/docs/components/appbar/BrnAppBar/img/BrnAppBarIntro.png b/doc/components/appbar/BrnAppBar/img/BrnAppBarIntro.png similarity index 100% rename from docs/components/appbar/BrnAppBar/img/BrnAppBarIntro.png rename to doc/components/appbar/BrnAppBar/img/BrnAppBarIntro.png diff --git a/docs/components/appbar/BrnAppBar/img/appbar_doubleright_icon.png b/doc/components/appbar/BrnAppBar/img/appbar_doubleright_icon.png similarity index 100% rename from docs/components/appbar/BrnAppBar/img/appbar_doubleright_icon.png rename to doc/components/appbar/BrnAppBar/img/appbar_doubleright_icon.png diff --git a/docs/components/appbar/BrnAppBar/img/appbar_down.png b/doc/components/appbar/BrnAppBar/img/appbar_down.png similarity index 100% rename from docs/components/appbar/BrnAppBar/img/appbar_down.png rename to doc/components/appbar/BrnAppBar/img/appbar_down.png diff --git a/docs/components/appbar/BrnAppBar/img/appbar_left_icon.png b/doc/components/appbar/BrnAppBar/img/appbar_left_icon.png similarity index 100% rename from docs/components/appbar/BrnAppBar/img/appbar_left_icon.png rename to doc/components/appbar/BrnAppBar/img/appbar_left_icon.png diff --git a/docs/components/appbar/BrnAppBar/img/appbar_leftright_icon.png b/doc/components/appbar/BrnAppBar/img/appbar_leftright_icon.png similarity index 100% rename from docs/components/appbar/BrnAppBar/img/appbar_leftright_icon.png rename to doc/components/appbar/BrnAppBar/img/appbar_leftright_icon.png diff --git a/docs/components/appbar/BrnAppBar/img/appbar_srolltitle.png b/doc/components/appbar/BrnAppBar/img/appbar_srolltitle.png similarity index 100% rename from docs/components/appbar/BrnAppBar/img/appbar_srolltitle.png rename to doc/components/appbar/BrnAppBar/img/appbar_srolltitle.png diff --git a/docs/components/appbar/BrnAppBar/img/appbar_three_tab.png b/doc/components/appbar/BrnAppBar/img/appbar_three_tab.png similarity index 100% rename from docs/components/appbar/BrnAppBar/img/appbar_three_tab.png rename to doc/components/appbar/BrnAppBar/img/appbar_three_tab.png diff --git a/docs/components/appbar/BrnAppBar/img/more_icon.png b/doc/components/appbar/BrnAppBar/img/more_icon.png similarity index 100% rename from docs/components/appbar/BrnAppBar/img/more_icon.png rename to doc/components/appbar/BrnAppBar/img/more_icon.png diff --git a/docs/components/appbar/BrnSearchAppbar/BrnSearchAppbar.md b/doc/components/appbar/BrnSearchAppbar/BrnSearchAppbar.md similarity index 100% rename from docs/components/appbar/BrnSearchAppbar/BrnSearchAppbar.md rename to doc/components/appbar/BrnSearchAppbar/BrnSearchAppbar.md diff --git a/docs/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarDemo1.png b/doc/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarDemo1.png similarity index 100% rename from docs/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarDemo1.png rename to doc/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarDemo1.png diff --git a/docs/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarDemo2.png b/doc/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarDemo2.png similarity index 100% rename from docs/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarDemo2.png rename to doc/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarDemo2.png diff --git a/docs/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarIntro.png b/doc/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarIntro.png similarity index 100% rename from docs/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarIntro.png rename to doc/components/appbar/BrnSearchAppbar/img/BrnSearchAppbarIntro.png diff --git a/docs/components/appraise/BrnAppraise/BrnAppraise.md b/doc/components/appraise/BrnAppraise/BrnAppraise.md similarity index 100% rename from docs/components/appraise/BrnAppraise/BrnAppraise.md rename to doc/components/appraise/BrnAppraise/BrnAppraise.md diff --git a/docs/components/appraise/BrnAppraise/img/BrnAppraiseDemo1.png b/doc/components/appraise/BrnAppraise/img/BrnAppraiseDemo1.png similarity index 100% rename from docs/components/appraise/BrnAppraise/img/BrnAppraiseDemo1.png rename to doc/components/appraise/BrnAppraise/img/BrnAppraiseDemo1.png diff --git a/docs/components/appraise/BrnAppraise/img/BrnAppraiseDemo2.png b/doc/components/appraise/BrnAppraise/img/BrnAppraiseDemo2.png similarity index 100% rename from docs/components/appraise/BrnAppraise/img/BrnAppraiseDemo2.png rename to doc/components/appraise/BrnAppraise/img/BrnAppraiseDemo2.png diff --git a/docs/components/appraise/BrnAppraise/img/BrnAppraiseDemo2_1.png b/doc/components/appraise/BrnAppraise/img/BrnAppraiseDemo2_1.png similarity index 100% rename from docs/components/appraise/BrnAppraise/img/BrnAppraiseDemo2_1.png rename to doc/components/appraise/BrnAppraise/img/BrnAppraiseDemo2_1.png diff --git a/docs/components/appraise/BrnAppraise/img/BrnAppraiseDemoIntro.png b/doc/components/appraise/BrnAppraise/img/BrnAppraiseDemoIntro.png similarity index 100% rename from docs/components/appraise/BrnAppraise/img/BrnAppraiseDemoIntro.png rename to doc/components/appraise/BrnAppraise/img/BrnAppraiseDemoIntro.png diff --git a/docs/components/appraise/BrnAppraiseBottomPicker/BrnAppraiseBottomPicker.md b/doc/components/appraise/BrnAppraiseBottomPicker/BrnAppraiseBottomPicker.md similarity index 100% rename from docs/components/appraise/BrnAppraiseBottomPicker/BrnAppraiseBottomPicker.md rename to doc/components/appraise/BrnAppraiseBottomPicker/BrnAppraiseBottomPicker.md diff --git a/docs/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo1.png b/doc/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo1.png similarity index 100% rename from docs/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo1.png rename to doc/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo1.png diff --git a/docs/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo2.png b/doc/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo2.png similarity index 100% rename from docs/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo2.png rename to doc/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo2.png diff --git a/docs/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo3.png b/doc/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo3.png similarity index 100% rename from docs/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo3.png rename to doc/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerDemo3.png diff --git a/docs/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerIntro.png b/doc/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerIntro.png similarity index 100% rename from docs/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerIntro.png rename to doc/components/appraise/BrnAppraiseBottomPicker/img/BrnAppraiseBottomPickerIntro.png diff --git a/docs/components/appraise/BrnAppraiseBottomPicker/img/brn_appraise_picker.png b/doc/components/appraise/BrnAppraiseBottomPicker/img/brn_appraise_picker.png similarity index 100% rename from docs/components/appraise/BrnAppraiseBottomPicker/img/brn_appraise_picker.png rename to doc/components/appraise/BrnAppraiseBottomPicker/img/brn_appraise_picker.png diff --git a/docs/components/bottomButtonPanel/BrnBottomButtonPanel/BrnBottomButtonPanel.md b/doc/components/bottomButtonPanel/BrnBottomButtonPanel/BrnBottomButtonPanel.md similarity index 100% rename from docs/components/bottomButtonPanel/BrnBottomButtonPanel/BrnBottomButtonPanel.md rename to doc/components/bottomButtonPanel/BrnBottomButtonPanel/BrnBottomButtonPanel.md diff --git a/docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/disable_and_enable.png b/doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/disable_and_enable.png similarity index 100% rename from docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/disable_and_enable.png rename to doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/disable_and_enable.png diff --git a/docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/disable_main.png b/doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/disable_main.png similarity index 100% rename from docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/disable_main.png rename to doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/disable_main.png diff --git a/docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_1.png b/doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_1.png similarity index 100% rename from docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_1.png rename to doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_1.png diff --git a/docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_2.png b/doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_2.png similarity index 100% rename from docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_2.png rename to doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_2.png diff --git a/docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_3.png b/doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_3.png similarity index 100% rename from docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_3.png rename to doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_3.png diff --git a/docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_4.png b/doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_4.png similarity index 100% rename from docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_4.png rename to doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_4.png diff --git a/docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_5.png b/doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_5.png similarity index 100% rename from docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_5.png rename to doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_5.png diff --git a/docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_6.png b/doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_6.png similarity index 100% rename from docs/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_6.png rename to doc/components/bottomButtonPanel/BrnBottomButtonPanel/img/pannel_6.png diff --git a/docs/components/bottomButtonPanel/BrnMultipleBottomButton/BrnMultipleBottomButton.md b/doc/components/bottomButtonPanel/BrnMultipleBottomButton/BrnMultipleBottomButton.md similarity index 100% rename from docs/components/bottomButtonPanel/BrnMultipleBottomButton/BrnMultipleBottomButton.md rename to doc/components/bottomButtonPanel/BrnMultipleBottomButton/BrnMultipleBottomButton.md diff --git a/docs/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo1.png b/doc/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo1.png similarity index 100% rename from docs/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo1.png rename to doc/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo1.png diff --git a/docs/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo2.png b/doc/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo2.png similarity index 100% rename from docs/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo2.png rename to doc/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo2.png diff --git a/docs/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo3.png b/doc/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo3.png similarity index 100% rename from docs/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo3.png rename to doc/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo3.png diff --git a/docs/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo4.png b/doc/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo4.png similarity index 100% rename from docs/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo4.png rename to doc/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonDemo4.png diff --git a/docs/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonIntro.png b/doc/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonIntro.png similarity index 100% rename from docs/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonIntro.png rename to doc/components/bottomButtonPanel/BrnMultipleBottomButton/img/BrnMultipleBottomButtonIntro.png diff --git a/docs/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md b/doc/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md similarity index 100% rename from docs/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md rename to doc/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md diff --git a/docs/components/bottomTabBar/BrnBottomTabBar/img/BrnBottomTabBar.png b/doc/components/bottomTabBar/BrnBottomTabBar/img/BrnBottomTabBar.png similarity index 100% rename from docs/components/bottomTabBar/BrnBottomTabBar/img/BrnBottomTabBar.png rename to doc/components/bottomTabBar/BrnBottomTabBar/img/BrnBottomTabBar.png diff --git a/docs/components/bubble/BrnBubbleText/BrnBubbleText.md b/doc/components/bubble/BrnBubbleText/BrnBubbleText.md similarity index 100% rename from docs/components/bubble/BrnBubbleText/BrnBubbleText.md rename to doc/components/bubble/BrnBubbleText/BrnBubbleText.md diff --git a/docs/components/bubble/BrnBubbleText/img/bubbleTextCollapsed.png b/doc/components/bubble/BrnBubbleText/img/bubbleTextCollapsed.png similarity index 100% rename from docs/components/bubble/BrnBubbleText/img/bubbleTextCollapsed.png rename to doc/components/bubble/BrnBubbleText/img/bubbleTextCollapsed.png diff --git a/docs/components/bubble/BrnBubbleText/img/bubbleTextExpaned.png b/doc/components/bubble/BrnBubbleText/img/bubbleTextExpaned.png similarity index 100% rename from docs/components/bubble/BrnBubbleText/img/bubbleTextExpaned.png rename to doc/components/bubble/BrnBubbleText/img/bubbleTextExpaned.png diff --git a/docs/components/bubble/BrnInsertInfo/BrnInsertInfo.md b/doc/components/bubble/BrnInsertInfo/BrnInsertInfo.md similarity index 100% rename from docs/components/bubble/BrnInsertInfo/BrnInsertInfo.md rename to doc/components/bubble/BrnInsertInfo/BrnInsertInfo.md diff --git a/docs/components/bubble/BrnInsertInfo/img/insert_info.png b/doc/components/bubble/BrnInsertInfo/img/insert_info.png similarity index 100% rename from docs/components/bubble/BrnInsertInfo/img/insert_info.png rename to doc/components/bubble/BrnInsertInfo/img/insert_info.png diff --git a/docs/components/buttonPanel/BrnButtonPanel/BrnButtonPanel.md b/doc/components/buttonPanel/BrnButtonPanel/BrnButtonPanel.md similarity index 100% rename from docs/components/buttonPanel/BrnButtonPanel/BrnButtonPanel.md rename to doc/components/buttonPanel/BrnButtonPanel/BrnButtonPanel.md diff --git a/docs/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo1.png b/doc/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo1.png similarity index 100% rename from docs/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo1.png rename to doc/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo1.png diff --git a/docs/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo2.png b/doc/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo2.png similarity index 100% rename from docs/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo2.png rename to doc/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo2.png diff --git a/docs/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo3.png b/doc/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo3.png similarity index 100% rename from docs/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo3.png rename to doc/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo3.png diff --git a/docs/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo4.png b/doc/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo4.png similarity index 100% rename from docs/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo4.png rename to doc/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo4.png diff --git a/docs/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo5.png b/doc/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo5.png similarity index 100% rename from docs/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo5.png rename to doc/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo5.png diff --git a/docs/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo6.png b/doc/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo6.png similarity index 100% rename from docs/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo6.png rename to doc/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelDemo6.png diff --git a/docs/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelIntro.png b/doc/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelIntro.png similarity index 100% rename from docs/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelIntro.png rename to doc/components/buttonPanel/BrnButtonPanel/img/BrnButtonPanelIntro.png diff --git a/docs/components/buttonPanel/BrnTextButtonPanel/BrnTextButtonPanel.md b/doc/components/buttonPanel/BrnTextButtonPanel/BrnTextButtonPanel.md similarity index 100% rename from docs/components/buttonPanel/BrnTextButtonPanel/BrnTextButtonPanel.md rename to doc/components/buttonPanel/BrnTextButtonPanel/BrnTextButtonPanel.md diff --git a/docs/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo1.png b/doc/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo1.png similarity index 100% rename from docs/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo1.png rename to doc/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo1.png diff --git a/docs/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo2.png b/doc/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo2.png similarity index 100% rename from docs/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo2.png rename to doc/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo2.png diff --git a/docs/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo3.png b/doc/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo3.png similarity index 100% rename from docs/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo3.png rename to doc/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo3.png diff --git a/docs/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo4.png b/doc/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo4.png similarity index 100% rename from docs/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo4.png rename to doc/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo4.png diff --git a/docs/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo5.png b/doc/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo5.png similarity index 100% rename from docs/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo5.png rename to doc/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelDemo5.png diff --git a/docs/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelIntro.png b/doc/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelIntro.png similarity index 100% rename from docs/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelIntro.png rename to doc/components/buttonPanel/BrnTextButtonPanel/img/BrnTextButtonPanelIntro.png diff --git a/docs/components/calendar/BrnCalendarView/BrnCalendarView.md b/doc/components/calendar/BrnCalendarView/BrnCalendarView.md similarity index 100% rename from docs/components/calendar/BrnCalendarView/BrnCalendarView.md rename to doc/components/calendar/BrnCalendarView/BrnCalendarView.md diff --git a/docs/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo1.png b/doc/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo1.png similarity index 100% rename from docs/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo1.png rename to doc/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo1.png diff --git a/docs/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo2.png b/doc/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo2.png similarity index 100% rename from docs/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo2.png rename to doc/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo2.png diff --git a/docs/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo3.png b/doc/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo3.png similarity index 100% rename from docs/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo3.png rename to doc/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo3.png diff --git a/docs/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo4.png b/doc/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo4.png similarity index 100% rename from docs/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo4.png rename to doc/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo4.png diff --git a/docs/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo5.png b/doc/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo5.png similarity index 100% rename from docs/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo5.png rename to doc/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo5.png diff --git a/docs/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo6.png b/doc/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo6.png similarity index 100% rename from docs/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo6.png rename to doc/components/calendar/BrnCalendarView/img/BrnCalendarViewDemo6.png diff --git a/docs/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro1.png b/doc/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro1.png similarity index 100% rename from docs/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro1.png rename to doc/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro1.png diff --git a/docs/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro2.png b/doc/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro2.png similarity index 100% rename from docs/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro2.png rename to doc/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro2.png diff --git a/docs/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro3.png b/doc/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro3.png similarity index 100% rename from docs/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro3.png rename to doc/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro3.png diff --git a/docs/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro4.png b/doc/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro4.png similarity index 100% rename from docs/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro4.png rename to doc/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro4.png diff --git a/docs/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro5.png b/doc/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro5.png similarity index 100% rename from docs/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro5.png rename to doc/components/calendar/BrnCalendarView/img/BrnCalendarViewIntro5.png diff --git a/docs/components/charts/BrnBrokenLine/BrnBrokenLine.md b/doc/components/charts/BrnBrokenLine/BrnBrokenLine.md similarity index 100% rename from docs/components/charts/BrnBrokenLine/BrnBrokenLine.md rename to doc/components/charts/BrnBrokenLine/BrnBrokenLine.md diff --git a/docs/components/charts/BrnBrokenLine/img/BrnBrokenLineDemo1.png b/doc/components/charts/BrnBrokenLine/img/BrnBrokenLineDemo1.png similarity index 100% rename from docs/components/charts/BrnBrokenLine/img/BrnBrokenLineDemo1.png rename to doc/components/charts/BrnBrokenLine/img/BrnBrokenLineDemo1.png diff --git a/docs/components/charts/BrnBrokenLine/img/BrnBrokenLineDemo2.png b/doc/components/charts/BrnBrokenLine/img/BrnBrokenLineDemo2.png similarity index 100% rename from docs/components/charts/BrnBrokenLine/img/BrnBrokenLineDemo2.png rename to doc/components/charts/BrnBrokenLine/img/BrnBrokenLineDemo2.png diff --git a/docs/components/charts/BrnBrokenLine/img/BrnBrokenLineIntro.png b/doc/components/charts/BrnBrokenLine/img/BrnBrokenLineIntro.png similarity index 100% rename from docs/components/charts/BrnBrokenLine/img/BrnBrokenLineIntro.png rename to doc/components/charts/BrnBrokenLine/img/BrnBrokenLineIntro.png diff --git a/docs/components/charts/BrnDoughnutChart/BrnDoughnutChart.md b/doc/components/charts/BrnDoughnutChart/BrnDoughnutChart.md similarity index 100% rename from docs/components/charts/BrnDoughnutChart/BrnDoughnutChart.md rename to doc/components/charts/BrnDoughnutChart/BrnDoughnutChart.md diff --git a/docs/components/charts/BrnDoughnutChart/img/BrnDoughnutChartDemo1.png b/doc/components/charts/BrnDoughnutChart/img/BrnDoughnutChartDemo1.png similarity index 100% rename from docs/components/charts/BrnDoughnutChart/img/BrnDoughnutChartDemo1.png rename to doc/components/charts/BrnDoughnutChart/img/BrnDoughnutChartDemo1.png diff --git a/docs/components/charts/BrnDoughnutChart/img/BrnDoughnutChartIntro.png b/doc/components/charts/BrnDoughnutChart/img/BrnDoughnutChartIntro.png similarity index 100% rename from docs/components/charts/BrnDoughnutChart/img/BrnDoughnutChartIntro.png rename to doc/components/charts/BrnDoughnutChart/img/BrnDoughnutChartIntro.png diff --git a/docs/components/charts/BrnFunnelChart/BrnFunnelChart.md b/doc/components/charts/BrnFunnelChart/BrnFunnelChart.md similarity index 100% rename from docs/components/charts/BrnFunnelChart/BrnFunnelChart.md rename to doc/components/charts/BrnFunnelChart/BrnFunnelChart.md diff --git a/docs/components/charts/BrnFunnelChart/img/BrnFunnelChart1.png b/doc/components/charts/BrnFunnelChart/img/BrnFunnelChart1.png similarity index 100% rename from docs/components/charts/BrnFunnelChart/img/BrnFunnelChart1.png rename to doc/components/charts/BrnFunnelChart/img/BrnFunnelChart1.png diff --git a/docs/components/charts/BrnFunnelChart/img/BrnFunnelChart2.png b/doc/components/charts/BrnFunnelChart/img/BrnFunnelChart2.png similarity index 100% rename from docs/components/charts/BrnFunnelChart/img/BrnFunnelChart2.png rename to doc/components/charts/BrnFunnelChart/img/BrnFunnelChart2.png diff --git a/docs/components/charts/BrnFunnelChart/img/BrnFunnelChart3.png b/doc/components/charts/BrnFunnelChart/img/BrnFunnelChart3.png similarity index 100% rename from docs/components/charts/BrnFunnelChart/img/BrnFunnelChart3.png rename to doc/components/charts/BrnFunnelChart/img/BrnFunnelChart3.png diff --git a/docs/components/charts/BrnFunnelChart/img/BrnFunnelChartIntro.png b/doc/components/charts/BrnFunnelChart/img/BrnFunnelChartIntro.png similarity index 100% rename from docs/components/charts/BrnFunnelChart/img/BrnFunnelChartIntro.png rename to doc/components/charts/BrnFunnelChart/img/BrnFunnelChartIntro.png diff --git a/docs/components/charts/BrnProgressBarChart/BrnProgressBarChart.md b/doc/components/charts/BrnProgressBarChart/BrnProgressBarChart.md similarity index 100% rename from docs/components/charts/BrnProgressBarChart/BrnProgressBarChart.md rename to doc/components/charts/BrnProgressBarChart/BrnProgressBarChart.md diff --git a/docs/components/charts/BrnProgressBarChart/img/BrnProgressBarChartDemo1.png b/doc/components/charts/BrnProgressBarChart/img/BrnProgressBarChartDemo1.png similarity index 100% rename from docs/components/charts/BrnProgressBarChart/img/BrnProgressBarChartDemo1.png rename to doc/components/charts/BrnProgressBarChart/img/BrnProgressBarChartDemo1.png diff --git a/docs/components/charts/BrnProgressBarChart/img/BrnProgressBarChartDemo2.png b/doc/components/charts/BrnProgressBarChart/img/BrnProgressBarChartDemo2.png similarity index 100% rename from docs/components/charts/BrnProgressBarChart/img/BrnProgressBarChartDemo2.png rename to doc/components/charts/BrnProgressBarChart/img/BrnProgressBarChartDemo2.png diff --git a/docs/components/charts/BrnProgressBarChart/img/BrnProgressBarChartIntro1.png b/doc/components/charts/BrnProgressBarChart/img/BrnProgressBarChartIntro1.png similarity index 100% rename from docs/components/charts/BrnProgressBarChart/img/BrnProgressBarChartIntro1.png rename to doc/components/charts/BrnProgressBarChart/img/BrnProgressBarChartIntro1.png diff --git a/docs/components/charts/BrnProgressBarChart/img/BrnProgressBarChartIntro2.png b/doc/components/charts/BrnProgressBarChart/img/BrnProgressBarChartIntro2.png similarity index 100% rename from docs/components/charts/BrnProgressBarChart/img/BrnProgressBarChartIntro2.png rename to doc/components/charts/BrnProgressBarChart/img/BrnProgressBarChartIntro2.png diff --git a/docs/components/charts/BrnProgressChart/BrnProgressChart.md b/doc/components/charts/BrnProgressChart/BrnProgressChart.md similarity index 100% rename from docs/components/charts/BrnProgressChart/BrnProgressChart.md rename to doc/components/charts/BrnProgressChart/BrnProgressChart.md diff --git a/docs/components/charts/BrnProgressChart/img/BrnProgressChartDemo1.png b/doc/components/charts/BrnProgressChart/img/BrnProgressChartDemo1.png similarity index 100% rename from docs/components/charts/BrnProgressChart/img/BrnProgressChartDemo1.png rename to doc/components/charts/BrnProgressChart/img/BrnProgressChartDemo1.png diff --git a/docs/components/charts/BrnProgressChart/img/BrnProgressChartIntro.png b/doc/components/charts/BrnProgressChart/img/BrnProgressChartIntro.png similarity index 100% rename from docs/components/charts/BrnProgressChart/img/BrnProgressChartIntro.png rename to doc/components/charts/BrnProgressChart/img/BrnProgressChartIntro.png diff --git a/docs/components/charts/BrnRadarChart/BrnRadarChart.md b/doc/components/charts/BrnRadarChart/BrnRadarChart.md similarity index 100% rename from docs/components/charts/BrnRadarChart/BrnRadarChart.md rename to doc/components/charts/BrnRadarChart/BrnRadarChart.md diff --git a/docs/components/charts/BrnRadarChart/img/BrnRadarChartDemo1.png b/doc/components/charts/BrnRadarChart/img/BrnRadarChartDemo1.png similarity index 100% rename from docs/components/charts/BrnRadarChart/img/BrnRadarChartDemo1.png rename to doc/components/charts/BrnRadarChart/img/BrnRadarChartDemo1.png diff --git a/docs/components/charts/BrnRadarChart/img/BrnRadarChartDemo2.png b/doc/components/charts/BrnRadarChart/img/BrnRadarChartDemo2.png similarity index 100% rename from docs/components/charts/BrnRadarChart/img/BrnRadarChartDemo2.png rename to doc/components/charts/BrnRadarChart/img/BrnRadarChartDemo2.png diff --git a/docs/components/charts/BrnRadarChart/img/BrnRadarChartIntro.png b/doc/components/charts/BrnRadarChart/img/BrnRadarChartIntro.png similarity index 100% rename from docs/components/charts/BrnRadarChart/img/BrnRadarChartIntro.png rename to doc/components/charts/BrnRadarChart/img/BrnRadarChartIntro.png diff --git a/docs/components/checkbox/BrnCheckbox/BrnCheckbox.md b/doc/components/checkbox/BrnCheckbox/BrnCheckbox.md similarity index 100% rename from docs/components/checkbox/BrnCheckbox/BrnCheckbox.md rename to doc/components/checkbox/BrnCheckbox/BrnCheckbox.md diff --git a/docs/components/citySelection/BrnSingleSelectCityPage/BrnSingleSelectCityPage.md b/doc/components/citySelection/BrnSingleSelectCityPage/BrnSingleSelectCityPage.md similarity index 100% rename from docs/components/citySelection/BrnSingleSelectCityPage/BrnSingleSelectCityPage.md rename to doc/components/citySelection/BrnSingleSelectCityPage/BrnSingleSelectCityPage.md diff --git a/docs/components/citySelection/BrnSingleSelectCityPage/img/BrnSingleSelectCityPageDemo1.png b/doc/components/citySelection/BrnSingleSelectCityPage/img/BrnSingleSelectCityPageDemo1.png similarity index 100% rename from docs/components/citySelection/BrnSingleSelectCityPage/img/BrnSingleSelectCityPageDemo1.png rename to doc/components/citySelection/BrnSingleSelectCityPage/img/BrnSingleSelectCityPageDemo1.png diff --git a/docs/components/citySelection/BrnSingleSelectCityPage/img/BrnSingleSelectCityPageIntro.png b/doc/components/citySelection/BrnSingleSelectCityPage/img/BrnSingleSelectCityPageIntro.png similarity index 100% rename from docs/components/citySelection/BrnSingleSelectCityPage/img/BrnSingleSelectCityPageIntro.png rename to doc/components/citySelection/BrnSingleSelectCityPage/img/BrnSingleSelectCityPageIntro.png diff --git a/docs/components/dashedLine/BrnDashedLine/BrnDashedLine.md b/doc/components/dashedLine/BrnDashedLine/BrnDashedLine.md similarity index 100% rename from docs/components/dashedLine/BrnDashedLine/BrnDashedLine.md rename to doc/components/dashedLine/BrnDashedLine/BrnDashedLine.md diff --git a/docs/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo1.png b/doc/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo1.png similarity index 100% rename from docs/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo1.png rename to doc/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo1.png diff --git a/docs/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo2.png b/doc/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo2.png similarity index 100% rename from docs/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo2.png rename to doc/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo2.png diff --git a/docs/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo3.png b/doc/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo3.png similarity index 100% rename from docs/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo3.png rename to doc/components/dashedLine/BrnDashedLine/img/BrnDashedLineDemo3.png diff --git a/docs/components/dashedLine/BrnDashedLine/img/BrnDashedLineIntro.png b/doc/components/dashedLine/BrnDashedLine/img/BrnDashedLineIntro.png similarity index 100% rename from docs/components/dashedLine/BrnDashedLine/img/BrnDashedLineIntro.png rename to doc/components/dashedLine/BrnDashedLine/img/BrnDashedLineIntro.png diff --git a/docs/components/dialog/BrnDialog/BrnDialog.md b/doc/components/dialog/BrnDialog/BrnDialog.md similarity index 100% rename from docs/components/dialog/BrnDialog/BrnDialog.md rename to doc/components/dialog/BrnDialog/BrnDialog.md diff --git a/docs/components/dialog/BrnDialog/img/common_dialog_2.png b/doc/components/dialog/BrnDialog/img/common_dialog_2.png similarity index 100% rename from docs/components/dialog/BrnDialog/img/common_dialog_2.png rename to doc/components/dialog/BrnDialog/img/common_dialog_2.png diff --git a/docs/components/dialog/BrnDialog/img/common_dialog_3.png b/doc/components/dialog/BrnDialog/img/common_dialog_3.png similarity index 100% rename from docs/components/dialog/BrnDialog/img/common_dialog_3.png rename to doc/components/dialog/BrnDialog/img/common_dialog_3.png diff --git a/docs/components/dialog/BrnDialog/img/common_dialog_4.png b/doc/components/dialog/BrnDialog/img/common_dialog_4.png similarity index 100% rename from docs/components/dialog/BrnDialog/img/common_dialog_4.png rename to doc/components/dialog/BrnDialog/img/common_dialog_4.png diff --git a/docs/components/dialog/BrnDialog/img/common_dialog_5.png b/doc/components/dialog/BrnDialog/img/common_dialog_5.png similarity index 100% rename from docs/components/dialog/BrnDialog/img/common_dialog_5.png rename to doc/components/dialog/BrnDialog/img/common_dialog_5.png diff --git a/docs/components/dialog/BrnDialog/img/common_dialog_6.png b/doc/components/dialog/BrnDialog/img/common_dialog_6.png similarity index 100% rename from docs/components/dialog/BrnDialog/img/common_dialog_6.png rename to doc/components/dialog/BrnDialog/img/common_dialog_6.png diff --git a/docs/components/dialog/BrnDialog/img/common_dialog_7.png b/doc/components/dialog/BrnDialog/img/common_dialog_7.png similarity index 100% rename from docs/components/dialog/BrnDialog/img/common_dialog_7.png rename to doc/components/dialog/BrnDialog/img/common_dialog_7.png diff --git a/docs/components/dialog/BrnDialog/img/common_dialog_8.png b/doc/components/dialog/BrnDialog/img/common_dialog_8.png similarity index 100% rename from docs/components/dialog/BrnDialog/img/common_dialog_8.png rename to doc/components/dialog/BrnDialog/img/common_dialog_8.png diff --git a/docs/components/dialog/BrnDialog/img/common_dialog_9.png b/doc/components/dialog/BrnDialog/img/common_dialog_9.png similarity index 100% rename from docs/components/dialog/BrnDialog/img/common_dialog_9.png rename to doc/components/dialog/BrnDialog/img/common_dialog_9.png diff --git a/docs/components/dialog/BrnDialog/img/common_diloag_0.png b/doc/components/dialog/BrnDialog/img/common_diloag_0.png similarity index 100% rename from docs/components/dialog/BrnDialog/img/common_diloag_0.png rename to doc/components/dialog/BrnDialog/img/common_diloag_0.png diff --git a/docs/components/dialog/BrnDialog/img/common_diloag_1.png b/doc/components/dialog/BrnDialog/img/common_diloag_1.png similarity index 100% rename from docs/components/dialog/BrnDialog/img/common_diloag_1.png rename to doc/components/dialog/BrnDialog/img/common_diloag_1.png diff --git a/docs/components/dialog/BrnEnhanceOperationDialog/BrnEnhanceOperationDialog.md b/doc/components/dialog/BrnEnhanceOperationDialog/BrnEnhanceOperationDialog.md similarity index 100% rename from docs/components/dialog/BrnEnhanceOperationDialog/BrnEnhanceOperationDialog.md rename to doc/components/dialog/BrnEnhanceOperationDialog/BrnEnhanceOperationDialog.md diff --git a/docs/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogDemo1.png b/doc/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogDemo1.png similarity index 100% rename from docs/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogDemo1.png rename to doc/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogDemo1.png diff --git a/docs/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogDemo2.png b/doc/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogDemo2.png similarity index 100% rename from docs/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogDemo2.png rename to doc/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogDemo2.png diff --git a/docs/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogIntro1.png b/doc/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogIntro1.png similarity index 100% rename from docs/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogIntro1.png rename to doc/components/dialog/BrnEnhanceOperationDialog/img/BrnEnhanceOperationDialogIntro1.png diff --git a/docs/components/dialog/BrnEnhanceOperationDialog/img/dialog_two_vertical_button_1.png b/doc/components/dialog/BrnEnhanceOperationDialog/img/dialog_two_vertical_button_1.png similarity index 100% rename from docs/components/dialog/BrnEnhanceOperationDialog/img/dialog_two_vertical_button_1.png rename to doc/components/dialog/BrnEnhanceOperationDialog/img/dialog_two_vertical_button_1.png diff --git a/docs/components/dialog/BrnLoadingDialog/BrnLoadingDialog.md b/doc/components/dialog/BrnLoadingDialog/BrnLoadingDialog.md similarity index 100% rename from docs/components/dialog/BrnLoadingDialog/BrnLoadingDialog.md rename to doc/components/dialog/BrnLoadingDialog/BrnLoadingDialog.md diff --git a/docs/components/dialog/BrnLoadingDialog/img/BrnLoadingDialogIntro.png b/doc/components/dialog/BrnLoadingDialog/img/BrnLoadingDialogIntro.png similarity index 100% rename from docs/components/dialog/BrnLoadingDialog/img/BrnLoadingDialogIntro.png rename to doc/components/dialog/BrnLoadingDialog/img/BrnLoadingDialogIntro.png diff --git a/docs/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md b/doc/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md similarity index 100% rename from docs/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md rename to doc/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md diff --git a/docs/components/dialog/BrnMiddleInputDialog/img/BrnMiddleInputDialogIntro1.png b/doc/components/dialog/BrnMiddleInputDialog/img/BrnMiddleInputDialogIntro1.png similarity index 100% rename from docs/components/dialog/BrnMiddleInputDialog/img/BrnMiddleInputDialogIntro1.png rename to doc/components/dialog/BrnMiddleInputDialog/img/BrnMiddleInputDialogIntro1.png diff --git a/docs/components/dialog/BrnMiddleInputDialog/img/BrnMiddleInputDialogIntro2.png b/doc/components/dialog/BrnMiddleInputDialog/img/BrnMiddleInputDialogIntro2.png similarity index 100% rename from docs/components/dialog/BrnMiddleInputDialog/img/BrnMiddleInputDialogIntro2.png rename to doc/components/dialog/BrnMiddleInputDialog/img/BrnMiddleInputDialogIntro2.png diff --git a/docs/components/dialog/BrnMiddleInputDialog/img/middleinoutdialog.png b/doc/components/dialog/BrnMiddleInputDialog/img/middleinoutdialog.png similarity index 100% rename from docs/components/dialog/BrnMiddleInputDialog/img/middleinoutdialog.png rename to doc/components/dialog/BrnMiddleInputDialog/img/middleinoutdialog.png diff --git a/docs/components/dialog/BrnMultiSelectDialog/BrnMultiSelectDialog.md b/doc/components/dialog/BrnMultiSelectDialog/BrnMultiSelectDialog.md similarity index 100% rename from docs/components/dialog/BrnMultiSelectDialog/BrnMultiSelectDialog.md rename to doc/components/dialog/BrnMultiSelectDialog/BrnMultiSelectDialog.md diff --git a/docs/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo1.png b/doc/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo1.png similarity index 100% rename from docs/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo1.png rename to doc/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo1.png diff --git a/docs/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo2.png b/doc/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo2.png similarity index 100% rename from docs/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo2.png rename to doc/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo2.png diff --git a/docs/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo3.png b/doc/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo3.png similarity index 100% rename from docs/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo3.png rename to doc/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogDemo3.png diff --git a/docs/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogIntro.png b/doc/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogIntro.png similarity index 100% rename from docs/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogIntro.png rename to doc/components/dialog/BrnMultiSelectDialog/img/BrnMultiSelectDialogIntro.png diff --git a/docs/components/dialog/BrnScrollableTextDialog/BrnScrollableTextDialog.md b/doc/components/dialog/BrnScrollableTextDialog/BrnScrollableTextDialog.md similarity index 100% rename from docs/components/dialog/BrnScrollableTextDialog/BrnScrollableTextDialog.md rename to doc/components/dialog/BrnScrollableTextDialog/BrnScrollableTextDialog.md diff --git a/docs/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo1.png b/doc/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo1.png similarity index 100% rename from docs/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo1.png rename to doc/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo1.png diff --git a/docs/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo2.png b/doc/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo2.png similarity index 100% rename from docs/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo2.png rename to doc/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo2.png diff --git a/docs/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo3.png b/doc/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo3.png similarity index 100% rename from docs/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo3.png rename to doc/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo3.png diff --git a/docs/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo4.png b/doc/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo4.png similarity index 100% rename from docs/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo4.png rename to doc/components/dialog/BrnScrollableTextDialog/img/BrnScrollableTextDialogDemo4.png diff --git a/docs/components/dialog/BrnShareDialog/BrnShareDialog.md b/doc/components/dialog/BrnShareDialog/BrnShareDialog.md similarity index 100% rename from docs/components/dialog/BrnShareDialog/BrnShareDialog.md rename to doc/components/dialog/BrnShareDialog/BrnShareDialog.md diff --git a/docs/components/dialog/BrnShareDialog/img/BrnShareDialogDemo1.png b/doc/components/dialog/BrnShareDialog/img/BrnShareDialogDemo1.png similarity index 100% rename from docs/components/dialog/BrnShareDialog/img/BrnShareDialogDemo1.png rename to doc/components/dialog/BrnShareDialog/img/BrnShareDialogDemo1.png diff --git a/docs/components/dialog/BrnShareDialog/img/BrnShareDialogDemo2.png b/doc/components/dialog/BrnShareDialog/img/BrnShareDialogDemo2.png similarity index 100% rename from docs/components/dialog/BrnShareDialog/img/BrnShareDialogDemo2.png rename to doc/components/dialog/BrnShareDialog/img/BrnShareDialogDemo2.png diff --git a/docs/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md b/doc/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md similarity index 100% rename from docs/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md rename to doc/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md diff --git a/docs/components/dialog/BrnSingleSelectDialog/img/BrnSingleSelectDialog.png b/doc/components/dialog/BrnSingleSelectDialog/img/BrnSingleSelectDialog.png similarity index 100% rename from docs/components/dialog/BrnSingleSelectDialog/img/BrnSingleSelectDialog.png rename to doc/components/dialog/BrnSingleSelectDialog/img/BrnSingleSelectDialog.png diff --git a/docs/components/form/BrnAddLabel/BrnAddLabel.md b/doc/components/form/BrnAddLabel/BrnAddLabel.md similarity index 100% rename from docs/components/form/BrnAddLabel/BrnAddLabel.md rename to doc/components/form/BrnAddLabel/BrnAddLabel.md diff --git a/docs/components/form/BrnAddLabel/img/BrnAddLabelDemo1.png b/doc/components/form/BrnAddLabel/img/BrnAddLabelDemo1.png similarity index 100% rename from docs/components/form/BrnAddLabel/img/BrnAddLabelDemo1.png rename to doc/components/form/BrnAddLabel/img/BrnAddLabelDemo1.png diff --git a/docs/components/form/BrnAddLabel/img/BrnAddLabelIntro.png b/doc/components/form/BrnAddLabel/img/BrnAddLabelIntro.png similarity index 100% rename from docs/components/form/BrnAddLabel/img/BrnAddLabelIntro.png rename to doc/components/form/BrnAddLabel/img/BrnAddLabelIntro.png diff --git a/docs/components/form/BrnBaseTitle/BrnBaseTitle.md b/doc/components/form/BrnBaseTitle/BrnBaseTitle.md similarity index 100% rename from docs/components/form/BrnBaseTitle/BrnBaseTitle.md rename to doc/components/form/BrnBaseTitle/BrnBaseTitle.md diff --git a/docs/components/form/BrnBaseTitle/img/BrnBaseTitleDemo1.png b/doc/components/form/BrnBaseTitle/img/BrnBaseTitleDemo1.png similarity index 100% rename from docs/components/form/BrnBaseTitle/img/BrnBaseTitleDemo1.png rename to doc/components/form/BrnBaseTitle/img/BrnBaseTitleDemo1.png diff --git a/docs/components/form/BrnBaseTitle/img/BrnBaseTitleDemo2.png b/doc/components/form/BrnBaseTitle/img/BrnBaseTitleDemo2.png similarity index 100% rename from docs/components/form/BrnBaseTitle/img/BrnBaseTitleDemo2.png rename to doc/components/form/BrnBaseTitle/img/BrnBaseTitleDemo2.png diff --git a/docs/components/form/BrnBaseTitle/img/BrnBaseTitleIntro.png b/doc/components/form/BrnBaseTitle/img/BrnBaseTitleIntro.png similarity index 100% rename from docs/components/form/BrnBaseTitle/img/BrnBaseTitleIntro.png rename to doc/components/form/BrnBaseTitle/img/BrnBaseTitleIntro.png diff --git a/docs/components/form/BrnExpandFormGroup/BrnExpandFormGroup.md b/doc/components/form/BrnExpandFormGroup/BrnExpandFormGroup.md similarity index 100% rename from docs/components/form/BrnExpandFormGroup/BrnExpandFormGroup.md rename to doc/components/form/BrnExpandFormGroup/BrnExpandFormGroup.md diff --git a/docs/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo1.png b/doc/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo1.png similarity index 100% rename from docs/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo1.png rename to doc/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo1.png diff --git a/docs/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo2.png b/doc/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo2.png similarity index 100% rename from docs/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo2.png rename to doc/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo2.png diff --git a/docs/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo3.png b/doc/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo3.png similarity index 100% rename from docs/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo3.png rename to doc/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupDemo3.png diff --git a/docs/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupIntro.png b/doc/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupIntro.png similarity index 100% rename from docs/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupIntro.png rename to doc/components/form/BrnExpandFormGroup/img/BrnExpandFormGroupIntro.png diff --git a/docs/components/form/BrnExpandableGroup/BrnExpandableGroup.md b/doc/components/form/BrnExpandableGroup/BrnExpandableGroup.md similarity index 100% rename from docs/components/form/BrnExpandableGroup/BrnExpandableGroup.md rename to doc/components/form/BrnExpandableGroup/BrnExpandableGroup.md diff --git a/docs/components/form/BrnExpandableGroup/img/BrnExpandableGroupIntro1.gif b/doc/components/form/BrnExpandableGroup/img/BrnExpandableGroupIntro1.gif similarity index 100% rename from docs/components/form/BrnExpandableGroup/img/BrnExpandableGroupIntro1.gif rename to doc/components/form/BrnExpandableGroup/img/BrnExpandableGroupIntro1.gif diff --git a/docs/components/form/BrnExpandableGroup/img/BrnExpandableGroupIntro2.png b/doc/components/form/BrnExpandableGroup/img/BrnExpandableGroupIntro2.png similarity index 100% rename from docs/components/form/BrnExpandableGroup/img/BrnExpandableGroupIntro2.png rename to doc/components/form/BrnExpandableGroup/img/BrnExpandableGroupIntro2.png diff --git a/docs/components/form/BrnMultiChoiceInputFormItem/BrnMultiChoiceInputFormItem.md b/doc/components/form/BrnMultiChoiceInputFormItem/BrnMultiChoiceInputFormItem.md similarity index 100% rename from docs/components/form/BrnMultiChoiceInputFormItem/BrnMultiChoiceInputFormItem.md rename to doc/components/form/BrnMultiChoiceInputFormItem/BrnMultiChoiceInputFormItem.md diff --git a/docs/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemDemo1.png b/doc/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemDemo1.png similarity index 100% rename from docs/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemDemo1.png rename to doc/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemDemo1.png diff --git a/docs/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemDemo2.png b/doc/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemDemo2.png similarity index 100% rename from docs/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemDemo2.png rename to doc/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemDemo2.png diff --git a/docs/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemIntro.png b/doc/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemIntro.png similarity index 100% rename from docs/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemIntro.png rename to doc/components/form/BrnMultiChoiceInputFormItem/img/BrnMultiChoiceInputFormItemIntro.png diff --git a/docs/components/form/BrnMultiChoicePortraitInputFormItem/BrnMultiChoicePortraitInputFormItem.md b/doc/components/form/BrnMultiChoicePortraitInputFormItem/BrnMultiChoicePortraitInputFormItem.md similarity index 100% rename from docs/components/form/BrnMultiChoicePortraitInputFormItem/BrnMultiChoicePortraitInputFormItem.md rename to doc/components/form/BrnMultiChoicePortraitInputFormItem/BrnMultiChoicePortraitInputFormItem.md diff --git a/docs/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemDemo1.png b/doc/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemDemo1.png similarity index 100% rename from docs/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemDemo1.png rename to doc/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemDemo1.png diff --git a/docs/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemDemo2.png b/doc/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemDemo2.png similarity index 100% rename from docs/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemDemo2.png rename to doc/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemDemo2.png diff --git a/docs/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemIntro.png b/doc/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemIntro.png similarity index 100% rename from docs/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemIntro.png rename to doc/components/form/BrnMultiChoicePortraitInputFormItem/img/BrnMultiChoicePortraitInputFormItemIntro.png diff --git a/docs/components/form/BrnNormalFormGroup/BrnNormalFormGroup.md b/doc/components/form/BrnNormalFormGroup/BrnNormalFormGroup.md similarity index 100% rename from docs/components/form/BrnNormalFormGroup/BrnNormalFormGroup.md rename to doc/components/form/BrnNormalFormGroup/BrnNormalFormGroup.md diff --git a/docs/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupDemo1.png b/doc/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupDemo1.png similarity index 100% rename from docs/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupDemo1.png rename to doc/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupDemo1.png diff --git a/docs/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupDemo2.png b/doc/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupDemo2.png similarity index 100% rename from docs/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupDemo2.png rename to doc/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupDemo2.png diff --git a/docs/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupIntro.png b/doc/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupIntro.png similarity index 100% rename from docs/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupIntro.png rename to doc/components/form/BrnNormalFormGroup/img/BrnNormalFormGroupIntro.png diff --git a/docs/components/form/BrnPortraitRadioGroup/BrnPortraitRadioGroup.md b/doc/components/form/BrnPortraitRadioGroup/BrnPortraitRadioGroup.md similarity index 100% rename from docs/components/form/BrnPortraitRadioGroup/BrnPortraitRadioGroup.md rename to doc/components/form/BrnPortraitRadioGroup/BrnPortraitRadioGroup.md diff --git a/docs/components/form/BrnPortraitRadioGroup/img/BrnPortraitRadioGroupDemo1.png b/doc/components/form/BrnPortraitRadioGroup/img/BrnPortraitRadioGroupDemo1.png similarity index 100% rename from docs/components/form/BrnPortraitRadioGroup/img/BrnPortraitRadioGroupDemo1.png rename to doc/components/form/BrnPortraitRadioGroup/img/BrnPortraitRadioGroupDemo1.png diff --git a/docs/components/form/BrnPortraitRadioGroup/img/BrnPortraitRadioGroupDemo2.png b/doc/components/form/BrnPortraitRadioGroup/img/BrnPortraitRadioGroupDemo2.png similarity index 100% rename from docs/components/form/BrnPortraitRadioGroup/img/BrnPortraitRadioGroupDemo2.png rename to doc/components/form/BrnPortraitRadioGroup/img/BrnPortraitRadioGroupDemo2.png diff --git a/docs/components/form/BrnRadioInputFormItem/BrnRadioInputFormItem.md b/doc/components/form/BrnRadioInputFormItem/BrnRadioInputFormItem.md similarity index 100% rename from docs/components/form/BrnRadioInputFormItem/BrnRadioInputFormItem.md rename to doc/components/form/BrnRadioInputFormItem/BrnRadioInputFormItem.md diff --git a/docs/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo1.png b/doc/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo1.png similarity index 100% rename from docs/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo1.png rename to doc/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo1.png diff --git a/docs/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo2.png b/doc/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo2.png similarity index 100% rename from docs/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo2.png rename to doc/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo2.png diff --git a/docs/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo3.png b/doc/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo3.png similarity index 100% rename from docs/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo3.png rename to doc/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo3.png diff --git a/docs/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo4.png b/doc/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo4.png similarity index 100% rename from docs/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo4.png rename to doc/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemDemo4.png diff --git a/docs/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemIntro.png b/doc/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemIntro.png similarity index 100% rename from docs/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemIntro.png rename to doc/components/form/BrnRadioInputFormItem/img/BrnRadioInputFormItemIntro.png diff --git a/docs/components/form/BrnRadioPortraitInputFormItem/BrnRadioPortraitInputFormItem.md b/doc/components/form/BrnRadioPortraitInputFormItem/BrnRadioPortraitInputFormItem.md similarity index 100% rename from docs/components/form/BrnRadioPortraitInputFormItem/BrnRadioPortraitInputFormItem.md rename to doc/components/form/BrnRadioPortraitInputFormItem/BrnRadioPortraitInputFormItem.md diff --git a/docs/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemDemo1.png b/doc/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemDemo1.png similarity index 100% rename from docs/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemDemo1.png rename to doc/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemDemo1.png diff --git a/docs/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemDemo2.png b/doc/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemDemo2.png similarity index 100% rename from docs/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemDemo2.png rename to doc/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemDemo2.png diff --git a/docs/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemIntro.png b/doc/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemIntro.png similarity index 100% rename from docs/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemIntro.png rename to doc/components/form/BrnRadioPortraitInputFormItem/img/BrnRadioPortraitInputFormItemIntro.png diff --git a/docs/components/form/BrnRangeInputFormItem/BrnRangeInputFormItem.md b/doc/components/form/BrnRangeInputFormItem/BrnRangeInputFormItem.md similarity index 100% rename from docs/components/form/BrnRangeInputFormItem/BrnRangeInputFormItem.md rename to doc/components/form/BrnRangeInputFormItem/BrnRangeInputFormItem.md diff --git a/docs/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemDemo1.png b/doc/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemDemo1.png similarity index 100% rename from docs/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemDemo1.png rename to doc/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemDemo1.png diff --git a/docs/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemDemo2.png b/doc/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemDemo2.png similarity index 100% rename from docs/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemDemo2.png rename to doc/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemDemo2.png diff --git a/docs/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemIntro.png b/doc/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemIntro.png similarity index 100% rename from docs/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemIntro.png rename to doc/components/form/BrnRangeInputFormItem/img/BrnRangeInputFormItemIntro.png diff --git a/docs/components/form/BrnRatioInputFormItem/BrnRatioInputFormItem.md b/doc/components/form/BrnRatioInputFormItem/BrnRatioInputFormItem.md similarity index 100% rename from docs/components/form/BrnRatioInputFormItem/BrnRatioInputFormItem.md rename to doc/components/form/BrnRatioInputFormItem/BrnRatioInputFormItem.md diff --git a/docs/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemDemo1.png b/doc/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemDemo1.png similarity index 100% rename from docs/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemDemo1.png rename to doc/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemDemo1.png diff --git a/docs/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemDemo2.png b/doc/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemDemo2.png similarity index 100% rename from docs/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemDemo2.png rename to doc/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemDemo2.png diff --git a/docs/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemIntro.png b/doc/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemIntro.png similarity index 100% rename from docs/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemIntro.png rename to doc/components/form/BrnRatioInputFormItem/img/BrnRatioInputFormItemIntro.png diff --git a/docs/components/form/BrnSelectAllTitle/BrnSelectAllTitle.md b/doc/components/form/BrnSelectAllTitle/BrnSelectAllTitle.md similarity index 100% rename from docs/components/form/BrnSelectAllTitle/BrnSelectAllTitle.md rename to doc/components/form/BrnSelectAllTitle/BrnSelectAllTitle.md diff --git a/docs/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleDemo1.png b/doc/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleDemo1.png similarity index 100% rename from docs/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleDemo1.png rename to doc/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleDemo1.png diff --git a/docs/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleDemo2.png b/doc/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleDemo2.png similarity index 100% rename from docs/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleDemo2.png rename to doc/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleDemo2.png diff --git a/docs/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleIntro.png b/doc/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleIntro.png similarity index 100% rename from docs/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleIntro.png rename to doc/components/form/BrnSelectAllTitle/img/BrnSelectAllTitleIntro.png diff --git a/docs/components/form/BrnStarsFormItem/BrnStarsFormItem.md b/doc/components/form/BrnStarsFormItem/BrnStarsFormItem.md similarity index 100% rename from docs/components/form/BrnStarsFormItem/BrnStarsFormItem.md rename to doc/components/form/BrnStarsFormItem/BrnStarsFormItem.md diff --git a/docs/components/form/BrnStarsFormItem/img/BrnStarsFormItemDemo1.png b/doc/components/form/BrnStarsFormItem/img/BrnStarsFormItemDemo1.png similarity index 100% rename from docs/components/form/BrnStarsFormItem/img/BrnStarsFormItemDemo1.png rename to doc/components/form/BrnStarsFormItem/img/BrnStarsFormItemDemo1.png diff --git a/docs/components/form/BrnStarsFormItem/img/BrnStarsFormItemDemo2.png b/doc/components/form/BrnStarsFormItem/img/BrnStarsFormItemDemo2.png similarity index 100% rename from docs/components/form/BrnStarsFormItem/img/BrnStarsFormItemDemo2.png rename to doc/components/form/BrnStarsFormItem/img/BrnStarsFormItemDemo2.png diff --git a/docs/components/form/BrnStarsFormItem/img/BrnStarsFormItemIntro.png b/doc/components/form/BrnStarsFormItem/img/BrnStarsFormItemIntro.png similarity index 100% rename from docs/components/form/BrnStarsFormItem/img/BrnStarsFormItemIntro.png rename to doc/components/form/BrnStarsFormItem/img/BrnStarsFormItemIntro.png diff --git a/docs/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md b/doc/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md similarity index 100% rename from docs/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md rename to doc/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md diff --git a/docs/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemDemo1.png b/doc/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemDemo1.png similarity index 100% rename from docs/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemDemo1.png rename to doc/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemDemo1.png diff --git a/docs/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemDemo2.png b/doc/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemDemo2.png similarity index 100% rename from docs/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemDemo2.png rename to doc/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemDemo2.png diff --git a/docs/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemIntro.png b/doc/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemIntro.png similarity index 100% rename from docs/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemIntro.png rename to doc/components/form/BrnStepInputFormItem/img/BrnStepInputFormItemIntro.png diff --git a/docs/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md b/doc/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md similarity index 100% rename from docs/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md rename to doc/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md diff --git a/docs/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo1.png b/doc/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo1.png similarity index 100% rename from docs/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo1.png rename to doc/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo1.png diff --git a/docs/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo2.png b/doc/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo2.png similarity index 100% rename from docs/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo2.png rename to doc/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo2.png diff --git a/docs/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo3.png b/doc/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo3.png similarity index 100% rename from docs/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo3.png rename to doc/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo3.png diff --git a/docs/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo4.png b/doc/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo4.png similarity index 100% rename from docs/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo4.png rename to doc/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemDemo4.png diff --git a/docs/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemIntro.png b/doc/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemIntro.png similarity index 100% rename from docs/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemIntro.png rename to doc/components/form/BrnTextBlockInputFormItem/img/BrnTextBlockInputFormItemIntro.png diff --git a/docs/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md b/doc/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md similarity index 100% rename from docs/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md rename to doc/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md diff --git a/docs/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo1.png b/doc/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo1.png similarity index 100% rename from docs/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo1.png rename to doc/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo1.png diff --git a/docs/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo2.png b/doc/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo2.png similarity index 100% rename from docs/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo2.png rename to doc/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo2.png diff --git a/docs/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo3.png b/doc/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo3.png similarity index 100% rename from docs/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo3.png rename to doc/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo3.png diff --git a/docs/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo4.png b/doc/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo4.png similarity index 100% rename from docs/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo4.png rename to doc/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemDemo4.png diff --git a/docs/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemIntro.png b/doc/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemIntro.png similarity index 100% rename from docs/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemIntro.png rename to doc/components/form/BrnTextInputFormItem/img/BrnTextInputFormItemIntro.png diff --git a/docs/components/form/BrnTextQuickSelectFormItem/BrnTextQuickSelectFormItem.md b/doc/components/form/BrnTextQuickSelectFormItem/BrnTextQuickSelectFormItem.md similarity index 100% rename from docs/components/form/BrnTextQuickSelectFormItem/BrnTextQuickSelectFormItem.md rename to doc/components/form/BrnTextQuickSelectFormItem/BrnTextQuickSelectFormItem.md diff --git a/docs/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemDemo1.png b/doc/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemDemo1.png similarity index 100% rename from docs/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemDemo1.png rename to doc/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemDemo1.png diff --git a/docs/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemDemo2.png b/doc/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemDemo2.png similarity index 100% rename from docs/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemDemo2.png rename to doc/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemDemo2.png diff --git a/docs/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemIntro.png b/doc/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemIntro.png similarity index 100% rename from docs/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemIntro.png rename to doc/components/form/BrnTextQuickSelectFormItem/img/BrnTextQuickSelectFormItemIntro.png diff --git a/docs/components/form/BrnTextSelectFormItem/BrnTextSelectFormItem.md b/doc/components/form/BrnTextSelectFormItem/BrnTextSelectFormItem.md similarity index 100% rename from docs/components/form/BrnTextSelectFormItem/BrnTextSelectFormItem.md rename to doc/components/form/BrnTextSelectFormItem/BrnTextSelectFormItem.md diff --git a/docs/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo1.png b/doc/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo1.png similarity index 100% rename from docs/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo1.png rename to doc/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo1.png diff --git a/docs/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo2.png b/doc/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo2.png similarity index 100% rename from docs/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo2.png rename to doc/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo2.png diff --git a/docs/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo3.png b/doc/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo3.png similarity index 100% rename from docs/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo3.png rename to doc/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo3.png diff --git a/docs/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo4.png b/doc/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo4.png similarity index 100% rename from docs/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo4.png rename to doc/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemDemo4.png diff --git a/docs/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemIntro.png b/doc/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemIntro.png similarity index 100% rename from docs/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemIntro.png rename to doc/components/form/BrnTextSelectFormItem/img/BrnTextSelectFormItemIntro.png diff --git a/docs/components/form/BrnTitleFormItem/BrnTitleFormItem.md b/doc/components/form/BrnTitleFormItem/BrnTitleFormItem.md similarity index 100% rename from docs/components/form/BrnTitleFormItem/BrnTitleFormItem.md rename to doc/components/form/BrnTitleFormItem/BrnTitleFormItem.md diff --git a/docs/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo1.png b/doc/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo1.png similarity index 100% rename from docs/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo1.png rename to doc/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo1.png diff --git a/docs/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo2.png b/doc/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo2.png similarity index 100% rename from docs/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo2.png rename to doc/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo2.png diff --git a/docs/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo3.png b/doc/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo3.png similarity index 100% rename from docs/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo3.png rename to doc/components/form/BrnTitleFormItem/img/BrnTitleFormItemDemo3.png diff --git a/docs/components/form/BrnTitleFormItem/img/BrnTitleFormItemIntro.png b/doc/components/form/BrnTitleFormItem/img/BrnTitleFormItemIntro.png similarity index 100% rename from docs/components/form/BrnTitleFormItem/img/BrnTitleFormItemIntro.png rename to doc/components/form/BrnTitleFormItem/img/BrnTitleFormItemIntro.png diff --git a/docs/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md b/doc/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md similarity index 100% rename from docs/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md rename to doc/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md diff --git a/docs/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemDemo1.png b/doc/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemDemo1.png similarity index 100% rename from docs/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemDemo1.png rename to doc/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemDemo1.png diff --git a/docs/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemDemo2.png b/doc/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemDemo2.png similarity index 100% rename from docs/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemDemo2.png rename to doc/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemDemo2.png diff --git a/docs/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemIntro.png b/doc/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemIntro.png similarity index 100% rename from docs/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemIntro.png rename to doc/components/form/BrnTitleSelectInputFormItem/img/BrnTitleSelectInputFormItemIntro.png diff --git a/docs/components/gallery/BrnGalleryDetailPage/BrnGalleryDetailPage.md b/doc/components/gallery/BrnGalleryDetailPage/BrnGalleryDetailPage.md similarity index 100% rename from docs/components/gallery/BrnGalleryDetailPage/BrnGalleryDetailPage.md rename to doc/components/gallery/BrnGalleryDetailPage/BrnGalleryDetailPage.md diff --git a/docs/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageDemo1.jpg b/doc/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageDemo1.jpg similarity index 100% rename from docs/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageDemo1.jpg rename to doc/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageDemo1.jpg diff --git a/docs/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageDemo3.gif b/doc/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageDemo3.gif similarity index 100% rename from docs/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageDemo3.gif rename to doc/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageDemo3.gif diff --git a/docs/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageIntro.png b/doc/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageIntro.png similarity index 100% rename from docs/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageIntro.png rename to doc/components/gallery/BrnGalleryDetailPage/img/BrnGalleryDetailPageIntro.png diff --git a/docs/components/gallery/BrnGalleryDetailPage/img/image-20211101121347565.png b/doc/components/gallery/BrnGalleryDetailPage/img/image-20211101121347565.png similarity index 100% rename from docs/components/gallery/BrnGalleryDetailPage/img/image-20211101121347565.png rename to doc/components/gallery/BrnGalleryDetailPage/img/image-20211101121347565.png diff --git a/docs/components/gallery/BrnGallerySummaryPage/BrnGallerySummaryPage.md b/doc/components/gallery/BrnGallerySummaryPage/BrnGallerySummaryPage.md similarity index 100% rename from docs/components/gallery/BrnGallerySummaryPage/BrnGallerySummaryPage.md rename to doc/components/gallery/BrnGallerySummaryPage/BrnGallerySummaryPage.md diff --git a/docs/components/gallery/BrnGallerySummaryPage/img/BrnGallerySummaryPageDemo.png b/doc/components/gallery/BrnGallerySummaryPage/img/BrnGallerySummaryPageDemo.png similarity index 100% rename from docs/components/gallery/BrnGallerySummaryPage/img/BrnGallerySummaryPageDemo.png rename to doc/components/gallery/BrnGallerySummaryPage/img/BrnGallerySummaryPageDemo.png diff --git a/docs/components/gallery/BrnGallerySummaryPage/img/BrnGallerySummaryPageIntro.png b/doc/components/gallery/BrnGallerySummaryPage/img/BrnGallerySummaryPageIntro.png similarity index 100% rename from docs/components/gallery/BrnGallerySummaryPage/img/BrnGallerySummaryPageIntro.png rename to doc/components/gallery/BrnGallerySummaryPage/img/BrnGallerySummaryPageIntro.png diff --git a/docs/components/guide/BrnGuide/BrnGuide.md b/doc/components/guide/BrnGuide/BrnGuide.md similarity index 100% rename from docs/components/guide/BrnGuide/BrnGuide.md rename to doc/components/guide/BrnGuide/BrnGuide.md diff --git a/docs/components/guide/BrnGuide/img/BrnGuideForceDemo.gif b/doc/components/guide/BrnGuide/img/BrnGuideForceDemo.gif similarity index 100% rename from docs/components/guide/BrnGuide/img/BrnGuideForceDemo.gif rename to doc/components/guide/BrnGuide/img/BrnGuideForceDemo.gif diff --git a/docs/components/guide/BrnGuide/img/BrnGuideIntroForceGuide.png b/doc/components/guide/BrnGuide/img/BrnGuideIntroForceGuide.png similarity index 100% rename from docs/components/guide/BrnGuide/img/BrnGuideIntroForceGuide.png rename to doc/components/guide/BrnGuide/img/BrnGuideIntroForceGuide.png diff --git a/docs/components/guide/BrnGuide/img/BrnGuideIntroSoftGuide.png b/doc/components/guide/BrnGuide/img/BrnGuideIntroSoftGuide.png similarity index 100% rename from docs/components/guide/BrnGuide/img/BrnGuideIntroSoftGuide.png rename to doc/components/guide/BrnGuide/img/BrnGuideIntroSoftGuide.png diff --git a/docs/components/guide/BrnGuide/img/BrnGuideSoftDemo.gif b/doc/components/guide/BrnGuide/img/BrnGuideSoftDemo.gif similarity index 100% rename from docs/components/guide/BrnGuide/img/BrnGuideSoftDemo.gif rename to doc/components/guide/BrnGuide/img/BrnGuideSoftDemo.gif diff --git a/docs/components/iconButton/BrnIconButton/BrnIconButton.md b/doc/components/iconButton/BrnIconButton/BrnIconButton.md similarity index 100% rename from docs/components/iconButton/BrnIconButton/BrnIconButton.md rename to doc/components/iconButton/BrnIconButton/BrnIconButton.md diff --git a/docs/components/iconButton/BrnIconButton/img/BrnIconButtonIntro.png b/doc/components/iconButton/BrnIconButton/img/BrnIconButtonIntro.png similarity index 100% rename from docs/components/iconButton/BrnIconButton/img/BrnIconButtonIntro.png rename to doc/components/iconButton/BrnIconButton/img/BrnIconButtonIntro.png diff --git a/docs/components/iconButton/BrnVerticalIconButton/BrnVerticalIconButton.md b/doc/components/iconButton/BrnVerticalIconButton/BrnVerticalIconButton.md similarity index 100% rename from docs/components/iconButton/BrnVerticalIconButton/BrnVerticalIconButton.md rename to doc/components/iconButton/BrnVerticalIconButton/BrnVerticalIconButton.md diff --git a/docs/components/iconButton/BrnVerticalIconButton/img/BrnVerticalIconButtonIntro.png b/doc/components/iconButton/BrnVerticalIconButton/img/BrnVerticalIconButtonIntro.png similarity index 100% rename from docs/components/iconButton/BrnVerticalIconButton/img/BrnVerticalIconButtonIntro.png rename to doc/components/iconButton/BrnVerticalIconButton/img/BrnVerticalIconButtonIntro.png diff --git a/docs/components/input/BrnInputText/BrnInputText.md b/doc/components/input/BrnInputText/BrnInputText.md similarity index 100% rename from docs/components/input/BrnInputText/BrnInputText.md rename to doc/components/input/BrnInputText/BrnInputText.md diff --git a/docs/components/input/BrnInputText/img/BrnInputTextDemoEmpty.png b/doc/components/input/BrnInputText/img/BrnInputTextDemoEmpty.png similarity index 100% rename from docs/components/input/BrnInputText/img/BrnInputTextDemoEmpty.png rename to doc/components/input/BrnInputText/img/BrnInputTextDemoEmpty.png diff --git a/docs/components/input/BrnInputText/img/BrnInputTextDemoFull.png b/doc/components/input/BrnInputText/img/BrnInputTextDemoFull.png similarity index 100% rename from docs/components/input/BrnInputText/img/BrnInputTextDemoFull.png rename to doc/components/input/BrnInputText/img/BrnInputTextDemoFull.png diff --git a/docs/components/input/BrnInputText/img/BrnInputTextIntro.png b/doc/components/input/BrnInputText/img/BrnInputTextIntro.png similarity index 100% rename from docs/components/input/BrnInputText/img/BrnInputTextIntro.png rename to doc/components/input/BrnInputText/img/BrnInputTextIntro.png diff --git a/docs/components/loading/BrnPageLoading/BrnPageLoading.md b/doc/components/loading/BrnPageLoading/BrnPageLoading.md similarity index 100% rename from docs/components/loading/BrnPageLoading/BrnPageLoading.md rename to doc/components/loading/BrnPageLoading/BrnPageLoading.md diff --git a/docs/components/loading/BrnPageLoading/img/BrnPageLoadingDemo1.png b/doc/components/loading/BrnPageLoading/img/BrnPageLoadingDemo1.png similarity index 100% rename from docs/components/loading/BrnPageLoading/img/BrnPageLoadingDemo1.png rename to doc/components/loading/BrnPageLoading/img/BrnPageLoadingDemo1.png diff --git a/docs/components/loading/BrnPageLoading/img/BrnPageLoadingDemo2.png b/doc/components/loading/BrnPageLoading/img/BrnPageLoadingDemo2.png similarity index 100% rename from docs/components/loading/BrnPageLoading/img/BrnPageLoadingDemo2.png rename to doc/components/loading/BrnPageLoading/img/BrnPageLoadingDemo2.png diff --git a/docs/components/normalButton/BrnBigGhostButton/BrnBigGhostButton.md b/doc/components/normalButton/BrnBigGhostButton/BrnBigGhostButton.md similarity index 100% rename from docs/components/normalButton/BrnBigGhostButton/BrnBigGhostButton.md rename to doc/components/normalButton/BrnBigGhostButton/BrnBigGhostButton.md diff --git a/docs/components/normalButton/BrnBigGhostButton/img/BrnBigGhostButtonDemo.png b/doc/components/normalButton/BrnBigGhostButton/img/BrnBigGhostButtonDemo.png similarity index 100% rename from docs/components/normalButton/BrnBigGhostButton/img/BrnBigGhostButtonDemo.png rename to doc/components/normalButton/BrnBigGhostButton/img/BrnBigGhostButtonDemo.png diff --git a/docs/components/normalButton/BrnBigMainButton/BrnBigMainButton.md b/doc/components/normalButton/BrnBigMainButton/BrnBigMainButton.md similarity index 100% rename from docs/components/normalButton/BrnBigMainButton/BrnBigMainButton.md rename to doc/components/normalButton/BrnBigMainButton/BrnBigMainButton.md diff --git a/docs/components/normalButton/BrnBigMainButton/img/BrnBigMainButton.png b/doc/components/normalButton/BrnBigMainButton/img/BrnBigMainButton.png similarity index 100% rename from docs/components/normalButton/BrnBigMainButton/img/BrnBigMainButton.png rename to doc/components/normalButton/BrnBigMainButton/img/BrnBigMainButton.png diff --git a/docs/components/normalButton/BrnBigMainButton/img/BrnBigMainButtonDisabled.png b/doc/components/normalButton/BrnBigMainButton/img/BrnBigMainButtonDisabled.png similarity index 100% rename from docs/components/normalButton/BrnBigMainButton/img/BrnBigMainButtonDisabled.png rename to doc/components/normalButton/BrnBigMainButton/img/BrnBigMainButtonDisabled.png diff --git a/docs/components/normalButton/BrnBigOutlineButton/BrnBigOutlineButton.md b/doc/components/normalButton/BrnBigOutlineButton/BrnBigOutlineButton.md similarity index 100% rename from docs/components/normalButton/BrnBigOutlineButton/BrnBigOutlineButton.md rename to doc/components/normalButton/BrnBigOutlineButton/BrnBigOutlineButton.md diff --git a/docs/components/normalButton/BrnBigOutlineButton/img/BrnBigOutlineButton.png b/doc/components/normalButton/BrnBigOutlineButton/img/BrnBigOutlineButton.png similarity index 100% rename from docs/components/normalButton/BrnBigOutlineButton/img/BrnBigOutlineButton.png rename to doc/components/normalButton/BrnBigOutlineButton/img/BrnBigOutlineButton.png diff --git a/docs/components/normalButton/BrnBigOutlineButton/img/BrnBigOutlineButtonDisabled.png b/doc/components/normalButton/BrnBigOutlineButton/img/BrnBigOutlineButtonDisabled.png similarity index 100% rename from docs/components/normalButton/BrnBigOutlineButton/img/BrnBigOutlineButtonDisabled.png rename to doc/components/normalButton/BrnBigOutlineButton/img/BrnBigOutlineButtonDisabled.png diff --git a/docs/components/normalButton/BrnSmallMainButton/BrnSmallMainButton.md b/doc/components/normalButton/BrnSmallMainButton/BrnSmallMainButton.md similarity index 100% rename from docs/components/normalButton/BrnSmallMainButton/BrnSmallMainButton.md rename to doc/components/normalButton/BrnSmallMainButton/BrnSmallMainButton.md diff --git a/docs/components/normalButton/BrnSmallMainButton/img/BrnSmallMainButton.png b/doc/components/normalButton/BrnSmallMainButton/img/BrnSmallMainButton.png similarity index 100% rename from docs/components/normalButton/BrnSmallMainButton/img/BrnSmallMainButton.png rename to doc/components/normalButton/BrnSmallMainButton/img/BrnSmallMainButton.png diff --git a/docs/components/normalButton/BrnSmallMainButton/img/BrnSmallMainButtonDisabled.png b/doc/components/normalButton/BrnSmallMainButton/img/BrnSmallMainButtonDisabled.png similarity index 100% rename from docs/components/normalButton/BrnSmallMainButton/img/BrnSmallMainButtonDisabled.png rename to doc/components/normalButton/BrnSmallMainButton/img/BrnSmallMainButtonDisabled.png diff --git a/docs/components/normalButton/BrnSmallOutlineButton/BrnSmallOutlineButton.md b/doc/components/normalButton/BrnSmallOutlineButton/BrnSmallOutlineButton.md similarity index 100% rename from docs/components/normalButton/BrnSmallOutlineButton/BrnSmallOutlineButton.md rename to doc/components/normalButton/BrnSmallOutlineButton/BrnSmallOutlineButton.md diff --git a/docs/components/normalButton/BrnSmallOutlineButton/img/BrnSmallOutlineButton.png b/doc/components/normalButton/BrnSmallOutlineButton/img/BrnSmallOutlineButton.png similarity index 100% rename from docs/components/normalButton/BrnSmallOutlineButton/img/BrnSmallOutlineButton.png rename to doc/components/normalButton/BrnSmallOutlineButton/img/BrnSmallOutlineButton.png diff --git a/docs/components/normalButton/BrnSmallOutlineButton/img/BrnSmallOutlineButtonDisabled.png b/doc/components/normalButton/BrnSmallOutlineButton/img/BrnSmallOutlineButtonDisabled.png similarity index 100% rename from docs/components/normalButton/BrnSmallOutlineButton/img/BrnSmallOutlineButtonDisabled.png rename to doc/components/normalButton/BrnSmallOutlineButton/img/BrnSmallOutlineButtonDisabled.png diff --git a/docs/components/notification/BrnNoticeBar/BrnNoticeBar.md b/doc/components/notification/BrnNoticeBar/BrnNoticeBar.md similarity index 100% rename from docs/components/notification/BrnNoticeBar/BrnNoticeBar.md rename to doc/components/notification/BrnNoticeBar/BrnNoticeBar.md diff --git a/docs/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo1.png b/doc/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo1.png similarity index 100% rename from docs/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo1.png rename to doc/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo1.png diff --git a/docs/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo2.png b/doc/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo2.png similarity index 100% rename from docs/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo2.png rename to doc/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo2.png diff --git a/docs/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo3.png b/doc/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo3.png similarity index 100% rename from docs/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo3.png rename to doc/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo3.png diff --git a/docs/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo4.gif b/doc/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo4.gif similarity index 100% rename from docs/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo4.gif rename to doc/components/notification/BrnNoticeBar/img/BrnNoticeBarDemo4.gif diff --git a/docs/components/notification/BrnNoticeBar/img/BrnNoticeBarIntro1.png b/doc/components/notification/BrnNoticeBar/img/BrnNoticeBarIntro1.png similarity index 100% rename from docs/components/notification/BrnNoticeBar/img/BrnNoticeBarIntro1.png rename to doc/components/notification/BrnNoticeBar/img/BrnNoticeBarIntro1.png diff --git a/docs/components/notification/BrnNoticeBar/img/BrnNoticeBarIntro2.png b/doc/components/notification/BrnNoticeBar/img/BrnNoticeBarIntro2.png similarity index 100% rename from docs/components/notification/BrnNoticeBar/img/BrnNoticeBarIntro2.png rename to doc/components/notification/BrnNoticeBar/img/BrnNoticeBarIntro2.png diff --git a/docs/components/notification/BrnNoticeBarWithButton/BrnNoticeBarWithButton.md b/doc/components/notification/BrnNoticeBarWithButton/BrnNoticeBarWithButton.md similarity index 100% rename from docs/components/notification/BrnNoticeBarWithButton/BrnNoticeBarWithButton.md rename to doc/components/notification/BrnNoticeBarWithButton/BrnNoticeBarWithButton.md diff --git a/docs/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo1.png b/doc/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo1.png similarity index 100% rename from docs/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo1.png rename to doc/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo1.png diff --git a/docs/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo2.png b/doc/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo2.png similarity index 100% rename from docs/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo2.png rename to doc/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo2.png diff --git a/docs/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo3.gif b/doc/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo3.gif similarity index 100% rename from docs/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo3.gif rename to doc/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonDemo3.gif diff --git a/docs/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonIntro.png b/doc/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonIntro.png similarity index 100% rename from docs/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonIntro.png rename to doc/components/notification/BrnNoticeBarWithButton/img/BrnNoticeBarWithButtonIntro.png diff --git a/docs/components/picker/BrnBottomPicker/BrnBottomPicker.md b/doc/components/picker/BrnBottomPicker/BrnBottomPicker.md similarity index 100% rename from docs/components/picker/BrnBottomPicker/BrnBottomPicker.md rename to doc/components/picker/BrnBottomPicker/BrnBottomPicker.md diff --git a/docs/components/picker/BrnBottomPicker/img/BrnBottomPickerDemo1.png b/doc/components/picker/BrnBottomPicker/img/BrnBottomPickerDemo1.png similarity index 100% rename from docs/components/picker/BrnBottomPicker/img/BrnBottomPickerDemo1.png rename to doc/components/picker/BrnBottomPicker/img/BrnBottomPickerDemo1.png diff --git a/docs/components/picker/BrnBottomPicker/img/BrnBottomPickerDemo2.png b/doc/components/picker/BrnBottomPicker/img/BrnBottomPickerDemo2.png similarity index 100% rename from docs/components/picker/BrnBottomPicker/img/BrnBottomPickerDemo2.png rename to doc/components/picker/BrnBottomPicker/img/BrnBottomPickerDemo2.png diff --git a/docs/components/picker/BrnBottomWritePicker/BrnBottomWritePicker.md b/doc/components/picker/BrnBottomWritePicker/BrnBottomWritePicker.md similarity index 100% rename from docs/components/picker/BrnBottomWritePicker/BrnBottomWritePicker.md rename to doc/components/picker/BrnBottomWritePicker/BrnBottomWritePicker.md diff --git a/docs/components/picker/BrnBottomWritePicker/img/BrnBottomWritePicker.png b/doc/components/picker/BrnBottomWritePicker/img/BrnBottomWritePicker.png similarity index 100% rename from docs/components/picker/BrnBottomWritePicker/img/BrnBottomWritePicker.png rename to doc/components/picker/BrnBottomWritePicker/img/BrnBottomWritePicker.png diff --git a/docs/components/picker/BrnDatePicker/BrnDatePicker.md b/doc/components/picker/BrnDatePicker/BrnDatePicker.md similarity index 100% rename from docs/components/picker/BrnDatePicker/BrnDatePicker.md rename to doc/components/picker/BrnDatePicker/BrnDatePicker.md diff --git a/docs/components/picker/BrnDatePicker/img/BrnDatePickerTime.png b/doc/components/picker/BrnDatePicker/img/BrnDatePickerTime.png similarity index 100% rename from docs/components/picker/BrnDatePicker/img/BrnDatePickerTime.png rename to doc/components/picker/BrnDatePicker/img/BrnDatePickerTime.png diff --git a/docs/components/picker/BrnDatePicker/img/BrnDatePickerYMD.png b/doc/components/picker/BrnDatePicker/img/BrnDatePickerYMD.png similarity index 100% rename from docs/components/picker/BrnDatePicker/img/BrnDatePickerYMD.png rename to doc/components/picker/BrnDatePicker/img/BrnDatePickerYMD.png diff --git a/docs/components/picker/BrnDatePicker/img/BrnDatePickerYMDHMS.png b/doc/components/picker/BrnDatePicker/img/BrnDatePickerYMDHMS.png similarity index 100% rename from docs/components/picker/BrnDatePicker/img/BrnDatePickerYMDHMS.png rename to doc/components/picker/BrnDatePicker/img/BrnDatePickerYMDHMS.png diff --git a/docs/components/picker/BrnDateRangePicker/BrnDateRangePicker.md b/doc/components/picker/BrnDateRangePicker/BrnDateRangePicker.md similarity index 100% rename from docs/components/picker/BrnDateRangePicker/BrnDateRangePicker.md rename to doc/components/picker/BrnDateRangePicker/BrnDateRangePicker.md diff --git a/docs/components/picker/BrnDateRangePicker/img/BrnDateRangePicker1.png b/doc/components/picker/BrnDateRangePicker/img/BrnDateRangePicker1.png similarity index 100% rename from docs/components/picker/BrnDateRangePicker/img/BrnDateRangePicker1.png rename to doc/components/picker/BrnDateRangePicker/img/BrnDateRangePicker1.png diff --git a/docs/components/picker/BrnDateRangePicker/img/BrnDateRangePicker2.png b/doc/components/picker/BrnDateRangePicker/img/BrnDateRangePicker2.png similarity index 100% rename from docs/components/picker/BrnDateRangePicker/img/BrnDateRangePicker2.png rename to doc/components/picker/BrnDateRangePicker/img/BrnDateRangePicker2.png diff --git a/docs/components/picker/BrnDateRangePicker/img/BrnDateRangePicker3.png b/doc/components/picker/BrnDateRangePicker/img/BrnDateRangePicker3.png similarity index 100% rename from docs/components/picker/BrnDateRangePicker/img/BrnDateRangePicker3.png rename to doc/components/picker/BrnDateRangePicker/img/BrnDateRangePicker3.png diff --git a/docs/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo1.png b/doc/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo1.png similarity index 100% rename from docs/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo1.png rename to doc/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo1.png diff --git a/docs/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo2.png b/doc/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo2.png similarity index 100% rename from docs/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo2.png rename to doc/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo2.png diff --git a/docs/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo3.png b/doc/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo3.png similarity index 100% rename from docs/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo3.png rename to doc/components/picker/BrnDateRangePicker/img/BrnDateRangePickerDemo3.png diff --git a/docs/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md b/doc/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md similarity index 100% rename from docs/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md rename to doc/components/picker/BrnMultiColumnPicker/BrnMultiColumnPicker.md diff --git a/docs/components/picker/BrnMultiColumnPicker/img/BrnMultiColumnPickerDemo.png b/doc/components/picker/BrnMultiColumnPicker/img/BrnMultiColumnPickerDemo.png similarity index 100% rename from docs/components/picker/BrnMultiColumnPicker/img/BrnMultiColumnPickerDemo.png rename to doc/components/picker/BrnMultiColumnPicker/img/BrnMultiColumnPickerDemo.png diff --git a/docs/components/picker/BrnMultiColumnPicker/img/BrnMultiColumnPickerIntro.png b/doc/components/picker/BrnMultiColumnPicker/img/BrnMultiColumnPickerIntro.png similarity index 100% rename from docs/components/picker/BrnMultiColumnPicker/img/BrnMultiColumnPickerIntro.png rename to doc/components/picker/BrnMultiColumnPicker/img/BrnMultiColumnPickerIntro.png diff --git a/docs/components/picker/BrnMultiDataPicker/BrnMultiDataPicker.md b/doc/components/picker/BrnMultiDataPicker/BrnMultiDataPicker.md similarity index 100% rename from docs/components/picker/BrnMultiDataPicker/BrnMultiDataPicker.md rename to doc/components/picker/BrnMultiDataPicker/BrnMultiDataPicker.md diff --git a/docs/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo1.png b/doc/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo1.png similarity index 100% rename from docs/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo1.png rename to doc/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo1.png diff --git a/docs/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo2.png b/doc/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo2.png similarity index 100% rename from docs/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo2.png rename to doc/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo2.png diff --git a/docs/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo3.png b/doc/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo3.png similarity index 100% rename from docs/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo3.png rename to doc/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo3.png diff --git a/docs/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo4.png b/doc/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo4.png similarity index 100% rename from docs/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo4.png rename to doc/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerDemo4.png diff --git a/docs/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerIntro.png b/doc/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerIntro.png similarity index 100% rename from docs/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerIntro.png rename to doc/components/picker/BrnMultiDataPicker/img/BrnMultiDataPickerIntro.png diff --git a/docs/components/picker/BrnMultiSelectListPicker/BrnMultiSelectListPicker.md b/doc/components/picker/BrnMultiSelectListPicker/BrnMultiSelectListPicker.md similarity index 100% rename from docs/components/picker/BrnMultiSelectListPicker/BrnMultiSelectListPicker.md rename to doc/components/picker/BrnMultiSelectListPicker/BrnMultiSelectListPicker.md diff --git a/docs/components/picker/BrnMultiSelectListPicker/img/BrnMultiSelectListPicker.png b/doc/components/picker/BrnMultiSelectListPicker/img/BrnMultiSelectListPicker.png similarity index 100% rename from docs/components/picker/BrnMultiSelectListPicker/img/BrnMultiSelectListPicker.png rename to doc/components/picker/BrnMultiSelectListPicker/img/BrnMultiSelectListPicker.png diff --git a/docs/components/picker/BrnMultiSelectTagsPicker/BrnMultiSelectTagsPicker.md b/doc/components/picker/BrnMultiSelectTagsPicker/BrnMultiSelectTagsPicker.md similarity index 100% rename from docs/components/picker/BrnMultiSelectTagsPicker/BrnMultiSelectTagsPicker.md rename to doc/components/picker/BrnMultiSelectTagsPicker/BrnMultiSelectTagsPicker.md diff --git a/docs/components/picker/BrnMultiSelectTagsPicker/img/BrnMultiSelectTagsPickerIntro.png b/doc/components/picker/BrnMultiSelectTagsPicker/img/BrnMultiSelectTagsPickerIntro.png similarity index 100% rename from docs/components/picker/BrnMultiSelectTagsPicker/img/BrnMultiSelectTagsPickerIntro.png rename to doc/components/picker/BrnMultiSelectTagsPicker/img/BrnMultiSelectTagsPickerIntro.png diff --git a/docs/components/picker/BrnSelectTagsWithInputPicker/BrnSelectTagsWithInputPicker.md b/doc/components/picker/BrnSelectTagsWithInputPicker/BrnSelectTagsWithInputPicker.md similarity index 100% rename from docs/components/picker/BrnSelectTagsWithInputPicker/BrnSelectTagsWithInputPicker.md rename to doc/components/picker/BrnSelectTagsWithInputPicker/BrnSelectTagsWithInputPicker.md diff --git a/docs/components/picker/BrnSelectTagsWithInputPicker/img/BrnSelectTagsWithInputPicker1.png b/doc/components/picker/BrnSelectTagsWithInputPicker/img/BrnSelectTagsWithInputPicker1.png similarity index 100% rename from docs/components/picker/BrnSelectTagsWithInputPicker/img/BrnSelectTagsWithInputPicker1.png rename to doc/components/picker/BrnSelectTagsWithInputPicker/img/BrnSelectTagsWithInputPicker1.png diff --git a/docs/components/radio/BrnRadioButton/BrnRadioButton.md b/doc/components/radio/BrnRadioButton/BrnRadioButton.md similarity index 100% rename from docs/components/radio/BrnRadioButton/BrnRadioButton.md rename to doc/components/radio/BrnRadioButton/BrnRadioButton.md diff --git a/docs/components/radio/BrnRadioButton/img/BrnRadioButtonIntro.png b/doc/components/radio/BrnRadioButton/img/BrnRadioButtonIntro.png similarity index 100% rename from docs/components/radio/BrnRadioButton/img/BrnRadioButtonIntro.png rename to doc/components/radio/BrnRadioButton/img/BrnRadioButtonIntro.png diff --git a/docs/components/radio/BrnRadioButton/img/BrnRadioItemDemo1.png b/doc/components/radio/BrnRadioButton/img/BrnRadioItemDemo1.png similarity index 100% rename from docs/components/radio/BrnRadioButton/img/BrnRadioItemDemo1.png rename to doc/components/radio/BrnRadioButton/img/BrnRadioItemDemo1.png diff --git a/docs/components/radio/BrnRadioButton/img/BrnRadioItemDemo3.png b/doc/components/radio/BrnRadioButton/img/BrnRadioItemDemo3.png similarity index 100% rename from docs/components/radio/BrnRadioButton/img/BrnRadioItemDemo3.png rename to doc/components/radio/BrnRadioButton/img/BrnRadioItemDemo3.png diff --git a/docs/components/ratingBar/BrnRatingStar/BrnRatingStar.md b/doc/components/ratingBar/BrnRatingStar/BrnRatingStar.md similarity index 100% rename from docs/components/ratingBar/BrnRatingStar/BrnRatingStar.md rename to doc/components/ratingBar/BrnRatingStar/BrnRatingStar.md diff --git a/docs/components/ratingBar/BrnRatingStar/img/BrnRatingStarDEmo4.png b/doc/components/ratingBar/BrnRatingStar/img/BrnRatingStarDEmo4.png similarity index 100% rename from docs/components/ratingBar/BrnRatingStar/img/BrnRatingStarDEmo4.png rename to doc/components/ratingBar/BrnRatingStar/img/BrnRatingStarDEmo4.png diff --git a/docs/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo1.png b/doc/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo1.png similarity index 100% rename from docs/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo1.png rename to doc/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo1.png diff --git a/docs/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo2.png b/doc/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo2.png similarity index 100% rename from docs/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo2.png rename to doc/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo2.png diff --git a/docs/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo3.png b/doc/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo3.png similarity index 100% rename from docs/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo3.png rename to doc/components/ratingBar/BrnRatingStar/img/BrnRatingStarDemo3.png diff --git a/docs/components/ratingBar/BrnRatingStar/img/BrnRatingStarIntro.png b/doc/components/ratingBar/BrnRatingStar/img/BrnRatingStarIntro.png similarity index 100% rename from docs/components/ratingBar/BrnRatingStar/img/BrnRatingStarIntro.png rename to doc/components/ratingBar/BrnRatingStar/img/BrnRatingStarIntro.png diff --git a/docs/components/search/BrnSearchText/BrnSearchText.md b/doc/components/search/BrnSearchText/BrnSearchText.md similarity index 100% rename from docs/components/search/BrnSearchText/BrnSearchText.md rename to doc/components/search/BrnSearchText/BrnSearchText.md diff --git a/docs/components/search/BrnSearchText/img/1620980916893bbbbb.gif b/doc/components/search/BrnSearchText/img/1620980916893bbbbb.gif similarity index 100% rename from docs/components/search/BrnSearchText/img/1620980916893bbbbb.gif rename to doc/components/search/BrnSearchText/img/1620980916893bbbbb.gif diff --git a/docs/components/search/BrnSearchText/img/1620981018721ccccc.gif b/doc/components/search/BrnSearchText/img/1620981018721ccccc.gif similarity index 100% rename from docs/components/search/BrnSearchText/img/1620981018721ccccc.gif rename to doc/components/search/BrnSearchText/img/1620981018721ccccc.gif diff --git a/docs/components/search/BrnSearchText/img/BrnSearchTextDemo1.gif b/doc/components/search/BrnSearchText/img/BrnSearchTextDemo1.gif similarity index 100% rename from docs/components/search/BrnSearchText/img/BrnSearchTextDemo1.gif rename to doc/components/search/BrnSearchText/img/BrnSearchTextDemo1.gif diff --git a/docs/components/search/BrnSearchText/img/BrnSearchTextDemo2.png b/doc/components/search/BrnSearchText/img/BrnSearchTextDemo2.png similarity index 100% rename from docs/components/search/BrnSearchText/img/BrnSearchTextDemo2.png rename to doc/components/search/BrnSearchText/img/BrnSearchTextDemo2.png diff --git a/docs/components/search/BrnSearchText/img/BrnSearchTextIntro.png b/doc/components/search/BrnSearchText/img/BrnSearchTextIntro.png similarity index 100% rename from docs/components/search/BrnSearchText/img/BrnSearchTextIntro.png rename to doc/components/search/BrnSearchText/img/BrnSearchTextIntro.png diff --git a/docs/components/selection/BrnFlatSelection/BrnFlatSelection.md b/doc/components/selection/BrnFlatSelection/BrnFlatSelection.md similarity index 100% rename from docs/components/selection/BrnFlatSelection/BrnFlatSelection.md rename to doc/components/selection/BrnFlatSelection/BrnFlatSelection.md diff --git a/docs/components/selection/BrnFlatSelection/img/BrnFlatSelectionDemo1.png b/doc/components/selection/BrnFlatSelection/img/BrnFlatSelectionDemo1.png similarity index 100% rename from docs/components/selection/BrnFlatSelection/img/BrnFlatSelectionDemo1.png rename to doc/components/selection/BrnFlatSelection/img/BrnFlatSelectionDemo1.png diff --git a/docs/components/selection/BrnFlatSelection/img/BrnFlatSelectionDemo2.png b/doc/components/selection/BrnFlatSelection/img/BrnFlatSelectionDemo2.png similarity index 100% rename from docs/components/selection/BrnFlatSelection/img/BrnFlatSelectionDemo2.png rename to doc/components/selection/BrnFlatSelection/img/BrnFlatSelectionDemo2.png diff --git a/docs/components/selection/BrnFlatSelection/img/BrnFlatSelectionIntro.png b/doc/components/selection/BrnFlatSelection/img/BrnFlatSelectionIntro.png similarity index 100% rename from docs/components/selection/BrnFlatSelection/img/BrnFlatSelectionIntro.png rename to doc/components/selection/BrnFlatSelection/img/BrnFlatSelectionIntro.png diff --git a/docs/components/selection/BrnSelectionView/BrnSelectionView.md b/doc/components/selection/BrnSelectionView/BrnSelectionView.md similarity index 100% rename from docs/components/selection/BrnSelectionView/BrnSelectionView.md rename to doc/components/selection/BrnSelectionView/BrnSelectionView.md diff --git a/docs/components/selection/BrnSelectionView/img/BrnSelectionViewDemo1.png b/doc/components/selection/BrnSelectionView/img/BrnSelectionViewDemo1.png similarity index 100% rename from docs/components/selection/BrnSelectionView/img/BrnSelectionViewDemo1.png rename to doc/components/selection/BrnSelectionView/img/BrnSelectionViewDemo1.png diff --git a/docs/components/selection/BrnSelectionView/img/BrnSelectionViewDemo2.png b/doc/components/selection/BrnSelectionView/img/BrnSelectionViewDemo2.png similarity index 100% rename from docs/components/selection/BrnSelectionView/img/BrnSelectionViewDemo2.png rename to doc/components/selection/BrnSelectionView/img/BrnSelectionViewDemo2.png diff --git a/docs/components/selection/BrnSelectionView/img/BrnSelectionViewDemo4.gif b/doc/components/selection/BrnSelectionView/img/BrnSelectionViewDemo4.gif similarity index 100% rename from docs/components/selection/BrnSelectionView/img/BrnSelectionViewDemo4.gif rename to doc/components/selection/BrnSelectionView/img/BrnSelectionViewDemo4.gif diff --git a/docs/components/selection/BrnSelectionView/img/BrnSelectionViewDemo5.png b/doc/components/selection/BrnSelectionView/img/BrnSelectionViewDemo5.png similarity index 100% rename from docs/components/selection/BrnSelectionView/img/BrnSelectionViewDemo5.png rename to doc/components/selection/BrnSelectionView/img/BrnSelectionViewDemo5.png diff --git a/docs/components/selection/BrnSelectionView/img/BrnSelectionViewIntro.png b/doc/components/selection/BrnSelectionView/img/BrnSelectionViewIntro.png similarity index 100% rename from docs/components/selection/BrnSelectionView/img/BrnSelectionViewIntro.png rename to doc/components/selection/BrnSelectionView/img/BrnSelectionViewIntro.png diff --git a/docs/components/selection/BrnSelectionView/img/BrnSelectionViewIntro2.png b/doc/components/selection/BrnSelectionView/img/BrnSelectionViewIntro2.png similarity index 100% rename from docs/components/selection/BrnSelectionView/img/BrnSelectionViewIntro2.png rename to doc/components/selection/BrnSelectionView/img/BrnSelectionViewIntro2.png diff --git a/docs/components/selection/BrnSelectionView/img/BrnSelectionViewIntro3.png b/doc/components/selection/BrnSelectionView/img/BrnSelectionViewIntro3.png similarity index 100% rename from docs/components/selection/BrnSelectionView/img/BrnSelectionViewIntro3.png rename to doc/components/selection/BrnSelectionView/img/BrnSelectionViewIntro3.png diff --git a/docs/components/selection/BrnSelectionView/img/BrnSelectionViewMorePage.png b/doc/components/selection/BrnSelectionView/img/BrnSelectionViewMorePage.png similarity index 100% rename from docs/components/selection/BrnSelectionView/img/BrnSelectionViewMorePage.png rename to doc/components/selection/BrnSelectionView/img/BrnSelectionViewMorePage.png diff --git a/docs/components/selection/BrnSelectionView/img/BrnSelectionViewMorePage2.png b/doc/components/selection/BrnSelectionView/img/BrnSelectionViewMorePage2.png similarity index 100% rename from docs/components/selection/BrnSelectionView/img/BrnSelectionViewMorePage2.png rename to doc/components/selection/BrnSelectionView/img/BrnSelectionViewMorePage2.png diff --git a/docs/components/selection/BrnSelectionView/img/image-20211030160608171.png b/doc/components/selection/BrnSelectionView/img/image-20211030160608171.png similarity index 100% rename from docs/components/selection/BrnSelectionView/img/image-20211030160608171.png rename to doc/components/selection/BrnSelectionView/img/image-20211030160608171.png diff --git a/docs/components/selection/BrnSelectionView/img/image-20211101155937783.png b/doc/components/selection/BrnSelectionView/img/image-20211101155937783.png similarity index 100% rename from docs/components/selection/BrnSelectionView/img/image-20211101155937783.png rename to doc/components/selection/BrnSelectionView/img/image-20211101155937783.png diff --git a/docs/components/selection/BrnSimpleSelection/BrnSimpleSelection.md b/doc/components/selection/BrnSimpleSelection/BrnSimpleSelection.md similarity index 100% rename from docs/components/selection/BrnSimpleSelection/BrnSimpleSelection.md rename to doc/components/selection/BrnSimpleSelection/BrnSimpleSelection.md diff --git a/docs/components/selection/BrnSimpleSelection/img/simple_selection_checkbox.png b/doc/components/selection/BrnSimpleSelection/img/simple_selection_checkbox.png similarity index 100% rename from docs/components/selection/BrnSimpleSelection/img/simple_selection_checkbox.png rename to doc/components/selection/BrnSimpleSelection/img/simple_selection_checkbox.png diff --git a/docs/components/selection/BrnSimpleSelection/img/simple_selection_radio.png b/doc/components/selection/BrnSimpleSelection/img/simple_selection_radio.png similarity index 100% rename from docs/components/selection/BrnSimpleSelection/img/simple_selection_radio.png rename to doc/components/selection/BrnSimpleSelection/img/simple_selection_radio.png diff --git a/docs/components/shadowCard/BrnShadowCard/BrnShadowCard.md b/doc/components/shadowCard/BrnShadowCard/BrnShadowCard.md similarity index 100% rename from docs/components/shadowCard/BrnShadowCard/BrnShadowCard.md rename to doc/components/shadowCard/BrnShadowCard/BrnShadowCard.md diff --git a/docs/components/shadowCard/BrnShadowCard/img/BrnShadowCardIntro.png b/doc/components/shadowCard/BrnShadowCard/img/BrnShadowCardIntro.png similarity index 100% rename from docs/components/shadowCard/BrnShadowCard/img/BrnShadowCardIntro.png rename to doc/components/shadowCard/BrnShadowCard/img/BrnShadowCardIntro.png diff --git a/docs/components/shadowCard/BrnShadowCard/img/BrnShadowCardIntroDemo1.png b/doc/components/shadowCard/BrnShadowCard/img/BrnShadowCardIntroDemo1.png similarity index 100% rename from docs/components/shadowCard/BrnShadowCard/img/BrnShadowCardIntroDemo1.png rename to doc/components/shadowCard/BrnShadowCard/img/BrnShadowCardIntroDemo1.png diff --git a/docs/components/stepBar/BrnHorizontalSteps/BrnHorizontalSteps.md b/doc/components/stepBar/BrnHorizontalSteps/BrnHorizontalSteps.md similarity index 100% rename from docs/components/stepBar/BrnHorizontalSteps/BrnHorizontalSteps.md rename to doc/components/stepBar/BrnHorizontalSteps/BrnHorizontalSteps.md diff --git a/docs/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps1.jpg b/doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps1.jpg similarity index 100% rename from docs/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps1.jpg rename to doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps1.jpg diff --git a/docs/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps2.jpg b/doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps2.jpg similarity index 100% rename from docs/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps2.jpg rename to doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps2.jpg diff --git a/docs/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps3.jpg b/doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps3.jpg similarity index 100% rename from docs/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps3.jpg rename to doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps3.jpg diff --git a/docs/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps4.jpg b/doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps4.jpg similarity index 100% rename from docs/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps4.jpg rename to doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps4.jpg diff --git a/docs/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps5.png b/doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps5.png similarity index 100% rename from docs/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps5.png rename to doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps5.png diff --git a/docs/components/stepBar/BrnStepLine/BrnStepLine.md b/doc/components/stepBar/BrnStepLine/BrnStepLine.md similarity index 100% rename from docs/components/stepBar/BrnStepLine/BrnStepLine.md rename to doc/components/stepBar/BrnStepLine/BrnStepLine.md diff --git a/docs/components/stepBar/BrnStepLine/img/BrnStepLine1.png b/doc/components/stepBar/BrnStepLine/img/BrnStepLine1.png similarity index 100% rename from docs/components/stepBar/BrnStepLine/img/BrnStepLine1.png rename to doc/components/stepBar/BrnStepLine/img/BrnStepLine1.png diff --git a/docs/components/stepBar/BrnStepLine/img/BrnStepLine2.png b/doc/components/stepBar/BrnStepLine/img/BrnStepLine2.png similarity index 100% rename from docs/components/stepBar/BrnStepLine/img/BrnStepLine2.png rename to doc/components/stepBar/BrnStepLine/img/BrnStepLine2.png diff --git a/docs/components/stepBar/BrnStepLine/img/BrnStepLine3.png b/doc/components/stepBar/BrnStepLine/img/BrnStepLine3.png similarity index 100% rename from docs/components/stepBar/BrnStepLine/img/BrnStepLine3.png rename to doc/components/stepBar/BrnStepLine/img/BrnStepLine3.png diff --git a/docs/components/stepBar/BrnStepLine/img/BrnStepLine4.png b/doc/components/stepBar/BrnStepLine/img/BrnStepLine4.png similarity index 100% rename from docs/components/stepBar/BrnStepLine/img/BrnStepLine4.png rename to doc/components/stepBar/BrnStepLine/img/BrnStepLine4.png diff --git a/docs/components/tabbar/BrnTabBar/BrnTabBar.md b/doc/components/tabbar/BrnTabBar/BrnTabBar.md similarity index 100% rename from docs/components/tabbar/BrnTabBar/BrnTabBar.md rename to doc/components/tabbar/BrnTabBar/BrnTabBar.md diff --git a/docs/components/tabbar/BrnTabBar/img/BrnTabBarDemo1.png b/doc/components/tabbar/BrnTabBar/img/BrnTabBarDemo1.png similarity index 100% rename from docs/components/tabbar/BrnTabBar/img/BrnTabBarDemo1.png rename to doc/components/tabbar/BrnTabBar/img/BrnTabBarDemo1.png diff --git a/docs/components/tabbar/BrnTabBar/img/BrnTabBarDemo2.png b/doc/components/tabbar/BrnTabBar/img/BrnTabBarDemo2.png similarity index 100% rename from docs/components/tabbar/BrnTabBar/img/BrnTabBarDemo2.png rename to doc/components/tabbar/BrnTabBar/img/BrnTabBarDemo2.png diff --git a/docs/components/tabbar/BrnTabBar/img/BrnTabBarDemo3.png b/doc/components/tabbar/BrnTabBar/img/BrnTabBarDemo3.png similarity index 100% rename from docs/components/tabbar/BrnTabBar/img/BrnTabBarDemo3.png rename to doc/components/tabbar/BrnTabBar/img/BrnTabBarDemo3.png diff --git a/docs/components/tabbar/BrnTabBar/img/BrnTabBarDemo4.png b/doc/components/tabbar/BrnTabBar/img/BrnTabBarDemo4.png similarity index 100% rename from docs/components/tabbar/BrnTabBar/img/BrnTabBarDemo4.png rename to doc/components/tabbar/BrnTabBar/img/BrnTabBarDemo4.png diff --git a/docs/components/tabbar/BrnTabBar/img/BrnTabBarDemo5.png b/doc/components/tabbar/BrnTabBar/img/BrnTabBarDemo5.png similarity index 100% rename from docs/components/tabbar/BrnTabBar/img/BrnTabBarDemo5.png rename to doc/components/tabbar/BrnTabBar/img/BrnTabBarDemo5.png diff --git a/docs/components/tabbar/BrnTabBar/img/BrnTabBarDemo6.png b/doc/components/tabbar/BrnTabBar/img/BrnTabBarDemo6.png similarity index 100% rename from docs/components/tabbar/BrnTabBar/img/BrnTabBarDemo6.png rename to doc/components/tabbar/BrnTabBar/img/BrnTabBarDemo6.png diff --git a/docs/components/tabbar/BrnTabBar/img/BrnTabBarIntro.png b/doc/components/tabbar/BrnTabBar/img/BrnTabBarIntro.png similarity index 100% rename from docs/components/tabbar/BrnTabBar/img/BrnTabBarIntro.png rename to doc/components/tabbar/BrnTabBar/img/BrnTabBarIntro.png diff --git a/docs/components/tag/BrnDeleteTag/BrnDeleteTag.md b/doc/components/tag/BrnDeleteTag/BrnDeleteTag.md similarity index 100% rename from docs/components/tag/BrnDeleteTag/BrnDeleteTag.md rename to doc/components/tag/BrnDeleteTag/BrnDeleteTag.md diff --git a/docs/components/tag/BrnDeleteTag/img/BrnDeleteTagDemo1.png b/doc/components/tag/BrnDeleteTag/img/BrnDeleteTagDemo1.png similarity index 100% rename from docs/components/tag/BrnDeleteTag/img/BrnDeleteTagDemo1.png rename to doc/components/tag/BrnDeleteTag/img/BrnDeleteTagDemo1.png diff --git a/docs/components/tag/BrnDeleteTag/img/BrnDeleteTagDemo2.png b/doc/components/tag/BrnDeleteTag/img/BrnDeleteTagDemo2.png similarity index 100% rename from docs/components/tag/BrnDeleteTag/img/BrnDeleteTagDemo2.png rename to doc/components/tag/BrnDeleteTag/img/BrnDeleteTagDemo2.png diff --git a/docs/components/tag/BrnDeleteTag/img/BrnDeleteTagIntro.png b/doc/components/tag/BrnDeleteTag/img/BrnDeleteTagIntro.png similarity index 100% rename from docs/components/tag/BrnDeleteTag/img/BrnDeleteTagIntro.png rename to doc/components/tag/BrnDeleteTag/img/BrnDeleteTagIntro.png diff --git a/docs/components/tag/BrnSelectTag/BrnSelectTag.md b/doc/components/tag/BrnSelectTag/BrnSelectTag.md similarity index 100% rename from docs/components/tag/BrnSelectTag/BrnSelectTag.md rename to doc/components/tag/BrnSelectTag/BrnSelectTag.md diff --git a/docs/components/tag/BrnSelectTag/img/BrnSelectTagDemo1.png b/doc/components/tag/BrnSelectTag/img/BrnSelectTagDemo1.png similarity index 100% rename from docs/components/tag/BrnSelectTag/img/BrnSelectTagDemo1.png rename to doc/components/tag/BrnSelectTag/img/BrnSelectTagDemo1.png diff --git a/docs/components/tag/BrnSelectTag/img/BrnSelectTagDemo2.png b/doc/components/tag/BrnSelectTag/img/BrnSelectTagDemo2.png similarity index 100% rename from docs/components/tag/BrnSelectTag/img/BrnSelectTagDemo2.png rename to doc/components/tag/BrnSelectTag/img/BrnSelectTagDemo2.png diff --git a/docs/components/tag/BrnSelectTag/img/BrnSelectTagDemo3.png b/doc/components/tag/BrnSelectTag/img/BrnSelectTagDemo3.png similarity index 100% rename from docs/components/tag/BrnSelectTag/img/BrnSelectTagDemo3.png rename to doc/components/tag/BrnSelectTag/img/BrnSelectTagDemo3.png diff --git a/docs/components/tag/BrnSelectTag/img/BrnSelectTagDemo4.png b/doc/components/tag/BrnSelectTag/img/BrnSelectTagDemo4.png similarity index 100% rename from docs/components/tag/BrnSelectTag/img/BrnSelectTagDemo4.png rename to doc/components/tag/BrnSelectTag/img/BrnSelectTagDemo4.png diff --git a/docs/components/tag/BrnSelectTag/img/BrnSelectTagDemo5.png b/doc/components/tag/BrnSelectTag/img/BrnSelectTagDemo5.png similarity index 100% rename from docs/components/tag/BrnSelectTag/img/BrnSelectTagDemo5.png rename to doc/components/tag/BrnSelectTag/img/BrnSelectTagDemo5.png diff --git a/docs/components/tag/BrnSelectTag/img/BrnSelectTagIntro.png b/doc/components/tag/BrnSelectTag/img/BrnSelectTagIntro.png similarity index 100% rename from docs/components/tag/BrnSelectTag/img/BrnSelectTagIntro.png rename to doc/components/tag/BrnSelectTag/img/BrnSelectTagIntro.png diff --git a/docs/components/tag/BrnStateTag/BrnStateTag.md b/doc/components/tag/BrnStateTag/BrnStateTag.md similarity index 100% rename from docs/components/tag/BrnStateTag/BrnStateTag.md rename to doc/components/tag/BrnStateTag/BrnStateTag.md diff --git a/docs/components/tag/BrnStateTag/img/BrnMetaStateTagIntro.png b/doc/components/tag/BrnStateTag/img/BrnMetaStateTagIntro.png similarity index 100% rename from docs/components/tag/BrnStateTag/img/BrnMetaStateTagIntro.png rename to doc/components/tag/BrnStateTag/img/BrnMetaStateTagIntro.png diff --git a/docs/components/tag/BrnStateTag/img/BrnMetaStateTagSucceed.png b/doc/components/tag/BrnStateTag/img/BrnMetaStateTagSucceed.png similarity index 100% rename from docs/components/tag/BrnStateTag/img/BrnMetaStateTagSucceed.png rename to doc/components/tag/BrnStateTag/img/BrnMetaStateTagSucceed.png diff --git a/docs/components/tag/BrnStateTag/img/BrnStateTagFailure.png b/doc/components/tag/BrnStateTag/img/BrnStateTagFailure.png similarity index 100% rename from docs/components/tag/BrnStateTag/img/BrnStateTagFailure.png rename to doc/components/tag/BrnStateTag/img/BrnStateTagFailure.png diff --git a/docs/components/tag/BrnTagCustom/BrnTagCustom.md b/doc/components/tag/BrnTagCustom/BrnTagCustom.md similarity index 100% rename from docs/components/tag/BrnTagCustom/BrnTagCustom.md rename to doc/components/tag/BrnTagCustom/BrnTagCustom.md diff --git a/docs/components/tag/BrnTagCustom/img/BrnTagCustomDemo1.png b/doc/components/tag/BrnTagCustom/img/BrnTagCustomDemo1.png similarity index 100% rename from docs/components/tag/BrnTagCustom/img/BrnTagCustomDemo1.png rename to doc/components/tag/BrnTagCustom/img/BrnTagCustomDemo1.png diff --git a/docs/components/tag/BrnTagCustom/img/BrnTagCustomDemo2.png b/doc/components/tag/BrnTagCustom/img/BrnTagCustomDemo2.png similarity index 100% rename from docs/components/tag/BrnTagCustom/img/BrnTagCustomDemo2.png rename to doc/components/tag/BrnTagCustom/img/BrnTagCustomDemo2.png diff --git a/docs/components/tag/BrnTagCustom/img/BrnTagCustomDemo3.png b/doc/components/tag/BrnTagCustom/img/BrnTagCustomDemo3.png similarity index 100% rename from docs/components/tag/BrnTagCustom/img/BrnTagCustomDemo3.png rename to doc/components/tag/BrnTagCustom/img/BrnTagCustomDemo3.png diff --git a/docs/components/text/BrnEnhanceNumberCard/BrnEnhanceNumberCard.md b/doc/components/text/BrnEnhanceNumberCard/BrnEnhanceNumberCard.md similarity index 100% rename from docs/components/text/BrnEnhanceNumberCard/BrnEnhanceNumberCard.md rename to doc/components/text/BrnEnhanceNumberCard/BrnEnhanceNumberCard.md diff --git a/docs/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo1.png b/doc/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo1.png similarity index 100% rename from docs/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo1.png rename to doc/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo1.png diff --git a/docs/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo2.png b/doc/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo2.png similarity index 100% rename from docs/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo2.png rename to doc/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo2.png diff --git a/docs/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo3.png b/doc/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo3.png similarity index 100% rename from docs/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo3.png rename to doc/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo3.png diff --git a/docs/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo4.png b/doc/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo4.png similarity index 100% rename from docs/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo4.png rename to doc/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo4.png diff --git a/docs/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo5.png b/doc/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo5.png similarity index 100% rename from docs/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo5.png rename to doc/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardDemo5.png diff --git a/docs/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardIntro.png b/doc/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardIntro.png similarity index 100% rename from docs/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardIntro.png rename to doc/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardIntro.png diff --git a/docs/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardIntro1.png b/doc/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardIntro1.png similarity index 100% rename from docs/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardIntro1.png rename to doc/components/text/BrnEnhanceNumberCard/img/BrnEnhanceNumberCardIntro1.png diff --git a/docs/components/text/BrnExpandableText/BrnExpandableText.md b/doc/components/text/BrnExpandableText/BrnExpandableText.md similarity index 100% rename from docs/components/text/BrnExpandableText/BrnExpandableText.md rename to doc/components/text/BrnExpandableText/BrnExpandableText.md diff --git a/docs/components/text/BrnExpandableText/img/BrnExpandableTextIntro1.png b/doc/components/text/BrnExpandableText/img/BrnExpandableTextIntro1.png similarity index 100% rename from docs/components/text/BrnExpandableText/img/BrnExpandableTextIntro1.png rename to doc/components/text/BrnExpandableText/img/BrnExpandableTextIntro1.png diff --git a/docs/components/text/BrnExpandableText/img/BrnExpandableTextIntro2.png b/doc/components/text/BrnExpandableText/img/BrnExpandableTextIntro2.png similarity index 100% rename from docs/components/text/BrnExpandableText/img/BrnExpandableTextIntro2.png rename to doc/components/text/BrnExpandableText/img/BrnExpandableTextIntro2.png diff --git a/docs/components/text/BrnPairInfoTable/BrnPairInfoTable.md b/doc/components/text/BrnPairInfoTable/BrnPairInfoTable.md similarity index 100% rename from docs/components/text/BrnPairInfoTable/BrnPairInfoTable.md rename to doc/components/text/BrnPairInfoTable/BrnPairInfoTable.md diff --git a/docs/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo3.png b/doc/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo3.png similarity index 100% rename from docs/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo3.png rename to doc/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo3.png diff --git a/docs/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo4.png b/doc/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo4.png similarity index 100% rename from docs/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo4.png rename to doc/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo4.png diff --git a/docs/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo5.png b/doc/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo5.png similarity index 100% rename from docs/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo5.png rename to doc/components/text/BrnPairInfoTable/img/BrnPairInfoTableDemo5.png diff --git a/docs/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro1.png b/doc/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro1.png similarity index 100% rename from docs/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro1.png rename to doc/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro1.png diff --git a/docs/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro2.png b/doc/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro2.png similarity index 100% rename from docs/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro2.png rename to doc/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro2.png diff --git a/docs/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro3.png b/doc/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro3.png similarity index 100% rename from docs/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro3.png rename to doc/components/text/BrnPairInfoTable/img/BrnPairInfoTableIntro3.png diff --git a/docs/components/text/BrnRichInfoGrid/BrnRichInfoGrid.md b/doc/components/text/BrnRichInfoGrid/BrnRichInfoGrid.md similarity index 100% rename from docs/components/text/BrnRichInfoGrid/BrnRichInfoGrid.md rename to doc/components/text/BrnRichInfoGrid/BrnRichInfoGrid.md diff --git a/docs/components/text/BrnRichInfoGrid/img/BrnRichInfoGridDemo1.png b/doc/components/text/BrnRichInfoGrid/img/BrnRichInfoGridDemo1.png similarity index 100% rename from docs/components/text/BrnRichInfoGrid/img/BrnRichInfoGridDemo1.png rename to doc/components/text/BrnRichInfoGrid/img/BrnRichInfoGridDemo1.png diff --git a/docs/components/text/BrnRichInfoGrid/img/BrnRichInfoGridDemo2.png b/doc/components/text/BrnRichInfoGrid/img/BrnRichInfoGridDemo2.png similarity index 100% rename from docs/components/text/BrnRichInfoGrid/img/BrnRichInfoGridDemo2.png rename to doc/components/text/BrnRichInfoGrid/img/BrnRichInfoGridDemo2.png diff --git a/docs/components/tips/BrnPopupWindow/BrnPopupWindow.md b/doc/components/tips/BrnPopupWindow/BrnPopupWindow.md similarity index 100% rename from docs/components/tips/BrnPopupWindow/BrnPopupWindow.md rename to doc/components/tips/BrnPopupWindow/BrnPopupWindow.md diff --git a/docs/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo1.png b/doc/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo1.png similarity index 100% rename from docs/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo1.png rename to doc/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo1.png diff --git a/docs/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo2.png b/doc/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo2.png similarity index 100% rename from docs/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo2.png rename to doc/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo2.png diff --git a/docs/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo3.png b/doc/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo3.png similarity index 100% rename from docs/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo3.png rename to doc/components/tips/BrnPopupWindow/img/BrnPopupWindowDemo3.png diff --git a/docs/components/tips/BrnPopupWindow/img/BrnPopupWindowIntro.png b/doc/components/tips/BrnPopupWindow/img/BrnPopupWindowIntro.png similarity index 100% rename from docs/components/tips/BrnPopupWindow/img/BrnPopupWindowIntro.png rename to doc/components/tips/BrnPopupWindow/img/BrnPopupWindowIntro.png diff --git a/docs/components/title/BrnActionCardTitle/BrnActionCardTitle.md b/doc/components/title/BrnActionCardTitle/BrnActionCardTitle.md similarity index 100% rename from docs/components/title/BrnActionCardTitle/BrnActionCardTitle.md rename to doc/components/title/BrnActionCardTitle/BrnActionCardTitle.md diff --git a/docs/components/title/BrnActionCardTitle/img/BrnActionCardTitleDemo.png b/doc/components/title/BrnActionCardTitle/img/BrnActionCardTitleDemo.png similarity index 100% rename from docs/components/title/BrnActionCardTitle/img/BrnActionCardTitleDemo.png rename to doc/components/title/BrnActionCardTitle/img/BrnActionCardTitleDemo.png diff --git a/docs/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md b/doc/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md similarity index 100% rename from docs/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md rename to doc/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md diff --git a/docs/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo1.png b/doc/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo1.png similarity index 100% rename from docs/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo1.png rename to doc/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo1.png diff --git a/docs/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo2.png b/doc/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo2.png similarity index 100% rename from docs/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo2.png rename to doc/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo2.png diff --git a/docs/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo3.png b/doc/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo3.png similarity index 100% rename from docs/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo3.png rename to doc/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleDemo3.png diff --git a/docs/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleIntro.png b/doc/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleIntro.png similarity index 100% rename from docs/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleIntro.png rename to doc/components/title/BrnCommonCardTitle/img/BrnCommonCardTitleIntro.png diff --git a/docs/components/title/BrnSubSwitchTitle/BrnSubSwitchTitle.md b/doc/components/title/BrnSubSwitchTitle/BrnSubSwitchTitle.md similarity index 100% rename from docs/components/title/BrnSubSwitchTitle/BrnSubSwitchTitle.md rename to doc/components/title/BrnSubSwitchTitle/BrnSubSwitchTitle.md diff --git a/docs/components/title/BrnSubSwitchTitle/img/BrnSubSwitchTitleDemo1.png b/doc/components/title/BrnSubSwitchTitle/img/BrnSubSwitchTitleDemo1.png similarity index 100% rename from docs/components/title/BrnSubSwitchTitle/img/BrnSubSwitchTitleDemo1.png rename to doc/components/title/BrnSubSwitchTitle/img/BrnSubSwitchTitleDemo1.png diff --git a/docs/components/title/BrnSubSwitchTitle/img/BrnSubSwitchTitleDemo2.gif b/doc/components/title/BrnSubSwitchTitle/img/BrnSubSwitchTitleDemo2.gif similarity index 100% rename from docs/components/title/BrnSubSwitchTitle/img/BrnSubSwitchTitleDemo2.gif rename to doc/components/title/BrnSubSwitchTitle/img/BrnSubSwitchTitleDemo2.gif diff --git a/docs/components/title/BrnSwitchTitle/BrnSwitchTitle.md b/doc/components/title/BrnSwitchTitle/BrnSwitchTitle.md similarity index 100% rename from docs/components/title/BrnSwitchTitle/BrnSwitchTitle.md rename to doc/components/title/BrnSwitchTitle/BrnSwitchTitle.md diff --git a/docs/components/title/BrnSwitchTitle/img/BrnSwitchTitleDemo1.png b/doc/components/title/BrnSwitchTitle/img/BrnSwitchTitleDemo1.png similarity index 100% rename from docs/components/title/BrnSwitchTitle/img/BrnSwitchTitleDemo1.png rename to doc/components/title/BrnSwitchTitle/img/BrnSwitchTitleDemo1.png diff --git a/docs/components/title/BrnSwitchTitle/img/BrnSwitchTitleDemo2.gif b/doc/components/title/BrnSwitchTitle/img/BrnSwitchTitleDemo2.gif similarity index 100% rename from docs/components/title/BrnSwitchTitle/img/BrnSwitchTitleDemo2.gif rename to doc/components/title/BrnSwitchTitle/img/BrnSwitchTitleDemo2.gif diff --git a/docs/components/toast/BrnToast/BrnToast.md b/doc/components/toast/BrnToast/BrnToast.md similarity index 100% rename from docs/components/toast/BrnToast/BrnToast.md rename to doc/components/toast/BrnToast/BrnToast.md diff --git a/docs/components/toast/BrnToast/img/brn_toast_fail.png b/doc/components/toast/BrnToast/img/brn_toast_fail.png similarity index 100% rename from docs/components/toast/BrnToast/img/brn_toast_fail.png rename to doc/components/toast/BrnToast/img/brn_toast_fail.png diff --git a/docs/components/toast/BrnToast/img/brn_toast_intro.png b/doc/components/toast/BrnToast/img/brn_toast_intro.png similarity index 100% rename from docs/components/toast/BrnToast/img/brn_toast_intro.png rename to doc/components/toast/BrnToast/img/brn_toast_intro.png diff --git a/docs/components/toast/BrnToast/img/brn_toast_normal.png b/doc/components/toast/BrnToast/img/brn_toast_normal.png similarity index 100% rename from docs/components/toast/BrnToast/img/brn_toast_normal.png rename to doc/components/toast/BrnToast/img/brn_toast_normal.png diff --git a/docs/components/toast/BrnToast/img/brn_toast_success.png b/doc/components/toast/BrnToast/img/brn_toast_success.png similarity index 100% rename from docs/components/toast/BrnToast/img/brn_toast_success.png rename to doc/components/toast/BrnToast/img/brn_toast_success.png diff --git a/docs/contribution.md b/doc/contribution.md similarity index 100% rename from docs/contribution.md rename to doc/contribution.md diff --git a/docs/sketch.md b/doc/sketch.md similarity index 100% rename from docs/sketch.md rename to doc/sketch.md diff --git a/docs/start.md b/doc/start.md similarity index 100% rename from docs/start.md rename to doc/start.md diff --git a/docs/theme.md b/doc/theme.md similarity index 100% rename from docs/theme.md rename to doc/theme.md

    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 z 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%0AjjB=nA^LXAh-K1Z zbO;V}m8Ht8>|X6_a6{-fuCCe?fO^wW@#jF<5Os5rkr7m+XX0=Mtltm5y|5k7g`bl#LOaoM9NdBIE&q2Bw2NsB4Hqg98n@LQ34C) z2V;P!q|U}krHn~uw4k%Zt`uB|L=82-C5VAjV5%=f`zVmPC=oObI5I>F4JQDiij8A9 zo=#aDq&qt}**@+l`@j@|uvLxcTh&CZdN$^KyG~{_$n)^efVNcD*0j|7lDnrvOB8mg3(%8WA-YyOdU0xkT&-OgnD0fi!lIJ zvl^3CS!KufM-40_&8}n>HTukuGd4r4Qd(ho)o`#DkUf`6L0Dgnfneje4d zMK+_uruSLmwq+R>R~c)~eox%4&RzL{i}l9ikuj~f4h+`#5e1{2s_<;p&ws&d(@ZH`stDwEgbF}f`~Rc>32oqt?mvsc*! z%W}qOH(5=VRZYmL!joakenwS=J8JB``6`DM5m%(cA;XT(%xCbV;d;;0sv0|Lt=`_G z@>~4YfX%x?Wph=z`J)OKkRF2f1?0(j{NA|j>5@v<(b%i-eNnwgrKYGgI6?Nd2ws?eYUqsj_wiKWKgrE=M8s`!}wcH zmBnte<=2Ad)(-dF+H{oz>TEStZDlIE!)~`%+wJP&G6vtq#dR5~>M9o;y`2GAz-#wb zx$;!@YUEF7b|_pm)h@x^<*D(yJnpzoBd)?-9M{%IK6li_{mjOd=^C1w8_2)9vND~n zj1I~F4#NKq!v8)AWFA8D~|s%PwSfA~|+sIoh@{?M-bdU4LA0=9lhsnxB&w zoj7ev+9TU?nKA2(9Z#%Nv+a>!i=&$Hn*-K>-S?d8eT5Ti30++R9-lAH!3Iki>6$mk zSy>tY^>HY$u(;f6d12{nE!dT7U>vN~ZFK>vX6sq(v}I!fv03eLtLqAutuJBZHN!^N z34*Iq(7+MS$qGXTcmJ*Z%%Up&oya>vKNE^T?_;fLO4 z4z2&`%+6Qjfc9j{-1{ukpj#h6o}P+bS5T{~;Gcb#ku-PV?4)xV{SUpPnxFqEOWa2M zrv>vBa-)CtGuc&)3O}l~^(zRT;T5);!aZBK&o#IYNL?gEc{}A5;=n2njeMce4zzAt|Se@kQ1F6uy%b0(D zPcGERF+F)p+OK2Zzn3=umDk{OAszTk+`paOo+h^%3V3346>u71w=oU(U)Z_^$*Y(qwv;BHFt z<JkNe0GmCt9bH)>X*mGh+qn1{$a^V689Un%`n{A)OJ5UKSm^*96_s=GgCMT2O# z`(w!<8JMB##AzwvfBwgJzw!$0);~rw#ifXSu2@xB zk|l&z1t0i@`WM;(Yqa{}B~pT#=yr^pSV(Y$Hg6OKbT-Aj_gA2&N135s(kEZu!_b;tv*W8imH z2FlCT2IJba^or(nRX~o^q;(hfnw4pLx3YcSu65O09DA0xtO{JbEyM&Bht-nyI z_Zam$ja6YXd;C>GvsG8OS~gfCF<9`D40h!PY7hi7{nD&dAaTX`DTEe@_`JbE3))(6 z&{BRwLTiga6JLadqVQBl0=|j&!6d&6uz3ao2FP7S(17g+#T(sRA;Xrs+}no!A8tou z$?9rhkHWFNpl@lNa!>MetlnN}ue5B=Qn>?lH4PeR=24u}PTb2Z?aSL&&Y!%8F__DZ zIhv&Eh-exay|rz8Z?cyHnU#{ zm^~(!aaW7V+Em$CUT+BKJY_EEpe|vJRi-MighBM(V%?mrswV$vq&xpaHsQ@uGh;Ct zY&uQ3&I35Qp%%&5&8ej-UtUA;I$gc7(b8yFJ_jk(+L}O3!0mJS;O9|(F+FOhK0$Yl zRc5=%4*As@pT9bwk*2?i3Mbj!b^eBW<;#l@&3-G~T~bL8Qg6J1v8L7%&{Qj$>YExZ zg0ZV;U8Y~z#I}|1MOCf*lqyZo~+XCiP{iWT+mtlLRy*Z56l3s=7q{NBqVNG0x-~+voqa_GOuN zC$O&?vto={BigZSbR-m>Qb=LmX2PBtSzRXj?zH~M0+oDfWFY|(_yGQr*AnU+xkA+^ z_9Fm3vL@0fd!)&UK^nx5=FBD7F6tB_Xi<0-kmU&gVuZ*vgXBd3rG-=&Wa?5sF3`CY zT6O@|J1fqbhPWfR%EM-wg%x+~#Yx%&E=@oTC}wqpSURLADq=`F5?j>Hgh(EXoV`R( z#yvRfg1GsNOx%2h?uXaUT&^x{(6#XJl{Gguv@})v^n`^EDO3|TCLNstlgEj((H%I8 zB&JlUhfIT!W=~2yB_63y(c6D=91yf8xsF1Rg7;2|{(;46Qra%jf-K;r?U9cd;H;rX zjGRr+3q`X*ISz91-YL;PCSCscZ4Pl>kH_ovSS=PS`Pbv+LsQPXlzILoQf~^eYV0|1 z%7MyQ`iXQO_rTM$K05I3y9Yj+_4EVETMkcTkR$Kl7dhGN`4gsU@<9C~YhU$<6dBt&O-=(O6Pi zUQtroRNf+-lz47m|K?zeAmu2uE&W;hWc=c#9N{l+H`Dh%#ezqL*9xvc?{ zMtTH6IHTDuJm0pXAb6#%J8o}*#r<#DX^jN$Cl#}AVrCB}Dk#W28E5uQxs(Ke|6K98 z_#NhbmZ11#y|y5bOW0MUBDMakb{f*3_k*mLyy7DF5DGORAtsXkLG~i#4!Y1@Vx=dL z)rk-nB)s`xa)Kg6SQU}rd3l-u-b+HOh@+?wlnsC!SLAE)$(LY;Ak0AamgwVHy5ICm zvdeBxR7}H2uooT)jKjZP1|yIik90y&p*JIFD6!H#BK~Cz{svQ%Mm#=-)Urn^fP$%< z3qG9tJvb$Dsig@iAxB129#f7tpdkPn{%?0gC$U}Ot;;_J<$bU2gXJNomZEgKT{Ga{48 zioZY9Ss;Opyg2i# z_3F3iRVqk(fiESwmpn**hjTCq$!|muA=p2nc0?YpE8KB}f6te#PmMY6Ne4IadDlqu z{=x5mUHl{0m%&&|ZEM$3eMZ6>O*AOiuC-Z9`HWtsp}WVsnXpq+(L`A~@uvv)ZT9xm zcMJcqpQ=ZbXPIt{8_P?1@v7Nel_Kx{{m%UN7za+9$6tHx`0*!Sn=|LhC+Ez0?aAXp zIl?hLinpYsY-joI2b^U~bDRiF5qISkZ%2=DJ5;Ssbbq zuPy!ZFL~m%6>p~;e5ihnJI_&I!B=W59;LqC+t%#q^>3-(YWlR~?Kuqz9XLjQU;3VO zeOF@B18sIIPTF&IBSEMdc%MzR~ z_BXEI!oRS5V>cr`(MnY(`)W5gZxDL3n934sagmx#nf5kMZ7aVylPO!1RhglYzAJvo zt>4n$_+ofwE~!W@NGDRM%^PYr%POiFS(RmLcw7=|q&Zv>ky+)X+2U-bwzbXEt|8j1 z#85|vo`JvlC)JM}wEr4u;VseHp6N%XH6r7t~Gv_h0NKo44+YuHe zTbEG_*%f+>Q0$dnY=X((To?b=<{UI|krzwkMI#j9t)qp&1!!jnri6dFLZf*~S~^}; zS9*lUd!3AD2`wyvQ)!(5Y9vC8f#WWpAS;NS0!x4715ipuJ}{6?`PY5M#@iQ+*SrY^ ziZTF3fGuRV(dF*+ujhAFFy<0laq*~~O7U8oxr8s@#rW5Ex&Z;AI~76tFT@l|%gakk znksPM!}g@2sRV-Oh)Bq)#q7Y8@Gt1@H(lR9`0V(m%{BBb9MT<*gj38+?MI6KR0cfi zPiwUc76i2i_w3yAqF;Ei8(9d*Kp~9}_Ke3jVQXpnTbnmH{&46?!5!yrIJ}$BH;rnh=Wh1XHcI08>pEN-3uLsLD$*)nqP?irEp?p~;v8-kl^an2_w$p3*wy zpQ+A%{GED=DMSwus76R`l=!Q7fKGz1ey8|7ELh@eV0JkpIut{(2hq|?Z30DQleX{t zC1bC#TWy+Dg~pM*)&?rWS7?_q#e>a z$we3PXTujU9*0utMSRl=(?`BJp#gTWUL+atQtqV~K^~(kZ0UiaYq=e>ng3tR+&jd> z9Mba$dkVYv*;{XwHG|^vy7Ib~JM;3OG$JuzaDyusSph`Jr7KU>mG^?PtLwARXu?&J z7~)cZSAo99A@-*~o&5cupCR`j7Jm#{b&{y0{Nf9_hB(wsYl!>oGx!aBmO6K>`uFl| z`I$mq8GEuwQ%UmRNK@nEfm^ExmsGR(M5bZZ#xxnfQ)kYKWU5 z=X*}={k%Q7H`Fns7o`*OT=6#YP76z!O)PZ=6(A&4?MM3Ce!7xQs#gKpD~eCLnd++( zadrOV!bPkRit0o|oqxILZu$rPB?nZA<3og|KAN3>Z&A1r_nj=QEO{Er(#uRiJEn>_KL)_OYG^G><-&zkDfS zSLxmMQrkYw;r**qw+fHlpLj~TO}ecY_d^3F;nW|SbL%qPX>mb?b#M8L`P<(*L8tKL zENk)5bzD_71DvD7Y+U@bN^ahQg(X?bgi5ocJYZB-gN~%m0fK|BExVd`54ZLH<3_&@ zIel@`KTH3N#6A!j#<}d|+3@@0kk6rb_x^yfvDzPqJN|KFeqgmXH?FceV5-&BC>jFw z4ON19XT`SS&B}vEe11p0*-syX%h)xfG=dmDf#jwo1W$!PeoFQ8C^0a}K_&{$LLy}F zz(0X7D`Bsq%$n^8N}mcQAj>OpAOVc$;`Av50vBN*2AyWTFffI1az!>kG)jwy_-|6< zPq;vx$7kk`%tPX~(`>cPdt7C<7_bEGNCwLqaULML9onIgrmuugL1xyxSpNZvl)J1K zl6NR-4Q{iApZ7RXATWDuM;=#UjRXDsj;~{z3~BRdGY5hkWdcf^0;c4kA`zYd`b)x; zVS*sCqX@D{@{R|QcRZu*mr_zwhi3JsiYfh|@>q`qIUS+R>eyw^9YjH!pwpU6i8UY0$WJ!sMh!`fQ&w3TowOB-kN!>zh-YUkZ zD{&ed^0p&;a`=Nkvn0#D)(?Fde(Td)4lsVN-(9O|s@Inb*VC2qg5A4_ZGfpl_hprh zGEGE+o3K?zR5r-$j(ka9K7kZRDpqfZgA=W8A`VV8O$zAI9C$<`hEZIX=UHRSsVrP$ z&8~c6-@?NIWxuayM^G)UI$shax<-h9OxUd7qv>FCOF=}~LghBbd~-W1UMF1_W^NN# zBtk0!*0_d{IKD&Aj0b>OA=l!`G5u9mdk;r6VSt{Oi=430eY9YJ*q;`kX0+17pud!5 z$|JJnwCe}Nqui@ey-SwgkF!|flXz0(!kLU=Qnvf0`&E{S?bOE(PK~6e(v(NSwnknF z;G;k_v=_ACRAif8S`SE{$*w*8ibGz0_*mNp`gF`%;AMc1+|PCvla$ocG3UUV4@5I? z1U&;B5$N#w9CjZ_4+pi$(sXu2_JdgA$`m>ou{G%cfe4e_*nmQMri1Htt?TMmi!9M< z2(R~$b|6Ti8EmCr@76i;9Yt$x1?E*fS=&4$7iUOMa0eOZVuvzd1}&!eC3T&Knh64m z^1nj2X3xqUiv{tiWUlhFImd6UMGnVO_SVWdb1H9DE=}F7sJ-?0oX;wiOOccDS?%%T zwVx?>_b*jQPeE$=j=9G^0Tu!O&b{LfU=!p=3z6`@VeuXGJWAf7d|{*;g_MR0(13cO zBhsHjr039gY(3u*=~xF|GL+g`FBJamdiWE7t$x>ki=xYv-Q)nM=vFhNic32_Xi0C*oCxn?IGV)}*qLq*(#Vt5^U2Q}HVJ?X`+iA$kh_dn=!> z2madWw|MS3q(Uz$zx>6=H`Xb2)dr(ZZSWgw9sH@vWB2`B{qwo^B~4dMeq@>gj0=s?SpmSR6aHlLRF_nP+HV)L4Cw#3NoW2rjkcn#! zzwD(1XOVdQQ?E+bw>!mzA=xN_q3?o3@c0}=2#D^pSR}m=CQ1jP_*Fk%;mj6iJbqM~ z(c|3t7ji|GOTf-Ea$9;|?{5<_Gx|VVBfSS1F7c`rKhAbOF3yl<9Ch~mWhc2J%lUyO zM4Bc}1C_dX^%I5vwQSeFb{v)sLkhd`P>Z*v%u*7UBHbuAB@Id%gzSSHg`FmN4G2?> z@((xNn!y-t7L!qJ^qTy3WO$?;lKzD;x%@~|3m(cgSKim}Fm4O7e(dZAS@J8Bv zDP0|k8H(XDSV|}4u2~dwqw4QlGai)Jzu9#5aoDlS<2+t6NIrkQI~EQr7KkZjSrn3+J!M6A1rq3D=*R+K-el z=x|9%{lg^MSF&`A_#Y4z3%k=o$ufgWTqqQNf|EnxJkE0QI%J@r1EuIdncRU=bfATF z;3Luj^jiMk=w6G@Ne>aAXv9-M=(mZtfbM*x^ccEy1%Uh}=x?yk(geAH_*JJ^vN8-;Glok{Dr<3eV~h?Ry8G8*sY@vyBt1Q)B{R>ov}E@zUM$`u-Lz*9 zvuBW-dAhXp^vsqP@~HeB*I6vh4U2dy=e{+5XCFQ`O1x4@)GK8{%s5H?7j(a>N>;{< zOAg5@mvJ>UQO4-STp6A?RaK{F*3^u=5QfUA*kSZ=3=EKwWS*A@GVQL96BEhM4h&qP z&4WR12&(i7qF4clb3d0XW-CG=M%qI5Iv4)*bdVDV!wK+%Vd6SzP#R=(xnYG>uhUnTIc4g*#qK6#tXtyUOJu#QL@+H__XU| zV_es3|JEv9oqhM+aYIR3E*N}%>$0w;&2fgudv!g<8`i`nCUX73(w4Oi#kFzzM+26C z8LmSpa&Z0H&d$w^n>}$GUw^9R$zrXRzH0s<+wrn=6-3Nh9QA=Cdp}tBzOn1D>Za!S zf?1DL7#u|nI_1zWrZhA-+AHdEIx}0->kW^qIxE-f+Dq#zTdM17l?e$PKJF;5tMpZR z4IaazDzLP0$SlW;rwL`AXty*`EB)9NeDGS6=w`+7a2oN~CmVbCQyE z)z;P2Y1}TS!!3xJkyZw!`xN5;$KJcZM^&9`<2~og-h1r5U$Z&MOuIK!TSZE1RZ_K< zcr9X75W_vd1PG8DA>@9UOy-_sW-|9=l8`$gHv$C62*^!TP@~vZyqq4Zp+|cvoPIq$ zE!p{X@%#7xti5MKfFuOP+H?7(#bhpPz3W|Tul26?@;pH)C~t+7+*FFgL**|k6UIJN zU?O5EO$(qWrbkieyrx{4Y7sYHT7(TBEXAc5QbsYTAT=kn^0G^rW^d(bTSrIXC zU4?mkhJXF>JNDnIx%G~<^B+fvE8Lv;VJo_ZEKXV@>hIOX>Cr_=;y|5CGzDT-jlj0K{U`nmr*65~S#aK@zQ0lnVfJtP5K7KJj<>00H-A z!eDX&{KyFdgM$h-{T1IH7-ZiWjvr=7Dn2C_4^N?uhoureenv!qL3S5vtOfa>ge%*4 zXGWmZUSKGVC7Tz>F#3WPAveX~Kxm3mkcO+nLdoo?YX#(vG%lgI+%Vi3aFWka26{p2 z0VMy-@dpRDH^20x_g8bbt$X94jE8#G&6`{7{pr#L#}=CJf46AgV`qBKWbAw6-EHPy z9Xkn7Muk_CJsXuQMdKDOJH@Z7iQ8B6o&`^rWh_fDSZ1g+8yw}a?uF}D$)KF3*uAT*3#!V!hCpTPNnOt}x1qKo z;EFxbej+Des|CtwY|pWi!9cY)P!))^oZ5H5>$B7F6j?>S5@r}UD>DqxJxO5{&lq(GaSoJ91LDrDzr`PfpZ{EoSCW&A{#>nw_1cdCek#aEFIktv0+n z{B7jCt|0>x@vrZT@H2sZ6dg+6bOv8 z0sd?_yJC>(?y zE^58JvTuO+HGr6~cHtcEb<9I%ou*YG*{WR#&v&q?^f2emK^rYlKqE4eb0v8+T* zk#*aeo7)1lJeL*^29iz-vZGo@`%_%=H_#wI3&2#d)zKylh`c6oVNz?2L&flhV`KQ zG38!Qqor34WokM?D!Y7swcu_A&nup+L-mPT-NPF85 ze<1<9*DTFJj^rf!yj7KmwJoL3!;Nd{Whzq^yDd{opcj7Y*^fFtAaQ1OK;}4!PHF%2?+WvfcSD)(+J^bI-258d-c% znk`c=Q;puZF#tR}mG9qUDC!ZP*r26|r=g#{3dGZl4TcmA`Qj`Y@s#48%E7Z^ux=5z zME&mCRk;hEP(RVOVE-zi%51JOYiMm2&0iJ=qVPSrjPm^Vr7!mH2{fYZJ=&lDO8u+Q z&tKgmG-hlFq$qV_Fr(f%^xEq?geG4_XMro%v(=Gpo28%o6T>VOXk7jP@8mZ$4fPIJ zo!H{4?kx1Fe%87A^|#d2SpFcyx3*M!TEx3MpZJ&a>hrJu%WpabPkw%N9+i8ve_3vP z*5QQh-{@%zl!^=c*S-FZ`kj5RpX?X>^_KQxVEI>RzT@~|e90{;5}W^@gp+t#!0YM5 z4*1ri!NcbL1-=T0!E99}rff`jNd3_6gcB)(*IH#TRjA6gWSY}8gujKtx3-AE4+ek! zYX!dbx~9P(dHLo4zW0OHJ{4hYKb%cCnajiz1ap~YcW+Tvv$)H!BW=Apy)bJ_sbFqt zv$bj7dVTLp{o-=#Z5=B=R^4?EZ)4lT5xlI8n-IYh>-O4fKyU>b768c0Ch>iez%RMG z>o=>#3442e&x%^YItfzEG$_?V>S5Q(o?H8blM_0Zpp05>!~LY#P$B za|!}TbfDVz+umx~?*f&Kv1+>R-q|h^rE=gVr-MyE2`@jzxKlf_ciIjm#W?kPN0~;_tmTPWGBd4Rd+PRTXzAv9-G)4+?Bf&l8xL}_ ziFz9=5%qBM8&YeVv&81kzS=#SJ$?FuPO%^>RlfmZy?%qm`n=Tf>H8fSWxPcmTBVu# z32AzM_;B`moz)((v51o1zAMejyMRm*sa;$lFVi)yF1WuDfOp=^0L^-_059RB@IEp?h zy~_p5u2OD`v|$3ZL9eoqbf60nr@a4HOoO++wh_*xDh8QbxFPj%=v;b;Jj_XDWSB2( zVoJ=V`XY_YWB?unP)W>vcT|frf6tSLrH2^uko2&uzQ3YX^3W*f1kD)&qk=*@@vHk8 z>0y?n4TAnFpQN?0(hC=3_@qP01E3v9OCCr%l$rVNT?ra}zyP8Y}t zTJS}sfrlu`Ci;Dt>ShXKagu)v&x*|zbJd8Rd}ZSKVBWuch?iD8mGxce=yq;f37vx% z-r%K6V(o=ZaNn<)?Z|0NI4pX%3mwg?5$dQxu)m zASICXc&a@vu`}xu%QD6PN9OWX9Ug?YR#yzfR;yJcUnkSULyhz~x|**~{wrEZJj9c~ zNPo%Bepbuq%tl>_8hk^M&ByI_I9y_TPDckrYNU_&-QC^0cXwxQ1Od8=ld{PcM*11o zM$_8zL+r_w&n-+`lf2X->|M`v$V+(zJ=3t;^8rgk7oF$H;dn zfA;TZ;(5`R7L64|*#&o|0iHmn(B4RX2@Ip=wxFj5b%3ayGMdUQ3T5u)ecr~QcvAWj zsN<0|2q*N|o>wHNuF?y8HZTEh)^>D!wFWxamONxBLO)C&c^A*zHV&LNX$&crpP4JW zlC)&9PVNivqXF_VpRp?|<_d*(upVOR{mEt^3+n*9Ffv_QYlqtW>9uto0VD27M7M4iX@3E ztS@a6qz<+rSX1v34<_|=$G>y;ZsWK|e z$h?tnU-9Z}@^wCiW~hG1HI>#E3X9pS?hW=c4>NmMa#&h{^(%dud}R{JpI;n#dXmUq zo?bGGOOc2bh6fYQ&Eknqdg3*OMDMzs9s9N$G+q>s0=2UhiTU;O^a z_Zex<#V>tA!Q?spSMoJ>-0768()+ymZRP@sBZk>ba)@L}Sq#YrQB^)dbq0V0cO&?W z@IwnZ!;LH|(LQL$>kMDn_PN3;D-Q7|tDGh0*Tgk07(Ps)M+eY2Te2{-rPl7!=|RCw_#;p{A!IFIXr>nE9u;SOiTZO#qYAe3dBt%s1}ojd5^5(VYe&RF?1) zGIR7WxN6oj<51)fH~A!!zJdG@FwgPNc8>CMT``kCpY{Qjcc~nB$4sX3QasoH+@X^K z`8@~w@?ZjYo~+vrxG zFy^$YsBQBhH-s71@9o=rs744@ z2Mszkd5d$+4qsKsdTD)3Se^0Mh{DeXR3FwWP$!fOCZ!-%HS(>C--@I3*=3BD?Ol<+L*tc-t{P|%1aL6GPs_s&)P!1jgqSG6Fqnl zE4VpBJ36HWWC1g1;K_UmbcFNsFOX)IKG*XT$W5}DPHT+rrIP~zkDQyROHDuw92I^k(Sieh;PxV zp|6dxCqOhoAJ?&cDuRbQ(vq+8N*9ZyMdOTtY?L<2$C?f&*F$gh?m{NvUd$gNoAe&< z=im&kRFi*@{(*7&=<{@P<)MWpb5)f|fT{m3zv3{itcXu3@aMJeTEACF4qbXq;T)mc zb%pE{-?X`NHykKVuZWk7$e%4#FMMw0$)+ZEpk5A*EE@SHGV3M~g3edw-Q4~0Uv9-0-D(l!hHRU}`Ug7cJU8TG& zotHg~^jSn|xm^eHOCvIi!7GB|^y^URV$|yvuNWcynp<)C;!zsVgzY!-djcrxZgMAULzBlp+ zE*y%O-O_Gu=cb+>c^J~WWE&5@_Gh>?Ya$<}8M=TRMNwlxVJ`J1wgW&~l-gihZ7kYS zq7xsuOZvieM!Fw`n!eh4O+ygi#pMGv-2RN6>jcEH@8QY)()}=p5z=1t7*nPXL29;1Tw(>+b&UAIVpxuQDg4ukaqP7j%?Mw?E}rlB@dYjuQ$) zQ2Y>_2bV;lq6uI*vhojbC~X{H4p~y+fxCJ#`}Q$^1W3=?edxTjyih}H7n^G88$4o8 zJ40?}3yrOHHR4OBY4{z+_D{(DJ(U-lkw(R zrfy4yKUI^x)oRG4cgE^q&{-#kp2ihdE&YydhzQKf<2M~-cQ^% zFSn`@dH&&|`HXIi3JcBpLRX%vB&chsXtg#6y-naiL-{$d7h@lk&LRX%C#9~oT;~)G zPQN*zp&8qv?6`GseU{A~n>1IHB7$m)%jzR7$zOcaXX`KXkm zX_sRW7e&cJlKD-$m?}BwNUw1?5xx^Pny~gB_bO^Qy z2Q!d*n)w;S%)B_(bNAk_zN?rJ;T`ai={*(+s{TJ&yfMS%;Bz zDc=7Ozkob{z`j?Cha(YL3DVu%>QHcyN$(uUKcpGp)}^*~7mIm)jJ_$yTVNtzSQT?? z=uNJ_Uf%ov#@*p|XEOPGqVz~Fd4w~WO-6z2ndbAjeNJ(oG%wAbLLOiY6+S~iBP9SM z=c?h>T>PS(h$~88=4!1qCZCYr9UN@S-dVWE5*w_jsR^nBX1~EHq`9{=>9*(f#bDUJ z0^_}@h#eS8i`C0$jxrDya8o@BB`hX87+po6tWE=uZonz-l4e7VGZgO#eTe_I3L3`Y z)SZc9IP&`e>G$04XTl9UlbTM*1EsrLBF_0_X$A+-HwUWM9FhYiQv+}gr^*ZUnr}z* zbo7GsWme|aRZeKdQ${IwW5}1s)XT)fkOm_kfSP1)!?pXrmh@l61yV^Se*gU#1XpOD zHQm$&M8n>{=kkIq@+Ij@VS9kUj~*@*f(+N_WEc<4fHZ@ZsD`=;)sQq}0N@j;)KM_` zyRaA%d0J&oR~NvCbr4A=IHz85AE63@=BO8i-n>L8Mot(f@yecl?e>pJUDOEz>%d*( z2snI|KAWr3RpGXFX2j$+?=0Dg(&P=vjcr>*t@H)D_}gjVfEo=nX-XtA8nBc=o?uof zl=cT%cwfI1K~J6y^kkZF)Y;g+-7h}NtuSoVE|swoDS%=?SR;cUX2~0^OjeD}1Xf6H zj$)M{RSf_N`~a7h*3ecUX7w;ux2@XdG`UPpLsfZ|$!a#Ac_=1#$3W2@cnLttF_q59 zY!HXzz@12Hx~yo*>sUePV=rov7B`g+q+HxFCZP`?%!E1X?b9b z*B3Wt^~78~NY$B#T8g_%y0N2F)&}GqrQ8|LBl|RhnzlwtC#f>-{E$;7k4ZvJ!&G!W z5WY4~lENF#50*0}M9ECdOy1@Vy7iN1K1?O!_`he1_dfR6y(9`7?7en7O!0fAs9&RQ zU2Gx;`IJ5V8`zhlQrMSYu=cB)i?XvfkKpooy#eI=x?I&RRkhpU za;p)xvAXdci_@ernE;0;;(L~I^+vWeP+t=eYHI5}4Vqw0h0QMptX^t-CyPaGTvx|Qw;tgCdC>`Aa3}tB`M~_M_X}r#HSqcoHB7~a z`H$Y4H~rB?KPK$$B4Pi1(Fea!55M=uN26=~NB7N}{@C%K{OO0H&s=Nwc~yV7RIAf!<=$S5@H0sxnoXEhbGBaJhVb(cy7; zTpoWzgFjHGstZ_lY}S;)2C#^z)~z&G8>=g7-Ck8gO=E4lrlV0`8W6o@?i_uQQk@GW zd)!W!ON7RtWKV@#RxpKbRcOO)wo0mOr_}{zyWEu?s%+gpKj(G0tKEVVh4o&K4=_A# zpUUNR`UC2k3cuAapqkBVaI0KKeYGBTq!~d4Si+@w>fLM&$W<{TFi(6MuNN~ax@^_Z ztF_8nVH1E&XtP)hMw8iQQrSRPU{p6DtZ@yUM&OpuAvf_d_V0X?78&+W0D*dmWXj0isrRsZiw>jM#u5fhwNnTu)>%<>7$;HB=k|A zK6N~XVKi{7;D!(J%hocw^87%f`qx}zOQ5b?IJ!1qw3ir+as=cWEssAmKs*5@l4kSJ zjGr)+B(kQFAbie&ycT+4kLSqD^SpEu`65GZlD;ShNNBPmj$awBsEV9pa1+PrCFd05 z8_0pCO%6bxGP?^(f(B3?#3sPSB;CXzqxU9;C=GSPiHW+QWVvn#A7Wc!0??LmB#KH( z{M8K)(S&W9Y&~=Ouu=jb4UVjWX;bbh2aWIqUp8?yvcY=Ge=>eVLbYMyDO!3QqSZmL zD(D3lKw9*_wJ1$S1rf5!l@euG1atZGitMwLI~zSYWksZ2oC{$9>@&qt%UqLpvfGWh zz)#7_E!t`n?+oXx%c!^*@zE<#ac8=D8rYx~J04{OIS?FqlDx>Th6VCX>6-^v(@Jax z8|b}!Uf${ht*ywzw!5sc-I;(mL$PIPz%8DmRdDIkwY&}-*OobvFb>o9P7N$~rgTU<-&tkZN*<1}ubdaq7?GKa(l43_9 z7JHr=CS#uEqcRtF8Yp5I|HawsnmPb7ZF zE9}MS8Td5theLq&h2QF8H2sGBsd#(}1u3JGC4O8 z0=)Lg{YOsJ31Gtxdvb(QuD+tq95kv5^2#@-!xPei%Ee10RPyddV>k)$}#K@-s$(_Mt;g?bT3<^l5xk4oA`zRibN+Z$=8mhDAAB9zg!qIywmaydV>8NEOuCCg}~wWC@LR@eI7L6y_( zfVCLM$|k}UqRUSRw!|qf8Eqbq=Q5f--V5r3UM;8(uzk(Lt$xa5fdp4B($aePD=%B5 zSy>SPh(5L{&=%B*2vN}!maddGF+3PTk!SoqN1f5HWJYaF+q&AcOjTAHK;}xo@2zo) zp8YL*x^}1}PY>}a|0oaO&o&Wfg={}ZOLy@9Jl^J6QBhf; zsjQ+uswx%?XqDCq=^3(02C@VSNMzrXpQrbu=#wE<(xBF}mtr%^?6<5KO;Vj{F91u^^Z<)UJv{yVm$diV>Ogk*D4;h$z+;zAUDmL zMQ$QDou4J$B;9oWJpFgpd2*9D3>a9F7Lw9Xzj5;r|Hv=9yZ5i9qyycV1IG1BAff#O%73+=E|3OT8Iv=LPUjePr+S9 zB;Wc2T0|7x9`yPB;6*^xvLhRjA)g;12_w=|P$7=Q6vBl05Ju;Jq5(`r1B22*K8ri{ z+|uWmEN+FlAl00zYTwpgvrE%W!S+&d*`bMVABV6pr)s&-NSfk?p$HAf!uSF4w6Yr? zI)gWKK@mBi0OD~ir7}h%gau4qTu%z%t@cRf^98y#d8Y zqm_QFl!o71q<9n;-9*&LUDxSabDuxH`1!otx>9Df5};YxyN8|@!{}ML+MH1W0}?X4 zko_zd?SrEDjFMa{bx%PSfE34r8wgd2==eYQfpXSRYx8)7&Q1o0n%Cya>Wr~?^j4#~ zdOM#5n(R>ULGr_I>20(V`{C#a`pHn!SX3X z486nCrJt%K`N~&udizYJSPbO?`J(iXeB25~XDSM8Q~x{H&{$Jv5{6dPne6#Gg@;2y zd&YviosM3b$vR*&Xwmj0qy9i@=CzB{)78mr@8aH&deo=C7&dlt`amyOA&{DTGUs^8 zULiM^*_qb7dbxUe!RoX$p)Hr`-`jrtr23*T?MU;1ojZlxHYR0#&XR@dh3!lF*9&cJ zOxn(Z14q=-(P`;rnfdwjD?4^H^zT>iFX`X1gErWbAIwZwlN?xqZA^YkS$D6xH`v|M zLfhK1r6gsodTm3>jxF*T`QJ#`av&dtW4<+!r7H>KDyDb**ky}(d(i_&U zRx-}Kxus`dj7`*-vT9#56u;xT*6t1M)6@FY5DD<#dwjveY9{*H!b!7cZTr`v8ZsS3C1(>JL%)uuOX z6+EU|yVomUq5dn)*~nKYr8;Uf2(9}_ODkTZRcp7c-kBz(^@WO`)jS*8wzE&%xpUir zkQ#rd?G%U;k4Y%FV|%;s(eFN*&1}yJW@}MCOgH!&-rAq|8Gj0Alg+p}CNrZTd6oJH z?>+#ihqr%suwWpwM5`k?vSeOzkaXm%Y+WN!XbYHDV8U*FAtVu%ri?c`_h z-+mZEoB$2{4ZB!7zv3BxB4IeA-fBUn`To&y&F1IHRx?Y}K{p2ecbzx!Hj)lQn=flq2beRU;xU{e-5yH|VxfCi{}R^X25*lxpI_3?`t@#$S-9^$#)iP7%lh7ZF*xkq zpguY-gF}hHh_ZqdP&%=ZM^hFrwb4_S$WT#${*)U!p28YytsbxN-g_|SJvLV?S^5Yd z!6@pKxFjV^o%!B%5he1`v#338y8RXWL`&Ve-}fN5V=a?`Zss< z5xq2z0lpe8GYD|e4PUu5mV@Mq=I+uvO|2jINP6uU0wIR{DN0GLTrH`1leP`;J{SZj z+(!Dqze~}#gZ73ai5Dmr73z&H^(hRtB3(}DDAKVwn8(wynMiN6cWTAyO(c%OH`efhw@1+Jg!{VBJz~fR4ld>Ux zAmQxb0IbDP7|RpilXG3)VQJ9ZgS~4>S^?R z3tQdptjXy#2CN>}4plyD%XJqt7PxT`m^Z7APrLNK#p535{npX%hu^p2`%UuqO`GLA ziD3tS+x9OC;a1Cu+*d z%gd@o-}0Tw&ldcc@G%yHQx~uVEJ3F?(6Tc|(y%%HiRSTcput+IkaVeWux@1fiO$BV zn*8l1-1wc1DmNt$M!3srvx=1kp5lgLmn~qbEWqT_FL^ZA_Z3Plh;Cdiw_{8{4)o)& zx~<5Ov>-!tv?D+5h&~pdZWYWTx9-Z_d4$1o&iQEKYKsR?uTv16O3YDCX?U%m~{YUw;+ zg3Kj45_b_jrdaV&igQ7*ipWiTV3>N_PpjJLw%29&|K=p_i=FsEy)fg(N;3!xe(VYM@uj>)q>=a)l=L~%LSRh=Si16G zEU`fZDkeP9!-UK@50Bo!)}m#m-OH_eTpggih+$6+ec>!_6Z95w=|(|q`^$$(*8=EZ zwd~NeLoV+G8~Yegg?aSlJHl|jIQ zqvWIjTbRzZ&S3`ReBtTr+19){%rHU=GMFIRRxGY-u~kQFk?usI6WG?XbMn9xOy&Y$ zA%UIKil)IYfcp;BD%Rm3n>XidE0e%UbEi?xfwOseXQ>;H{lV|}XPTZVYYFOiR+NoQWV%hj)$~M z3a!P4Qt_21QGE>UNR==ynzkY2D;`_g-M#b}6R3Bixb(O-v}B1^yJSg7dmN?EQQhr8 zu>vE==A8EKuJ-n>DakOFFjVR56AtFbfRIl*#1xk0ShHR0eCd7GeWt+^&kq{*nRljn z*12-5x%xstoGQ=&Mge?7AJGiSp z#_FhD*RN@A3$(YC)}+>oxxSTk gEBPVKv9sSwdUUOZB%aE#z@m3gGvoxi-ro4hi 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