dialog_content_wrap.dart 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. import 'package:cs_resources/generated/assets.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:cs_resources/generated/l10n.dart';
  4. import 'package:flutter_hooks/flutter_hooks.dart';
  5. import 'package:hooks_riverpod/hooks_riverpod.dart';
  6. import 'package:shared/utils/log_utils.dart';
  7. import 'package:widgets/ext/ex_widget.dart';
  8. import 'package:cs_resources/theme/app_colors_theme.dart';
  9. import 'package:widgets/my_text_view.dart';
  10. import 'package:widgets/no_shadow_scroll_behavior.dart';
  11. import 'package:widgets/utils/dark_theme_util.dart';
  12. import 'package:widgets/widget_export.dart';
  13. import '../load_state_layout.dart';
  14. import '../my_load_image.dart';
  15. ///四种视图状态
  16. // enum DialogLoadingState { State_Success, State_Error, State_Loading, State_Empty }
  17. /*
  18. * 弹窗内容的包装组件
  19. * 弹框内容自定义传入 messageBuilder
  20. */
  21. class DialogContentWrap extends StatefulWidget {
  22. LoadState? loadingState;
  23. String? title;
  24. Widget Function(BuildContext)? titleBuilder;
  25. String? message;
  26. Widget Function(BuildContext)? messageBuilder;
  27. VoidCallback confirmAction;
  28. VoidCallback? cancelAction;
  29. VoidCallback? closeAction;
  30. bool isShowConfirmBtn;
  31. bool isShowCancelBtn;
  32. bool isConfirmAutoClose;
  33. Widget Function(BuildContext)? bottomFooterBuilder; // 自定义底部按钮区
  34. bool showCloseIcon;
  35. String? confirmTxt;
  36. String? cancelTxt;
  37. TextStyle? titleTextStyle;
  38. Color? titleBackgroundColor;
  39. Color? backgroundColor;
  40. Color? noBtnBg;
  41. Color? yesBtnBg;
  42. Color? closeIconColor;
  43. TextStyle? yesBtnTextStyle;
  44. TextStyle? noBtnTextStyle;
  45. double? bottomBtnRadius;
  46. EdgeInsets? bottomBtnSectionPadding;
  47. EdgeInsets? contentPadding;
  48. Color? contentBgColor;
  49. Color? bottomBtnSectionBgColor;
  50. final double? bottomBtnSpace;
  51. final double? topLeftRadius;
  52. final double? topRightRadius;
  53. final double? bottomRightRadius;
  54. final double? bottomLeftRadius;
  55. final double? minHeight;
  56. final double? maxHeight;
  57. final double? dialogWidth;
  58. DialogContentWrap({
  59. Key? key,
  60. this.loadingState = LoadState.State_Loading,
  61. this.title,
  62. this.message,
  63. Widget Function(BuildContext)? this.titleBuilder,
  64. Widget Function(BuildContext)? this.messageBuilder,
  65. Widget Function(BuildContext)? this.bottomFooterBuilder,
  66. required this.confirmAction,
  67. this.cancelAction,
  68. this.closeAction,
  69. this.showCloseIcon = true,
  70. this.isShowConfirmBtn = true,
  71. this.isShowCancelBtn = true,
  72. this.isConfirmAutoClose = true,
  73. this.confirmTxt,
  74. this.cancelTxt,
  75. this.titleTextStyle,
  76. this.titleBackgroundColor = Colors.white,
  77. this.backgroundColor = Colors.white,
  78. this.closeIconColor = Colors.white,
  79. this.bottomBtnRadius = 7,
  80. this.noBtnBg,
  81. this.yesBtnBg,
  82. this.yesBtnTextStyle,
  83. this.noBtnTextStyle,
  84. this.bottomBtnSectionPadding,
  85. this.contentPadding = const EdgeInsets.only(
  86. left: 0, right: 0, bottom: 0, top: 0),
  87. this.bottomBtnSpace = 0,
  88. topLeftRadius,
  89. topRightRadius,
  90. bottomLeftRadius,
  91. bottomRightRadius,
  92. minHeight,
  93. maxHeight,
  94. dialogWidth,
  95. })
  96. : minHeight = minHeight ?? 0,
  97. maxHeight = maxHeight ?? 500,
  98. dialogWidth = dialogWidth ?? 300.0,
  99. topLeftRadius = topLeftRadius ?? 0,
  100. topRightRadius = topRightRadius ?? 0,
  101. bottomLeftRadius = bottomLeftRadius ?? 0,
  102. bottomRightRadius = bottomRightRadius ?? 0,
  103. super(key: key);
  104. @override
  105. DialogContentWrapState createState() => DialogContentWrapState();
  106. }
  107. class DialogContentWrapState extends State<DialogContentWrap> {
  108. @override
  109. void initState() {
  110. super.initState();
  111. }
  112. // 修改 dialogLoadingState
  113. void changeDialogLoadingState(LoadState state){
  114. Log.d("change loadState");
  115. setState(() {
  116. widget.loadingState = state;
  117. });
  118. }
  119. @override
  120. Widget build(BuildContext context) {
  121. Log.d("dialogWidth ${widget.dialogWidth} ");
  122. double _dialogWidth = widget.dialogWidth?? MediaQuery.of(context).size.width * 0.65;
  123. bool _showTitleSection = (widget.title != null && widget.title!.isNotEmpty) || widget.titleBuilder != null;
  124. bool _showBottomBtnSection = widget.isShowConfirmBtn || widget.isShowCancelBtn || widget.bottomFooterBuilder != null;
  125. double _bottomBtnSectionHeight = _showBottomBtnSection ? 50 : 0;
  126. double _scrollMaxHeight = widget.maxHeight! - _bottomBtnSectionHeight;
  127. double _bottomBtnMargin = 0;
  128. String _errorMessage = 'Data loading failed! Please refresh and try again';
  129. if(widget.isShowConfirmBtn && widget.isShowCancelBtn){
  130. _bottomBtnMargin = widget.bottomBtnSpace??0/2;
  131. }
  132. return Stack(
  133. children: [
  134. ClipRRect(
  135. borderRadius: BorderRadius.only(
  136. topLeft: Radius.circular(widget.topLeftRadius!),
  137. topRight: Radius.circular(widget.topRightRadius!),
  138. bottomLeft: Radius.circular(widget.bottomLeftRadius!),
  139. bottomRight: Radius.circular(widget.bottomRightRadius!),
  140. ),
  141. child: Container(
  142. width: _dialogWidth,
  143. constraints: BoxConstraints(
  144. minHeight: widget.minHeight!,
  145. maxHeight: widget.maxHeight!,
  146. ),
  147. decoration: BoxDecoration(
  148. color: DarkThemeUtil.multiColors(context, widget.backgroundColor?? context.appColors.whiteBG, darkColor: AppColorsTheme.color666666),
  149. // borderRadius: BorderRadius.only(
  150. // topLeft: Radius.circular(topLeftRadius!),
  151. // topRight: Radius.circular(topRightRadius!),
  152. // ),
  153. ),
  154. child: LoadStateLayout(
  155. state: widget.loadingState??LoadState.State_Loading,
  156. errorMessage: _errorMessage,
  157. errorRetry: () {
  158. },
  159. successSliverWidget: [
  160. SliverList(delegate: SliverChildBuilderDelegate(
  161. (context, index){
  162. return Container(
  163. height: _scrollMaxHeight + _bottomBtnSectionHeight ,
  164. color: DarkThemeUtil.multiColors(context, context.appColors.whiteBG, darkColor: AppColorsTheme.color666666),
  165. child: Column(
  166. children: [
  167. // 标题区
  168. Container(
  169. width: double.infinity,
  170. color: DarkThemeUtil.multiColors(context, widget.titleBackgroundColor, darkColor: Colors.black),
  171. child: Visibility(
  172. visible: _showTitleSection,
  173. child: (widget.title != null && widget.title!.isNotEmpty)? MyTextView(
  174. widget.title ?? '',
  175. fontSize: 18,
  176. isFontMedium: true,
  177. textColor: widget.titleTextStyle?.color ?? context.appColors.textBlack,
  178. paddingTop: 15,
  179. paddingBottom: 15,
  180. textAlign: TextAlign.center,
  181. textStyle: widget.titleTextStyle,
  182. ): widget.titleBuilder!.call(context),
  183. ),
  184. ),
  185. // 内容区
  186. Expanded(
  187. child: Scrollbar(
  188. child: ScrollConfiguration(
  189. behavior: NoShadowScrollBehavior(),
  190. child: SingleChildScrollView(
  191. child: Container(
  192. width: double.infinity,
  193. padding: widget.contentPadding,
  194. color: widget.contentBgColor?? DarkThemeUtil.multiColors(context, context.appColors.whiteBG, darkColor: AppColorsTheme.color666666),
  195. child: widget.messageBuilder?.call(context) ??
  196. MyTextView(
  197. widget.message!,
  198. fontSize: 18,
  199. textColor: context.appColors.textBlack,
  200. isFontRegular: true,
  201. textAlign: TextAlign.center,
  202. ),
  203. ),
  204. ),
  205. ),
  206. ).constrained(maxHeight: _scrollMaxHeight),
  207. ),
  208. // 底部按钮区
  209. Visibility(
  210. visible: _showBottomBtnSection,
  211. child: (widget.isShowCancelBtn || widget.isShowConfirmBtn)? Container(
  212. height: _bottomBtnSectionHeight,
  213. color: widget.bottomBtnSectionBgColor?? DarkThemeUtil.multiColors(context, context.appColors.whiteBG, darkColor: Colors.black),
  214. padding: widget.bottomBtnSectionPadding,
  215. child: Row(
  216. mainAxisAlignment: MainAxisAlignment.center,
  217. children: [
  218. Visibility(
  219. visible: widget.isShowCancelBtn,
  220. child: Expanded(
  221. flex: 1,
  222. child: InkWell(
  223. onTap: () {
  224. onCancel();
  225. widget.cancelAction?.call();
  226. },
  227. child: MyTextView(
  228. widget.cancelTxt ?? S.current.no,
  229. fontSize: 16,
  230. isFontMedium: true,
  231. paddingTop: 13,
  232. paddingBottom: 13,
  233. textAlign: TextAlign.center,
  234. textColor: context.appColors.whiteBG,
  235. backgroundColor: widget.noBtnBg ?? context.appColors.orangeBG,
  236. cornerRadius: widget.bottomBtnRadius ?? 0,
  237. textStyle: widget.noBtnTextStyle,
  238. ),
  239. )),
  240. ),
  241. SizedBox(
  242. width: _bottomBtnMargin,
  243. ),
  244. Visibility(
  245. visible: widget.isShowConfirmBtn,
  246. child: Expanded(
  247. flex: 1,
  248. child: InkWell(
  249. onTap: () async {
  250. if(widget.isConfirmAutoClose){
  251. onCancel();
  252. }
  253. widget.confirmAction();
  254. },
  255. child: MyTextView(
  256. widget.confirmTxt ?? S.current.yes,
  257. fontSize: 16,
  258. paddingTop: 13,
  259. paddingBottom: 13,
  260. isFontMedium: true,
  261. textAlign: TextAlign.center,
  262. textColor: Colors.white,
  263. backgroundColor: widget.yesBtnBg?? context.appColors.btnBgDefault,
  264. cornerRadius: widget.bottomBtnRadius ?? 0,
  265. textStyle: widget.yesBtnTextStyle,
  266. ),
  267. )),
  268. ),
  269. ],
  270. ),
  271. ): Container(
  272. child: widget.bottomFooterBuilder?.call(context),
  273. ),
  274. ),
  275. ],
  276. ),
  277. );
  278. },
  279. childCount: 1
  280. ),
  281. )
  282. ]
  283. ),
  284. ),
  285. ),
  286. // 右上角 关闭按钮
  287. Visibility(
  288. visible: widget.showCloseIcon,
  289. child: Positioned(
  290. top: 0,
  291. right: 0,
  292. child: MyAssetImage(
  293. Assets.baseServiceDialogDeleteIcon,
  294. width: 25,
  295. height: 25.5,
  296. color: widget.closeIconColor ?? context.appColors.textPrimary,
  297. ).onTap((){
  298. widget.closeAction ?.call();
  299. onCancel();
  300. },padding: 10),
  301. ),
  302. )
  303. ],
  304. );
  305. }
  306. //取消弹框
  307. void onCancel() async {
  308. SmartDialog.dismiss();
  309. }
  310. }