template.dart 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. import 'dart:async';
  2. import 'dart:convert';
  3. import 'dart:io';
  4. import 'dart:ui' as ui;
  5. import 'package:another_flushbar/flushbar.dart';
  6. import 'package:auto_route/auto_route.dart';
  7. import 'package:cached_network_image/cached_network_image.dart';
  8. import 'package:dotted_line/dotted_line.dart';
  9. import 'package:easy_localization/easy_localization.dart';
  10. import 'package:flutter/foundation.dart';
  11. import 'package:flutter/material.dart';
  12. import 'package:flutter/services.dart';
  13. import 'package:flutter_cache_manager/flutter_cache_manager.dart';
  14. import 'package:fluttertoast/fluttertoast.dart';
  15. import 'package:loading_indicator/loading_indicator.dart';
  16. import 'package:lottie/lottie.dart';
  17. import 'package:page_transition/page_transition.dart';
  18. import 'package:photo_view/photo_view.dart';
  19. import 'package:photo_view/photo_view_gallery.dart';
  20. import 'package:provider/provider.dart';
  21. import 'package:telnow_mobile_new/src/api/api_auth_provider.dart';
  22. import 'package:telnow_mobile_new/src/api/jwt_token.dart';
  23. import 'package:telnow_mobile_new/src/injector/injector.dart';
  24. import 'package:telnow_mobile_new/src/layouts/auth/qr.dart';
  25. import 'package:telnow_mobile_new/src/storage/sharedpreferences/shared_preferences_manager.dart';
  26. import 'package:telnow_mobile_new/src/utils/U.dart';
  27. import 'package:telnow_mobile_new/src/utils/cache_manager.dart';
  28. import 'package:telnow_mobile_new/src/utils/dio_logging_interceptors.dart';
  29. import 'package:uuid/uuid.dart';
  30. import '../../utils/provider.dart';
  31. PreferredSizeWidget appBarTemplate({required BuildContext context, required String title, String icon = 'arrow-left', List<Widget>? action, exc = false}){
  32. return AppBar(
  33. elevation: 0,
  34. bottomOpacity: 0,
  35. backgroundColor: backgroundColor,
  36. leading: GestureDetector(
  37. child: U.iconsax(icon, color: textColor),
  38. onTap: ()=>Navigator.of(context).pop(exc),
  39. ),
  40. titleSpacing: 0,
  41. title: Text(title, style: TextStyle(color: textColor, fontSize: 17, fontWeight: FontWeight.w500), overflow: TextOverflow.ellipsis),
  42. actions: action,
  43. );
  44. }
  45. Widget buttonTemplate({double width = double.infinity, double height = 51, required String text, required action(), backgroundColor = primaryColor, textColor = Colors.white, borderColor = primaryColor}){
  46. return SizedBox(
  47. width: width,
  48. height: height,
  49. child: ElevatedButton(
  50. style: ButtonStyle(
  51. elevation: MaterialStateProperty.all<double>(0),
  52. backgroundColor: MaterialStateProperty.all<Color>(backgroundColor),
  53. shape: MaterialStateProperty.all<RoundedRectangleBorder>(RoundedRectangleBorder(borderRadius: BorderRadius.circular(12))),
  54. side: MaterialStateProperty.all<BorderSide>(BorderSide(color: borderColor))
  55. ),
  56. onPressed: ()=>action(),
  57. child: Text(text, style: TextStyle(fontSize: 16, color: textColor, fontWeight: FontWeight.w500)),
  58. ),
  59. );
  60. }
  61. Widget textVertical(String title, String subtitle){
  62. return Column(
  63. crossAxisAlignment: CrossAxisAlignment.start,
  64. children: [
  65. Text(title, style: TextStyle(color: textColor)),
  66. SizedBox(height: 5),
  67. Text(subtitle, style: TextStyle(color: textColor, fontSize: 12, fontWeight: FontWeight.w300)),
  68. ],
  69. );
  70. }
  71. Widget textHorizontal(String title, String subtitle, {double size = 14, double opacity = 1, bool copy = false}){
  72. return Row(
  73. crossAxisAlignment: CrossAxisAlignment.start,
  74. children: [
  75. Text(title, style: TextStyle(color: textColor.withValues(alpha: opacity), fontSize: size)),
  76. Expanded(
  77. child: copy?Row(
  78. mainAxisAlignment: MainAxisAlignment.end,
  79. children: [
  80. Expanded(child: Text(subtitle, style: TextStyle(color: textColor, fontSize: size), maxLines: 3, overflow: TextOverflow.ellipsis, textAlign: TextAlign.end)),
  81. SizedBox(width: 5),
  82. InkWell(
  83. child: Icon(Icons.copy, color: textColor, size: size+2),
  84. onTap: ()async{
  85. await Clipboard.setData(ClipboardData(text: subtitle));
  86. Fluttertoast.showToast(msg: 'link_copied'.tr());
  87. },
  88. ),
  89. ],
  90. ):Text("$subtitle", style: TextStyle(color: textColor, fontSize: size), maxLines: 3, overflow: TextOverflow.ellipsis, textAlign: TextAlign.end,),
  91. ),
  92. ],
  93. );
  94. }
  95. Widget divider({opacity = 0.15, EdgeInsetsGeometry padding = const EdgeInsets.only(top: 0)}){
  96. return Padding(
  97. padding: padding,
  98. child: Divider(height: 1, thickness: 1, color: textColor.withValues(alpha: opacity)),
  99. );
  100. }
  101. Widget dashed({double top = 8, double bottom = 8, double left = 0, double right = 0, Color color = textColor, double width = double.infinity}){
  102. return Padding(padding: EdgeInsets.only(top: top, bottom: bottom, left: left, right: right), child: DottedLine(dashColor: color, lineLength: width, dashLength: 5, dashGapLength: 5, lineThickness: 0.15, dashRadius: 1));
  103. }
  104. Widget separator(){
  105. return Container(
  106. color: Color(0xffF3F3F3),
  107. width: double.infinity, height: 8,
  108. );
  109. }
  110. //------------------------------------------------------------------------------
  111. Widget categoryContainer({required BuildContext context, required String iconUrl}){
  112. double size = U.bodyWidth(context)/6;
  113. String ext = iconUrl.split(".").last;
  114. return Container(
  115. padding: EdgeInsets.all(5),
  116. child: Image(image: CachedNetworkImageProvider(iconUrl+'?bridge-cache=true', cacheManager: CacheManager(CacheMan.config(iconUrl+'?bridge-cache=true'))), width: size, height: size),
  117. decoration: BoxDecoration(
  118. color: Colors.white,
  119. borderRadius: BorderRadius.all(Radius.circular(20)),
  120. border: Border.all(width: 0.2, color: Colors.black12),
  121. boxShadow: [BoxShadow(color: Colors.grey.withValues(alpha: 0.3), blurRadius: 2, offset: Offset(0, 2))]
  122. ),
  123. );
  124. }
  125. Widget shimmerTopMenu(BuildContext context){
  126. double size = (U.bodyWidth(context)/6)+10;
  127. return Row(
  128. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  129. children: List.generate(4, (index){
  130. return Container(
  131. width: size, height: size,
  132. decoration: BoxDecoration(
  133. color: Colors.black26,
  134. borderRadius: BorderRadius.all(Radius.circular(20)),
  135. ),
  136. );
  137. // return Shimmer.fromColors(
  138. // baseColor: Colors.grey[400]!,
  139. // highlightColor: Colors.white,
  140. // child: Container(
  141. // width: size, height: size,
  142. // decoration: BoxDecoration(
  143. // color: Colors.white,
  144. // borderRadius: BorderRadius.all(Radius.circular(20)),
  145. // ),
  146. // ),
  147. // );
  148. }),
  149. );
  150. }
  151. //------------------------------------------------------------------------------
  152. Widget requestTiles({required String image, required String title, required String subtitle, bool border = false, double vertical = 16}){
  153. return Container(
  154. margin: EdgeInsets.symmetric(vertical: vertical),
  155. padding: EdgeInsetsDirectional.only(end: border?16:0),
  156. child: Row(
  157. children: [
  158. imageTiles(imageUrl: image),
  159. SizedBox(width: 16),
  160. Expanded(
  161. child: Column(
  162. crossAxisAlignment: CrossAxisAlignment.start,
  163. children: [
  164. Text(title, style: TextStyle(color: textColor, fontWeight: FontWeight.w500), overflow: TextOverflow.ellipsis),
  165. dashed(),
  166. Text(subtitle, style: TextStyle(color: textColor, fontSize: 13, fontWeight: FontWeight.w300), maxLines: 2, overflow: TextOverflow.ellipsis)
  167. ],
  168. ),
  169. )
  170. ],
  171. ),
  172. decoration: BoxDecoration(
  173. color: Colors.white,
  174. border: border?Border.all(color: textColor.withValues(alpha: 0.15)):null,
  175. borderRadius: border?BorderRadius.all(Radius.circular(12)):null
  176. ),
  177. );
  178. }
  179. Widget imageTiles({required String imageUrl, double width = 100, double height = 80, double radius = 12}){
  180. return imageUrl != "null" ? Container(
  181. padding: EdgeInsets.fromLTRB(1, 0, 1, 0),
  182. decoration: BoxDecoration(
  183. color: textColor.withValues(alpha: 0.1),
  184. borderRadius: BorderRadius.all(Radius.circular(radius)),
  185. ),
  186. child: Container(
  187. width: width, height: height,
  188. decoration: BoxDecoration(
  189. color: textColor.withValues(alpha: 0.1),
  190. borderRadius: BorderRadius.all(Radius.circular(radius)),
  191. image: DecorationImage(
  192. image: CachedNetworkImageProvider(imageUrl+'?bridge-cache=true', cacheManager: CacheManager(CacheMan.config(imageUrl+'?bridge-cache=true'))),
  193. fit: BoxFit.cover,
  194. ),
  195. ),
  196. ),
  197. ): Container(
  198. height: height,
  199. width: width,
  200. child: Center(child: Text("noImage".tr(), style: TextStyle(fontStyle: FontStyle.italic, fontSize: width<100?10:14, color: Colors.black38), maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center,)),
  201. decoration: BoxDecoration(
  202. color: Colors.black12,
  203. borderRadius: BorderRadius.all(Radius.circular(12.0))
  204. ),
  205. );
  206. }
  207. Widget loginFieldTemplate({required String value, placeholder = '', required action(value), required submit(value), isPassword = false}){
  208. TextEditingController controller = TextEditingController()..text = value;
  209. bool hidePass = true;
  210. return SizedBox(
  211. width: double.infinity,
  212. child: StatefulBuilder(
  213. builder: (context, fieldState) => TextFormField(
  214. controller: controller,
  215. style: TextStyle(fontSize: 16, color: Colors.white),
  216. keyboardType: TextInputType.text,
  217. obscureText: isPassword?hidePass:false,
  218. cursorColor: Colors.white,
  219. decoration: InputDecoration(
  220. hintText: placeholder,
  221. hintStyle: TextStyle(fontSize: 16, color: Colors.white.withValues(alpha: 0.6)),
  222. filled: true,
  223. fillColor: Colors.white.withValues(alpha: 0.25),
  224. hoverColor: Colors.white.withValues(alpha: 0.26),
  225. contentPadding: EdgeInsets.all(16),
  226. border: InputBorder.none,
  227. suffixIconConstraints: BoxConstraints(maxHeight: 40, maxWidth: 40, minHeight: 40, minWidth: 40),
  228. suffixIcon: isPassword?GestureDetector(child: U.iconsax(hidePass?'eye':'eye-slash', color: Colors.white.withValues(alpha: 0.6)), onTap: ()=>fieldState(()=>hidePass=!hidePass)):null,
  229. enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.white)),
  230. focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.white)),
  231. isDense: true
  232. ),
  233. onChanged: (val)=>action(val.toString()),
  234. onFieldSubmitted: (val)=>submit(val.toString()),
  235. ),
  236. ),
  237. );
  238. }
  239. Widget loadingTemplate(VoidCallback setState){
  240. Future.delayed(Duration(seconds: 10),() {
  241. setState();
  242. });
  243. return Center(
  244. child: Container(
  245. height: 36,
  246. child: LoadingIndicator(
  247. indicatorType: Indicator.ballPulseRise,
  248. colors: U.defaultRainbowColors(),
  249. strokeWidth: 2,
  250. backgroundColor: Colors.black.withValues(alpha: 0),
  251. pathBackgroundColor: Colors.black,
  252. ),
  253. ),
  254. );
  255. }
  256. Widget showButton(BuildContext context){
  257. var pid = U.getPidFromUrl(context.router.currentUrl);
  258. return Center(
  259. child: GestureDetector(
  260. onTap: (){
  261. context.router.removeLast();
  262. context.navigateToPath("/app/$pid/login");
  263. },
  264. child: Container(
  265. decoration: BoxDecoration(color: Colors.amber.withAlpha(0)),
  266. height: MediaQuery.of(context).size.height,
  267. width: MediaQuery.of(context).size.width,
  268. child: Center(
  269. child: Column(
  270. mainAxisAlignment: MainAxisAlignment.center,
  271. children: [
  272. Text("failedLoad".tr()),
  273. SizedBox(height: 12,),
  274. Container(
  275. decoration: BoxDecoration(
  276. border: Border.all(color: Color(0xFFA5A5A5)),
  277. borderRadius: BorderRadius.all(Radius.circular(4))
  278. ),
  279. child: Padding(
  280. padding: const EdgeInsets.all(8.0),
  281. child: Text("tap2retry".tr()),
  282. ),
  283. )
  284. ],
  285. )
  286. )
  287. ),
  288. ),
  289. );
  290. }
  291. Widget infoContainer(String text){
  292. return Container(
  293. width: double.infinity,
  294. padding: EdgeInsets.all(12),
  295. child: Text(text, style: TextStyle(color: textColor), textAlign: TextAlign.center),
  296. decoration: BoxDecoration(
  297. color: secondaryColor.withValues(alpha: 0.1),
  298. border: Border.all(color: secondaryColor),
  299. borderRadius: BorderRadius.all(Radius.circular(12))
  300. ),
  301. );
  302. }
  303. class PhotoPreview extends StatelessWidget {
  304. final title;
  305. final imageUrl;
  306. final bool isUrl;
  307. final bool isNetwork;
  308. PhotoPreview(this.title, this.imageUrl, this.isUrl, {this.isNetwork = false});
  309. @override
  310. Widget build(BuildContext context) {
  311. return Scaffold(
  312. backgroundColor: Colors.black,
  313. appBar: AppBar(
  314. elevation: 0,
  315. bottomOpacity: 0,
  316. titleSpacing: 0,
  317. title: Text(title, style: TextStyle(color: Colors.white, fontSize: 17, fontWeight: FontWeight.w500), overflow: TextOverflow.ellipsis),
  318. backgroundColor: Colors.black.withValues(alpha: 0.4),
  319. leading: GestureDetector(
  320. child: U.iconsax('arrow-left', color: Colors.white),
  321. onTap: () => Navigator.of(context).pop(),
  322. ),
  323. ),
  324. body: Container(
  325. width: MediaQuery.of(context).size.width,
  326. height: MediaQuery.of(context).size.height,
  327. child: PhotoView(
  328. maxScale: 5.0,
  329. minScale: 0.3,
  330. imageProvider: (isUrl ? NetworkImage(imageUrl) : isNetwork ? MemoryImage(imageUrl) : FileImage(imageUrl)) as ImageProvider<Object>?,
  331. )),
  332. );
  333. }
  334. }
  335. class PhotoPreviewGallery extends StatelessWidget {
  336. final String title;
  337. final List imageList;
  338. final int startIndex;
  339. final bool isUrl;
  340. final String column;
  341. const PhotoPreviewGallery({required this.title, required this.imageList, required this.startIndex, this.isUrl = true, this.column = 'image', super.key});
  342. @override
  343. Widget build(BuildContext context) {
  344. return Scaffold(
  345. backgroundColor: Colors.black,
  346. appBar: AppBar(
  347. title: Text(title, style: TextStyle(fontSize: 18)),
  348. backgroundColor: Colors.black.withValues(alpha: 0.4),
  349. titleSpacing: 0,
  350. leading: new IconButton(
  351. icon: new Icon(Icons.arrow_back_rounded),
  352. onPressed: () => Navigator.of(context).pop(),
  353. ),
  354. ),
  355. body: Container(
  356. width: MediaQuery.of(context).size.width,
  357. height: MediaQuery.of(context).size.height,
  358. child: PhotoViewGallery.builder(
  359. itemCount: imageList.length,
  360. pageController: PageController(initialPage: startIndex),
  361. builder: (context, index) {
  362. var uuid = Uuid().v1().replaceAll('-', '');
  363. return PhotoViewGalleryPageOptions(
  364. imageProvider: (isUrl?NetworkImage(imageList[index][column]+'?uuid='+uuid):imageList[index] is File?FileImage(imageList[index]):MemoryImage(imageList[index])) as ImageProvider<Object>?,
  365. maxScale: 5.0, minScale: 0.3,
  366. );
  367. },
  368. )
  369. ),
  370. );
  371. }
  372. }
  373. //------------------------------------------------------------------------------
  374. class MyClipper extends CustomClipper<Path> {
  375. final isNip;
  376. MyClipper(this.isNip);
  377. @override
  378. Path getClip(Size size) {
  379. var path = Path();
  380. double factor = 6.0;
  381. path.lineTo(0, size.height - factor);
  382. path.quadraticBezierTo(0, size.height, factor, size.height);
  383. if (isNip) {
  384. path.lineTo(size.width - (factor * 2), size.height);
  385. path.quadraticBezierTo(size.width - factor, size.height, size.width - factor, size.height - factor);
  386. path.lineTo(size.width - factor, factor);
  387. } else {
  388. path.lineTo(size.width - factor, size.height);
  389. path.quadraticBezierTo(size.width, size.height, size.width, size.height - factor);
  390. path.lineTo(size.width, factor);
  391. path.quadraticBezierTo(size.width, 0, size.width - factor, 0);
  392. }
  393. path.lineTo(size.width, 0);
  394. path.lineTo(factor, 0);
  395. path.quadraticBezierTo(0, 0, 0, factor);
  396. return path;
  397. }
  398. @override
  399. bool shouldReclip(CustomClipper oldClipper) => true;
  400. }
  401. class YourClipper extends CustomClipper<Path> {
  402. final isNip;
  403. YourClipper(this.isNip);
  404. @override
  405. Path getClip(Size size) {
  406. var path = Path();
  407. double factor = 6.0;
  408. if (isNip) {
  409. path.lineTo(factor, factor);
  410. path.lineTo(factor, size.height - factor);
  411. path.quadraticBezierTo(factor, size.height, factor * 2, size.height);
  412. } else {
  413. path.lineTo(0, size.height - factor);
  414. path.quadraticBezierTo(0, size.height, factor, size.height);
  415. }
  416. path.lineTo(size.width - factor, size.height);
  417. path.quadraticBezierTo(size.width, size.height, size.width, size.height - factor);
  418. path.lineTo(size.width, factor);
  419. path.quadraticBezierTo(size.width, 0, size.width - factor, 0);
  420. if (!isNip) {
  421. path.lineTo(factor, 0);
  422. path.quadraticBezierTo(0, 0, 0, factor);
  423. }
  424. return path;
  425. }
  426. @override
  427. bool shouldReclip(CustomClipper oldClipper) => true;
  428. }
  429. isBase64(value) {
  430. try {
  431. base64Decode(value);
  432. return true;
  433. } catch (e) {
  434. return false;
  435. }
  436. }
  437. //------------------------------------------------------------------------------
  438. class Debouncer {
  439. final int? milliseconds;
  440. VoidCallback? action;
  441. Timer? _timer;
  442. Debouncer({this.milliseconds});
  443. run(VoidCallback action) {
  444. if (null != _timer) {
  445. _timer?.cancel();
  446. }
  447. _timer = Timer(Duration(milliseconds: milliseconds!), action);
  448. }
  449. }
  450. navigateTo(BuildContext context, child){
  451. return Navigator.push(context, PageTransition(type: PageTransitionType.rightToLeft, child: child));
  452. }
  453. navigateToThen(BuildContext context, child, act){
  454. Navigator.push(context, PageTransition(type: PageTransitionType.rightToLeft, child: child)).then((v) => act());
  455. }
  456. navigateBack(BuildContext context, {exc = false}){
  457. return Navigator.of(context).pop(exc);
  458. }
  459. void showError(BuildContext context, message) {
  460. Flushbar(
  461. message: message,
  462. icon: Icon(
  463. Icons.info_outline,
  464. size: 28.0,
  465. color: Colors.red,
  466. ),
  467. duration: Duration(seconds: 5),
  468. flushbarPosition: FlushbarPosition.BOTTOM,
  469. margin: EdgeInsets.all(8),
  470. borderRadius: BorderRadius.all(Radius.circular(8)),
  471. )..show(context);
  472. }
  473. void showSuccess(context, message) {
  474. Flushbar(
  475. message: message,
  476. icon: Icon(
  477. Icons.info_outline,
  478. size: 28.0,
  479. color: Colors.green,
  480. ),
  481. duration: Duration(seconds: 5),
  482. flushbarPosition: FlushbarPosition.BOTTOM,
  483. margin: EdgeInsets.all(8),
  484. borderRadius: BorderRadius.all(Radius.circular(8)),
  485. )..show(context);
  486. }
  487. String convertDate(date, String locale) {
  488. if (date == "-" || date.isEmpty) {
  489. return date;
  490. }
  491. final dateToCheck = DateTime.parse(date);
  492. final now = DateTime.now();
  493. final today = DateTime(now.year, now.month, now.day);
  494. final yesterday = DateTime(now.year, now.month, now.day - 1);
  495. final aDate = DateTime(dateToCheck.year, dateToCheck.month, dateToCheck.day);
  496. if (aDate == today) {
  497. return 'today'.tr()+' '+DateFormat('HH:mm', locale).format(DateTime.parse(date));
  498. } else if (aDate == yesterday) {
  499. return 'yesterday'.tr()+' '+DateFormat('HH:mm', locale).format(DateTime.parse(date));
  500. } else {
  501. return DateFormat('dd MMM HH:mm', locale).format(DateTime.parse(date));
  502. }
  503. }
  504. //------------------------------------------------------------------------------
  505. class RefreshPage extends StatelessWidget {
  506. final VoidCallback onRefresh;
  507. RefreshPage(this.onRefresh);
  508. @override
  509. Widget build(BuildContext context) {
  510. return Container(
  511. padding: EdgeInsets.only(top: MediaQuery.of(context).size.height / 2.5),
  512. height: MediaQuery.of(context).size.height,
  513. child: Center(
  514. child: GestureDetector(
  515. child: Column(
  516. children: [
  517. Icon(Icons.refresh_rounded, size: 50, color: Colors.grey),
  518. Text('refresh'.tr(), style: TextStyle(color: Colors.grey))
  519. ],
  520. ),
  521. onTap: () => onRefresh(),
  522. ),
  523. ),
  524. );
  525. }
  526. }
  527. //------------------------------------------------------------------------------
  528. final JwtToken token = JwtToken();
  529. final SharedPreferencesManager _sharedPreferencesManager = locator<SharedPreferencesManager>();
  530. class NoDataPage extends StatelessWidget {
  531. @override
  532. Widget build(BuildContext context) {
  533. return Center(
  534. child: Column(
  535. mainAxisSize: MainAxisSize.min,
  536. children: <Widget>[
  537. kIsWeb && !isCanvasKit ? Container(
  538. width: 150, margin: EdgeInsets.only(top: 20, bottom: 10), padding: EdgeInsets.all(10),
  539. child: Image(image: AssetImage('assets/image/error/EmptyData.png'))
  540. ) : Lottie.asset('assets/image/lottie/Nodata.json', width: 250, height: 250, fit: BoxFit.fill),
  541. Padding(
  542. padding: const EdgeInsets.fromLTRB(15, 0, 15, 10),
  543. child: Text('notFound'.tr(),
  544. style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
  545. textAlign: TextAlign.center),
  546. ),
  547. Padding(
  548. padding: const EdgeInsets.fromLTRB(15, 0, 15, 10),
  549. child: Text('notFound2'.tr(),
  550. style: TextStyle(fontSize: 14), textAlign: TextAlign.center),
  551. )
  552. ],
  553. ),
  554. );
  555. }
  556. }
  557. handlingError(context, type) {
  558. var data = [
  559. {
  560. 'image': 'NoInternet.png',
  561. 'title': 'noInternetTitle'.tr(),
  562. 'description': 'noInternetDesc'.tr()
  563. },
  564. {
  565. 'image': 'ErrorServer.png',
  566. 'title': 'errorServerTitle'.tr(),
  567. 'description': 'errorServerDesc'.tr()
  568. },
  569. {
  570. 'image': 'ErrorConnection.png',
  571. 'title': 'errorConnectTitle'.tr(),
  572. 'description': 'errorConnectDesc'.tr()
  573. },
  574. {
  575. 'image': 'ErrorAuth.png',
  576. 'title': 'invalidAccountTitle'.tr(),
  577. 'description': 'invalidAccountDesc'.tr()
  578. },
  579. {
  580. 'image': 'ErrorAuth.png',
  581. 'title': 'expAccountTitle'.tr(),
  582. 'description': 'expAccountDesc'.tr()
  583. }
  584. ];
  585. showModalBottomSheet<void>(
  586. context: context,
  587. backgroundColor: Colors.white,
  588. isDismissible: false,
  589. enableDrag: false,
  590. builder: (BuildContext context) {
  591. return SingleChildScrollView(
  592. child: Column(
  593. mainAxisSize: MainAxisSize.min,
  594. children: <Widget>[
  595. Container(
  596. padding: const EdgeInsets.fromLTRB(15, 10, 15, 0),
  597. alignment: Alignment.centerRight,
  598. child: GestureDetector(
  599. child: Icon(Icons.clear),
  600. onTap: () => Navigator.of(context).pop(),
  601. ),
  602. ),
  603. Container(
  604. width: 200,
  605. padding: const EdgeInsets.fromLTRB(15, 0, 15, 10),
  606. child: Image(
  607. image: AssetImage('assets/image/error/' + data[type]['image']!))),
  608. Padding(
  609. padding: const EdgeInsets.fromLTRB(15, 0, 15, 10),
  610. child: Text(data[type]['title']!,
  611. style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
  612. textAlign: TextAlign.center),
  613. ),
  614. Padding(
  615. padding: const EdgeInsets.fromLTRB(15, 0, 15, 10),
  616. child: Text(data[type]['description']!,
  617. style: TextStyle(fontSize: 14),
  618. textAlign: TextAlign.center),
  619. ),
  620. type > 2
  621. ? Padding(
  622. padding: const EdgeInsets.fromLTRB(15, 0, 15, 10),
  623. child: SizedBox(
  624. width: double.infinity,
  625. height: 45,
  626. child: TextButton(
  627. style: ButtonStyle(
  628. backgroundColor:
  629. MaterialStateProperty.all<Color>(primaryColor),
  630. shape: MaterialStateProperty.all<
  631. RoundedRectangleBorder>(
  632. RoundedRectangleBorder(
  633. borderRadius: BorderRadius.circular(5),
  634. ))),
  635. child: new Text('logout'.tr().toUpperCase(),
  636. style: TextStyle(color: Colors.white),
  637. textAlign: TextAlign.center),
  638. onPressed: () {
  639. if (type == 4) {
  640. _sharedPreferencesManager.clearKey(
  641. SharedPreferencesManager.keyAccessCode);
  642. _sharedPreferencesManager.clearKey(
  643. SharedPreferencesManager.keySerialCode);
  644. _sharedPreferencesManager.clearKey(
  645. SharedPreferencesManager.keyAccessToken);
  646. _sharedPreferencesManager.clearKey(
  647. SharedPreferencesManager.keyRefreshToken);
  648. _sharedPreferencesManager.clearKey(
  649. SharedPreferencesManager.keyUsername);
  650. _sharedPreferencesManager.clearKey(
  651. SharedPreferencesManager.keyIsLogin);
  652. _sharedPreferencesManager.clearKey(
  653. SharedPreferencesManager.keyScoope);
  654. _sharedPreferencesManager.clearKey(
  655. SharedPreferencesManager.debugString);
  656. _sharedPreferencesManager.clearKey(SharedPreferencesManager.keyHistoryMark);
  657. Navigator.pushAndRemoveUntil(
  658. context,
  659. MaterialPageRoute(
  660. builder: (context) => NewQrPage()),
  661. ModalRoute.withName("/home"));
  662. } else {
  663. var pid = U.getPidFromUrl(context.router.currentUrl);
  664. token.logout();
  665. context.router.removeLast();
  666. context.navigateToPath("/app/$pid/login");
  667. // print(pid);
  668. // context.router.removeLast();
  669. // context.navigateToPath('/app/$pid/login');
  670. }
  671. },
  672. )),
  673. )
  674. : Container(height: 1, width: 1)
  675. ],
  676. ),
  677. );
  678. });
  679. }
  680. // ignore: must_be_immutable
  681. class NoImageFound extends StatelessWidget {
  682. bool show = true;
  683. NoImageFound(this.show);
  684. @override
  685. Widget build(BuildContext context) {
  686. return Container(
  687. width: MediaQuery.of(context).size.width - 150,
  688. height: MediaQuery.of(context).size.height / 4,
  689. child: Stack(
  690. fit: StackFit.expand,
  691. children: [
  692. Image.asset('assets/image/general/QrCode.jpg', fit: BoxFit.cover),
  693. ClipRRect(
  694. // Clip it cleanly.
  695. child: BackdropFilter(
  696. filter: ui.ImageFilter.blur(sigmaX: 10, sigmaY: 10),
  697. child: Container(
  698. color: Colors.grey.withValues(alpha: 0.5),
  699. alignment: Alignment.center,
  700. child: show
  701. ? Container(
  702. padding: const EdgeInsets.all(10),
  703. child: Text('notFoundImg'.tr(),
  704. style: TextStyle(fontSize: 12)),
  705. decoration: BoxDecoration(
  706. color: Colors.white24,
  707. borderRadius:
  708. BorderRadius.all(Radius.circular(50))),
  709. )
  710. : Center(
  711. child: CircularProgressIndicator(),
  712. ),
  713. ),
  714. ),
  715. ),
  716. ],
  717. ),
  718. );
  719. }
  720. }
  721. dialogConfirm({required BuildContext context, required String title, required String text, required Function actionYes}){
  722. showDialog(
  723. context: context,
  724. builder: (BuildContext context) {
  725. return AlertDialog(
  726. title: Text(title),
  727. content: Text(text),
  728. actions: <Widget>[
  729. TextButton(
  730. child: Text("buttonNo".tr()),
  731. onPressed: () {
  732. Navigator.of(context).pop();
  733. },
  734. ),
  735. TextButton(
  736. onPressed: (){
  737. Navigator.of(context).pop();
  738. actionYes();
  739. },
  740. child: Text("buttonYes".tr())),
  741. ],
  742. );
  743. },
  744. );
  745. }
  746. showLoading(BuildContext context, {String? text, String? lottie}){
  747. showDialog(
  748. context: context,
  749. barrierDismissible: false,
  750. barrierColor: lottie!=null?Colors.white:null,
  751. builder: (BuildContext context) {
  752. return WillPopScope(
  753. onWillPop: ()=>Future.value(false),
  754. child: Center(
  755. child: Column(
  756. mainAxisSize: MainAxisSize.min,
  757. children: [
  758. lottie != null ? Lottie.asset('assets/image/lottie/$lottie', width: 250, height: 250, fit: BoxFit.fill) : CircularProgressIndicator(color: primaryColor),
  759. SizedBox(height: 5),
  760. Text(text??'inProcess'.tr(), style: TextStyle(color: lottie!=null?Colors.black:Colors.white))
  761. ],
  762. ),
  763. ),
  764. );
  765. },
  766. );
  767. }
  768. closeLoading(BuildContext context){
  769. Navigator.of(context, rootNavigator: true).pop();
  770. }