state_wrapper.dart 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_screenutil/flutter_screenutil.dart';
  3. import 'package:flutter_spinkit/flutter_spinkit.dart';
  4. import 'package:flutter_svg/flutter_svg.dart';
  5. import 'package:get/get.dart';
  6. import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
  7. import '../../../config/translations/strings_enum.dart';
  8. import '../../base/base_controller.dart';
  9. import '../../constants/assets.dart';
  10. import '../../constants/enums.dart';
  11. import '../submit_btn.dart';
  12. class StateWrapper extends StatelessWidget {
  13. final Widget child;
  14. final BaseController controller;
  15. final double? width;
  16. final double? height;
  17. final VoidCallback? onRefresh;
  18. // 可选的自定义状态视图
  19. final Widget Function(BuildContext)? loadingBuilder;
  20. final Widget Function(BuildContext)? emptyBuilder;
  21. final Widget Function(BuildContext, String?)? errorBuilder;
  22. const StateWrapper({
  23. super.key,
  24. required this.child,
  25. required this.controller,
  26. this.width,
  27. this.height,
  28. this.loadingBuilder,
  29. this.emptyBuilder,
  30. this.errorBuilder,
  31. this.onRefresh,
  32. });
  33. // 默认加载视图
  34. Widget _defaultLoadingView(BuildContext context) {
  35. return Center(
  36. // child: CircularProgressIndicator(),
  37. child: SpinKitRing(
  38. size: 24.w,
  39. lineWidth: 2.w,
  40. color: Get.reactiveTheme.primaryColor,
  41. ),
  42. );
  43. }
  44. // 默认空视图
  45. Widget _defaultEmptyView(BuildContext context) {
  46. return Center(
  47. child: Column(
  48. mainAxisAlignment: MainAxisAlignment.center,
  49. children: [
  50. SvgPicture.asset(Assets.oops, width: 160.w, height: 160.w),
  51. Text(
  52. Strings.noData.tr,
  53. style: TextStyle(
  54. fontSize: 14.sp,
  55. color: Get.reactiveTheme.textTheme.bodyLarge!.color!,
  56. ),
  57. ),
  58. 24.verticalSpaceFromWidth,
  59. SizedBox(
  60. width: 247.w,
  61. child: SubmitSvgButton(
  62. onPressed: onRefresh ?? () {},
  63. text: Strings.refresh.tr,
  64. svgPath: Assets.refersh,
  65. svgColor: Get.reactiveTheme.textTheme.bodyLarge!.color,
  66. bgColor: Get.reactiveTheme.primaryColor,
  67. textColor: Get.reactiveTheme.textTheme.bodyLarge!.color,
  68. borderColor: Get.reactiveTheme.dividerColor,
  69. ),
  70. ),
  71. 40.verticalSpaceFromWidth,
  72. ],
  73. ),
  74. );
  75. }
  76. // 默认错误视图
  77. Widget _defaultErrorView(
  78. BuildContext context,
  79. bool isNetworkError,
  80. String error,
  81. ) {
  82. return Center(
  83. child: Column(
  84. mainAxisAlignment: MainAxisAlignment.center,
  85. children: [
  86. SvgPicture.asset(
  87. isNetworkError ? Assets.oops : Assets.oops,
  88. width: 160.w,
  89. height: 160.w,
  90. ),
  91. Padding(
  92. padding: EdgeInsets.symmetric(horizontal: 20.w),
  93. child: Text(
  94. error.isNotEmpty ? error : Strings.unableToConnectServer.tr,
  95. style: TextStyle(
  96. fontSize: 14.sp,
  97. color: Get.reactiveTheme.textTheme.bodyLarge!.color,
  98. ),
  99. ),
  100. ),
  101. 24.verticalSpaceFromWidth,
  102. SizedBox(
  103. width: 247.w,
  104. child: SubmitSvgButton(
  105. onPressed: onRefresh ?? () {},
  106. text: Strings.retry.tr,
  107. svgPath: Assets.refersh,
  108. svgColor: Get.reactiveTheme.textTheme.bodyLarge!.color,
  109. bgColor: Get.reactiveTheme.primaryColor,
  110. textColor: Get.reactiveTheme.textTheme.bodyLarge!.color,
  111. borderColor: Get.reactiveTheme.dividerColor,
  112. ),
  113. ),
  114. 40.verticalSpaceFromWidth,
  115. ],
  116. ),
  117. );
  118. }
  119. @override
  120. Widget build(BuildContext context) {
  121. return SizedBox(
  122. width: width,
  123. height: height,
  124. child: Obx(() {
  125. switch (controller.viewState.value) {
  126. case ViewState.loading:
  127. return loadingBuilder?.call(context) ??
  128. _defaultLoadingView(context);
  129. case ViewState.empty:
  130. return emptyBuilder?.call(context) ?? _defaultEmptyView(context);
  131. case ViewState.error:
  132. return errorBuilder?.call(context, controller.errorMessage.value) ??
  133. _defaultErrorView(
  134. context,
  135. controller.isNetworkError.value,
  136. controller.errorMessage.value,
  137. );
  138. case ViewState.success:
  139. return child;
  140. }
  141. }),
  142. );
  143. }
  144. }