easy_loading.dart 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. import 'container.dart';
  4. import 'indicator.dart';
  5. import 'progress.dart';
  6. import 'theme.dart';
  7. /// loading style
  8. enum EasyLoadingStyle {
  9. light,
  10. dark,
  11. custom,
  12. }
  13. /// loading indicator type. see [https://github.com/jogboms/flutter_spinkit#-showcase]
  14. enum EasyLoadingIndicatorType {
  15. fadingCircle,
  16. circle,
  17. threeBounce,
  18. chasingDots,
  19. wave,
  20. wanderingCubes,
  21. rotatingPlain,
  22. doubleBounce,
  23. fadingFour,
  24. fadingCube,
  25. pulse,
  26. cubeGrid,
  27. rotatingCircle,
  28. foldingCube,
  29. pumpingHeart,
  30. dualRing,
  31. hourGlass,
  32. pouringHourGlass,
  33. fadingGrid,
  34. ring,
  35. ripple,
  36. spinningCircle,
  37. squareCircle,
  38. }
  39. /// loading mask type
  40. /// [none] default mask type, allow user interactions while loading is displayed
  41. /// [clear] don't allow user interactions while loading is displayed
  42. /// [black] don't allow user interactions while loading is displayed
  43. /// [custom] while mask type is custom, maskColor should not be null
  44. enum EasyLoadingMaskType {
  45. none,
  46. clear,
  47. black,
  48. custom,
  49. }
  50. class EasyLoading {
  51. /// loading style, default [EasyLoadingStyle.dark].
  52. EasyLoadingStyle loadingStyle;
  53. /// loading indicator type, default [EasyLoadingIndicatorType.fadingCircle].
  54. EasyLoadingIndicatorType indicatorType;
  55. /// loading mask type, default [EasyLoadingMaskType.none].
  56. EasyLoadingMaskType maskType;
  57. /// textAlign of status, default [TextAlign.center].
  58. TextAlign textAlign;
  59. Alignment alignment;
  60. /// content padding of loading.
  61. EdgeInsets contentPadding;
  62. EdgeInsets contentMargin;
  63. /// padding of [status].
  64. EdgeInsets textPadding;
  65. /// size of indicator, default 40.0.
  66. double indicatorSize;
  67. /// radius of loading, default 5.0.
  68. double radius;
  69. /// fontSize of loading, default 15.0.
  70. double fontSize;
  71. /// width of progress indicator, default 2.0.
  72. double progressWidth;
  73. /// width of indicator, default 4.0, only used for [EasyLoadingIndicatorType.ring, EasyLoadingIndicatorType.dualRing].
  74. double lineWidth;
  75. /// display duration of [showSuccess] [showError] [showInfo] [showToast], default 2000ms.
  76. Duration displayDuration;
  77. /// color of loading status, only used for [EasyLoadingStyle.custom].
  78. Color textColor;
  79. /// color of loading indicator, only used for [EasyLoadingStyle.custom].
  80. Color indicatorColor;
  81. /// progress color of loading, only used for [EasyLoadingStyle.custom].
  82. Color progressColor;
  83. /// background color of loading, only used for [EasyLoadingStyle.custom].
  84. Color backgroundColor;
  85. /// mask color of loading, only used for [EasyLoadingMaskType.custom].
  86. Color maskColor;
  87. /// should allow user interactions while loading is displayed.
  88. bool userInteractions;
  89. /// success widget of loading
  90. Widget successWidget;
  91. /// error widget of loading
  92. Widget errorWidget;
  93. /// info widget of loading
  94. Widget infoWidget;
  95. BuildContext context;
  96. OverlayEntry _overlayEntry;
  97. Widget _progress;
  98. GlobalKey<LoadingContainerState> _key;
  99. GlobalKey<ProgressState> _progressKey;
  100. Timer _timer;
  101. OverlayEntry get overlayEntry => _overlayEntry;
  102. Widget get progress => _progress;
  103. GlobalKey<LoadingContainerState> get key => _key;
  104. GlobalKey<ProgressState> get progressKey => _progressKey;
  105. Timer get timer => _timer;
  106. factory EasyLoading() => _getInstance();
  107. static EasyLoading _instance;
  108. static EasyLoading get instance => _getInstance();
  109. EasyLoading._internal() {
  110. /// set deafult value
  111. loadingStyle = EasyLoadingStyle.dark;
  112. indicatorType = EasyLoadingIndicatorType.fadingCircle;
  113. maskType = EasyLoadingMaskType.none;
  114. textAlign = TextAlign.center;
  115. indicatorSize = 40.0;
  116. radius = 5.0;
  117. fontSize = 15.0;
  118. progressWidth = 2.0;
  119. lineWidth = 4.0;
  120. displayDuration = const Duration(milliseconds: 2000);
  121. textPadding = const EdgeInsets.only(bottom: 10.0);
  122. alignment = Alignment.center;
  123. contentPadding = const EdgeInsets.symmetric(
  124. vertical: 15.0,
  125. horizontal: 20.0,
  126. );
  127. }
  128. static EasyLoading _getInstance() {
  129. if (_instance == null) {
  130. _instance = EasyLoading._internal();
  131. }
  132. return _instance;
  133. }
  134. /// show loading with [status]
  135. /// [indicator] custom indicator
  136. static void show({
  137. String status,
  138. Widget indicator,
  139. }) {
  140. Widget w = indicator ?? LoadingIndicator();
  141. _getInstance()._show(status: status, w: w, isShow: true);
  142. }
  143. /// show progress with [value] [status], value should be 0.0 ~ 1.0.
  144. static void showProgress(
  145. double value, {
  146. String status,
  147. }) {
  148. assert(value >= 0.0 && value <= 1.0, 'value should be 0.0 ~ 1.0');
  149. if (_getInstance().progress == null) {
  150. GlobalKey<ProgressState> _progressKey = GlobalKey<ProgressState>();
  151. Widget w = Progress(
  152. key: _progressKey,
  153. value: value,
  154. );
  155. _getInstance()._show(
  156. status: status,
  157. w: w,
  158. );
  159. _getInstance()._progressKey = _progressKey;
  160. _getInstance()._progress = w;
  161. }
  162. _getInstance()
  163. .progressKey
  164. .currentState
  165. ?.updateProgress(value >= 1 ? 1 : value);
  166. if (status != null) {
  167. _getInstance().key.currentState?.updateStatus(status);
  168. }
  169. }
  170. /// showSuccess [status] [duration]
  171. static void showSuccess(
  172. String status, {
  173. Duration duration,
  174. }) {
  175. Widget w = _getInstance().successWidget ??
  176. Icon(
  177. Icons.done,
  178. color: EasyLoadingTheme.indicatorColor,
  179. size: EasyLoadingTheme.indicatorSize,
  180. );
  181. _getInstance()._show(
  182. status: status,
  183. duration: duration ?? EasyLoadingTheme.displayDuration,
  184. w: w,
  185. );
  186. }
  187. /// showError [status] [duration]
  188. static void showError(
  189. String status, {
  190. Duration duration,
  191. }) {
  192. Widget w = _getInstance().errorWidget ??
  193. Icon(
  194. Icons.clear,
  195. color: EasyLoadingTheme.indicatorColor,
  196. size: EasyLoadingTheme.indicatorSize,
  197. );
  198. _getInstance()._show(
  199. status: status,
  200. duration: duration ?? EasyLoadingTheme.displayDuration,
  201. w: w,
  202. );
  203. }
  204. /// showInfo [status] [duration]
  205. static void showInfo(
  206. String status, {
  207. Duration duration,
  208. }) {
  209. Widget w = _getInstance().infoWidget ??
  210. Icon(
  211. Icons.info_outline,
  212. color: EasyLoadingTheme.indicatorColor,
  213. size: EasyLoadingTheme.indicatorSize,
  214. );
  215. _getInstance()._show(
  216. status: status,
  217. duration: duration ?? EasyLoadingTheme.displayDuration,
  218. w: w,
  219. );
  220. }
  221. /// showToast [status] [duration]
  222. static void showToast(
  223. String status, {
  224. Duration duration,
  225. }) {
  226. EasyLoading.instance
  227. ..contentPadding = EdgeInsets.symmetric(horizontal: 20, vertical: 12)
  228. ..alignment = Alignment.center
  229. ..loadingStyle = EasyLoadingStyle.light
  230. ..contentMargin = EdgeInsets.all(20);
  231. _getInstance()._show(
  232. status: status,
  233. duration: duration ?? EasyLoadingTheme.displayDuration,
  234. );
  235. }
  236. /// dismiss loading
  237. static void dismiss({
  238. bool animation = true,
  239. }) async {
  240. // cancel timer
  241. _getInstance()._cancelTimer();
  242. if (animation) {
  243. LoadingContainerState loadingContainerState =
  244. _getInstance().key?.currentState;
  245. if (loadingContainerState != null) {
  246. final Completer<void> completer = Completer<void>();
  247. loadingContainerState.dismiss(completer);
  248. completer.future.then((value) {
  249. _getInstance()._remove();
  250. });
  251. return;
  252. }
  253. }
  254. _getInstance()._remove();
  255. }
  256. /// show loading
  257. void _show({Widget w, String status, Duration duration, bool isShow}) {
  258. _cancelTimer();
  259. if (_getInstance().loadingStyle == EasyLoadingStyle.custom) {
  260. assert(
  261. _getInstance().backgroundColor != null,
  262. 'while loading style is custom, backgroundColor should not be null',
  263. );
  264. assert(
  265. _getInstance().indicatorColor != null,
  266. 'while loading style is custom, indicatorColor should not be null',
  267. );
  268. assert(
  269. _getInstance().progressColor != null,
  270. 'while loading style is custom, progressColor should not be null',
  271. );
  272. assert(
  273. _getInstance().textColor != null,
  274. 'while loading style is custom, textColor should not be null',
  275. );
  276. }
  277. if (_getInstance().maskType == EasyLoadingMaskType.custom) {
  278. assert(
  279. _getInstance().maskColor != null,
  280. 'while mask type is custom, maskColor should not be null',
  281. );
  282. }
  283. GlobalKey<LoadingContainerState> _key = GlobalKey<LoadingContainerState>();
  284. bool _animation = _getInstance().overlayEntry == null;
  285. _remove();
  286. OverlayEntry _overlayEntry = OverlayEntry(
  287. builder: (BuildContext context) => LoadingContainer(
  288. key: _key,
  289. status: status,
  290. indicator: w,
  291. animation: _animation,
  292. ),
  293. );
  294. Overlay.of(_getInstance().context).insert(_overlayEntry);
  295. _getInstance()._overlayEntry = _overlayEntry;
  296. _getInstance()._key = _key;
  297. if (duration != null) {
  298. _getInstance()._timer = Timer.periodic(duration, (Timer timer) {
  299. dismiss();
  300. });
  301. }
  302. }
  303. void _cancelTimer() {
  304. _getInstance().timer?.cancel();
  305. _getInstance()._timer = null;
  306. }
  307. void _remove() {
  308. _getInstance().overlayEntry?.remove();
  309. _getInstance()._overlayEntry = null;
  310. _getInstance()._key = null;
  311. _getInstance()._progress = null;
  312. _getInstance()._progressKey = null;
  313. }
  314. }