import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:ui'; import 'package:another_flushbar/flushbar.dart'; import 'package:auto_route/auto_route.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:dotted_line/dotted_line.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:loading_indicator/loading_indicator.dart'; import 'package:lottie/lottie.dart'; import 'package:page_transition/page_transition.dart'; import 'package:photo_view/photo_view.dart'; import 'package:photo_view/photo_view_gallery.dart'; import 'package:telnow_mobile_new/src/api/api_auth_provider.dart'; import 'package:telnow_mobile_new/src/api/jwt_token.dart'; import 'package:telnow_mobile_new/src/injector/injector.dart'; import 'package:telnow_mobile_new/src/layouts/auth/qr.dart'; import 'package:telnow_mobile_new/src/storage/sharedpreferences/shared_preferences_manager.dart'; import 'package:telnow_mobile_new/src/utils/U.dart'; import 'package:telnow_mobile_new/src/utils/cache_manager.dart'; import 'package:uuid/uuid.dart'; PreferredSizeWidget appBarTemplate({required BuildContext context, required String title, String icon = 'arrow-left', List? action, exc = false}){ return AppBar( elevation: 0, bottomOpacity: 0, backgroundColor: backgroundColor, leading: GestureDetector( child: U.iconsax(icon, color: textColor), onTap: ()=>Navigator.of(context).pop(exc), ), titleSpacing: 0, title: Text(title, style: TextStyle(color: textColor, fontSize: 17, fontWeight: FontWeight.w500), overflow: TextOverflow.ellipsis), actions: action, ); } Widget buttonTemplate({double width = double.infinity, double height = 51, required String text, required action(), backgroundColor = primaryColor, textColor = Colors.white, borderColor = primaryColor}){ return SizedBox( width: width, height: height, child: ElevatedButton( style: ButtonStyle( elevation: MaterialStateProperty.all(0), backgroundColor: MaterialStateProperty.all(backgroundColor), shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(12))), side: MaterialStateProperty.all(BorderSide(color: borderColor)) ), onPressed: ()=>action(), child: Text(text, style: TextStyle(fontSize: 16, color: textColor, fontWeight: FontWeight.w500)), ), ); } Widget textVertical(String title, String subtitle){ return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: TextStyle(color: textColor)), SizedBox(height: 5), Text(subtitle, style: TextStyle(color: textColor, fontSize: 12, fontWeight: FontWeight.w300)), ], ); } Widget textHorizontal(String title, String subtitle, {double size = 14, double opacity = 1, bool copy = false}){ return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: TextStyle(color: textColor.withValues(alpha: opacity), fontSize: size)), Expanded( child: copy?Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Expanded(child: Text(subtitle, style: TextStyle(color: textColor, fontSize: size), maxLines: 3, overflow: TextOverflow.ellipsis, textAlign: TextAlign.right)), SizedBox(width: 5), InkWell( child: Icon(Icons.copy, color: textColor, size: size+2), onTap: ()async{ await Clipboard.setData(ClipboardData(text: subtitle)); Fluttertoast.showToast(msg: 'Copied to Clipboard!'.tr()); }, ), ], ):Text(subtitle, style: TextStyle(color: textColor, fontSize: size), maxLines: 3, overflow: TextOverflow.ellipsis, textAlign: TextAlign.right), ), ], ); } Widget divider({opacity = 0.15}){ return Divider(height: 1, thickness: 1, color: textColor.withValues(alpha: opacity)); } Widget dashed({double top = 8, double bottom = 8, double left = 0, double right = 0, Color color = textColor, double width = double.infinity}){ 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)); } Widget separator(){ return Container( color: Color(0xffF3F3F3), width: double.infinity, height: 8, ); } //------------------------------------------------------------------------------ Widget categoryContainer({required BuildContext context, required String iconUrl}){ double size = U.bodyWidth(context)/6; String ext = iconUrl.split(".").last; return Container( padding: EdgeInsets.all(5), child: Image(image: CachedNetworkImageProvider(iconUrl+'?bridge-cache=true', cacheManager: CacheManager(CacheMan.config(iconUrl+'?bridge-cache=true'))), width: size, height: size), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20)), border: Border.all(width: 0.2, color: Colors.black12), boxShadow: [BoxShadow(color: Colors.grey.withValues(alpha: 0.3), blurRadius: 2, offset: Offset(0, 2))] ), ); } Widget shimmerTopMenu(BuildContext context){ double size = (U.bodyWidth(context)/6)+10; return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: List.generate(4, (index){ return Container( width: size, height: size, decoration: BoxDecoration( color: Colors.black26, borderRadius: BorderRadius.all(Radius.circular(20)), ), ); // return Shimmer.fromColors( // baseColor: Colors.grey[400]!, // highlightColor: Colors.white, // child: Container( // width: size, height: size, // decoration: BoxDecoration( // color: Colors.white, // borderRadius: BorderRadius.all(Radius.circular(20)), // ), // ), // ); }), ); } //------------------------------------------------------------------------------ Widget requestTiles({required String image, required String title, required String subtitle, bool border = false, double vertical = 16}){ return Container( margin: EdgeInsets.symmetric(vertical: vertical), padding: EdgeInsets.only(right: border?16:0), child: Row( children: [ imageTiles(imageUrl: image), SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: TextStyle(color: textColor, fontWeight: FontWeight.w500), overflow: TextOverflow.ellipsis), dashed(), Text(subtitle, style: TextStyle(color: textColor, fontSize: 13, fontWeight: FontWeight.w300), maxLines: 2, overflow: TextOverflow.ellipsis) ], ), ) ], ), decoration: BoxDecoration( color: Colors.white, border: border?Border.all(color: textColor.withValues(alpha: 0.15)):null, borderRadius: border?BorderRadius.all(Radius.circular(12)):null ), ); } Widget imageTiles({required String imageUrl, double width = 100, double height = 80, double radius = 12}){ return imageUrl != "null" ? Container( padding: EdgeInsets.fromLTRB(1, 0, 1, 0), decoration: BoxDecoration( color: textColor.withValues(alpha: 0.1), borderRadius: BorderRadius.all(Radius.circular(radius)), ), child: Container( width: width, height: height, decoration: BoxDecoration( color: textColor.withValues(alpha: 0.1), borderRadius: BorderRadius.all(Radius.circular(radius)), image: DecorationImage( image: CachedNetworkImageProvider(imageUrl+'?bridge-cache=true', cacheManager: CacheManager(CacheMan.config(imageUrl+'?bridge-cache=true'))), fit: BoxFit.cover, ), ), ), ): Container( height: height, width: width, 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,)), decoration: BoxDecoration( color: Colors.black12, borderRadius: BorderRadius.all(Radius.circular(12.0)) ), ); } Widget loginFieldTemplate({required String value, placeholder = '', required action(value), required submit(value), isPassword = false}){ TextEditingController controller = TextEditingController()..text = value; bool hidePass = true; return SizedBox( width: double.infinity, child: StatefulBuilder( builder: (context, fieldState) => TextFormField( controller: controller, style: TextStyle(fontSize: 16, color: Colors.white), keyboardType: TextInputType.text, obscureText: isPassword?hidePass:false, cursorColor: Colors.white, decoration: InputDecoration( hintText: placeholder, hintStyle: TextStyle(fontSize: 16, color: Colors.white.withValues(alpha: 0.6)), filled: true, fillColor: Colors.white.withValues(alpha: 0.25), hoverColor: Colors.white.withValues(alpha: 0.26), contentPadding: EdgeInsets.all(16), border: InputBorder.none, suffixIconConstraints: BoxConstraints(maxHeight: 40, maxWidth: 40, minHeight: 40, minWidth: 40), suffixIcon: isPassword?GestureDetector(child: U.iconsax(hidePass?'eye':'eye-slash', color: Colors.white.withValues(alpha: 0.6)), onTap: ()=>fieldState(()=>hidePass=!hidePass)):null, enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.white)), focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.white)), isDense: true ), onChanged: (val)=>action(val.toString()), onFieldSubmitted: (val)=>submit(val.toString()), ), ), ); } Widget loadingTemplate(){ return Center( child: Container( height: 36, child: LoadingIndicator( indicatorType: Indicator.ballPulseRise, colors: U.defaultRainbowColors(), strokeWidth: 2, backgroundColor: Colors.black.withValues(alpha: 0), pathBackgroundColor: Colors.black, ), ), ); } Widget infoContainer(String text){ return Container( width: double.infinity, padding: EdgeInsets.all(12), child: Text(text, style: TextStyle(color: textColor), textAlign: TextAlign.center), decoration: BoxDecoration( color: secondaryColor.withValues(alpha: 0.1), border: Border.all(color: secondaryColor), borderRadius: BorderRadius.all(Radius.circular(12)) ), ); } class PhotoPreview extends StatelessWidget { final title; final imageUrl; final bool isUrl; final bool isNetwork; PhotoPreview(this.title, this.imageUrl, this.isUrl, {this.isNetwork = false}); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, appBar: AppBar( elevation: 0, bottomOpacity: 0, titleSpacing: 0, title: Text(title, style: TextStyle(color: Colors.white, fontSize: 17, fontWeight: FontWeight.w500), overflow: TextOverflow.ellipsis), backgroundColor: Colors.black.withValues(alpha: 0.4), leading: GestureDetector( child: U.iconsax('arrow-left', color: Colors.white), onTap: () => Navigator.of(context).pop(), ), ), body: Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, child: PhotoView( maxScale: 5.0, minScale: 0.3, imageProvider: (isUrl ? NetworkImage(imageUrl) : isNetwork ? MemoryImage(imageUrl) : FileImage(imageUrl)) as ImageProvider?, )), ); } } class PhotoPreviewGallery extends StatelessWidget { final String title; final List imageList; final int startIndex; final bool isUrl; final String column; const PhotoPreviewGallery({required this.title, required this.imageList, required this.startIndex, this.isUrl = true, this.column = 'image', super.key}); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, appBar: AppBar( title: Text(title, style: TextStyle(fontSize: 18)), backgroundColor: Colors.black.withValues(alpha: 0.4), titleSpacing: 0, leading: new IconButton( icon: new Icon(Icons.arrow_back_rounded), onPressed: () => Navigator.of(context).pop(), ), ), body: Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, child: PhotoViewGallery.builder( itemCount: imageList.length, pageController: PageController(initialPage: startIndex), builder: (context, index) { var uuid = Uuid().v1().replaceAll('-', ''); return PhotoViewGalleryPageOptions( imageProvider: (isUrl?NetworkImage(imageList[index][column]+'?uuid='+uuid):imageList[index] is File?FileImage(imageList[index]):MemoryImage(imageList[index])) as ImageProvider?, maxScale: 5.0, minScale: 0.3, ); }, ) ), ); } } //------------------------------------------------------------------------------ class MyClipper extends CustomClipper { final isNip; MyClipper(this.isNip); @override Path getClip(Size size) { var path = Path(); double factor = 6.0; path.lineTo(0, size.height - factor); path.quadraticBezierTo(0, size.height, factor, size.height); if (isNip) { path.lineTo(size.width - (factor * 2), size.height); path.quadraticBezierTo(size.width - factor, size.height, size.width - factor, size.height - factor); path.lineTo(size.width - factor, factor); } else { path.lineTo(size.width - factor, size.height); path.quadraticBezierTo(size.width, size.height, size.width, size.height - factor); path.lineTo(size.width, factor); path.quadraticBezierTo(size.width, 0, size.width - factor, 0); } path.lineTo(size.width, 0); path.lineTo(factor, 0); path.quadraticBezierTo(0, 0, 0, factor); return path; } @override bool shouldReclip(CustomClipper oldClipper) => true; } class YourClipper extends CustomClipper { final isNip; YourClipper(this.isNip); @override Path getClip(Size size) { var path = Path(); double factor = 6.0; if (isNip) { path.lineTo(factor, factor); path.lineTo(factor, size.height - factor); path.quadraticBezierTo(factor, size.height, factor * 2, size.height); } else { path.lineTo(0, size.height - factor); path.quadraticBezierTo(0, size.height, factor, size.height); } path.lineTo(size.width - factor, size.height); path.quadraticBezierTo(size.width, size.height, size.width, size.height - factor); path.lineTo(size.width, factor); path.quadraticBezierTo(size.width, 0, size.width - factor, 0); if (!isNip) { path.lineTo(factor, 0); path.quadraticBezierTo(0, 0, 0, factor); } return path; } @override bool shouldReclip(CustomClipper oldClipper) => true; } isBase64(value) { try { base64Decode(value); return true; } catch (e) { return false; } } //------------------------------------------------------------------------------ class Debouncer { final int? milliseconds; VoidCallback? action; Timer? _timer; Debouncer({this.milliseconds}); run(VoidCallback action) { if (null != _timer) { _timer?.cancel(); } _timer = Timer(Duration(milliseconds: milliseconds!), action); } } navigateTo(BuildContext context, child){ return Navigator.push(context, PageTransition(type: PageTransitionType.rightToLeft, child: child)); } navigateToThen(BuildContext context, child, act){ return Navigator.push(context, PageTransition(type: PageTransitionType.rightToLeft, child: child)).then((v) => act()); } navigateBack(BuildContext context, {exc = false}){ return Navigator.of(context).pop(exc); } void showError(BuildContext context, message) { Flushbar( message: message, icon: Icon( Icons.info_outline, size: 28.0, color: Colors.red, ), duration: Duration(seconds: 5), flushbarPosition: FlushbarPosition.BOTTOM, margin: EdgeInsets.all(8), borderRadius: BorderRadius.all(Radius.circular(8)), )..show(context); } void showSuccess(context, message) { Flushbar( message: message, icon: Icon( Icons.info_outline, size: 28.0, color: Colors.green, ), duration: Duration(seconds: 5), flushbarPosition: FlushbarPosition.BOTTOM, margin: EdgeInsets.all(8), borderRadius: BorderRadius.all(Radius.circular(8)), )..show(context); } String convertDate(date, locale) { if (date == "-" || date.isEmpty) { return date; } final dateToCheck = DateTime.parse(date); final now = DateTime.now(); final today = DateTime(now.year, now.month, now.day); final yesterday = DateTime(now.year, now.month, now.day - 1); final aDate = DateTime(dateToCheck.year, dateToCheck.month, dateToCheck.day); if (aDate == today) { return 'today'.tr()+' '+DateFormat('HH:mm', locale).format(DateTime.parse(date)); } else if (aDate == yesterday) { return 'yesterday'.tr()+' '+DateFormat('HH:mm', locale).format(DateTime.parse(date)); } else { return DateFormat('dd MMM HH:mm', locale).format(DateTime.parse(date)); } } //------------------------------------------------------------------------------ class RefreshPage extends StatelessWidget { final VoidCallback onRefresh; RefreshPage(this.onRefresh); @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.only(top: MediaQuery.of(context).size.height / 2.5), height: MediaQuery.of(context).size.height, child: Center( child: GestureDetector( child: Column( children: [ Icon(Icons.refresh_rounded, size: 50, color: Colors.grey), Text('refresh'.tr(), style: TextStyle(color: Colors.grey)) ], ), onTap: () => onRefresh(), ), ), ); } } //------------------------------------------------------------------------------ final JwtToken token = JwtToken(); final SharedPreferencesManager _sharedPreferencesManager = locator(); class NoDataPage extends StatelessWidget { @override Widget build(BuildContext context) { print(ApiAuthProvider().getServiceAsset('TNSendRequest.json')); return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ kIsWeb && !isCanvasKit ? Container( width: 150, margin: EdgeInsets.only(top: 20, bottom: 10), padding: EdgeInsets.all(10), child: Image(image: AssetImage('assets/image/error/EmptyData.png')) ) : Lottie.asset('assets/image/lottie/Nodata.json', width: 250, height: 250, fit: BoxFit.fill), Padding( padding: const EdgeInsets.fromLTRB(15, 0, 15, 10), child: Text('notFound'.tr(), style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), textAlign: TextAlign.center), ), Padding( padding: const EdgeInsets.fromLTRB(15, 0, 15, 10), child: Text('notFound2'.tr(), style: TextStyle(fontSize: 14), textAlign: TextAlign.center), ) ], ), ); } } handlingError(context, type) { var data = [ { 'image': 'NoInternet.png', 'title': 'noInternetTitle'.tr(), 'description': 'noInternetDesc'.tr() }, { 'image': 'ErrorServer.png', 'title': 'errorServerTitle'.tr(), 'description': 'errorServerDesc'.tr() }, { 'image': 'ErrorConnection.png', 'title': 'errorConnectTitle'.tr(), 'description': 'errorConnectDesc'.tr() }, { 'image': 'ErrorAuth.png', 'title': 'invalidAccountTitle'.tr(), 'description': 'invalidAccountDesc'.tr() }, { 'image': 'ErrorAuth.png', 'title': 'expAccountTitle'.tr(), 'description': 'expAccountDesc'.tr() } ]; showModalBottomSheet( context: context, backgroundColor: Colors.white, isDismissible: false, enableDrag: false, builder: (BuildContext context) { return SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( padding: const EdgeInsets.fromLTRB(15, 10, 15, 0), alignment: Alignment.centerRight, child: GestureDetector( child: Icon(Icons.clear), onTap: () => Navigator.of(context).pop(), ), ), Container( width: 200, padding: const EdgeInsets.fromLTRB(15, 0, 15, 10), child: Image( image: AssetImage('assets/image/error/' + data[type]['image']!))), Padding( padding: const EdgeInsets.fromLTRB(15, 0, 15, 10), child: Text(data[type]['title']!, style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), textAlign: TextAlign.center), ), Padding( padding: const EdgeInsets.fromLTRB(15, 0, 15, 10), child: Text(data[type]['description']!, style: TextStyle(fontSize: 14), textAlign: TextAlign.center), ), type == 3 || type == 4 ? Padding( padding: const EdgeInsets.fromLTRB(15, 0, 15, 10), child: SizedBox( width: double.infinity, height: 45, child: TextButton( style: ButtonStyle( backgroundColor: MaterialStateProperty.all(primaryColor), shape: MaterialStateProperty.all< RoundedRectangleBorder>( RoundedRectangleBorder( borderRadius: BorderRadius.circular(5), ))), child: new Text('logout'.tr().toUpperCase(), style: TextStyle(color: Colors.white), textAlign: TextAlign.center), onPressed: () { if (type == 4) { _sharedPreferencesManager.clearKey( SharedPreferencesManager.keyAccessCode); _sharedPreferencesManager.clearKey( SharedPreferencesManager.keySerialCode); _sharedPreferencesManager.clearKey( SharedPreferencesManager.keyAccessToken); _sharedPreferencesManager.clearKey( SharedPreferencesManager.keyRefreshToken); _sharedPreferencesManager.clearKey( SharedPreferencesManager.keyUsername); _sharedPreferencesManager.clearKey( SharedPreferencesManager.keyIsLogin); _sharedPreferencesManager.clearKey( SharedPreferencesManager.keyScoope); _sharedPreferencesManager.clearKey( SharedPreferencesManager.debugString); _sharedPreferencesManager.clearKey(SharedPreferencesManager.keyHistoryMark); Navigator.pushAndRemoveUntil( context, MaterialPageRoute( builder: (context) => NewQrPage()), ModalRoute.withName("/home")); } else { var pid = U.getPidFromUrl(context.router.currentUrl); token.logout(); context.router.removeLast(); context.navigateToPath("/app/$pid/login"); // print(pid); // context.router.removeLast(); // context.navigateToPath('/app/$pid/login'); } }, )), ) : Container(height: 1, width: 1) ], ), ); }); } // ignore: must_be_immutable class NoImageFound extends StatelessWidget { bool show = true; NoImageFound(this.show); @override Widget build(BuildContext context) { return Container( width: MediaQuery.of(context).size.width - 150, height: MediaQuery.of(context).size.height / 4, child: Stack( fit: StackFit.expand, children: [ Image.asset('assets/image/general/QrCode.jpg', fit: BoxFit.cover), ClipRRect( // Clip it cleanly. child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), child: Container( color: Colors.grey.withValues(alpha: 0.5), alignment: Alignment.center, child: show ? Container( padding: const EdgeInsets.all(10), child: Text('notFoundImg'.tr(), style: TextStyle(fontSize: 12)), decoration: BoxDecoration( color: Colors.white24, borderRadius: BorderRadius.all(Radius.circular(50))), ) : Center( child: CircularProgressIndicator(), ), ), ), ), ], ), ); } } dialogConfirm({required BuildContext context, required String title, required String text, required Function actionYes}){ showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text(title), content: Text(text), actions: [ TextButton( child: Text("buttonNo".tr()), onPressed: () { Navigator.of(context).pop(); }, ), TextButton( onPressed: (){ Navigator.of(context).pop(); actionYes(); }, child: Text("buttonYes".tr())), ], ); }, ); } showLoading(BuildContext context, {String? text, String? lottie}){ showDialog( context: context, barrierDismissible: false, barrierColor: lottie!=null?Colors.white:null, builder: (BuildContext context) { return WillPopScope( onWillPop: ()=>Future.value(false), child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ lottie != null ? Lottie.asset('assets/image/lottie/$lottie', width: 250, height: 250, fit: BoxFit.fill) : CircularProgressIndicator(color: primaryColor), SizedBox(height: 5), Text(text??'inProcess'.tr(), style: TextStyle(color: lottie!=null?Colors.black:Colors.white)) ], ), ), ); }, ); } closeLoading(BuildContext context){ Navigator.of(context, rootNavigator: true).pop(); }