dialog_content_wrap.dart 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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,
  77. this.backgroundColor,
  78. this.closeIconColor,
  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. Color _titleBackgroundColor = widget.titleBackgroundColor?? context.appColors.whiteBG;
  123. Color _backgroundColor = widget.backgroundColor?? context.appColors.whiteBG;
  124. Color _closeIconColor = widget.closeIconColor?? context.appColors.whiteBG;
  125. double _dialogWidth = widget.dialogWidth?? MediaQuery.of(context).size.width * 0.65;
  126. bool _showTitleSection = (widget.title != null && widget.title!.isNotEmpty) || widget.titleBuilder != null;
  127. bool _showBottomBtnSection = widget.isShowConfirmBtn || widget.isShowCancelBtn || widget.bottomFooterBuilder != null;
  128. double _bottomBtnSectionHeight = _showBottomBtnSection ? 50 : 0;
  129. double _scrollMaxHeight = widget.maxHeight! - _bottomBtnSectionHeight;
  130. double _bottomBtnMargin = 0;
  131. String _errorMessage = 'Data loading failed! Please refresh and try again';
  132. if(widget.isShowConfirmBtn && widget.isShowCancelBtn){
  133. _bottomBtnMargin = widget.bottomBtnSpace??0/2;
  134. }
  135. return Stack(
  136. children: [
  137. ClipRRect(
  138. borderRadius: BorderRadius.only(
  139. topLeft: Radius.circular(widget.topLeftRadius!),
  140. topRight: Radius.circular(widget.topRightRadius!),
  141. bottomLeft: Radius.circular(widget.bottomLeftRadius!),
  142. bottomRight: Radius.circular(widget.bottomRightRadius!),
  143. ),
  144. child: Container(
  145. width: _dialogWidth,
  146. constraints: BoxConstraints(
  147. minHeight: widget.minHeight!,
  148. maxHeight: widget.maxHeight!,
  149. ),
  150. decoration: BoxDecoration(
  151. color: DarkThemeUtil.multiColors(context, _backgroundColor, darkColor: widget.backgroundColor??AppColorsTheme.color666666),
  152. // borderRadius: BorderRadius.only(
  153. // topLeft: Radius.circular(topLeftRadius!),
  154. // topRight: Radius.circular(topRightRadius!),
  155. // ),
  156. ),
  157. child: LoadStateLayout(
  158. state: widget.loadingState??LoadState.State_Loading,
  159. errorMessage: _errorMessage,
  160. errorRetry: () {
  161. },
  162. successSliverWidget: [
  163. SliverList(delegate: SliverChildBuilderDelegate(
  164. (context, index){
  165. return Container(
  166. height: _scrollMaxHeight + _bottomBtnSectionHeight ,
  167. color: DarkThemeUtil.multiColors(context, context.appColors.whiteBG, darkColor: AppColorsTheme.color666666),
  168. child: Column(
  169. children: [
  170. // 标题区
  171. Container(
  172. width: double.infinity,
  173. color: DarkThemeUtil.multiColors(context, _titleBackgroundColor, darkColor: widget.titleBackgroundColor??Colors.black.withOpacity(0.8)),
  174. child: Visibility(
  175. visible: _showTitleSection,
  176. child: (widget.title != null && widget.title!.isNotEmpty)? MyTextView(
  177. widget.title ?? '',
  178. fontSize: 18,
  179. isFontMedium: true,
  180. textColor: widget.titleTextStyle?.color ?? context.appColors.textBlack,
  181. paddingTop: 15,
  182. paddingBottom: 15,
  183. textAlign: TextAlign.center,
  184. textStyle: widget.titleTextStyle,
  185. ): widget.titleBuilder!.call(context),
  186. ),
  187. ),
  188. // 内容区
  189. Expanded(
  190. child: Scrollbar(
  191. child: ScrollConfiguration(
  192. behavior: NoShadowScrollBehavior(),
  193. child: SingleChildScrollView(
  194. child: Container(
  195. width: double.infinity,
  196. padding: widget.contentPadding,
  197. color: widget.contentBgColor?? DarkThemeUtil.multiColors(context, context.appColors.whiteBG, darkColor: AppColorsTheme.color666666),
  198. child: widget.messageBuilder?.call(context) ??
  199. MyTextView(
  200. widget.message!,
  201. fontSize: 18,
  202. textColor: context.appColors.textBlack,
  203. isFontRegular: true,
  204. textAlign: TextAlign.center,
  205. ),
  206. ),
  207. ),
  208. ),
  209. ).constrained(maxHeight: _scrollMaxHeight),
  210. ),
  211. // 底部按钮区
  212. Visibility(
  213. visible: _showBottomBtnSection,
  214. child: (widget.isShowCancelBtn || widget.isShowConfirmBtn)? Container(
  215. height: _bottomBtnSectionHeight,
  216. color: widget.bottomBtnSectionBgColor?? DarkThemeUtil.multiColors(context, context.appColors.whiteBG, darkColor: Colors.black),
  217. padding: widget.bottomBtnSectionPadding,
  218. child: Row(
  219. mainAxisAlignment: MainAxisAlignment.center,
  220. children: [
  221. Visibility(
  222. visible: widget.isShowCancelBtn,
  223. child: Expanded(
  224. flex: 1,
  225. child: InkWell(
  226. onTap: () {
  227. onCancel();
  228. widget.cancelAction?.call();
  229. },
  230. child: MyTextView(
  231. widget.cancelTxt ?? S.current.no,
  232. fontSize: 16,
  233. isFontMedium: true,
  234. paddingTop: 13,
  235. paddingBottom: 13,
  236. textAlign: TextAlign.center,
  237. textColor: context.appColors.whiteBG,
  238. backgroundColor: widget.noBtnBg ?? context.appColors.orangeBG,
  239. cornerRadius: widget.bottomBtnRadius ?? 0,
  240. textStyle: widget.noBtnTextStyle,
  241. ),
  242. )),
  243. ),
  244. SizedBox(
  245. width: _bottomBtnMargin,
  246. ),
  247. Visibility(
  248. visible: widget.isShowConfirmBtn,
  249. child: Expanded(
  250. flex: 1,
  251. child: InkWell(
  252. onTap: () async {
  253. if(widget.isConfirmAutoClose){
  254. onCancel();
  255. }
  256. widget.confirmAction();
  257. },
  258. child: MyTextView(
  259. widget.confirmTxt ?? S.current.yes,
  260. fontSize: 16,
  261. paddingTop: 13,
  262. paddingBottom: 13,
  263. isFontMedium: true,
  264. textAlign: TextAlign.center,
  265. textColor: Colors.white,
  266. backgroundColor: widget.yesBtnBg?? context.appColors.btnBgDefault,
  267. cornerRadius: widget.bottomBtnRadius ?? 0,
  268. textStyle: widget.yesBtnTextStyle,
  269. ),
  270. )),
  271. ),
  272. ],
  273. ),
  274. ): Container(
  275. child: widget.bottomFooterBuilder?.call(context),
  276. ),
  277. ),
  278. ],
  279. ),
  280. );
  281. },
  282. childCount: 1
  283. ),
  284. )
  285. ]
  286. ),
  287. ),
  288. ),
  289. // 右上角 关闭按钮
  290. Visibility(
  291. visible: widget.showCloseIcon,
  292. child: Positioned(
  293. top: 0,
  294. right: 0,
  295. child: MyAssetImage(
  296. Assets.baseServiceDialogDeleteIcon,
  297. width: 25,
  298. height: 25.5,
  299. color: DarkThemeUtil.multiColors(context, _closeIconColor, darkColor: widget.closeIconColor ?? context.appColors.textPrimary),
  300. ).onTap((){
  301. widget.closeAction ?.call();
  302. onCancel();
  303. },padding: 10),
  304. ),
  305. )
  306. ],
  307. );
  308. }
  309. //取消弹框
  310. void onCancel() async {
  311. SmartDialog.dismiss();
  312. }
  313. }