import 'dart:convert'; import 'dart:ffi'; import 'dart:math'; import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:package_info/package_info.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:ysairplane2/code/YSLogin.dart'; import 'package:flutter_screenutil/screenutil.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'dart:math' as math; class YSDatePicker extends StatefulWidget { final ValueSetter choose; final bool isBefore; final bool isDate; const YSDatePicker({Key key, this.choose, this.isBefore, this.isDate = false}) : super(key: key); @override _YSDatePickerState createState() => _YSDatePickerState(); } class _YSDatePickerState extends State { String birthday = DateTime.now().year.toString()+'-'+DateTime.now().month.toString().padLeft(2,'0')+'-'+DateTime.now().day.toString().padLeft(2,'0')+' '+ DateTime.now().hour.toString().padLeft(2,'0')+':'+DateTime.now().minute.toString().padLeft(2,'0'); @override void initState() { if(widget.isDate==true){ birthday = DateTime.now().year.toString()+'-'+DateTime.now().month.toString().padLeft(2,'0')+'-'+DateTime.now().day.toString().padLeft(2,'0'); } super.initState(); } @override Widget build(BuildContext context) { return Container( color: Colors.transparent, height: 280, child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Container( height: 40, padding: EdgeInsets.only(left: wsp(40),right: wsp(40)), decoration: BoxDecoration( color: Colors.white, border: Border(bottom: BorderSide(width: 0.5,color: Color(0xFFEEEEEE))) ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ GestureDetector( child: Text('取消',style: TextStyle(fontSize: zsp(30),color: Color(0xFF999999)),), onTap: (){ Navigator.pop(context); }, ), GestureDetector( child: Text('确定',style: TextStyle(fontSize: zsp(30),color: Color(0xFF108DE9)),), onTap: (){ widget.choose(birthday); Navigator.pop(context); }, ) ], ), ), Container( height: 240, padding: EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only(topLeft: Radius.circular(20),topRight: Radius.circular(20)) ), child: CupertinoDatePicker( initialDateTime: DateTime.now(), use24hFormat: true, minimumDate: widget.isBefore==true?null:DateTime.parse(DateTime.now().year.toString()+'-'+DateTime.now().month.toString().padLeft(2,'0')+'-'+ DateTime.now().day.toString().padLeft(2,'0')+' '+ DateTime.now().hour.toString().padLeft(2,'0')+':'+DateTime.now().minute.toString().padLeft(2,'0')), onDateTimeChanged: (date) { if(widget.isDate==true){ birthday = date.year.toString()+'-'+date.month.toString().padLeft(2,'0')+'-'+date.day.toString().padLeft(2,'0'); }else{ birthday = date.year.toString()+'-'+date.month.toString().padLeft(2,'0')+'-'+date.day.toString().padLeft(2,'0')+' '+ date.hour.toString().padLeft(2,'0')+':'+date.minute.toString().padLeft(2,'0'); } }, mode: widget.isDate==true?CupertinoDatePickerMode.date:CupertinoDatePickerMode.dateAndTime, ), ), ], ), ); } } class BottomInputDialog extends StatefulWidget { final Widget inputView; final double height; final Color color; const BottomInputDialog({Key key, this.inputView,this.height,this.color}) : super(key: key); @override _State createState() => _State(); } class _State extends State with WidgetsBindingObserver{ @override void initState() { WidgetsBinding.instance.addObserver(this); super.initState(); } @override void didChangeMetrics() { WidgetsBinding.instance.addPostFrameCallback((_) { if(MediaQuery.of(context).viewInsets.bottom <= 0){ Navigator.pop(context); if (!mounted) { return; } WidgetsBinding.instance.removeObserver(this); } }); super.didChangeMetrics(); } @override void dispose() { super.dispose(); if (!mounted) { return; } WidgetsBinding.instance.removeObserver(this); } @override Widget build(BuildContext context) { return CupertinoPageScaffold( backgroundColor: Colors.transparent, child: Stack( children: [ GestureDetector( child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 3, sigmaY: 3), child: Container( height: MediaQuery.of(context).size.height, color: widget.color!=null?widget.color:Colors.black12.withOpacity(0.8), ), ), onTap: () { Navigator.pop(context); if (!mounted) { return; } WidgetsBinding.instance.removeObserver(this); }, ), Container( margin: EdgeInsets.only(top: MediaQuery.of(context).size.height-widget.height-MediaQuery.of(context).viewInsets.bottom), height: widget.height, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only(topLeft: Radius.circular(10),topRight: Radius.circular(10)), boxShadow: [ BoxShadow( color: Colors.black12, offset: Offset(-1, -3), blurRadius: 5 ) ] ), padding: EdgeInsets.all(10), child: widget.inputView, ) ], ), ); } } class PopRoute extends PopupRoute{ final Duration _duration = Duration(milliseconds: 300); Widget child; PopRoute({@required this.child}); @override Color get barrierColor => null; @override bool get barrierDismissible => true; @override String get barrierLabel => null; @override Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { return child; } @override Duration get transitionDuration => _duration; } wsp(int number){ return ScreenUtil().setWidth(number); } hsp(int number){ return ScreenUtil().setHeight(number); } zsp(int number){ return ScreenUtil().setSp(number,allowFontScalingSelf: false); } isLogin(BuildContext context,{VoidCallback login}) async{ SharedPreferences prefs = await SharedPreferences.getInstance(); String token = prefs.getString('token'); if(token==null){ Navigator.of(context,rootNavigator: true).push( CupertinoPageRoute( fullscreenDialog: true, builder: (context){ return YSLogin(); } ) ).then((value){ if(value!=null){ login(); } }); }else{ login(); } } ///手机号验证 bool isChinaPhoneLegal(String str) { return RegExp(r"^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\d{8}$").hasMatch(str); } ///邮箱验证 bool isEmail(String str) { return RegExp(r"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$").hasMatch(str); } ///验证URL bool isUrl(String value) { return RegExp(r"^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+").hasMatch(value); } ///验证身份证 bool isIdCard(String value) { return RegExp(r"\d{17}[\d|x]|\d{15}").hasMatch(value); } ///验证中文 bool isChinese(String value) { return RegExp(r"[\u4e00-\u9fa5]").hasMatch(value); } class LogUtil { static var _separator = "="; static var _split = "$_separator$_separator$_separator$_separator$_separator$_separator$_separator$_separator$_separator"; static var _title = "Yl-Log"; static var _isDebug = true; static int _limitLength = 800; static String _startLine = "$_split$_title$_split"; static String _endLine = "$_split$_separator$_separator$_separator$_split"; static void init({String title, @required bool isDebug,int limitLength}) { _title = title; _isDebug = isDebug; _limitLength = limitLength??=_limitLength; _startLine = "$_split$_title$_split"; var endLineStr = StringBuffer(); var cnCharReg = RegExp("[\u4e00-\u9fa5]"); for (int i = 0; i < _startLine.length; i++) { if (cnCharReg.stringMatch(_startLine[i]) != null) { endLineStr.write(_separator); } endLineStr.write(_separator); } _endLine = endLineStr.toString(); } //仅Debug模式可见 static void d(dynamic obj) { if (_isDebug) { _log(obj.toString()); } } static void v(dynamic obj) { _log(obj.toString()); } static void _log(String msg) { print("$_startLine"); _logEmpyLine(); if(msg.length<_limitLength){ print(msg); }else{ segmentationLog(msg); } _logEmpyLine(); print("$_endLine"); } static void segmentationLog(String msg) { var outStr = StringBuffer(); for (var index = 0; index < msg.length; index++) { outStr.write(msg[index]); if (index % _limitLength == 0 && index!=0) { print(outStr); outStr.clear(); var lastIndex = index+1; if(msg.length-lastIndex<_limitLength){ var remainderStr = msg.substring(lastIndex,msg.length); print(remainderStr); break; } } } } static void _logEmpyLine(){ print(""); } } //indicate Widget indicateString(String longStr,String str,String otherStr){ List strings = longStr.split(str); print(strings); return Container( child: RichText( text: longStr!=str?TextSpan( children: [ for(int i = 0;i createState() { return _ExpandableTextState(text, maxLines, style, expand); } } class _ExpandableTextState extends State { final String text; final int maxLines; final TextStyle style; bool expand; _ExpandableTextState(this.text, this.maxLines, this.style, this.expand) { if (expand == null) { expand = false; } } @override Widget build(BuildContext context) { return LayoutBuilder(builder: (context, size) { final span = TextSpan(text: text ?? '', style: style); final tp = TextPainter( text: span, maxLines: maxLines, textDirection: TextDirection.ltr); tp.layout(maxWidth: size.maxWidth); if (tp.didExceedMaxLines) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ expand ? Text(text ?? '', style: style) : Text(text ?? '', maxLines: maxLines,overflow: TextOverflow.ellipsis,style: style), GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { setState(() { expand = !expand; }); }, child: Container( padding: EdgeInsets.only(top: 2), child: Text(expand ? '收起' : '全文', style: TextStyle( fontSize: style != null ? style.fontSize : null, color: Colors.blue)), ), ), ], ); } else { return Text(text ?? '', style: style); } }); } } Widget ysTextExpend({String text,int maxLines,TextStyle style,bool expand = false}) { return StatefulBuilder( builder: (context,ysState){ return LayoutBuilder(builder: (context, size) { final span = TextSpan(text: text ?? '', style: style); final tp = TextPainter( text: span, maxLines: maxLines, textDirection: TextDirection.ltr); tp.layout(maxWidth: size.maxWidth); if (tp.didExceedMaxLines) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ expand ? Text(text ?? '', style: style) : Text(text ?? '', maxLines: maxLines, overflow: TextOverflow.ellipsis, style: style), GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { ysState(() { expand = !expand; }); }, child: Container( padding: EdgeInsets.only(top: 2), child: Text(expand ? '收起' : '全文', style: TextStyle( fontSize: style != null ? style.fontSize : null, color: Colors.blue)), ), ), ], ); } else { return Text(text ?? '', style: style); } }); }, ); } class YSPicker extends StatefulWidget { final ValueSetter choose; final List dataArray; final String title; const YSPicker({Key key, this.choose, this.dataArray, this.title}) : super(key: key); @override _YSPickerState createState() => _YSPickerState(); } class _YSPickerState extends State { var _value; @override Widget build(BuildContext context) { _value = widget.dataArray[0]; return Container( color: Colors.transparent, height: hsp(600), child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Container( height: hsp(100), padding: EdgeInsets.only(left: wsp(40),right: wsp(40)), decoration: BoxDecoration( color: Colors.white, border: Border(bottom: BorderSide(width: 0.5,color: Color(0xFFEEEEEE))) ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ GestureDetector( child: Text('取消',style: TextStyle(fontSize: zsp(30),color: Color(0xFF999999)),), onTap: (){ Navigator.pop(context); }, ), GestureDetector( child: Text('确定',style: TextStyle(fontSize: zsp(30),color: Color(0xFF108DE9)),), onTap: (){ widget.choose(_value); Navigator.pop(context); }, ) ], ), ), Container( height: hsp(500), padding: EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only(topLeft: Radius.circular(20),topRight: Radius.circular(20)) ), child: CupertinoPicker( children: [ for(int i=0;i-24){ tagStr = '今天'; }else if(now.difference(date).inHours<=-24 && now.difference(date).inHours>-48){ tagStr = '明天'; }else if(now.difference(date).inHours<=-48 && now.difference(date).inHours>-72){ tagStr = '后天'; }else{ switch(date.weekday){ case 1: tagStr = '周一';break; case 2: tagStr = '周二';break; case 3: tagStr = '周三';break; case 4: tagStr = '周四';break; case 5: tagStr = '周五';break; case 6: tagStr = '周六';break; case 7: tagStr = '周日';break; } } return tagStr; } class DashedRect extends StatelessWidget { final Color color; final double strokeWidth; final double gap; DashedRect( {this.color = Colors.black, this.strokeWidth = 1.0, this.gap = 5.0}); @override Widget build(BuildContext context) { return Container( child: Padding( padding: EdgeInsets.all(strokeWidth / 2), child: CustomPaint( painter: DashRectPainter(color: color, strokeWidth: strokeWidth, gap: gap), ), ), ); } } class DashRectPainter extends CustomPainter { double strokeWidth; Color color; double gap; DashRectPainter( {this.strokeWidth = 5.0, this.color = Colors.red, this.gap = 5.0}); @override void paint(Canvas canvas, Size size) { Paint dashedPaint = Paint() ..color = color ..strokeWidth = strokeWidth ..style = PaintingStyle.stroke; double x = size.width; double y = size.height; Path _topPath = getDashedPath( a: math.Point(0, 0), b: math.Point(x, 0), gap: gap, ); Path _rightPath = getDashedPath( a: math.Point(x, 0), b: math.Point(x, y), gap: gap, ); Path _bottomPath = getDashedPath( a: math.Point(0, y), b: math.Point(x, y), gap: gap, ); Path _leftPath = getDashedPath( a: math.Point(0, 0), b: math.Point(0.001, y), gap: gap, ); canvas.drawPath(_topPath, dashedPaint); canvas.drawPath(_rightPath, dashedPaint); canvas.drawPath(_bottomPath, dashedPaint); canvas.drawPath(_leftPath, dashedPaint); } Path getDashedPath({ @required math.Point a, @required math.Point b, @required gap, }) { Size size = Size(b.x - a.x, b.y - a.y); Path path = Path(); path.moveTo(a.x, a.y); bool shouldDraw = true; math.Point currentPoint = math.Point(a.x, a.y); num radians = math.atan(size.height / size.width); num dx = math.cos(radians) * gap < 0 ? math.cos(radians) * gap * -1 : math.cos(radians) * gap; num dy = math.sin(radians) * gap < 0 ? math.sin(radians) * gap * -1 : math.sin(radians) * gap; while (currentPoint.x <= b.x && currentPoint.y <= b.y) { shouldDraw ? path.lineTo(currentPoint.x, currentPoint.y) : path.moveTo(currentPoint.x, currentPoint.y); shouldDraw = !shouldDraw; currentPoint = math.Point( currentPoint.x + dx, currentPoint.y + dy, ); } return path; } @override bool shouldRepaint(CustomPainter oldDelegate) { return true; } } getSecretStr(String str) { String secret = str.length==11?'****':'***********'; return str.substring(0,3)+secret+str.substring(str.length-4,str.length); } class CirclePageRoute extends PageRoute { CirclePageRoute({ @required this.builder, this.transitionDuration = const Duration(milliseconds: 500), this.opaque = true, this.barrierDismissible = false, this.barrierColor, this.barrierLabel, this.maintainState = true, }); final WidgetBuilder builder; @override final Duration transitionDuration; @override final bool opaque; @override final bool barrierDismissible; @override final Color barrierColor; @override final String barrierLabel; @override final bool maintainState; @override Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { return AnimatedBuilder( animation: animation, builder: (context, child) { return ClipPath( clipper: CirclePath(animation.value), child: child, ); }, child: builder(context), ); } } class CirclePath extends CustomClipper { CirclePath(this.value); final double value; @override Path getClip(Size size) { var path = Path(); double radius = value * sqrt(size.height * size.height + size.width * size.width); path.addOval(Rect.fromLTRB( size.width - radius, -radius, size.width + radius, radius)); return path; } @override bool shouldReclip(CustomClipper oldClipper) { return true; } } loadingView() { return Center( //child: CircularProgressIndicator(), ); } Widget platformView({ValueSetter platforms,Map message}){ if(message==null)message = {'type':2}; if(defaultTargetPlatform == TargetPlatform.android){ return AndroidView( viewType: 'plugins.flutter.io/custom_platform_view', onPlatformViewCreated: (viewId) { platforms(MethodChannel('com.flutter.guide.MyFlutterView_$viewId')); }, creationParams: message, creationParamsCodec: StandardMessageCodec(), ); }else{ return UiKitView( viewType: 'plugins.flutter.io/custom_platform_view', onPlatformViewCreated: (viewId) { platforms(MethodChannel('com.flutter.guide.MyFlutterView_$viewId')); }, creationParams: message, creationParamsCodec: StandardMessageCodec(), ); } } Future checkVersion() async{ PackageInfo packageInfo = await PackageInfo.fromPlatform(); SharedPreferences prefer = await SharedPreferences.getInstance(); String locVer = prefer.getString('version')??''; String version = packageInfo.version; prefer.setString('version', version); return locVer==version; } Widget ysHtml(String content) { double htmlHeight = 1; WebViewController _controller; return StatefulBuilder( builder: (context,heightSet){ return Container( height: htmlHeight, width: MediaQuery.of(context).size.width, color: Colors.white, child: WebView( javascriptMode: JavascriptMode.unrestricted, onWebViewCreated: (WebViewController controller) { controller.loadUrl(Uri.dataFromString(content, mimeType: 'text/html', encoding: Encoding.getByName('utf-8')).toString()); _controller = controller; }, onPageFinished: (url){ _controller.evaluateJavascript("document.body.scrollHeight").then((result){ heightSet(() { htmlHeight = double.parse(result); }); }); }, ) ); }, ); } showNegotiateAlertDio(BuildContext context,{String content,VoidCallback sure}){ showGeneralDialog( context: context, barrierDismissible:true, barrierColor: Colors.black.withOpacity(0.6), barrierLabel: '', transitionDuration: Duration(milliseconds: 200), pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) { return Center( child: Container( height: MediaQuery.of(context).size.height-(MediaQuery.of(context).padding.top+hsp(100)*2), width: MediaQuery.of(context).size.width-wsp(100), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(5)) ), child: Column( children: [ Container( height: hsp(100), padding: EdgeInsets.only(left: wsp(30),right: wsp(30)), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container(width: hsp(50),), Text('预定须知',style: TextStyle(fontSize: zsp(34),color: Color(0xFF242329),decoration: TextDecoration.none),), GestureDetector( child: Icon(Icons.close,size: hsp(50),color: Color(0xFF242329)), onTap: (){Navigator.pop(context);}, ) ], ), ), Container( height: MediaQuery.of(context).size.height-(MediaQuery.of(context).padding.top+hsp(100)*2)-hsp(200), width: MediaQuery.of(context).size.width-wsp(100), padding: EdgeInsets.all(wsp(20)), color: Colors.white, child: SingleChildScrollView( child: ysHtml(content), ) ), GestureDetector( onTap: (){Navigator.pop(context);sure();}, child: Container( height: hsp(100), alignment: Alignment.center, child: Text('我知道了',style: TextStyle(fontSize: zsp(34),color: Color(0xFF007EFF),decoration: TextDecoration.none),), ), ), ], ), ), ); } ); } showAgreeAlert(BuildContext context,{String title = '',String content = '',ValueSetter agree,bool isWelcome = false}) async{ showGeneralDialog( context: context, barrierDismissible:true, barrierColor: Colors.black.withOpacity(0.6), barrierLabel: '', transitionDuration: Duration(milliseconds: 200), pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) { return Center( child: Container( height: MediaQuery.of(context).size.height-(MediaQuery.of(context).padding.top+hsp(100)*2), width: MediaQuery.of(context).size.width-wsp(100), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(5)) ), child: Column( children: [ Container( height: hsp(100), padding: EdgeInsets.only(left: wsp(30),right: wsp(30)), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container(width: hsp(34),), Text(title,style: TextStyle(fontSize: zsp(34),color: Color(0xFF242329),decoration: TextDecoration.none),), GestureDetector( onTap: (){Navigator.pop(context);}, child: Icon(Icons.close,size: hsp(50),color: Color(0xFF242329)), ) ], ), ), Container( height: MediaQuery.of(context).size.height-(MediaQuery.of(context).padding.top+hsp(100)*2)-hsp(200), width: MediaQuery.of(context).size.width-wsp(100), padding: EdgeInsets.all(wsp(20)), color: Color(0xFFF9F9F9), child: WebView( javascriptMode: JavascriptMode.unrestricted, onWebViewCreated: (WebViewController webViewController) { webViewController.loadUrl(Uri.dataFromString(content, mimeType: 'text/html', encoding: Encoding.getByName('utf-8')).toString()); }, ) ), Container( height: hsp(100), alignment: Alignment.center, child: Row( children: [ GestureDetector( onTap: (){ agree(false); }, child: Container( width: (MediaQuery.of(context).size.width-wsp(100))/2-wsp(1), alignment: Alignment.center, child: Text(isWelcome?'不同意并退出':'不同意',style: TextStyle(fontSize: zsp(34),color: Color(0xFF999999),decoration: TextDecoration.none),), ), ), Container( height: hsp(100), width: wsp(2), color: Color(0xFFF9F9F9), ), GestureDetector( onTap: (){ agree(true); }, child: Container( width: (MediaQuery.of(context).size.width-wsp(100))/2-wsp(1), alignment: Alignment.center, child: Text('同意',style: TextStyle(fontSize: zsp(34),color: Color(0xFF0079FF),decoration: TextDecoration.none),), ), ) ], ) ), ], ), ), ); } ); } showKnowAlert(BuildContext context,{String title = '',String content = '',VoidCallback know}) async{ showGeneralDialog( context: context, barrierDismissible:true, barrierColor: Colors.black.withOpacity(0.6), barrierLabel: '', transitionDuration: Duration(milliseconds: 200), pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) { return Center( child: Container( height: MediaQuery.of(context).size.height-(MediaQuery.of(context).padding.top+hsp(100)*2), width: MediaQuery.of(context).size.width-wsp(100), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(5)) ), child: Column( children: [ Container( height: hsp(100), padding: EdgeInsets.only(left: wsp(30),right: wsp(30)), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container(), Text(title,style: TextStyle(fontSize: zsp(34),color: Color(0xFF242329),decoration: TextDecoration.none),), GestureDetector( onTap: (){Navigator.pop(context);}, child: Icon(Icons.close,size: hsp(50),color: Color(0xFF242329)), ) ], ), ), Container( height: MediaQuery.of(context).size.height-(MediaQuery.of(context).padding.top+hsp(100)*2)-hsp(200), width: MediaQuery.of(context).size.width-wsp(100), padding: EdgeInsets.all(wsp(20)), color: Color(0xFFF9F9F9), child: WebView( // initialUrl: 'data:text/html;base64,${base64Encode(const Utf8Encoder().convert(content))}', javascriptMode: JavascriptMode.unrestricted, onWebViewCreated: (WebViewController webViewController) { webViewController.loadUrl(Uri.dataFromString(content, mimeType: 'text/html', encoding: Encoding.getByName('utf-8')).toString()); }, ) ), GestureDetector( child: Container( height: hsp(100), alignment: Alignment.center, child: Text('我知道了',style: TextStyle(fontSize: zsp(34),color: Color(0xFF0079FF),decoration: TextDecoration.none),), ), onTap: (){ Navigator.pop(context); know(); }, behavior: HitTestBehavior.opaque, ), ], ), ), ); } ); } showInformAlert(BuildContext context,{String title = '',String content = '',VoidCallback sure}){ double htmlHeight = MediaQuery.of(context).size.height*0.85-0.5-hsp(100); WebViewController _controller; showModalBottomSheet( isScrollControlled: true, context: context, backgroundColor: Colors.transparent, builder: (context){ return Container( height: MediaQuery.of(context).size.height*0.85, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only(topRight: Radius.circular(10),topLeft: Radius.circular(10)) ), child: Column( children: [ Container( height: hsp(100), padding: EdgeInsets.only(left: hsp(30),right: hsp(30)), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container(width: wsp(50),), Text(title,style: TextStyle(fontSize: 15,color: Color(0xFF000000),decoration: TextDecoration.none,fontWeight: FontWeight.bold),), GestureDetector( child: Text('关闭',style: TextStyle(fontSize: 15,color: Color(0xFF007EFF),decoration: TextDecoration.none,fontWeight: FontWeight.bold),), onTap: (){ Navigator.pop(context); }, ), ], ), ), Divider(height: 0.5,thickness: 0.5,color: Color(0xFFE5E5E5),), Container( height: MediaQuery.of(context).size.height*0.85-0.5-hsp(100), child: WebView( // initialUrl: 'data:text/html;base64,${base64Encode(const Utf8Encoder().convert(content))}', javascriptMode: JavascriptMode.unrestricted, onWebViewCreated: (WebViewController webViewController) { webViewController.loadUrl(Uri.dataFromString(content, mimeType: 'text/html', encoding: Encoding.getByName('utf-8')).toString()); }, ), ), ], ), ); } ); } alertPhone(BuildContext context, String phoneStr) async{ showCupertinoDialog( context: context, builder: (context) { return CupertinoAlertDialog( title: Text('提示'), content: Text('拨打 $phoneStr ?'), actions: [ CupertinoDialogAction(child: Text('取消'),onPressed: (){Navigator.pop(context);},), CupertinoDialogAction(child: Text('确认'),onPressed: (){Navigator.pop(context);launch('tel:$phoneStr');},), ], ); }); } _getMonthDay() async{ } getDateArray({ValueSetter dates,int count = 90,String startStr}) { List zhongQius = ['2021-9-21','2022-9-10','2023-9-29','2024-9-17','2025-10-6','2026-9-25','2027-9-15','2028-10-3','2029-9-22','2030-9-12']; List chuXis = ['2021-2-11','2022-1-31','2023-1-21','2024-2-9','2025-1-28','2026-2-16','2027-2-5','2028-1-25','2029-2-12','2030-2-2']; List chunJies = ['2021-2-12','2022-2-1','2023-1-22','2024-2-10','2025-1-29','2026-2-17','2027-2-6','2028-1-26','2029-2-13','2030-2-3']; List duanWus = ['2021-6-14','2022-6-3','2023-6-22','2024-6-10','2025-5-31','2026-6-19','2027-6-9','2028-6-27','2029-6-16','2030-6-5']; DateTime _time = startStr!=null?DateTime.parse(startStr):DateTime.now(); int year = _time.year; List dateArray = []; int month = _time.month; int days = DateTime(year, month + 1, 0).day; int days2 = DateTime(year, month + 2, 0).day; int months = count>days-_time.day+days2+1?3:2; int number = 1; for(int i = 0;i12){ year++; month = 1; } int days3 = DateTime(year, month + 1, 0).day; dateArray.add({'year':year,'month':month,'days':[]}); int firstNum = 0; int week = DateTime.parse('$year-${'$month'.padLeft(2,'0')}-01 00:00:00').weekday; if(week==7){ firstNum = 0; }else{ firstNum = week; } for(int j=1;jcount||(year==_time.year&&month==_time.month&&j-firstNum<_time.day)){ //print('$i=============$days================${count+_time.day}'); dateArray[i]['days'].add((j-firstNum)*0.01); }else{ number++; String yStr = '$year-$month-${j-firstNum}'; String str = '$month-${j-firstNum}'; if(zhongQius.contains(yStr)==true){ dateArray[i]['days'].add({'day':j-firstNum,'fes':'中秋'}); }else if(chuXis.contains(yStr)==true){ dateArray[i]['days'].add({'day':j-firstNum,'fes':'除夕'}); }else if(chunJies.contains(yStr)==true){ dateArray[i]['days'].add({'day':j-firstNum,'fes':'春节'}); }else if(chunJies.contains(yStr)==true){ dateArray[i]['days'].add({'day':j-firstNum,'fes':'端午'}); }else if(str=='1-1'){ dateArray[i]['days'].add({'day':j-firstNum,'fes':'元旦'}); }else if(str=='4-4'){ dateArray[i]['days'].add({'day':j-firstNum,'fes':'清明'}); }else if(str=='10-1'){ dateArray[i]['days'].add({'day':j-firstNum,'fes':'国庆'}); }else if(str=='5-1'){ dateArray[i]['days'].add({'day':j-firstNum,'fes':'劳动节'}); }else if(str=='6-1'){ dateArray[i]['days'].add({'day':j-firstNum,'fes':'儿童节'}); }else if(str=='12-25'){ dateArray[i]['days'].add({'day':j-firstNum,'fes':'圣诞节'}); }else{ dateArray[i]['days'].add(j-firstNum); } } } month++; } print(dateArray); dates(dateArray); } dateChooseAlert(BuildContext context,{ValueSetter dateValue,int count = 90,String startStr}) { List dates = []; getDateArray( dates: (value){dates = value;},count: count,startStr: startStr); List weeks = ['日','一','二','三','四','五','六']; int today = DateTime.now().day; int thisMonth = DateTime.now().month; int thisYear = DateTime.now().year; int year = DateTime.now().year; int month = DateTime.now().month; int day = DateTime.now().day; showModalBottomSheet( context: context, backgroundColor: Colors.transparent, isScrollControlled: true, builder: (context){ return StatefulBuilder( builder: (context,dateSet){ return Container( height: MediaQuery.of(context).size.height*0.7, width: MediaQuery.of(context).size.width, color: Colors.white, child: SingleChildScrollView( child: Column( children: [ Container( height: hsp(80), padding: EdgeInsets.only(left: hsp(30),right: hsp(40),top: hsp(10)), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ GestureDetector( onTap: (){Navigator.pop(context);}, child: Icon(Icons.close,size: hsp(40),color: Color(0xFF4B4B4B),), ), Text('选择日期',style: TextStyle(fontSize: zsp(30),color: Colors.black,fontWeight: FontWeight.bold),), Container(width: hsp(40),) ], ), ), Container( height: hsp(80), width: MediaQuery.of(context).size.width, child: ListView.builder( itemCount: weeks.length, scrollDirection: Axis.horizontal, padding: EdgeInsets.all(0), itemBuilder: (context,index){ return Container( height: hsp(80), width: MediaQuery.of(context).size.width/weeks.length, alignment: Alignment.center, child: Text('${weeks[index]}',style: TextStyle(fontSize: zsp(32),color: index==0||index==6?Color(0xFFE85D54):Color(0xFF666666)),), ); }, ), ), Container( height: MediaQuery.of(context).size.height*0.7-hsp(300), width: MediaQuery.of(context).size.width, child: SingleChildScrollView( child: ListView.separated( padding: EdgeInsets.all(0), itemCount: dates.length, shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemBuilder: (context,index){ Map dateMonth = dates[index]; return Column( children: [ Container( width: MediaQuery.of(context).size.width, padding: EdgeInsets.only(left: hsp(30),right: hsp(30)), alignment: Alignment.center, child: Text('${dateMonth['year']}年 '+'${dateMonth['month']}'.padLeft(2,'0')+'月'), height: hsp(70), ), Divider(height: 1,thickness: 1,color: Color(0xFFF4F4F7),), GridView.builder( itemCount: dateMonth['days'].length, padding: EdgeInsets.all(0), shrinkWrap: true, physics: NeverScrollableScrollPhysics(), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 7, ), itemBuilder: (context,indexSub){ var dateDay = dateMonth['days'][indexSub]; return dateDay==0?Container():GestureDetector( onTap: (){ if((dateDay is Map?dateDay['day']:dateDay)<1)return; dateSet(() { month = dateMonth['month']; day = dateDay is Map?dateDay['day']:dateDay; year = dateMonth['year']; }); }, child: Container( alignment: Alignment.center, child: dates[index]['days'][indexSub] is Map?Column( children: [ Text( dateDay['day']-today==0&&dateMonth['month']==thisMonth&&dateMonth['year']==thisYear?'今天': dateDay['day']-today==1&&dateMonth['month']==thisMonth&&dateMonth['year']==thisYear?'明天': dateDay['day']-today==2&&dateMonth['month']==thisMonth&&dateMonth['year']==thisYear?'后天': '${dateDay['day']~/(dateDay['day']<1?0.01:1)}',style: TextStyle(fontSize: zsp(28), color: dateDay['day']==day&&dateMonth['month']==month&&dateMonth['year']==year?Colors.white: dateDay['day']<1?Color(0xFFCBCBCB):Color(0xFF333333)),), Text('${dateDay['fes']}',style: TextStyle(fontSize: zsp(20), color: dateDay['day']==day&&dateMonth['month']==month&&dateMonth['year']==year?Colors.white: dateDay['day']<1?Color(0xFFCBCBCB):Color(0xFFE85D54)),) ], mainAxisSize: MainAxisSize.min, ):Text( dateDay-today==0&&dateMonth['month']==thisMonth&&dateMonth['year']==thisYear?'今天': dateDay-today==1&&dateMonth['month']==thisMonth&&dateMonth['year']==thisYear?'明天': dateDay-today==2&&dateMonth['month']==thisMonth&&dateMonth['year']==thisYear?'后天': '${dateDay~/(dateDay<1?0.01:1)}',style: TextStyle(fontSize: zsp(28), color: dateDay==day&&dateMonth['month']==month&&dateMonth['year']==year?Colors.white: dateDay<1?Color(0xFFCBCBCB):Color(0xFF333333)),), margin: EdgeInsets.all(hsp(15)), decoration: BoxDecoration( color: (dateDay is Map?dateDay['day']:dateDay)==day &&dateMonth['month']==month&&dateMonth['year']==year?Color(0xFF007AFF):Colors.transparent, borderRadius: BorderRadius.all(Radius.circular(5)) ), ), ); }, ) ], ); }, separatorBuilder: (context,index){ return Divider(height: hsp(20),thickness: hsp(20),color: Color(0xFFF4F4F7),); }, ), ), ), GestureDetector( onTap: (){ Navigator.pop(context); String date = '$year-${'$month'.padLeft(2,'0')}-${'$day'.padLeft(2,'0')}'; dateValue(date); }, child: Container( margin: EdgeInsets.only(top: hsp(26)), height: hsp(88), width: MediaQuery.of(context).size.width-hsp(80), decoration: BoxDecoration( color: Color(0xFF007EFF), borderRadius: BorderRadius.all(Radius.circular(5)) ), alignment: Alignment.center, child: Text('完成',style: TextStyle(fontSize: zsp(36),color: Colors.white),), ), ) ], ), ), ); }, ); } ); } dateChooseAlert1(BuildContext context,{ValueSetter dateValue}) { List dates = []; getDateArray( dates: (value){dates = value;}); List weeks = ['日','一','二','三','四','五','六']; int today = DateTime.now().day; int thisMonth = DateTime.now().month; int thisYear = DateTime.now().year; int year = DateTime.now().year; int month = DateTime.now().month; int day = DateTime.now().day; showModalBottomSheet( context: context, backgroundColor: Colors.transparent, isScrollControlled: true, builder: (context){ return StatefulBuilder( builder: (context,dateSet){ return Container( height: MediaQuery.of(context).size.height*0.7, width: MediaQuery.of(context).size.width, color: Colors.white, child: SingleChildScrollView( child: Column( children: [ Container( height: hsp(80), padding: EdgeInsets.only(left: hsp(30),right: hsp(40),top: hsp(10)), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ GestureDetector( onTap: (){Navigator.pop(context);}, child: Icon(Icons.close,size: hsp(40),color: Color(0xFF4B4B4B),), ), Text('选择日期',style: TextStyle(fontSize: zsp(30),color: Colors.black,fontWeight: FontWeight.bold),), Container(width: hsp(40),) ], ), ), Container( height: hsp(80), width: MediaQuery.of(context).size.width, child: ListView.builder( itemCount: weeks.length, scrollDirection: Axis.horizontal, padding: EdgeInsets.all(0), itemBuilder: (context,index){ return Container( height: hsp(80), width: MediaQuery.of(context).size.width/weeks.length, alignment: Alignment.center, child: Text('${weeks[index]}',style: TextStyle(fontSize: zsp(32),color: index==0||index==6?Color(0xFFE85D54):Color(0xFF666666)),), ); }, ), ), Container( height: MediaQuery.of(context).size.height*0.7-hsp(300), width: MediaQuery.of(context).size.width, child: SingleChildScrollView( child: ListView.separated( padding: EdgeInsets.all(0), itemCount: dates.length, shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemBuilder: (context,index){ return Column( children: [ Container( width: MediaQuery.of(context).size.width, padding: EdgeInsets.only(left: hsp(30),right: hsp(30)), alignment: Alignment.center, child: Text('${dates[index]['year']}年 '+'${dates[index]['month']}'.padLeft(2,'0')+'月'), height: hsp(70), ), Divider(height: 1,thickness: 1,color: Color(0xFFF4F4F7),), GridView.builder( itemCount: dates[index]['days'].length, padding: EdgeInsets.all(0), shrinkWrap: true, physics: NeverScrollableScrollPhysics(), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 7, ), itemBuilder: (context,indexSub){ return dates[index]['days'][indexSub]==0?Container():GestureDetector( onTap: (){ if((dates[index]['days'][indexSub] is Map?dates[index]['days'][indexSub]['day']:dates[index]['days'][indexSub])< today&&dates[index]['month']==thisMonth&&dates[index]['year']==thisYear)return; dateSet(() { month = dates[index]['month']; day = dates[index]['days'][indexSub] is Map?dates[index]['days'][indexSub]['day']:dates[index]['days'][indexSub]; year = dates[index]['year']; }); }, child: Container( alignment: Alignment.center, child: dates[index]['days'][indexSub] is Map?Column( children: [ Text( dates[index]['days'][indexSub]['day']-today==0&&dates[index]['month']==thisMonth&&dates[index]['year']==thisYear?'今天': dates[index]['days'][indexSub]['day']-today==1&&dates[index]['month']==thisMonth&&dates[index]['year']==thisYear?'明天': dates[index]['days'][indexSub]['day']-today==2&&dates[index]['month']==thisMonth&&dates[index]['year']==thisYear?'后天': '${dates[index]['days'][indexSub]['day']}',style: TextStyle(fontSize: zsp(28), color: dates[index]['days'][indexSub]['day']==day&&dates[index]['month']==month&&dates[index]['year']==year?Colors.white: dates[index]['days'][indexSub]['day'] animation, Animation secondaryAnimation) { return Center( child: Container( height: MediaQuery.of(context).size.height*0.5, width: MediaQuery.of(context).size.width-hsp(100), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(5)) ), child: Column( children: [ Container( padding: EdgeInsets.all(hsp(30)), child: Text('版本更新',style: TextStyle(fontSize: zsp(32),color: Colors.black,decoration: TextDecoration.none,fontWeight: FontWeight.normal),), alignment: Alignment.center, ), Divider(height: 1,thickness: 1,color: Color(0xFFF4F4F7),), Container( height: MediaQuery.of(context).size.height*0.5-hsp(215), width: MediaQuery.of(context).size.width-hsp(100), child: ListView.separated( itemCount: 5, padding: EdgeInsets.only(left: hsp(50),right: hsp(50),top: hsp(30),bottom: hsp(30)), itemBuilder: (context,index){ return Container( child: Text('${index+1}、更新更新更新更新更新更新更新更新更新更新更新更新', style: TextStyle(fontSize: zsp(30),color: Colors.black,decoration: TextDecoration.none,fontWeight: FontWeight.normal),), width: MediaQuery.of(context).size.width-hsp(160), ); }, separatorBuilder: (context,index){ return Divider(height: hsp(20),thickness: hsp(20),color: Colors.transparent,); }, ), ), Divider(height: 1,thickness: 1,color: Color(0xFFF4F4F7),), Container( height: hsp(100), child: Row( children: [ GestureDetector( onTap: (){ Navigator.pop(context); }, child: Container( width: (MediaQuery.of(context).size.width-hsp(100))/2-hsp(1), height: hsp(100), alignment: Alignment.center, child: Text('忽略此版',style: TextStyle(fontSize: zsp(32),color: Colors.black,decoration: TextDecoration.none,fontWeight: FontWeight.normal),), ), ), Container(height: hsp(100),color: Color(0xFFF4F4F7),width: hsp(2),), GestureDetector( onTap: (){ Navigator.pop(context); }, child: Container( width: (MediaQuery.of(context).size.width-hsp(100))/2-hsp(1), height: hsp(100), alignment: Alignment.center, child: Text('立即更新',style: TextStyle(fontSize: zsp(32),color: Color(0xFF007AFF),decoration: TextDecoration.none),), ), ) ], ), ) ], ), ), ); } ); } class NumberFormat extends TextInputFormatter { NumberFormat({this.decimalRange = 3}) : assert(decimalRange == null || decimalRange > 0); final int decimalRange; @override TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { // 拿到录入后的字符 String nValue = newValue.text; //当前所选择的文字区域 TextSelection nSelection = newValue.selection; // 先来一波过滤,过滤出数字及小数点 // 匹配包含数字和小数点的字符 Pattern p = RegExp(r'(\d+\.?)|(\.?\d+)|(\.?)'); nValue = p.allMatches(nValue) .map((Match match) => match.group(0)) .join(); // 用匹配完的字符判断 if (nValue.startsWith('.')) { //如果小数点开头,我们给他补个0 nValue = '0.'; } else if (nValue.contains('.')) { //来验证小数点位置 if (nValue.substring(nValue.indexOf('.') + 1).length > decimalRange) { nValue = oldValue.text; } else { if (nValue.split('.').length > 2) { //多个小数点,去掉后面的 List split = nValue.split('.'); nValue = split[0] + '.' + split[1]; } } } //使光标定位到最后一个字符后面 nSelection = newValue.selection.copyWith( baseOffset: math.min(nValue.length, nValue.length + 1), extentOffset: math.min(nValue.length, nValue.length + 1), ); return TextEditingValue( text: nValue, selection: nSelection, composing: TextRange.empty ); } }