diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index fef521c5..616607cf 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -14,18 +14,15 @@ jobs: matrix: os: [macos-latest] steps: - - uses: actions/checkout@v1 - - uses: actions/setup-java@v1 - with: - java-version: '8.x' - - uses: subosito/flutter-action@v1 + - uses: actions/checkout@v3 + - uses: subosito/flutter-action@v2 with: - flutter-version: '2.10.5' + flutter-version: '3.3.0' - run: dart --version - run: flutter --version - run: flutter pub get - run: flutter pub publish --dry-run - - run: cd example; flutter build ios --no-codesign + - run: cd example; pod install --project-directory=./ios; flutter build ios --target=./lib/main.dart --no-codesign test_android: name: Test Android on ${{ matrix.os }} @@ -40,7 +37,7 @@ jobs: java-version: '8.x' - uses: subosito/flutter-action@v1 with: - flutter-version: '2.10.5' + flutter-version: '3.3.0' - run: dart --version - run: flutter --version - run: flutter pub get diff --git a/assets/images/content_failed.png b/assets/images/content_failed.png new file mode 100644 index 00000000..3e3a7e9a Binary files /dev/null and b/assets/images/content_failed.png differ diff --git a/assets/images/network_error.png b/assets/images/network_error.png index 682631ff..2c1b9867 100644 Binary files a/assets/images/network_error.png and b/assets/images/network_error.png differ diff --git a/assets/images/no_data.png b/assets/images/no_data.png index aa03fe2d..10d07379 100644 Binary files a/assets/images/no_data.png and b/assets/images/no_data.png differ diff --git a/doc/components/abnormalCard/BrnAbnormalStateWidget/BrnAbnormalStateWidget.md b/doc/components/abnormalCard/BrnAbnormalStateWidget/BrnAbnormalStateWidget.md index f90d1542..ad782e93 100644 --- a/doc/components/abnormalCard/BrnAbnormalStateWidget/BrnAbnormalStateWidget.md +++ b/doc/components/abnormalCard/BrnAbnormalStateWidget/BrnAbnormalStateWidget.md @@ -8,9 +8,7 @@ group: # BrnAbnormalStateWidget ## 一、效果总览 - -![](./img/empty_state_intro.png) - + ## 二、描述 @@ -76,7 +74,7 @@ BrnAbnormalStateWidget({ ```dart BrnAbnormalStateWidget( img: Image.asset( - 'assets/image/empty_state.png', + 'assets/image/content_failed.png', scale: 3.0, ), isCenterVertical: true, @@ -95,13 +93,12 @@ BrnAbnormalStateWidget( ```dart BrnAbnormalStateWidget( - isCenterVertical: true, - img: Image.asset( - 'assets/image/empty_state.png', - scale: 3.0, - ), - title: BrnStrings.noData, -) + img: Image.asset( + 'assets/image/network_error.png', + scale: 3.0, + ), + title: '网络数据异常', +); ``` ### 效果 3:大模块空态 @@ -110,12 +107,12 @@ BrnAbnormalStateWidget( ```dart BrnAbnormalStateWidget( - img: Image.asset( - 'assets/image/empty_state.png', - scale: 3.0, - ), - content: '您的门店暂无用户', -) + img: Image.asset( + 'assets/image/no_data.png', + scale: 3.0, + ), + content: '您的门店暂无用户', +); ``` ### 效果 4:单按钮效果 @@ -124,18 +121,18 @@ BrnAbnormalStateWidget( ```dart BrnAbnormalStateWidget( - img: Image.asset( - 'assets/image/empty_state.png', - scale: 3.0, - ), - title: "这是副标题内容这是副标题内容这是副标", - content: '您的门店暂无用户', - operateAreaType: OperateAreaType.SingleButton, - operateTexts: ["切换账号"], - action: (_) { - BrnToast.show("第$_个按钮被点击了", context); - }, -) + img: Image.asset( + 'assets/image/no_data.png', + scale: 3.0, + ), + title: "这是副标题内容这是副标题内容这是副标", + content: '您的门店暂无用户', + operateAreaType: OperateAreaType.singleButton, + operateTexts: ["切换账号"], + action: (_) { + BrnToast.show("第$_个按钮被点击了", context); + }, +); ``` ### 效果 5:双按钮效果 @@ -144,16 +141,16 @@ BrnAbnormalStateWidget( ```dart BrnAbnormalStateWidget( - img: Image.asset( - 'assets/image/empty_state.png', - scale: 3.0, - ), - title: "暂无", - content: '您还没有在维护的信息哦', - operateAreaType: OperateAreaType.DoubleButton, - operateTexts: ['去添加', '去修改'], - action: (_) { - BrnToast.show("第$_个按钮被点击了", context); - }, -) + img: Image.asset( + 'assets/image/no_data.png', + scale: 3.0, + ), + title: "暂无", + content: '您还没有在维护的信息哦', + operateAreaType: OperateAreaType.doubleButton, + operateTexts: ['去添加', '去修改'], + action: (_) { + BrnToast.show("第$_个按钮被点击了", context); + }, +); ``` diff --git a/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_1.png b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_1.png index efa9f4d0..e49aa92e 100644 Binary files a/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_1.png and b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_1.png differ diff --git a/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_2.png b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_2.png index 9c3181ce..8183942f 100644 Binary files a/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_2.png and b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_2.png differ diff --git a/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_3.png b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_3.png index 41cfb3f1..98876e52 100644 Binary files a/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_3.png and b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_3.png differ diff --git a/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_4.png b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_4.png index 53906561..027a34a7 100644 Binary files a/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_4.png and b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_4.png differ diff --git a/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_5.png b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_5.png index eda0e45e..687dcce2 100644 Binary files a/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_5.png and b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_5.png differ diff --git a/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_intro.png b/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_intro.png deleted file mode 100644 index 53906561..00000000 Binary files a/doc/components/abnormalCard/BrnAbnormalStateWidget/img/empty_state_intro.png and /dev/null differ diff --git a/doc/components/citySelection/BrnSingleSelectCityPage/BrnSingleSelectCityPage.md b/doc/components/citySelection/BrnSingleSelectCityPage/BrnSingleSelectCityPage.md index b3219430..f58bec7c 100644 --- a/doc/components/citySelection/BrnSingleSelectCityPage/BrnSingleSelectCityPage.md +++ b/doc/components/citySelection/BrnSingleSelectCityPage/BrnSingleSelectCityPage.md @@ -30,6 +30,7 @@ BrnSingleSelectCityPage({ this.showSearchBar = true, this.locationText = '', this.onValueChanged, + this.emptyImage, }); ``` @@ -39,50 +40,59 @@ BrnSingleSelectCityPage({ | **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | | --- | --- | --- | --- | --- | -| appBarTitle | String | 导航栏标题 | 否 | "" | -| hotCityTitle | String | 热门推荐标题 | 否 | "" | +| appBarTitle | String? | 导航栏标题 | 否 | "" | +| hotCityTitle | String? | 热门推荐标题 | 否 | "" | | showSearchBar | bool | 是否展示searchBar | 否 | | | locationText | String | 当前定位城市文案 | 否 | "" | -| cityList | `List` | 城市列表 | 否 | | -| onValueChanged | ValueChanged | 点击时间 | 否 | | -| hotCityList | `List` | 热门推荐城市列表 | 否 | | +| cityList | `List?` | 城市列表 | 否 | | +| onValueChanged | ValueChanged? | 点击时间 | 否 | | +| hotCityList | `List?` | 热门推荐城市列表 | 否 | | +| emptyImage | `Image?` | 暂无搜索结果页面占位图 | 否 | | ### 其它数据 ```dart - - ///页面标题 - final String appBarTitle; - - ///热门推荐标题 - final String hotCityTitle; - - ///是否 展示searchBar true - final bool showSearchBar; - - ///当前城市定位文案展示 - final String locationText; - - ///城市列表 - List cityList; - - ///热门推荐城市列表 - List hotCityList; - - /// 单选项 点击的回调 - final ValueChanged onValueChanged; + +/// 页面标题,默认空 +final String? appBarTitle; + +/// 热门推荐标题,默认空 +final String? hotCityTitle; + +/// 是否展示searchBar,默认 true +final bool showSearchBar; + +/// 当前城市定位文案展示 +final String locationText; + +/// 城市列表 +final List? cityList; + +/// 热门推荐城市列表 +final List hotCityList; + +/// 单选项 点击的回调 +final ValueChanged? onValueChanged; + +/// 空页面中间展位图展示 +final Image? emptyImage; ///城市信息 - CityInfo { - //城市名称 - String name; - //城市名称前这是的标记符号 - String tagIndex; - //拼音 - String namePinyin; - //唯一标记 - String tag; +BrnSelectCityModel { + /// 城市名称 + String name = ""; + + /// 城市名称前这是的标记符号 + String tagIndex = ""; + + /// 拼音 + String? namePinyin; + + String tag = ""; + + /// 城市编码 + String cityCode = ""; } ``` @@ -94,21 +104,19 @@ BrnSingleSelectCityPage({ ```dart -List hotCityList = List(); - hotCityList.addAll([ - CityInfo(name: "北京市"), - CityInfo(name: "广州市"), - CityInfo(name: "成都市"), - CityInfo(name: "深圳市"), - CityInfo(name: "杭州市"), - CityInfo(name: "武汉市"), - ]); - -BrnSingleSelectCityPage( - appBarTitle: '城市单选', - hotCityTitle: '这里是推荐城市', - hotCityList: hotCityList, - cityList: hotCityList, - ); + List hotCityList = []; + hotCityList.addAll([ + BrnSelectCityModel(name: "北京市"), + BrnSelectCityModel(name: "广州市"), + BrnSelectCityModel(name: "成都市"), + BrnSelectCityModel(name: "深圳市"), + BrnSelectCityModel(name: "杭州市"), + BrnSelectCityModel(name: "武汉市"), + ]); + return BrnSingleSelectCityPage( + appBarTitle: '城市单选', + hotCityTitle: '这里是推荐城市', + hotCityList: hotCityList, + ); ``` \ No newline at end of file diff --git a/example/assets/image/content_failed.png b/example/assets/image/content_failed.png new file mode 100644 index 00000000..3e3a7e9a Binary files /dev/null and b/example/assets/image/content_failed.png differ diff --git a/example/assets/image/network_error.png b/example/assets/image/network_error.png new file mode 100644 index 00000000..2c1b9867 Binary files /dev/null and b/example/assets/image/network_error.png differ diff --git a/example/assets/image/no_data.png b/example/assets/image/no_data.png new file mode 100644 index 00000000..10d07379 Binary files /dev/null and b/example/assets/image/no_data.png differ 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 7a5759e0..29c02099 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 @@ -61,10 +61,11 @@ class _BrokenLineExampleState extends State { showPointDashLine: true, yHintLineOffset: 30, isTipWindowAutoDismiss: false, + isShowXDial: true, lines: [ BrnPointsLine( isShowPointText: true, - isShowXDial: true, + isShowXDial: false, lineWidth: 3, pointRadius: 4, isShowPoint: true, @@ -325,31 +326,37 @@ class _BrokenLineExampleState extends State { BrnDialItem( dialText: '1月', dialTextStyle: TextStyle(fontSize: 12.0, color: Color(0xFF999999)), + selectedDialTextStyle: TextStyle(fontSize: 14.0, color: Colors.green), value: 1, ), BrnDialItem( dialText: '2月', dialTextStyle: TextStyle(fontSize: 12.0, color: Color(0xFF999999)), + selectedDialTextStyle: TextStyle(fontSize: 14.0, color: Colors.red), value: 2, ), BrnDialItem( dialText: '3月', dialTextStyle: TextStyle(fontSize: 12.0, color: Color(0xFF999999)), + selectedDialTextStyle: TextStyle(fontSize: 14.0, color: Colors.black), value: 3, ), BrnDialItem( dialText: '5月', dialTextStyle: TextStyle(fontSize: 12.0, color: Color(0xFF999999)), + selectedDialTextStyle: TextStyle(fontSize: 14.0, color: Colors.orange), value: 5, ), BrnDialItem( dialText: '6月', dialTextStyle: TextStyle(fontSize: 12.0, color: Color(0xFF999999)), + selectedDialTextStyle: TextStyle(fontSize: 14.0, color: Colors.yellow), value: 6, ), BrnDialItem( dialText: '7月', dialTextStyle: TextStyle(fontSize: 12.0, color: Color(0xFF999999)), + selectedDialTextStyle: TextStyle(fontSize: 14.0, color: Colors.amberAccent), value: 7, ) ]; 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 6d71c9dc..8e3bead6 100644 --- a/example/lib/sample/components/charts/progress_chart_entry_page.dart +++ b/example/lib/sample/components/charts/progress_chart_entry_page.dart @@ -1,5 +1,3 @@ - - import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -25,13 +23,17 @@ class ProgressChartExampleState extends State { height: 44, ), BrnProgressChart( - key: UniqueKey(), - width: 200, + width: 300, height: 20, value: count, + duration: Duration(milliseconds: 500), + colors: [Colors.lightBlueAccent, Colors.blue], + backgroundColor: Colors.grey, + showAnimation: true, + isFromLastValue: true, brnProgressIndicatorBuilder: (BuildContext context, double value) { return Text( - '自定义文本:$value', + '自定义:$value', style: TextStyle(color: Colors.white), ); }, @@ -48,6 +50,7 @@ class ProgressChartExampleState extends State { value: count, divisions: 10, onChanged: (data) { + if (!mounted) return; setState(() { count = data; }); diff --git a/example/lib/sample/components/dialog/dialog_entry_page.dart b/example/lib/sample/components/dialog/dialog_entry_page.dart index 704f85bd..25466a7c 100644 --- a/example/lib/sample/components/dialog/dialog_entry_page.dart +++ b/example/lib/sample/components/dialog/dialog_entry_page.dart @@ -1,5 +1,3 @@ - - import 'package:bruno/bruno.dart'; import 'package:example/sample/home/list_item.dart'; import 'package:flutter/material.dart'; @@ -75,7 +73,7 @@ class DialogEntryPage extends StatelessWidget { }, ), ListItem( - title: "标题+信息+警示+单按钮", + title: "标题+信息+警示", isSupportTheme: true, describe: '有标题、单按钮、有辅助文案', onPressed: () { @@ -83,7 +81,7 @@ class DialogEntryPage extends StatelessWidget { }, ), ListItem( - title: "标题+信息+自定义警示UI+单按钮", + title: "标题+信息+自定义警示UI", isSupportTheme: true, describe: '有标题、单按钮、有辅助文案', onPressed: () { @@ -201,6 +199,13 @@ class DialogEntryPage extends StatelessWidget { _showBrnLoadingDialog(context); }, ), + ListItem( + title: "Safe Dialog", + describe: '可以放心 pop 的 Dialog,防止误关闭页面', + onPressed: () { + _showSafeDialog(context); + }, + ), ListItem( title: "Share Dialog", isSupportTheme: true, @@ -307,8 +312,7 @@ class DialogEntryPage extends StatelessWidget { decoration: InputDecoration( contentPadding: EdgeInsets.all(8.0), hintText: hintText, - hintStyle: - TextStyle(fontSize: 14, color: Color(0xFFCCCCCC)), + hintStyle: TextStyle(fontSize: 14, color: Color(0xFFCCCCCC)), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(2.0), borderSide: BorderSide( @@ -400,8 +404,7 @@ class DialogEntryPage extends StatelessWidget { decoration: InputDecoration( contentPadding: EdgeInsets.all(8.0), hintText: hintText, - hintStyle: - TextStyle(fontSize: 14, color: Color(0xFFCCCCCC)), + hintStyle: TextStyle(fontSize: 14, color: Color(0xFFCCCCCC)), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(2.0), borderSide: BorderSide( @@ -547,8 +550,7 @@ class DialogEntryPage extends StatelessWidget { ///对话框样式一:无标题、单按钮 void _showStyle1Dialog0(BuildContext context) { - BrnDialogManager.showSingleButtonDialog(context, - label: "知道了", message: "辅助内容容信息", onTap: () { + BrnDialogManager.showSingleButtonDialog(context, label: "知道了", message: "辅助内容容信息", onTap: () { BrnToast.show('知道了', context); Navigator.pop(context); }); @@ -580,9 +582,7 @@ class DialogEntryPage extends StatelessWidget { ///对话框样式二:有标题、单按钮、有辅助文案 void _showStyle2Dialog(BuildContext context) { BrnDialogManager.showSingleButtonDialog(context, - title: "标题内容", - label: "知道了", - message: "辅助内容信息辅助内容信息辅助内容信息辅助内容信息辅助内容信息", onTap: () { + title: "标题内容", label: "知道了", message: "辅助内容信息辅助内容信息辅助内容信息辅助内容信息辅助内容信息", onTap: () { BrnToast.show('知道了', context); Navigator.pop(context); }); @@ -634,8 +634,7 @@ class DialogEntryPage extends StatelessWidget { '选项二', '选项三', ], - title: "标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题", - indexedActionClickCallback: (index) { + title: "标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题", indexedActionClickCallback: (index) { BrnToast.show("$index", context); }); } @@ -648,8 +647,7 @@ class DialogEntryPage extends StatelessWidget { '选项二', '选项三', ], - message: "辅助内容信息辅助内容信息辅助内容信息辅助内容信息辅助内容信息", - indexedActionClickCallback: (index) { + message: "辅助内容信息辅助内容信息辅助内容信息辅助内容信息辅助内容信息", indexedActionClickCallback: (index) { BrnToast.show("$index", context); }); } @@ -663,8 +661,7 @@ class DialogEntryPage extends StatelessWidget { '选项二', '选项三', ], - message: "辅助内容信息辅助内容信息辅助内容信息辅助内容信息辅助内容信息", - indexedActionClickCallback: (index) { + message: "辅助内容信息辅助内容信息辅助内容信息辅助内容信息辅助内容信息", indexedActionClickCallback: (index) { BrnToast.show("$index", context); }); } @@ -687,8 +684,8 @@ class DialogEntryPage extends StatelessWidget { ///对话框样式七:单按钮 有头部Icon、辅助信息为文案 void _showStyle7Dialog(BuildContext context) { - BrnDialogManager.showSingleButtonDialog(context, - showIcon: true, title: "恭喜你完成填写", label: "确定", onTap: () { + BrnDialogManager.showSingleButtonDialog(context, showIcon: true, title: "恭喜你完成填写", label: "确定", + onTap: () { BrnToast.show("确定", context); Navigator.pop(context); }); @@ -697,9 +694,7 @@ class DialogEntryPage extends StatelessWidget { ///对话框样式八:两个按钮,换行标题 void _showStyle8Dialog(BuildContext context) { BrnDialogManager.showConfirmDialog(context, - title: "标题内容,标题内容,标题内容标题内容,标题内容标题内容,标题内容", - cancel: '取消', - confirm: '确定', onConfirm: () { + title: "标题内容,标题内容,标题内容标题内容,标题内容标题内容,标题内容", cancel: '取消', confirm: '确定', onConfirm: () { BrnToast.show("确定", context); }, onCancel: () { BrnToast.show("取消", context); @@ -753,11 +748,43 @@ class DialogEntryPage extends StatelessWidget { ///底部有输入框弹框 void _showBrnLoadingDialog(BuildContext context) { - BrnLoadingDialog.show(context); + BrnLoadingDialog.show(context).then((value) { + BrnToast.show('result: $value', context); + }); + Future.delayed(Duration(seconds: 5)).then((_) { + BrnLoadingDialog.dismiss(context, 'dismiss 定时取消'); + }); + } + + ///安全关闭的弹框 + void _showSafeDialog(BuildContext context) { + BrnSafeDialog.show( + context: context, + tag: "AA", + builder: (context) { + return BrnPageLoading( + content: 'Safe AA', + ); + }).then((result) { + BrnToast.show('result: $result ', context); + }); + + BrnSafeDialog.show( + context: context, + builder: (context) { + return BrnPageLoading( + content: 'Safe BB', + ); + }).then((result) { + BrnToast.show('result: $result ', context); + }); + + Future.delayed(Duration(seconds: 5)).then((_) { + BrnSafeDialog.dismiss(context: context, tag: "AA", result: 'delete dialog AA by tag AA'); + }); Future.delayed(Duration(seconds: 10)).then((_) { - BrnLoadingDialog.dismiss(context); - BrnToast.show('定时取消', context); + BrnSafeDialog.dismiss(context: context, result: 'delete dialog BB by default tag'); }); } diff --git a/example/lib/sample/components/empty/abnormal_state_example.dart b/example/lib/sample/components/empty/abnormal_state_example.dart index 9ec98bd5..68fe5911 100644 --- a/example/lib/sample/components/empty/abnormal_state_example.dart +++ b/example/lib/sample/components/empty/abnormal_state_example.dart @@ -23,7 +23,7 @@ class AbnomalStateExample extends StatelessWidget { case 0: widget = BrnAbnormalStateWidget( img: Image.asset( - 'assets/image/empty_state.png', + 'assets/image/content_failed.png', scale: 3.0, ), isCenterVertical: true, @@ -39,25 +39,25 @@ class AbnomalStateExample extends StatelessWidget { widget = BrnAbnormalStateWidget( isCenterVertical: true, img: Image.asset( - 'assets/image/empty_state.png', + 'assets/image/no_data.png', scale: 3.0, ), - title: BrnStrings.noData, + title: '暂无数据', ); break; case 2: widget = BrnAbnormalStateWidget( img: Image.asset( - 'assets/image/empty_state.png', + 'assets/image/network_error.png', scale: 3.0, ), - title: '暂无数据', + title: '网络数据异常', ); break; case 3: widget = BrnAbnormalStateWidget( img: Image.asset( - 'assets/image/empty_state.png', + 'assets/image/no_data.png', scale: 3.0, ), content: '您的门店暂无用户', @@ -66,7 +66,7 @@ class AbnomalStateExample extends StatelessWidget { case 4: widget = BrnAbnormalStateWidget( img: Image.asset( - 'assets/image/empty_state.png', + 'assets/image/no_data.png', scale: 3.0, ), title: "这是副标题内容这是副标题内容这是副标", @@ -81,7 +81,7 @@ class AbnomalStateExample extends StatelessWidget { case 5: widget = BrnAbnormalStateWidget( img: Image.asset( - 'assets/image/empty_state.png', + 'assets/image/no_data.png', scale: 3.0, ), title: "暂无", diff --git a/example/lib/sample/components/loading/loading_widget_example.dart b/example/lib/sample/components/loading/loading_widget_example.dart index 53b9aa05..e7214f74 100644 --- a/example/lib/sample/components/loading/loading_widget_example.dart +++ b/example/lib/sample/components/loading/loading_widget_example.dart @@ -1,5 +1,3 @@ - - import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -10,7 +8,19 @@ class LoadingExample extends StatelessWidget { appBar: BrnAppBar( title: 'Loading案例', ), - body: BrnPageLoading(), + body: Center( + child: Column(children: [ + Text("正常 Loading 展示"), + BrnPageLoading(), + Text("短文案 Loading 展示"), + BrnPageLoading( + content: "我是较短的 Loading", + ), + Text("长文案 Loading 展示"), + BrnPageLoading( + content: "我是较长的我是较长的我是较长的Loading", + ) + ])), ); } } diff --git a/i10n.md b/i10n.md new file mode 100644 index 00000000..8489f73c --- /dev/null +++ b/i10n.md @@ -0,0 +1,69 @@ +| **中文** | **英文** | ****** | +| ------------------------------------------------------------ | -------- | ------ | +| 请输入 | | | +| 您输入的区间有误 | | | +| 请选择 | | | +| 您选择的区间有误 | | | +| 取消 | | | +| 确认 | | | +| 确定 | | | +| 重置 | | | +| 确定要清空已选列表吗? | | | +| 已选列表 | | | +| 清空 | | | +| 分享至 | | | +| '不好', '还行', '满意', '很棒', '超惊喜' | | | +| yyyy年MM月 | | | +| yyyy年MM月dd日 | | | +| yyyy年,MMMM月,dd日 | | | +| 展开 | | | +| 收起 | | | +| 更多 | | | +| 全部图片 | | | +| 提交 | | | +| 未配置tags数据 | | | +| '日', '一', '二', '三', '四', '五', '六' | | | +| 跳过 | | | +| 我知道了 | | | +| 下一步 | | | +| 请输入搜索内容 | | | +| 请输入搜索信息 | | | +| 完成 | | | +| 未配置tags数据 | | | +| 未配置数据 | | | +| 全选 | | | +| 已选 | | | +| 你可以通过以下方式分享给客户 | | | +| 最小 | | | +| 最大 | | | +| 暂未配置可选标签数据 | | | +| 子类需重写getConfirmData()函数 | | | +| 您选择的数量已达上限 | | | +| 至 | | | +| 这里是推荐城市 | | | +| 城市选择 | | | +| 您选择的筛选条件数量已达上限 | | | +| 最小值 | | | +| 最大值 | | | +| 选择${widget.entityData.title} | | | +| 自定义区间 | | | +| 开始日期 | | | +| 结束日期 | | | +| 请选择结束时间 | | | +| 请选择开始时间 | | | +| "微信", "朋友圈", "QQ", "QQ空间", "微博", "链接", "短信", "剪贴板", "浏览器", "相册" | | | +| 获取数据失败,请重试 | | | +| 网络连接失败,检查后重试 | | | +| 暂无数据 | | | +| 暂无搜索结果 | | | +| 请点击页面重试 | | | +| 加载中... | | | +| '星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日', | | | +| '周一', '周二', '周三', '周四', '周五', '周六', '周日', | | | +| | | | +| | | | +| | | | +| | | | +| | | | + + diff --git a/lib/bruno.dart b/lib/bruno.dart index 54b9dab8..d8deab8b 100644 --- a/lib/bruno.dart +++ b/lib/bruno.dart @@ -22,6 +22,7 @@ export 'src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart'; export 'src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart'; //弹框 +export 'src/components/dialog/brn_safe_dialog.dart'; export 'src/components/dialog/brn_share_dialog.dart'; export 'src/components/dialog/brn_enhance_operation_dialog.dart'; export 'src/components/dialog/brn_scrollable_text_dialog.dart'; diff --git a/lib/src/components/appraise/brn_appraise.dart b/lib/src/components/appraise/brn_appraise.dart index 96963656..b10d8be3 100644 --- a/lib/src/components/appraise/brn_appraise.dart +++ b/lib/src/components/appraise/brn_appraise.dart @@ -178,7 +178,7 @@ class _BrnAppraiseState extends State { /// 标签 Widget _getTags() { if (widget.tags?.isEmpty ?? true) { - return Container(); + return const SizedBox.shrink(); } return Padding( padding: EdgeInsets.only(top: 24), @@ -227,7 +227,7 @@ class _BrnAppraiseState extends State { ), ); } - return Container(); + return const SizedBox.shrink(); } /// 提交按钮 @@ -250,7 +250,7 @@ class _BrnAppraiseState extends State { ); } - return Container(); + return const SizedBox.shrink(); } List string2Tag(List? tags) { 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 80cd04e1..b3e57b2b 100644 --- a/lib/src/components/appraise/brn_appraise_emoji_list_view.dart +++ b/lib/src/components/appraise/brn_appraise_emoji_list_view.dart @@ -66,7 +66,7 @@ class _BrnAppraiseEmojiListViewState extends State { @override Widget build(BuildContext context) { if (widget.indexes.isEmpty) { - return Container(); + return const SizedBox.shrink(); } List list = []; diff --git a/lib/src/components/appraise/brn_appraise_header.dart b/lib/src/components/appraise/brn_appraise_header.dart index 43d985cf..b7568c3a 100644 --- a/lib/src/components/appraise/brn_appraise_header.dart +++ b/lib/src/components/appraise/brn_appraise_header.dart @@ -96,7 +96,7 @@ class BrnAppraiseHeader extends StatelessWidget { ), ), ), - InkWell( + GestureDetector( onTap: () { if (cancelCallBack != null) { cancelCallBack!(context); diff --git a/lib/src/components/button/brn_icon_button.dart b/lib/src/components/button/brn_icon_button.dart index b99f456b..70b371da 100644 --- a/lib/src/components/button/brn_icon_button.dart +++ b/lib/src/components/button/brn_icon_button.dart @@ -40,6 +40,7 @@ class BrnIconButton extends StatefulWidget { final double iconHeight; /// 字体大小,默认 11 + @Deprecated('该字段废弃,请使用 style ,未来版本会删除该字段') final double fontSize; /// 文字样式 @@ -64,6 +65,7 @@ class BrnIconButton extends StatefulWidget { this.onTap, this.iconWidth = 24, this.iconHeight = 24, + @Deprecated('该字段废弃,请使用 style ,未来版本会删除该字段') this.fontSize = 11, this.widgetWidth = 80, this.widgetHeight = 80, @@ -100,7 +102,7 @@ class _BrnIconButtonState extends State { widget.name, style: widget.style ?? TextStyle( - fontSize: 11, + fontSize: widget.fontSize, color: BrnThemeConfigurator.instance .getConfig() .commonConfig @@ -130,7 +132,7 @@ class _BrnIconButtonState extends State { widget.name, style: widget.style ?? TextStyle( - fontSize: 11, + fontSize: widget.fontSize, color: BrnThemeConfigurator.instance .getConfig() .commonConfig @@ -155,7 +157,7 @@ class _BrnIconButtonState extends State { widget.name, style: widget.style ?? TextStyle( - fontSize: 11, + fontSize: widget.fontSize, color: BrnThemeConfigurator.instance .getConfig() .commonConfig @@ -185,7 +187,7 @@ class _BrnIconButtonState extends State { widget.name, style: widget.style ?? TextStyle( - fontSize: 11, + fontSize: widget.fontSize, color: BrnThemeConfigurator.instance .getConfig() .commonConfig diff --git a/lib/src/components/calendar/brn_calendar_view.dart b/lib/src/components/calendar/brn_calendar_view.dart index 2152008e..7fdfae0d 100644 --- a/lib/src/components/calendar/brn_calendar_view.dart +++ b/lib/src/components/calendar/brn_calendar_view.dart @@ -413,11 +413,8 @@ class _CustomCalendarViewState extends State { ), Material( color: Colors.transparent, - child: InkWell( - highlightColor: Colors.transparent, - splashColor: Colors.transparent, - borderRadius: - const BorderRadius.all(Radius.circular(32.0)), + child: GestureDetector( + behavior: HitTestBehavior.opaque, onTap: () { final DateTime newMinimumDate = DateTime( _minDate.year, _minDate.month, _minDate.day - 1); 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 86bcf5e4..22a27a34 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 @@ -102,17 +102,11 @@ class BrnEnhanceNumberCard extends StatelessWidget { .merge(defaultConfig); if (itemChildren == null || itemChildren!.isEmpty) { - return Container( - height: 0, - width: 0, - ); + return const SizedBox.shrink(); } return LayoutBuilder( builder: (context, constraints) { - Widget contentWidget = Container( - height: 0, - width: 0, - ); + Widget contentWidget = const SizedBox.shrink(); // 容错显示的行数 显示三行 int count = rowCount; if (rowCount <= 0 || rowCount > itemChildren!.length) { @@ -280,10 +274,7 @@ class BrnEnhanceNumberCard extends StatelessWidget { Widget _getPreWidget(String? preDesc, BrnEnhanceNumberCardConfig config) { if (preDesc == null || preDesc.isEmpty) { - return Container( - height: 0, - width: 0, - ); + return const SizedBox.shrink(); } return Padding( padding: const EdgeInsets.only(left: 1), @@ -302,10 +293,7 @@ class BrnEnhanceNumberCard extends StatelessWidget { Widget _getLastWidget(String? lastDesc, BrnEnhanceNumberCardConfig config) { if (lastDesc == null || lastDesc.isEmpty) { - return Container( - height: 0, - width: 0, - ); + return const SizedBox.shrink(); } return Padding( padding: const EdgeInsets.only(left: 1, top: 0), 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 3e74a527..ccea24d4 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 @@ -72,10 +72,7 @@ class BrnRichInfoGrid extends StatelessWidget { @override Widget build(BuildContext context) { if (pairInfoList == null || pairInfoList!.isEmpty) { - return Container( - height: 0, - width: 0, - ); + return const SizedBox.shrink(); } return _buildGridView(context); @@ -139,10 +136,7 @@ class BrnRichInfoGrid extends StatelessWidget { Widget _getKeyWidget(BrnRichGridInfo info, double width, BuildContext context, BrnPairRichInfoGridConfig config) { if (info.keyPart == null) { - return Container( - height: 0, - width: 0, - ); + return const SizedBox.shrink(); } if (info.keyPart is String) { @@ -158,10 +152,7 @@ class BrnRichInfoGrid extends StatelessWidget { return info.keyPart; } - return Container( - height: 0, - width: 0, - ); + return const SizedBox.shrink(); } Widget _getValueWidget( @@ -182,10 +173,7 @@ class BrnRichInfoGrid extends StatelessWidget { return info.valuePart; } - return Container( - height: 0, - width: 0, - ); + return const SizedBox.shrink(); } } @@ -285,10 +273,7 @@ class BrnRichGridInfo { ), isShowKeyQuestion ? _getQuestionImage(true) - : Container( - height: 0, - width: 0, - ), + : const SizedBox.shrink(), Text( ':', style: _getKeyStyle(themeData: themeData), @@ -313,16 +298,10 @@ class BrnRichGridInfo { ), isShowValueClick ? _getClickValue(themeData: themeData) - : Container( - height: 0, - width: 0, - ), + : const SizedBox.shrink(), isShowValueQuestion ? _getQuestionImage(false) - : Container( - height: 0, - width: 0, - ), + : const SizedBox.shrink(), ], ), ); 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 564ca01e..55a90339 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 @@ -809,10 +809,7 @@ class BrnInfoModal { } }, ) - .addIcon(Container( - height: 0, - width: 0, - )) + .addIcon(const SizedBox.shrink()) .build(); } 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 2bcb46a0..cecf2504 100644 --- a/lib/src/components/card_title/brn_common_card_title.dart +++ b/lib/src/components/card_title/brn_common_card_title.dart @@ -70,7 +70,7 @@ class BrnCommonCardTitle extends StatelessWidget { /// 标题下方文字 默认是深色的222222 final Color? detailColor; - /// 内容的padding 默认上下16 左右0 + /// 内容的padding 默认上16下12 左右0 final EdgeInsetsGeometry? padding; /// 标题最大行数 @@ -95,22 +95,23 @@ class BrnCommonCardTitle extends StatelessWidget { this.padding, this.titleMaxLines, this.titleOverflow = TextOverflow.clip, - this.themeData}) + this.themeData}) : super(key: key); @override Widget build(BuildContext context) { BrnCardTitleConfig defaultConfig = themeData ?? BrnCardTitleConfig(); - defaultConfig = defaultConfig.merge(BrnCardTitleConfig( + BrnCardTitleConfig cardTitleConfig = BrnCardTitleConfig( alignment: alignment, cardTitlePadding: padding as EdgeInsets?, - detailTextStyle: BrnTextStyle(color: detailColor))); + detailTextStyle: BrnTextStyle(color: detailColor)); defaultConfig = BrnThemeConfigurator.instance .getConfig(configId: defaultConfig.configId) .cardTitleConfig - .merge(defaultConfig); + .merge(themeData) + .merge(cardTitleConfig); Widget titleContainer = Container( color: defaultConfig.cardBackgroundColor, @@ -127,7 +128,7 @@ class BrnCommonCardTitle extends StatelessWidget { List children = []; children.add(Expanded(child: _titleWidget(context, defaultConfig))); - Widget accessory = SizedBox.shrink(); + Widget accessory = const SizedBox.shrink(); // 左侧的文本的行高是25,那么右侧的widget最大为25 if (this.accessoryWidget != null) { accessory = Container( @@ -176,7 +177,7 @@ class BrnCommonCardTitle extends StatelessWidget { ///标题widget Widget _titleWidget(BuildContext context, BrnCardTitleConfig defaultConfig) { - Widget subWidget = SizedBox.shrink(); + Widget subWidget = const SizedBox.shrink(); if (subTitleWidget != null) { subWidget = _subTitleWidgetFromWidget(); 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 30a27266..1764dcdd 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,6 +1,7 @@ import 'package:bruno/src/components/charts/brn_progress_chart/brn_progress_chart_painter.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; /// 在进度条上展示的 Widget @@ -36,6 +37,12 @@ class BrnProgressChart extends StatefulWidget { /// 是否展示动画,默认 false final bool showAnimation; + /// 动画时长,默认 Duration(milliseconds: 250) + final Duration duration; + + /// 进度条是否从上次的值开始 + final bool isFromLastValue; + const BrnProgressChart( {Key? key, this.width = 0, @@ -46,7 +53,9 @@ class BrnProgressChart extends StatefulWidget { this.brnProgressIndicatorBuilder, this.colors = const [Colors.blueAccent, Colors.blue], this.backgroundColor = Colors.lightBlueAccent, - this.showAnimation = false}) + this.showAnimation = false, + this.isFromLastValue = false, + this.duration = const Duration(milliseconds: 250),}) : assert(0 <= value && value <= 1, 'value 必须在 0 到 1 之间'), super(key: key); @@ -59,59 +68,125 @@ class BrnProgressChart extends StatefulWidget { class BrnProgressChartState extends State with SingleTickerProviderStateMixin { late Animation _animation; - AnimationController? _animationController; - double _value = 0; + late AnimationController _animationController = + AnimationController(vsync: this); + double _lastValue = 0; + + bool get _isAnimation => widget.showAnimation; + + void _initAnimation() { + final double begin = widget.isFromLastValue ? _lastValue : 0; + final double end = widget.value; + final Tween tween = Tween(begin: begin, end: end); + _animationController.duration = + _isAnimation ? widget.duration : Duration.zero; + _animation = tween.animate(_animationController); + _animationController.reset(); + _animationController.forward(); + _lastValue = end; + } @override void initState() { super.initState(); - if (widget.showAnimation) { - _animationController = AnimationController( - vsync: this, duration: Duration(milliseconds: 250)); - Tween tween = Tween(begin: 0, end: widget.value); - _animation = tween.animate(_animationController!) as Animation; - _animation.addListener(() { - setState(() { - _value = _animation.value; - }); - }); - _animationController!.forward(); - } else { - _value = widget.value; + _initAnimation(); + } + + @override + void didUpdateWidget(covariant BrnProgressChart oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.value != widget.value) { + if (_animationController.isAnimating == true) { + _animationController.stop(); + } + _initAnimation(); } } @override void dispose() { - _animationController?.dispose(); + _animationController.dispose(); super.dispose(); } - Widget _indicatorWidgetBuilder(BuildContext context, double value) { - return Text( - '$value', - style: widget.textStyle, - ); - } - @override Widget build(BuildContext context) { + final double _value = widget.value; return Stack( children: [ CustomPaint( size: Size(widget.width, widget.height), - painter: BrnProgressChartPainter(value: _value), + painter: BrnProgressChartPainter( + value: _value, + animation: _animation, + backgroundColor: widget.backgroundColor, + colors: widget.colors, + ), ), Container( width: widget.width, height: widget.height, padding: EdgeInsets.only(left: widget.indicatorLeftPadding), alignment: Alignment.centerLeft, - child: null != widget.brnProgressIndicatorBuilder - ? widget.brnProgressIndicatorBuilder!(context, _value) - : _indicatorWidgetBuilder(context, _value), + child: IndicatorWidgetBuilder( + notifier: _animation, + value: _value, + textStyle: widget.textStyle, + brnProgressIndicatorBuilder: widget.brnProgressIndicatorBuilder, + ), ) ], ); } } + +class IndicatorWidgetBuilder extends StatefulWidget { + const IndicatorWidgetBuilder({ + Key? key, + required this.value, + required this.textStyle, + this.notifier, + this.brnProgressIndicatorBuilder, + }) : super(key: key); + + final ValueListenable? notifier; + final double value; + final TextStyle textStyle; + final BrnProgressIndicatorBuilder? brnProgressIndicatorBuilder; + + @override + State createState() => _IndicatorWidgetBuilderState(); +} + +class _IndicatorWidgetBuilderState extends State { + late double _value; + + void _changeListener() { + final double value = widget.notifier?.value ?? widget.value; + if(!mounted) return; + setState(() { + _value = value; + }); + } + + @override + void initState() { + super.initState(); + _value = widget.value; + widget.notifier?.addListener(_changeListener); + } + + @override + void dispose() { + widget.notifier?.removeListener(_changeListener); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final BrnProgressIndicatorBuilder? builder = + widget.brnProgressIndicatorBuilder; + return builder?.call(context, _value) ?? + Text('$_value', style: widget.textStyle); + } +} 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 396e6981..ffb8c83a 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 @@ -6,6 +6,9 @@ class BrnProgressChartPainter extends CustomPainter { /// 进度值 final double value; + /// 动画 + final Animation? animation; + /// 背景色 final Color backgroundColor; @@ -20,13 +23,18 @@ class BrnProgressChartPainter extends CustomPainter { BrnProgressChartPainter( {this.value = 0.2, + this.animation, this.colors = const [Color(0xFF1545FD), Color(0xFF0984F9)], this.backgroundColor = const Color(0x7A90C9FF), this.radius = 4, - this.alwaysShowRadius = true}); + this.alwaysShowRadius = true}) + : super(repaint: animation){ + assert(colors.isNotEmpty, 'colors must not be empty'); + } @override void paint(Canvas canvas, Size size) { + final double curValue = animation?.value ?? this.value; Paint backgroundPaint = Paint() ..color = this.backgroundColor ..style = PaintingStyle.fill; @@ -34,36 +42,38 @@ class BrnProgressChartPainter extends CustomPainter { Rect backgroundRect = Rect.fromLTWH(0, 0, size.width, size.height); if (this.alwaysShowRadius) { RRect backgroundRRect = RRect.fromRectAndCorners(backgroundRect, - bottomRight: Radius.circular(value < 1 ? 0 : this.radius), - topRight: Radius.circular(value < 1 ? 0 : this.radius)); + bottomRight: Radius.circular(curValue < 1 ? 0 : this.radius), + topRight: Radius.circular(curValue < 1 ? 0 : this.radius)); canvas.drawRRect(backgroundRRect, backgroundPaint); } else { canvas.drawRect(backgroundRect, backgroundPaint); } - Rect progressBarRect = Rect.fromLTWH(0, 0, size.width * value, size.height); + Rect progressBarRect = Rect.fromLTWH(0, 0, size.width * curValue, size.height); RRect progressBarRRect = RRect.fromRectAndCorners(progressBarRect, bottomRight: Radius.circular( - 1 == value && false == this.alwaysShowRadius ? 0 : this.radius), + 1 == curValue && 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]]) - .createShader(progressBarRect); - Paint progressBarPaint = Paint()..shader = progressBarShader; + 1 == curValue && false == this.alwaysShowRadius ? 0 : this.radius)); + final bool isNotSingleColor = colors.length > 1; + Paint progressBarPaint = Paint(); + if (isNotSingleColor) { + progressBarPaint.shader = LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + tileMode: TileMode.clamp, + colors: colors) + .createShader(progressBarRect); + } else { + progressBarPaint.color = colors[0]; + } canvas.drawRRect(progressBarRRect, progressBarPaint); } @override bool shouldRepaint(BrnProgressChartPainter oldDelegate) { - return this.value != oldDelegate.value; + return false; } } 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 95f5dd8c..4bdcea07 100644 --- a/lib/src/components/charts/broken_line/brn_broken_line.dart +++ b/lib/src/components/charts/broken_line/brn_broken_line.dart @@ -69,6 +69,9 @@ class BrnBrokenLine extends StatefulWidget { /// 提示 widget 是否自动消失。默认为 true final bool isTipWindowAutoDismiss; + /// 是否绘制 x 刻度 + final bool isShowXDial; + BrnBrokenLine({ Key? key, required this.size, @@ -94,6 +97,7 @@ class BrnBrokenLine extends StatefulWidget { this.isTipWindowAutoDismiss = true, this.isShowXDialText = false, this.isShowYDialText = false, + this.isShowXDial = true }) : super(key: key) { // 设置自定义 X 轴时,检查 x 轴的最大、最小刻度范围 if (xDialValues != null) { @@ -131,6 +135,7 @@ class BrnBrokenLineState extends State { hintLineSolid: widget.isHintLineSolid, hintLineColor: widget.hintLineColor, isShowXText: widget.isShowXDialText, + isShowXDial: widget.isShowXDial, ); var yPainter = BrnLineYPainter( widget.lines, 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 e8ea7466..7086a97a 100644 --- a/lib/src/components/charts/broken_line/brn_line_data.dart +++ b/lib/src/components/charts/broken_line/brn_line_data.dart @@ -8,10 +8,13 @@ class BrnDialItem { /// 刻度标志样式 TextStyle? dialTextStyle; + /// 刻度选中样式 + TextStyle? selectedDialTextStyle; + /// x,y 轴刻度值。用于刻度在坐标的真实定位 double value; - BrnDialItem({this.dialText, this.dialTextStyle, required this.value}); + BrnDialItem({this.dialText, this.dialTextStyle, this.selectedDialTextStyle,required this.value}); } class BrnPointData { @@ -101,6 +104,7 @@ class BrnPointsLine { double? pointInnerRadius; /// 是否显示x轴的文字,用来处理多个线条绘制的时候,同一x轴坐标不需要绘制多次,则只需要将多条线中一个标记绘制即可 + @Deprecated('该字段废弃,X刻度是否绘制由 [BrnBrokenLine.isShowXDial]') bool isShowXDial; /// 标记是否为曲线 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 cc1fc89a..a4506970 100644 --- a/lib/src/components/charts/broken_line/brn_line_painter.dart +++ b/lib/src/components/charts/broken_line/brn_line_painter.dart @@ -49,6 +49,8 @@ class BrnLinePainter extends BrnBasePainter { bool isShowXText, isShowYText; + final bool isShowXDial; + final bool showPointDashLine; /// 默认的边距 @@ -96,6 +98,7 @@ class BrnLinePainter extends BrnBasePainter { required this.isShowHintY, required this.hintLineSolid, required this.hintLineColor, + this.isShowXDial = true, this.isShowXText = false, this.isShowYText = false, }) { @@ -133,6 +136,7 @@ class BrnLinePainter extends BrnBasePainter { ..style = PaintingStyle.stroke; _init(canvas, size, xyPaint); _initPath(canvas, xyPaint); + _drawXy(canvas, xyPaint); //坐标轴 _drawSelectPointWithIndex(canvas, xyPaint); _drawLine(canvas); //曲线或折线 _drawPointDisplayText(canvas); @@ -148,7 +152,6 @@ class BrnLinePainter extends BrnBasePainter { //初始化参数 _initValue(); _initBorder(size); - _drawXy(canvas, xyPaint); //坐标轴 } void _initValue() { @@ -309,36 +312,53 @@ class BrnLinePainter extends BrnBasePainter { if (lines.isNotEmpty) { //绘制x轴的文字部分 - for (var item in lines) { - if (item.points.isNotEmpty && item.isShowXDial) { - _drawXRuler(canvas, paint..color = xDialColor!, item.points); + if (isShowXDial) { + _drawXRuler(canvas, paint..color = xDialColor!); + } else { + // 此处兼容之前 item.isShowXDial属性,建议使用全局isShowXDial + for (var item in lines) { + if (item.isShowXDial) { + _drawXRuler(canvas, paint..color = xDialColor!); + } } } } } ///x轴刻度 & 辅助线 - void _drawXRuler(Canvas canvas, Paint paint, List points) { + void _drawXRuler(Canvas canvas, Paint paint) { + double? _selectedPointX = -1.0; + if (lineSelectIndex >= 0 && pointSelectIndex >= 0) { + _selectedPointX = _linePointPositions[lineSelectIndex][pointSelectIndex].x as double? ; + } if (xDialValues != null && xDialValues!.isNotEmpty) { // 获取刻度长度 for (var i = 0; i < xDialValues!.length; i++) { + double _xPosition = _startX + + (xDialValues![i].value - xDialMin!) / + (xDialMax! - xDialMin!) * + _fixedWidth; + + _selectedPointX = _selectedPointX ?? 0.0; + bool isXRulerSelected = (_selectedPointX - _xPosition).abs() < 1.0; + ///绘制x轴文本 var tpX = TextPainter( textAlign: TextAlign.center, ellipsis: '.', text: TextSpan( text: xDialValues![i].dialText, - style: xDialValues![i].dialTextStyle), + style: isXRulerSelected + ? xDialValues![i].selectedDialTextStyle ?? + xDialValues![i].dialTextStyle + : xDialValues![i].dialTextStyle), textDirection: TextDirection.ltr) ..layout(); // 开始绘制刻度 _drawXRuleByPointPosition( tpX, canvas, - _startX + - (xDialValues![i].value - xDialMin!) / - (xDialMax! - xDialMin!) * - _fixedWidth, + _xPosition, paint); } } diff --git a/lib/src/components/dialog/brn_content_export_dialog.dart b/lib/src/components/dialog/brn_content_export_dialog.dart index 61d8b9eb..2a4c8020 100644 --- a/lib/src/components/dialog/brn_content_export_dialog.dart +++ b/lib/src/components/dialog/brn_content_export_dialog.dart @@ -103,7 +103,7 @@ class BrnContentExportWidget extends StatelessWidget { child: BrunoTools.getAssetImage(BrnAsset.iconPickerClose), ))); } - return Container(); + return const SizedBox.shrink(); } /// 构建Dialog标题 @@ -128,7 +128,7 @@ class BrnContentExportWidget extends StatelessWidget { ? EdgeInsets.fromLTRB(20, 12, 20, 20) : EdgeInsets.only(top: 20), child: isShowOperateWidget - ? InkWell( + ? GestureDetector( child: Container( decoration: BoxDecoration( //背景 @@ -149,6 +149,6 @@ class BrnContentExportWidget extends StatelessWidget { if (onSubmit != null) onSubmit!(); }, ) - : Container()); + : const SizedBox.shrink()); } } diff --git a/lib/src/components/dialog/brn_dialog.dart b/lib/src/components/dialog/brn_dialog.dart index 97483046..8d8d20fb 100644 --- a/lib/src/components/dialog/brn_dialog.dart +++ b/lib/src/components/dialog/brn_dialog.dart @@ -227,10 +227,7 @@ class BrnDialog extends AlertDialog { children.add(Padding( padding: defaultConfig.dividerPadding, - child: SizedBox( - height: 0, - width: 0, - ), + child: const SizedBox.shrink(), )); if (!_isEmptyAction()) { @@ -279,10 +276,7 @@ class BrnDialog extends AlertDialog { BrunoTools.getAssetImageWithBandColor("icons/icon_alter.png")); } - return SizedBox( - width: 0, - height: 0, - ); + return const SizedBox.shrink(); } /// 标题widget:以titleWidget为准,辅以title生成的Text。 diff --git a/lib/src/components/dialog/brn_middle_input_diaolg.dart b/lib/src/components/dialog/brn_middle_input_diaolg.dart index edd807f2..f188e41f 100644 --- a/lib/src/components/dialog/brn_middle_input_diaolg.dart +++ b/lib/src/components/dialog/brn_middle_input_diaolg.dart @@ -58,11 +58,15 @@ class BrnMiddleInputDialog { /// 点击取消/确认按钮之后,是否自动关闭弹窗,默认为 true,关闭 BrnDialogConfig? themeData; + + /// 键盘类型 + final TextInputType? keyboardType; BrnMiddleInputDialog( {this.title, this.message, this.hintText, + this.keyboardType, this.maxLength = 20, this.maxLines, this.minLines: 1, @@ -126,6 +130,7 @@ class BrnMiddleInputDialog { controller: inputEditingController, maxLines: maxLines ?? minLines, minLines: minLines, + keyboardType: keyboardType, //光标颜色 cursorColor: BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary, @@ -200,4 +205,4 @@ class BrnMiddleInputDialog { } return Alignment.center; } -} \ No newline at end of file +} diff --git a/lib/src/components/dialog/brn_multi_select_dialog.dart b/lib/src/components/dialog/brn_multi_select_dialog.dart index d75c5b1c..18a80dcb 100644 --- a/lib/src/components/dialog/brn_multi_select_dialog.dart +++ b/lib/src/components/dialog/brn_multi_select_dialog.dart @@ -182,10 +182,7 @@ class MultiSelectPickerWidgetState extends State { padding: EdgeInsets.only( left: 20, right: 20, top: 12), ) - : Container( - width: 0, - height: 0, - ), + : const SizedBox.shrink(), ], ), ) @@ -203,10 +200,7 @@ class MultiSelectPickerWidgetState extends State { padding: EdgeInsets.only(left: 20, right: 20, top: 12), ) - : Container( - width: 0, - height: 0, - ), + : const SizedBox.shrink(), ], ), ) @@ -306,7 +300,7 @@ class MultiSelectPickerWidgetState extends State { ? Padding( padding: EdgeInsets.fromLTRB(20, 0, 20, 0), child: BrnLine()) - : Container() + : const SizedBox.shrink() ], )); } diff --git a/lib/src/components/dialog/brn_safe_dialog.dart b/lib/src/components/dialog/brn_safe_dialog.dart new file mode 100644 index 00000000..8551dc3f --- /dev/null +++ b/lib/src/components/dialog/brn_safe_dialog.dart @@ -0,0 +1,120 @@ +import 'dart:async'; + +import 'package:bruno/bruno.dart'; +import 'package:flutter/material.dart'; + +/// * * * * * * * * * * * +/// * 描述: 可以放心 dismiss 的 Dialog 工具类, +/// * 可基于该类进行二次封装,类似 [BrnLoadingDialog] 的 show、dismiss 方法 +/// * +/// * 注意:若想删除指定 Dialog,必须在 show、dismiss 方法时传 tag, +/// * * * * * * * * * * * + +class BrnSafeDialog { + static const String _safeDialogDefaultTag = '_safeDialogDefaultTag'; + + /// 根据 tag 区分是某一类 Dialog 的队列状态 + static Map> _dialogStates = {}; + + /// 用于关闭某个 Dialog,仅移除对应 tag 列表中最后入栈的 Dialog + /// [tag]: 用于移除对应 tag 的 Dialog + /// + /// 注意, + /// 1、直接 remove 不会调用 push future 的 then 回调,使用 Completer 转发; + /// 2、当 router 不在队列队列中时会抛异常,catch 并打印异常日志。 + static void dismiss({ + required BuildContext context, + String tag = _safeDialogDefaultTag, + T? result, + }) { + List<_SafeDialogRoute> typeStates = (_dialogStates[tag] ??= []); + if (typeStates.isNotEmpty) { + try { + _SafeDialogRoute _safeDialogRoute = typeStates.removeLast(); + Navigator.removeRoute(context, _safeDialogRoute); + if (!_safeDialogRoute.completer.isCompleted) { + _safeDialogRoute.completer.complete(result); + } + } catch (e) { + /// TODO 可能会抛出异常, 直接打印到日志区 + print(e); + } + } + } + + /// 展示 Dialog + /// [tag] : 用于标记 Dialog 类型 + static Future show({ + required BuildContext context, + required WidgetBuilder builder, + String tag = _safeDialogDefaultTag, + bool barrierDismissible = true, + Color? barrierColor = Colors.black54, + String? barrierLabel, + bool useSafeArea = true, + bool useRootNavigator = true, + RouteSettings? routeSettings, + }) { + assert(debugCheckHasMaterialLocalizations(context)); + final CapturedThemes themes = InheritedTheme.capture( + from: context, + to: Navigator.of( + context, + rootNavigator: useRootNavigator, + ).context, + ); + + _SafeDialogRoute safeDialogRoute = _SafeDialogRoute( + context: context, + builder: builder, + barrierColor: barrierColor, + barrierDismissible: barrierDismissible, + barrierLabel: barrierLabel, + useSafeArea: useSafeArea, + settings: routeSettings, + themes: themes, + ); + + // Notice: + // 关键点, 手动管理 Router + // 将结果通过 Completer 转发出去 + _dialogStates[tag] ??= []; + _dialogStates[tag]?.add(safeDialogRoute); + Future future = + Navigator.of(context, rootNavigator: useRootNavigator).push(safeDialogRoute); + future.then((result) { + _dialogStates[tag]?.remove(safeDialogRoute); + if (!safeDialogRoute.completer.isCompleted) { + safeDialogRoute.completer.complete(result); + } + }); + return safeDialogRoute.completer.future; + } +} + +/// 基于 DialogRoute 简单封装了 Completer,用于 Route 结果的转发 +class _SafeDialogRoute extends DialogRoute { + + /// 转发 Route 结果 + final Completer completer = Completer(); + + _SafeDialogRoute({ + required BuildContext context, + required WidgetBuilder builder, + CapturedThemes? themes, + Color? barrierColor = Colors.black54, + bool barrierDismissible = true, + String? barrierLabel, + bool useSafeArea = true, + RouteSettings? settings, + }) : super( + context:context, + builder: builder, + themes: themes, + barrierColor: barrierColor, + barrierDismissible: barrierDismissible, + barrierLabel: barrierLabel, + useSafeArea: useSafeArea, + settings: settings, + ); +} \ No newline at end of file diff --git a/lib/src/components/dialog/brn_share_dialog.dart b/lib/src/components/dialog/brn_share_dialog.dart index a45f761c..6900bf60 100644 --- a/lib/src/components/dialog/brn_share_dialog.dart +++ b/lib/src/components/dialog/brn_share_dialog.dart @@ -153,9 +153,7 @@ class BrnShareDialog extends StatelessWidget { Positioned( top: 10, right: 10, - child: InkWell( - splashColor: Colors.transparent, - highlightColor: Colors.transparent, + child: GestureDetector( child: Container( width: 30, height: 30, @@ -227,7 +225,7 @@ class BrnShareDialog extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - InkWell( + GestureDetector( child: Container( child: image, width: 39, diff --git a/lib/src/components/dialog/brn_single_select.dart b/lib/src/components/dialog/brn_single_select.dart index 22bebc18..563192e8 100644 --- a/lib/src/components/dialog/brn_single_select.dart +++ b/lib/src/components/dialog/brn_single_select.dart @@ -196,10 +196,7 @@ class BrnSingleSelectDialogWidgetState padding: EdgeInsets.only( left: 20, right: 20, top: 12), ) - : Container( - width: 0, - height: 0, - ), + : const SizedBox.shrink(), ], ), ) @@ -218,16 +215,13 @@ class BrnSingleSelectDialogWidgetState padding: EdgeInsets.only( left: 20, right: 20, top: 12), ) - : Container( - width: 0, - height: 0, - ), + : const SizedBox.shrink(), ], ), ), Padding( padding: EdgeInsets.fromLTRB(20, 12, 20, 20), - child: InkWell( + child: GestureDetector( child: Container( decoration: BoxDecoration( //背景 @@ -261,7 +255,7 @@ class BrnSingleSelectDialogWidgetState widget.isClose ? Positioned( right: 0.0, - child: InkWell( + child: GestureDetector( onTap: () { if (widget.onCloseClick != null) { widget.onCloseClick!(); @@ -274,7 +268,7 @@ class BrnSingleSelectDialogWidgetState child: BrunoTools.getAssetImage( BrnAsset.iconPickerClose), ))) - : SizedBox.shrink() + : const SizedBox.shrink() ], ), ))); @@ -300,13 +294,13 @@ class BrnSingleSelectDialogWidgetState ), ); } - return Container(); + return const SizedBox.shrink(); } Widget _buildItem(BuildContext context, int index) { if (widget.conditions == null) { - return Container(); + return const SizedBox.shrink(); } else { return Container( child: Column( @@ -316,7 +310,7 @@ class BrnSingleSelectDialogWidgetState child: Row( children: [ Expanded( - child: InkWell( + child: GestureDetector( onTap: () { setState(() { for (dynamic item in widget.conditions!) { @@ -348,7 +342,7 @@ class BrnSingleSelectDialogWidgetState .commonConfig .colorTextBase)), )), - InkWell( + GestureDetector( child: Container( alignment: Alignment.center, height: 44, @@ -372,7 +366,7 @@ class BrnSingleSelectDialogWidgetState index != widget.conditions!.length - 1 ? Padding( padding: EdgeInsets.fromLTRB(20, 0, 20, 0), child: BrnLine()) - : Container() + : const SizedBox.shrink() ], )); } diff --git a/lib/src/components/empty/brn_empty_status.dart b/lib/src/components/empty/brn_empty_status.dart index 3a3af529..afb69f27 100644 --- a/lib/src/components/empty/brn_empty_status.dart +++ b/lib/src/components/empty/brn_empty_status.dart @@ -29,25 +29,25 @@ class BrnAbnormalStateUtils { {Image? img, BrnEmptyStatusIndexedActionClickCallback? action}) { if (AbnormalState.getDataFailed == status) { return BrnAbnormalStateWidget( - img: img ?? BrunoTools.getAssetImage(BrnAsset.emptyState), + img: img ?? BrunoTools.getAssetImage(BrnAsset.contentFailed), title: BrnStrings.getDateFailed, operateTexts: [BrnStrings.clickPageRetry], action: action, ); } else if (AbnormalState.networkConnectError == status) { return BrnAbnormalStateWidget( - img: img ?? BrunoTools.getAssetImage(BrnAsset.emptyState), + img: img ?? BrunoTools.getAssetImage(BrnAsset.networkError), title: BrnStrings.networkConnectError, operateTexts: [BrnStrings.clickPageRetry], action: action, ); } else if (AbnormalState.noData == status) { return BrnAbnormalStateWidget( - img: img ?? BrunoTools.getAssetImage(BrnAsset.emptyState), + img: img ?? BrunoTools.getAssetImage(BrnAsset.noData), title: BrnStrings.noData, ); } else { - return Container(); + return const SizedBox.shrink(); } } } @@ -169,7 +169,7 @@ class BrnAbnormalStateWidget extends StatelessWidget { : EdgeInsets.only(top: topOffset ?? height * topPercent), child: img, ) - : SizedBox.shrink(); + : const SizedBox.shrink(); } ///文案区域:标题 @@ -182,7 +182,7 @@ class BrnAbnormalStateWidget extends StatelessWidget { textAlign: TextAlign.center, style: themeData!.titleTextStyle.generateTextStyle()), ) - : SizedBox.shrink(); + : const SizedBox.shrink(); } ///文案区域:内容 @@ -195,7 +195,7 @@ class BrnAbnormalStateWidget extends StatelessWidget { textAlign: TextAlign.center, style: themeData!.contentTextStyle.generateTextStyle()), ) - : SizedBox.shrink(); + : const SizedBox.shrink(); } ///操作区域 @@ -205,7 +205,7 @@ class BrnAbnormalStateWidget extends StatelessWidget { padding: EdgeInsets.only(top: 36), child: _buildOperateContentWidget(), ) - : SizedBox.shrink(); + : const SizedBox.shrink(); } ///操作区按钮 @@ -277,6 +277,6 @@ class BrnAbnormalStateWidget extends StatelessWidget { child: Text(operateTexts![0], style: themeData!.operateTextStyle.generateTextStyle())); } - return Container(); + return const SizedBox.shrink(); } } 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 8cc56f2b..23d70374 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 @@ -175,7 +175,7 @@ class BrnMultiChoiceInputFormItemState List getCheckboxList(List? options) { List result = []; if (options == null || options.isEmpty) { - result.add(Container()); + result.add(const SizedBox.shrink()); return result; } 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 4821a0f0..9fa73013 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 @@ -310,7 +310,7 @@ class QuickButtonsState extends State { Widget getQuickButtons() { if (!widget.isEdit) { - return Container(); + return const SizedBox.shrink(); } if (widget.btns != null) { 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 f14a5d37..1be47869 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 @@ -14,6 +14,12 @@ import 'package:flutter/services.dart'; /// // ignore: must_be_immutable class BrnTextInputFormItem extends StatefulWidget { + /// 录入项的焦点控制对象,主要用于控制焦点 + final FocusNode? focusNode; + + /// 选择键盘的完成按钮 + final TextInputAction? textInputAction; + /// 录入项的唯一标识,主要用于录入类型页面框架中 final String? label; @@ -95,6 +101,8 @@ class BrnTextInputFormItem extends StatefulWidget { this.title = "", this.subTitle, this.tipLabel, + this.focusNode, + this.textInputAction, this.prefixIconType = BrnPrefixIconType.normal, this.error = "", this.isEdit = true, @@ -185,6 +193,7 @@ class BrnTextInputFormItemState extends State { Expanded( child: TextField( autofocus: widget.autofocus, + focusNode: widget.focusNode, keyboardType: BrnFormUtil.getInputType(widget.inputType), enabled: widget.isEdit, maxLines: 1, diff --git a/lib/src/components/form/items/misc/brn_general_item.dart b/lib/src/components/form/items/misc/brn_general_item.dart index deb7efc3..d2874b6b 100644 --- a/lib/src/components/form/items/misc/brn_general_item.dart +++ b/lib/src/components/form/items/misc/brn_general_item.dart @@ -182,7 +182,7 @@ class BrnGeneralFormItemState extends State { Container( - child: widget.operateWidget ?? SizedBox.shrink(), + child: widget.operateWidget ?? const SizedBox.shrink(), ), ], 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 81bd7958..496d6c4e 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 @@ -125,7 +125,7 @@ class BrnTitleState extends State { // 自定义操作区 Offstage( offstage: (widget.customActionWidget == null), - child: widget.customActionWidget ?? Container(), + child: widget.customActionWidget ?? const SizedBox.shrink(), ), ], ), diff --git a/lib/src/components/form/utils/brn_form_util.dart b/lib/src/components/form/utils/brn_form_util.dart index d1b9b0f3..8d17c564 100644 --- a/lib/src/components/form/utils/brn_form_util.dart +++ b/lib/src/components/form/utils/brn_form_util.dart @@ -36,14 +36,12 @@ class BrnFormUtil { /// 获取错误提示widget static Widget buildErrorWidget(String error, BrnFormItemConfig themeData) { - return Container( - padding: errorEdgeInsets(themeData), - child: Offstage( - offstage: (error.isEmpty), - child: Text( - error, - style: getErrorTextStyle(themeData), - )), + return Offstage( + offstage: error.isEmpty, + child: Container( + padding: errorEdgeInsets(themeData), + child: Text(error, style: getErrorTextStyle(themeData)), + ), ); } diff --git a/lib/src/components/input/brn_input_text.dart b/lib/src/components/input/brn_input_text.dart index 8642af4b..42f754f9 100644 --- a/lib/src/components/input/brn_input_text.dart +++ b/lib/src/components/input/brn_input_text.dart @@ -58,6 +58,7 @@ class BrnInputText extends StatelessWidget { /// 搜索框的焦点控制器 final FocusNode? focusNode; + /// 键盘输入行为, 默认为 TextInputAction.done final TextInputAction textInputAction; diff --git a/lib/src/components/loading/brn_loading.dart b/lib/src/components/loading/brn_loading.dart index 9e83fdd7..e4548bcc 100644 --- a/lib/src/components/loading/brn_loading.dart +++ b/lib/src/components/loading/brn_loading.dart @@ -1,3 +1,4 @@ +import 'package:bruno/bruno.dart'; import 'package:bruno/src/constants/brn_strings_constants.dart'; import 'package:flutter/material.dart'; @@ -34,10 +35,34 @@ class BrnPageLoading extends StatelessWidget { @override Widget build(BuildContext context) { + double _loadingMaxWidth = MediaQuery.of(context).size.width * 2 / 3; + double _iconSize = 19.0; + double _textLeftPadding = 8.0; + double _outPadding = 10.0; + + // 获取实际文字长度 + TextPainter textPainter = TextPainter( + textDirection: TextDirection.ltr, + textScaleFactor: MediaQuery.of(context).textScaleFactor, + text: TextSpan( + text: content, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w600, + color: Colors.white, + decoration: TextDecoration.none)), + )..layout( + maxWidth: _loadingMaxWidth - _iconSize - _textLeftPadding, minWidth: 0); + double maxWidth = + textPainter.width + _iconSize + _textLeftPadding + _outPadding * 2; + return Center( child: Container( + padding: EdgeInsets.all(_outPadding), + constraints: BoxConstraints( + maxWidth: maxWidth, minWidth: _iconSize + _textLeftPadding), height: 50, - width: 130, + width: _loadingMaxWidth, decoration: BoxDecoration( color: Color(0xff222222), borderRadius: BorderRadius.circular(5)), child: Center( @@ -45,22 +70,25 @@ class BrnPageLoading extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Container( - height: 19, - width: 19, + height: _iconSize, + width: _iconSize, child: CircularProgressIndicator( strokeWidth: 2.0, valueColor: AlwaysStoppedAnimation(Colors.white), ), ), - Container( - margin: EdgeInsets.only(left: 8), - child: Text( - content, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.w600, - color: Colors.white, - decoration: TextDecoration.none), + Expanded( + child: Container( + margin: EdgeInsets.only(left: _textLeftPadding), + child: Text( + content, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w600, + color: Colors.white, + decoration: TextDecoration.none), + overflow: TextOverflow.ellipsis, + ), ), ) ], @@ -69,16 +97,35 @@ class BrnPageLoading extends StatelessWidget { ), ); } + + _buildText(BuildContext context, double maxWidth) { + TextPainter textPainter = TextPainter( + textScaleFactor: MediaQuery.of(context).textScaleFactor, + text: TextSpan( + text: content, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w600, + color: Colors.white, + decoration: TextDecoration.none)), + )..layout(maxWidth: maxWidth, minWidth: 0); + return BoxConstraints( + maxWidth: maxWidth, + minWidth: 0, + ); + } } /// 通过 [BrnPageLoading] 构建出的加载状态的弹窗,加载动画和加载文字并排展示,且在屏幕中间。可通 /// 过 [BrnLoadingDialog.show] 和 [BrnLoadingDialog.dismiss] 控制弹窗的显示和关闭。不会自动关闭。 class BrnLoadingDialog extends Dialog { + /// tag 用于在 BrnSafeDialog 中标记类型 + static const String _loadingDialogTag = '_loadingDialogTag'; + /// 加载时的提示文案,默认为 `加载中...` final String content; - const BrnLoadingDialog({Key? key, this.content = BrnStrings.loadingContent}) - : super(key: key); + const BrnLoadingDialog({Key? key, this.content = BrnStrings.loadingContent}) : super(key: key); @override Widget build(BuildContext context) { @@ -98,8 +145,9 @@ class BrnLoadingDialog extends Dialog { bool barrierDismissible = true, bool useRootNavigator = true, }) { - return showDialog( + return BrnSafeDialog.show( context: context, + tag: _loadingDialogTag, barrierDismissible: barrierDismissible, useRootNavigator: useRootNavigator, builder: (_) { @@ -111,6 +159,6 @@ class BrnLoadingDialog extends Dialog { /// /// * [context] 上下文。 static void dismiss(BuildContext context, [T? result]) { - Navigator.pop(context, result); + BrnSafeDialog.dismiss(context: context, tag: _loadingDialogTag, result: result); } } diff --git a/lib/src/components/navbar/brn_search_bar.dart b/lib/src/components/navbar/brn_search_bar.dart index 2e37c059..c8b34f30 100644 --- a/lib/src/components/navbar/brn_search_bar.dart +++ b/lib/src/components/navbar/brn_search_bar.dart @@ -384,10 +384,7 @@ class __SearchInputWidgetState extends State<_SearchInputWidget> { ], ), ) - : Container( - height: 0, - width: 0, - ); + : const SizedBox.shrink(); }, ), ], @@ -409,9 +406,6 @@ class __SearchInputWidgetState extends State<_SearchInputWidget> { return widget.leading; } - return Container( - height: 0, - width: 0, - ); + return const SizedBox.shrink(); } } diff --git a/lib/src/components/noticebar/brn_marquee_text.dart b/lib/src/components/noticebar/brn_marquee_text.dart index 9e52aff8..674f56d6 100644 --- a/lib/src/components/noticebar/brn_marquee_text.dart +++ b/lib/src/components/noticebar/brn_marquee_text.dart @@ -128,9 +128,9 @@ class BrnMarqueeTextState extends State Widget getCenterChild() { if (widget.scrollAxis == Axis.horizontal) { - return new Container(width: blankWidth); + return Container(width: blankWidth); } else { - return new Container(height: blankHeight); + return Container(height: blankHeight); } } 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 a1507a0f..187869b4 100644 --- a/lib/src/components/picker/brn_mulit_select_tags_picker.dart +++ b/lib/src/components/picker/brn_mulit_select_tags_picker.dart @@ -1,5 +1,3 @@ - - 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'; @@ -239,8 +237,12 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { padding: EdgeInsets.symmetric(vertical: 16, horizontal: 16), child: Wrap( spacing: 15.0, + runSpacing: 15.0, children: this._sourceTags.map((choice) { bool selected = choice.isSelect; + Color titleColor = selected + ? tagConfig.selectTagTextStyle.color! + : tagConfig.tagTextStyle.color!; EdgeInsets edgeInsets = this.tagPickerConfig.chipPadding ?? EdgeInsets.only(top: 9.0, left: 10.0, right: 10, bottom: 11.0); return ChoiceChip( @@ -248,8 +250,7 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { padding: edgeInsets, pressElevation: 0, backgroundColor: tagConfig.tagBackgroundColor, - selectedColor: tagConfig.selectedTagBackgroundColor - .withAlpha(0x14), + selectedColor: tagConfig.selectedTagBackgroundColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(2.0)), label: Text( @@ -257,10 +258,14 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, strutStyle: StrutStyle(forceStrutHeight: true, height: 1), - style: TextStyle(color: Colors.grey), + style: TextStyle( + height: 1, + color: titleColor, + fontWeight: selected ? FontWeight.w600 : FontWeight.w400, + fontSize: this.tagPickerConfig.tagTitleFontSize), ), onSelected: (bool value) { - if (_selectedTags.length > this.maxSelectItemCount && + if (_selectedTags.length >= this.maxSelectItemCount && this.maxSelectItemCount > 0 && value == true) { if (this.onMaxSelectClick != null) { 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 9988365d..c6d8e131 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 @@ -256,7 +256,7 @@ class _BrnSelectTagsWithInputPickerWidgetState fontWeight: FontWeight.w600, ), ), - InkWell( + GestureDetector( onTap: () { if (widget.cancelCallBack != null) { widget.cancelCallBack!(context); 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 88dced65..fcf0e698 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 @@ -180,7 +180,7 @@ class MultiSelectDialogWidgetState extends State { ? Padding( padding: EdgeInsets.fromLTRB(20, 0, 20, 0), child: BrnLine()) - : Container() + : const SizedBox.shrink() ], )); } diff --git a/lib/src/components/radio/brn_checkbox.dart b/lib/src/components/radio/brn_checkbox.dart index 5a866c57..02d97efb 100644 --- a/lib/src/components/radio/brn_checkbox.dart +++ b/lib/src/components/radio/brn_checkbox.dart @@ -76,6 +76,15 @@ class BrnCheckboxState extends State { _isSelected = widget.isSelected; } + @override + void didUpdateWidget(covariant BrnCheckbox oldWidget) { + super.didUpdateWidget(oldWidget); + + if (oldWidget.isSelected != widget.isSelected) { + _isSelected = widget.isSelected; + } + } + @override Widget build(BuildContext context) { return BrnRadioCore( 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 fe4f6cee..fccc8445 100644 --- a/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart +++ b/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart @@ -132,7 +132,7 @@ class _BrnScrollAnchorTabWidgetState extends State }); }, ), - widget.tabDivider ?? SizedBox.shrink(), + widget.tabDivider ?? const SizedBox.shrink(), Expanded( child: SingleChildScrollView( child: Column( diff --git a/lib/src/components/selectcity/brn_select_city_model.dart b/lib/src/components/selectcity/brn_select_city_model.dart index d8c28a6b..d80b5ebc 100644 --- a/lib/src/components/selectcity/brn_select_city_model.dart +++ b/lib/src/components/selectcity/brn_select_city_model.dart @@ -1,10 +1,19 @@ import 'package:bruno/src/components/selectcity/brn_az_common.dart'; class BrnSelectCityModel extends ISuspensionBean { + + /// 城市名称 String name = ""; + + /// 城市名称前这是的标记符号 String tagIndex = ""; + + /// 拼音 String? namePinyin; + String tag = ""; + + /// 城市编码 String cityCode = ""; BrnSelectCityModel({ 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 7d5d54a3..f71cff48 100644 --- a/lib/src/components/selectcity/brn_single_select_city_page.dart +++ b/lib/src/components/selectcity/brn_single_select_city_page.dart @@ -38,6 +38,9 @@ class BrnSingleSelectCityPage extends StatefulWidget { /// 单选项 点击的回调 final ValueChanged? onValueChanged; + /// 空页面中间展位图展示 + final Image? emptyImage; + BrnSingleSelectCityPage({ this.appBarTitle = '', this.hotCityTitle = '', @@ -46,6 +49,7 @@ class BrnSingleSelectCityPage extends StatefulWidget { this.showSearchBar = true, this.locationText = '', this.onValueChanged, + this.emptyImage, }); @override @@ -279,9 +283,9 @@ class _BrnSingleSelectCityPageState extends State { child: Column( children: [ widget.locationText.isEmpty - ? Container() + ? const SizedBox.shrink() : _buildLocationBar(widget.locationText), - widget.showSearchBar ? _buildSearchBar() : Container(), + widget.showSearchBar ? _buildSearchBar() : const SizedBox.shrink(), Divider( height: .0, ), @@ -359,7 +363,7 @@ class _BrnSingleSelectCityPageState extends State { Widget _noDataWidget() { return Container( child: BrnAbnormalStateWidget( - img: BrunoTools.getAssetImage(BrnAsset.emptyState), + img: widget.emptyImage ?? BrunoTools.getAssetImage(BrnAsset.noData), title: BrnStrings.noSearchData, ), ); 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 12b781e2..f9921c17 100644 --- a/lib/src/components/selection/widget/brn_flat_selection_item.dart +++ b/lib/src/components/selection/widget/brn_flat_selection_item.dart @@ -222,10 +222,7 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { /// 自定义筛选条件的显示 Widget _buildRangeWidget() { return widget.selectionEntity.currentRangeListForEntity().isEmpty - ? Container( - height: 0, - width: 0, - ) + ? const SizedBox.shrink() : _MoreRangeWidget( streamController: _streamController, clearController: widget.clearController, 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 52a9d1f2..1f7b5d75 100644 --- a/lib/src/components/selection/widget/brn_selection_list_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_list_widget.dart @@ -226,10 +226,7 @@ class _BrnSelectionGroupViewState extends State { ), ), ) - : Container( - height: 0, - width: 0, - ) + : const SizedBox.shrink() ], ); } @@ -246,7 +243,7 @@ class _BrnSelectionGroupViewState extends State { padding: EdgeInsets.fromLTRB(8, 11, 20, 11), child: Row( children: [ - InkWell( + GestureDetector( child: Container( padding: EdgeInsets.only(left: 12, right: 20), child: Column( 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 e2ac2a89..4c8e7baa 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 @@ -191,10 +191,7 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { /// 自定义筛选条件的显示 Widget _buildRangeWidget() { return widget.selectionEntity.currentRangeListForEntity().isEmpty - ? Container( - height: 0, - width: 0, - ) + ? const SizedBox.shrink() : _MoreRangeWidget( themeData: widget.themeData, streamController: streamController, 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 3b7ec3c5..94865188 100644 --- a/lib/src/components/selection/widget/brn_selection_range_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_range_widget.dart @@ -360,7 +360,7 @@ class _BrnRangeSelectionGroupWidgetState padding: EdgeInsets.fromLTRB(8, 11, 20, 11), child: Row( children: [ - InkWell( + GestureDetector( child: Container( padding: EdgeInsets.only(left: 12, right: 20), child: Column( diff --git a/lib/src/components/step/brn_horizontal_steps.dart b/lib/src/components/step/brn_horizontal_steps.dart index fd6644ef..dea76abd 100644 --- a/lib/src/components/step/brn_horizontal_steps.dart +++ b/lib/src/components/step/brn_horizontal_steps.dart @@ -124,11 +124,11 @@ class BrnHorizontalStepsState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [ index == 0 - ? Expanded(child: SizedBox.shrink()) + ? Expanded(child: const SizedBox.shrink()) : _applyLineItem(index, true), _applyStepIcon(step, index), index == widget.steps.length - 1 - ? Expanded(child: SizedBox.shrink()) + ? Expanded(child: const SizedBox.shrink()) : _applyLineItem(index, false), ], ); diff --git a/lib/src/components/sugsearch/brn_search_text.dart b/lib/src/components/sugsearch/brn_search_text.dart index 343a2f1d..def1cbed 100644 --- a/lib/src/components/sugsearch/brn_search_text.dart +++ b/lib/src/components/sugsearch/brn_search_text.dart @@ -226,7 +226,9 @@ class _SearchTextState extends State { .colorTextBase, fontSize: 16), decoration: InputDecoration( - border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: widget.borderRadius, + borderSide: BorderSide.none), contentPadding: EdgeInsets.only(left: 8, right: 6), // 填充颜色属性,填充装饰容器的颜色。 fillColor: widget.innerColor, 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 2ce74ff9..2af3c6ef 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 @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; /// 简述:[BrnBottomTabBar]中的单个选择按钮组件 /// 功能:为了每个Tab独立控制操作 -/// 特别注意:Tab的右上角小红点可能不符合UI规范,可以使用BrnBadge小红点组件 class BrnBottomTabBarItem { const BrnBottomTabBarItem({ this.title, 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 948f903b..6d2a3454 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 @@ -478,7 +478,7 @@ class _BottomNavigationTile extends StatelessWidget { style: TextStyle( fontSize: _kActiveFontSize, color: colorTween?.evaluate(animation), - ), + ).merge(selected ? item.selectedTextStyle : item.unSelectedTextStyle), /// 使用矩阵变化控制字体大小 child: Transform( 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 47d43f5c..2bfdf0a7 100644 --- a/lib/src/components/tabbar/normal/brn_sub_switch_title.dart +++ b/lib/src/components/tabbar/normal/brn_sub_switch_title.dart @@ -72,10 +72,7 @@ class _BrnSubSwitchTitleState extends State Widget _toggleButtonsWidget(context) { if (widget.nameList.isEmpty) { - return Container( - height: 0, - width: 0, - ); + return const SizedBox.shrink(); } List widgetChildren = widget.nameList.map((name) { diff --git a/lib/src/components/tabbar/normal/brn_switch_title.dart b/lib/src/components/tabbar/normal/brn_switch_title.dart index 8c3873b8..2f5d6dea 100644 --- a/lib/src/components/tabbar/normal/brn_switch_title.dart +++ b/lib/src/components/tabbar/normal/brn_switch_title.dart @@ -102,10 +102,7 @@ class _BrnSwitchTitleState extends State Widget _toggleButtonsWidget(context) { if (widget.nameList.isEmpty) { - return Container( - height: 0, - width: 0, - ); + return const SizedBox.shrink(); } List widgetChildren = widget.nameList.map((name) { diff --git a/lib/src/components/toast/brn_toast.dart b/lib/src/components/toast/brn_toast.dart index d9a314d9..37be57f5 100644 --- a/lib/src/components/toast/brn_toast.dart +++ b/lib/src/components/toast/brn_toast.dart @@ -111,11 +111,11 @@ class BrnToast { final double defaultOffset; switch (gravity) { case BrnToastGravity.bottom: - final offset = verticalOffset ?? _defaultTopOffset; + final offset = verticalOffset ?? _defaultBottomOffset; defaultOffset = MediaQuery.of(context).viewInsets.bottom + offset; break; case BrnToastGravity.top: - final offset = verticalOffset ?? _defaultBottomOffset; + final offset = verticalOffset ?? _defaultTopOffset; defaultOffset = MediaQuery.of(context).viewInsets.top + offset; break; case BrnToastGravity.center: diff --git a/lib/src/constants/brn_asset_constants.dart b/lib/src/constants/brn_asset_constants.dart index 63f6f41b..456376e9 100644 --- a/lib/src/constants/brn_asset_constants.dart +++ b/lib/src/constants/brn_asset_constants.dart @@ -1,7 +1,10 @@ class BrnAsset { const BrnAsset._(); - static const String emptyState = "images/empty_state.png"; + static const String contentFailed = "images/content_failed.png"; + static const String noData = "images/no_data.png"; + static const String networkError = "images/network_error.png"; + static const String stepTitle = 'images/img_step_title.png'; static const String refreshArrowUp = "images/refresh_arrow_up.png"; diff --git a/pubspec.yaml b/pubspec.yaml index 5994cdd1..baff314d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,7 +9,7 @@ environment: dependencies: flutter: sdk: flutter - xml: ^5.1.2 + xml: ^6.1.0 lpinyin: ^2.0.3 path_drawing: ^1.0.0 flutter_easyrefresh: ^2.2.1