dialog_content_wrap.dart 13 KB

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