You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

722 lines
23 KiB
Dart

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import 'dart:convert';
import 'dart:developer' as developer;
import 'dart:io';
import 'dart:math';
import 'package:camera/camera.dart';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart' as crypto;
import 'package:device_info/device_info.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
//import '../my_wechat_assets_picker_fix/my_asset_picker_1.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:hyzp_ybqx/provider/player_region.dart';
import 'UserInfo.dart';
////////////////////////////////////////////
// begin 统一的全局区县信息
// 1、修改手机桌面的App图标文本
// R:\FlutterProject\FlutterProject51-hyzp_ybqx\hyzp_ybqx\android\app\src\main\AndroidManifest.xml
// android:label="宜宾市翠屏黑烟抓拍"
// 2、修改App的android启动图片
// (1)、分别制作并拷贝不同分辨率的图片文件hyzp_ybqx_cuipingqu_launche.png到下面目录
// r:\FlutterProject\FlutterProject51-hyzp_ybqx\hyzp_ybqx\android\app\src\main\res\mipmap-hdpi\
// r:\FlutterProject\FlutterProject51-hyzp_ybqx\hyzp_ybqx\android\app\src\main\res\mipmap-mdpi\
// r:\FlutterProject\FlutterProject51-hyzp_ybqx\hyzp_ybqx\android\app\src\main\res\mipmap-xhdpi\
// r:\FlutterProject\FlutterProject51-hyzp_ybqx\hyzp_ybqx\android\app\src\main\res\mipmap-xxhdpi\
// r:\FlutterProject\FlutterProject51-hyzp_ybqx\hyzp_ybqx\android\app\src\main\res\mipmap-xxxhdpi\
// (2)、然后修改文件
// R:\FlutterProject\FlutterProject51-hyzp_ybqx\hyzp_ybqx\android\app\src\main\res\drawable\launch_background.xml
// android:src="@mipmap/hyzp_yibin_launche" />
// android:src="@mipmap/hyzp_ybqx_cuipingqu_launche" />
// 3、App的Flutter启动图片
// (1)、拷贝 750 * 1334 的图片文件到:
// r:\FlutterProject\FlutterProject51-hyzp_ybqx\hyzp_ybqx\assets\images\hyzp_ybqx_cuipingqu_launche.png
// (2)、然后修改文件
// R:\FlutterProject\FlutterProject51-hyzp_ybqx\hyzp_ybqx\lib\main.dart
// child: new Image.asset('assets/images/hyzp_ybqx_cuipingqu_launche.png'),
// child: Image.asset('assets/images/hyzp_ybqx_cuipingqu_launche.png', fit: BoxFit.cover),
// 4、文本信息
// (1)、宜宾市
// String service_tel = '\n服务热线187-8467-8300';
// String yibin_QuXian = '宜宾';
// String copyright_info = '© 宜宾市生态环境局 四川省踏石科技有限公司 版权所有' + service_tel;
// String copyright_info_PinYin = 'YIBIN BLACK SMOKE CAR CAPTURE SYSTEM';
// (2)、翠屏区
String service_tel = '';
String yibin_QuXian = '宜宾市翠屏';
String copyright_info = '© 宜宾市翠屏生态环境局 版权所有' + service_tel;
String copyright_info_PinYin = 'YIBIN CUIPING BLACK SMOKE CAR CAPTURE SYSTEM';
// end 统一的全局版权信息
////////////////////////////////////////////
//LED字幕信息
//String g_ledMessage = '绿水青山就是金山银山 宜宾市翠屏生态环境局宣。';
// 是否已经调用 FlutterDownloader.initialize(debug: true)
bool bFlutterDownloader_initialize = false;
bool bNewVer = false; //是否发现新版本
//处理延时登录,判断从网络获取三种统计数据是否完成
bool bMayLogin = false;
//处理延时登录,判断是否已经点击登录按钮
bool bPreLoading = false;
//处理延时登录,判断用户名登录是否验证通过
bool bLoginVerify = false;
bool bHasMore = true;
//part library
//dart中通过使用part、part of、library来实现拆分库这样就可以将一个庞大的库拆分成各种小库只要引用主库即可
//点位总数
int dwSum = -1;
Size sizeWindowPhysicalSize;
//String dateAppCompile = '2020.12.30'; //1.0.1+1
//String dateAppCompile = '2021.02.20'; //1.2.5+1
//String dateAppCompile = '2021.03.18'; //1.2.6+1
//String dateAppCompile = '2021.05.18'; //1.2.7
List<String> g_list = [];
//正在获取点位视频标志,禁止重入
bool getingDwVideo = false;
int getCount = 1; //获取点位视频地址尝试次数
int getSumTime = 0; //获取点位视频地址耗时(秒)
int getingIndex = -1; //正在获取视频的点位的索引号
String getingDwmc = ''; //正在获取视频的点位名称
String urlnew =
"http://www.yibinu.edu.cn/__local/5/35/DF/264049B7E978EEE2F5849688986_05D4A6FE_152CDB8C.mp4?e=.mp4";
bool isVideoUrl(String url, {bool showToast = false}) {
print('url = $url');
String prefix = url.substring(0, 4);
List list = ['http', 'rtmp', 'rstp'];
for (String item in list) {
if (prefix == item) {
return true;
}
}
if (showToast) {
Fluttertoast.showToast(
msg: '获取视频地址失败',
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
);
}
return false;
}
final TextEditingController myController = TextEditingController();
bool Playing = false; //禁止同时启动两次播放器
//final FijkPlayer player = FijkPlayer();
int g_iIndex = 0;
PlayerRegionProvide playerRegionProvide;
Future<void> sysPop() async {
// currentPos = player.currentPos.inMilliseconds; //seekto方法的参数是毫秒
// await writeCurrentPosFile();
// await player.stop();
await SystemChannels.platform.invokeMethod('SystemNavigator.pop');
}
//人脸注册和人脸识别登录成功标志
int faceReg = -1; //1 成功0 失败,-1 处理中
int faceLogin = -1; //1 成功0 失败,-1 处理中
//人脸注册时所需用户ID
int faceRegUserID = -1; //人脸注册时所需用户ID-1 非法
List<CameraDescription> cameras;
UserInfo g_userInfo = UserInfo(mapUserInfoRet: {
"ret": 200,
"data": {
"is_login": true,
"user_id": 1,
"token": "B93EC91FA2FE293B7077162D4527FC4BB228CD6C0A4F24A882B9A8BBE6C3FB47"
},
"msg": ""
});
Future<Map> getMapFromJson(var response) async {
String _str = json.encode(response);
Map _map = json.decode(_str);
return _map;
}
// Future<void> getVideoList(BuildContext context) async {
// List<AssetEntity> assets = <AssetEntity>[];
// return await MyAssetPicker.pickAssets(
// context,
// maxAssets: 1,
// selectedAssets: assets,
// requestType: RequestType.video,
// );
// }
Future<String> getAndroidId() async {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
//print('每个手机唯一的设备号:${androidInfo.androidId}'); // e.g. "Moto G (4)"
g_userInfo.thisAndroidId = androidInfo.androidId;
return g_userInfo.thisAndroidId;
}
// void playOrPause() {
// playerRegionProvide.changePlayerState(bPlaying);
//
// if (bPlaying) {
// player.start();
// } else {
// player.pause();
// }
//
// Storage.setString('bFirstPlay', bFirstPlay ? 'true' : 'false');
// Storage.setString('bPlaying', bPlaying ? 'true' : 'false');
//
// //updateFile();
// }
//
// void playAndPause() {
// if (player.state == FijkState.started) {
// bPlaying = false;
// player.pause();
// } else if (player.state == FijkState.paused) {
// bPlaying = true;
// player.start();
// }
// //setState(() {});
// playerRegionProvide.changePlayerState(bPlaying);
// Storage.setString('bPlaying', bPlaying ? 'true' : 'false');
// }
Alignment getAlignment(Offset offset, Size size) {
// final double centerX = offset.dx / 2.0;
// final double centerY = offset.dy / 2.0;
//offset.dx = centerX + alignment.x * centerX;
//double alignmentX = (0.0 == centerX) ? 0.0 : ((offset.dx - centerX) / centerX);
double alignmentX = (offset.dx / size.width).clamp(-1.0, 1.0);
//offset.dy = centerY + alignment.y * centerY;
//double alignmentY = (0.0 == centerY) ? 0.0 : ((offset.dy - centerY) / centerY);
double alignmentY = (offset.dy / size.height).clamp(-1.0, 1.0);
// print('offset.dx = ${offset.dx}, offset.dy = ${offset.dy}');
print('Alignment.X = $alignmentX, Alignment.Y = $alignmentY');
return Alignment(alignmentX, alignmentY);
}
//flutter dart生成N位随机数
//https://blog.csdn.net/qq_36071410/article/details/101268640
// 庄童 2019-09-24 10:24:58 10271 收藏
String RandomBit(int len) {
String scopeF = '123456789'; //首位
String scopeC = '0123456789'; //中间
String result = '';
for (int i = 0; i < len; i++) {
if (i == 0) {
result = scopeF[Random().nextInt(scopeF.length)];
} else {
result = result + scopeC[Random().nextInt(scopeC.length)];
}
}
return result;
}
// sign=md5(ijddvzgEGaxbzsbmCtpdohxHyrAArwJB1003)
// =3967eaebec0eed0642a1d395ac9293dd
String APPkey = 'ijddvzgEGaxbzsbmCtpdohxHyrAArwJB';
//Flutter对字符串进行MD5运算 发表于 2019-03-26 更新于 2020-12-04 分类于 Flutter 阅读次
String GenerateMd5(String str) {
var content = new Utf8Encoder().convert(str);
var md5 = crypto.md5;
var digest = md5.convert(content);
return hex.encode(digest.bytes);
}
//加载中的圈圈
Widget getMoreWidget2({
Color color = Colors.white,
String text = '加载中...',
double size = 30.0,
double strokeWidth = 3.0,
FontWeight fontWeight,
double edge = 10.0,
double height = 34,
}) {
return Center(
child: Padding(
padding: EdgeInsets.all(edge),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: size,
width: size,
child: CircularProgressIndicator(
strokeWidth: strokeWidth,
valueColor: AlwaysStoppedAnimation<Color>(color),
),
),
SizedBox(
height: ScreenUtil().setHeight(height),
),
Text(
text,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: size, // 文字大小
color: color,
fontWeight: fontWeight, // 文字颜色
),
),
],
),
),
);
}
//加载中的圈圈
Widget getMoreWidget({
String text = '加载中...',
Color color = Colors.white,
double size = 30.0,
double strokeWidth = 3.0,
TextAlign textAlign = TextAlign.left,
}) {
return Center(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: size,
width: size,
child: CircularProgressIndicator(
strokeWidth: strokeWidth,
valueColor: AlwaysStoppedAnimation<Color>(color),
),
),
SizedBox(
height: 10,
),
Text(
text,
textAlign: textAlign,
style: TextStyle(
fontSize: size, // 文字大小
color: color,
),
),
],
),
),
);
}
//自定义带说明图标按钮函数。点击说明文字有反应
Widget getIconAndTextButton(
{IconData iconData, Color iconColor = Colors.black, var onPress = null}) {
return Container(
width: 50,
height: 50,
alignment: const Alignment(0, 0),
child: FlatButton(
padding: EdgeInsets.all(0),
onPressed: onPress,
//color: Colors.blue,
color: Colors.transparent,
//解决报错问题FittedBox ← Expanded ← ConstrainedBox ← Container ← Center ← Padding ←
// Container ← IconTheme ← Builder ← _PointerListener
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 36, //最大高度
maxWidth: 36, //最大宽度
),
child: Padding(
padding: EdgeInsets.only(top: 1),
child: Icon(iconData, color: iconColor, size: 32),
// child: Image.asset(
// 'assets/images/left_arrow.png',
// fit: BoxFit.fitWidth,
// color: iconColor,
// //fit: BoxFit.cover,
// ),
),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.center,
// crossAxisAlignment: CrossAxisAlignment.end,
// children: [
// Image.asset('assets/images/left_arrow.png', fit: BoxFit.cover),
// // Expanded(
// // //child: Icon(iconData, color: iconColor, size: 24),
// // child: Image.asset('assets/images/left_arrow.png', fit: BoxFit.cover),
// // ),
// ],
// ),
),
//The offending Expanded is currently placed inside a ConstrainedBox widget.
//The ownership chain for the RenderObject that received the incompatible parent data was:
// FittedBox ← Expanded ← ConstrainedBox ← Container ← Center ← Padding ← Container ← IconTheme ←
//Builder ← _PointerListener
//The ParentDataWidget Expanded(flex: 1) wants to apply ParentData of type FlexParentData to a
//RenderObject, which has been set up to accept ParentData of incompatible type ParentData.
//Usually, this means that the Expanded widget has the wrong ancestor RenderObjectWidget. Typically,
//Expanded widgets are placed directly inside Flex widgets.
//The offending Expanded is currently placed inside a FittedBox widget.
//The ownership chain for the RenderObject that received the incompatible parent data was:
// ConstrainedBox ← Container ← Expanded ← FittedBox ← Center ← Padding ← Container ← IconTheme ←
//Builder ← _PointerListener ← ⋯
// child: ConstrainedBox(
// constraints: BoxConstraints(
// maxHeight: 20, //最大高度
// maxWidth: 28, //最大宽度
// ),
// child: Container(
// child: Expanded(
// child: new Icon(iconData, color: iconColor),
// ),
// ),
// ),
// child: ConstrainedBox(
// constraints: BoxConstraints(
// maxHeight: 30, //最大高度
// maxWidth: 38, //最大宽度
// minWidth: 38, //最大宽度
// ),
// child: Row(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Expanded(
// child: Icon(iconData, color: iconColor, size: 24),
// ),
// ],
// ),
// ),
// child: Container(
// width: 28,
// height: 20,
// child: Expanded(
// child: new FittedBox(
// fit: BoxFit.fill,
// child: new Icon(iconData, color: iconColor),
// ),
// ),
// ),
// child: FittedBox(
// fit: BoxFit.fitWidth,
// alignment: Alignment.topLeft,
// child: Container(
// width: 28,
// height: 20,
// child: Expanded(
// child: new FittedBox(
// fit: BoxFit.fill,
// child: new Icon(iconData, color: iconColor),
// ),
// ),
// ),
// ),
),
);
}
///获取缩进空白符
String getDeepSpace(int deep) {
var tab = StringBuffer();
for (int i = 0; i < deep; i++) {
tab.write("\t");
}
return tab.toString();
}
// List map2list(Map _map) {
// List _list = [];
// _list = List.generate(listContacts2[widget.contactIndex].length, (index) {
// String key = listContacts2[widget.contactIndex].keys.elementAt(index);
// //return TextEditingController(text: listContacts2[widget.contactIndex][key]);
// return TextEditingController(text: getUserText3(widget.contactIndex, key));
// });
//
// }
/// [object] 解析的对象
/// [deep] 递归的深度,用来获取缩进的空白长度
/// [isObject] 用来区分当前map或list是不是来自某个字段则不用显示缩进。单纯的map或list需要添加缩进
String json_print(dynamic object, int deep, {bool isObject = false}) {
var buffer = StringBuffer();
var nextDeep = deep + 1;
if (object is Map) {
var list = object.keys.toList();
if (!isObject) {
//如果map来自某个字段则不需要显示缩进
buffer.write("${getDeepSpace(deep)}");
}
buffer.write("{");
if (list.isEmpty) {
//当map为空直接返回}
buffer.write("}");
} else {
buffer.write("\n");
for (int i = 0; i < list.length; i++) {
buffer.write("${getDeepSpace(nextDeep)}\"${list[i]}\":");
buffer.write(json_print(object[list[i]], nextDeep, isObject: true));
if (i < list.length - 1) {
buffer.write(",");
buffer.write("\n");
}
}
buffer.write("\n");
buffer.write("${getDeepSpace(deep)}}");
}
} else if (object is List) {
if (!isObject) {
//如果list来自某个字段则不需要显示缩进
buffer.write("${getDeepSpace(deep)}");
}
buffer.write("[");
if (object.isEmpty) {
//当list为空直接返回]
buffer.write("]");
} else {
buffer.write("\n");
for (int i = 0; i < object.length; i++) {
buffer.write(json_print(object[i], nextDeep));
if (i < object.length - 1) {
buffer.write(",");
buffer.write("\n");
}
}
buffer.write("\n");
buffer.write("${getDeepSpace(deep)}]");
}
} else if (object is String) {
//为字符串时,需要添加双引号并返回当前内容
buffer.write("\"$object\"");
} else if (object is num || object is bool) {
//为数字或者布尔值时,返回当前内容
buffer.write(object);
} else {
//如果对象为空则返回null字符串
buffer.write("null");
}
return buffer.toString();
}
//人脸识别和上传的图片,都需要转换为 Base64 格式的字符串提交
//通过图片路径将图片转换成 Base64 字符串
Future image2Base64(String imagePath) async {
File file = File(imagePath);
List<int> imageBytes = await file.readAsBytes();
String bs64 = base64Encode(imageBytes);
String ext = getFileExtension(imagePath);
print('imagePath = $imagePath, ext = $ext');
//String bs64Image = "data:image/png;base64," + bs64;
String bs64Image = "data:image/${ext};base64," + bs64;
return bs64Image;
}
//从字符路径 path 获取扩展名,不含点号
getFileExtension(String path) {
//return path.substring(path.lastIndexOf('.'));
//imagePath = /data/user/0/com.flutter.hyzp_ybqx/app_flutter/Pictures/flutter_test/1614662209478.jpg, ext = .jpg
return path.substring(path.lastIndexOf('.') + 1); //不含点号
}
//从字符路径 path 获取文件名(含扩展名)
getFileName(String path) {
//return path.substring(path.lastIndexOf('.'));
//imagePath = /data/user/0/com.flutter.hyzp_ybqx/app_flutter/Pictures/flutter_test/1614662209478.jpg, ext = .jpg
return path.substring(path.lastIndexOf('/') + 1); //不含点号
}
Widget getBtnSizeX({@required text, double width = 70.0, double height = 40.0, onPressedFun}) {
return Container(
color: Colors.white12, //onPressedFun为null时无效
width: width,
height: height,
child: RaisedButton(
padding: EdgeInsets.all(0),
textColor: Colors.black,
child: Text(text),
onPressed: onPressedFun,
),
);
}
//返回主页ashamp
// 博客园首页新随笔联系管理订阅订阅随笔 - 33 文章 - 0 评论 - 51 阅读 - 55018
// 在debug时使Flutter中的print打印json数据时更美观易读
// 为了避免deubg信息在生产环境打印,只在测试时打印,在main函数中,改变debugPrint的指向
//
// 复制代码
// main(){
// if (Api.isDebug) {
// debugPrint = (String message, {int wrapWidth}) {
// try {
// var object = json.decode(message);
// message = JsonEncoder.withIndent(' ').convert(object);
// } catch (e) {}
// printWrapped(message);
// };
// } else {
// debugPrint = (String message, {int wrapWidth}) {};
// }
// }
// 复制代码
// 将printWrapped方法放入工具类或你需要的地方
//
// void printWrapped(String text) {
// final pattern = new RegExp('.{1,800}'); // 800 is the size of each chunk
// pattern.allMatches(text).forEach((match) => developer.log(match.group(0)));
// }
// log方法需要引入
//
// import 'dart:developer' as developer;
//
//在debug时使 Flutter 中的 print 打印 json 数据时更美观易读
void jsonPrint(String message, {int len = 800}) {
//是否在生产环境
const bool isDebug = !const bool.fromEnvironment("dart.vm.product");
// if (!isDebug) {
// return;
// }
try {
var object = json.decode(message);
message = JsonEncoder.withIndent(' ').convert(object);
} catch (e) {
print('e = $e');
}
printWrapped(message);
}
// 打印长字符串
void printWrapped(String text, {int len = 800}) {
final pattern = RegExp('.{1,$len}'); // 800 is the size of each chunk
pattern.allMatches(text).forEach((match) => developer.log(match.group(0)));
}
//OK
void my_segmentPrint(String str, {int len = 800}) {
//是否在生产环境
const bool isDebug = !const bool.fromEnvironment("dart.vm.product");
if (!isDebug) {
return;
}
List list = strToList(str);
for (int i = 0; i < list.length; i++) {
print('${list[i]}');
}
}
//OK
List strToList(String str, {int len = 800}) {
List<String> strList = [];
if (str.length <= len) {
strList.add(str);
} else {
int splitCount = str.length ~/ len; //应该切割的次数
for (int i = 0; i < splitCount; i++) {
strList.add(str.substring(len * i, len * (i + 1)));
}
//处理最后一段
if (str.length % len != 0) {
strList.add(str.substring(len * splitCount));
}
}
print('strList:${strList.toString}');
return strList;
}
Widget getImageWidget() {
return Container(
alignment: Alignment(0, 0),
height: ScreenUtil().setHeight(346),
width: ScreenUtil().setWidth(942),
decoration: BoxDecoration(
image: DecorationImage(image: AssetImage('assets/images/装饰图片10.png'), fit: BoxFit.cover),
),
child: Column(
children: [
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(top: ScreenUtil().setWidth(30), left: ScreenUtil().setWidth(55)),
child: Text('改善城市空气质量', style: TextStyle(fontSize: 17, color: Colors.white)),
),
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: ScreenUtil().setWidth(55)),
child: Text('建设长江生态第一城',
style: TextStyle(
fontSize: 19,
color: Color.fromRGBO(49, 216, 123, 1),
fontWeight: FontWeight.bold)),
),
],
),
// child: Image.asset(
// 'assets/images/装饰图片10.png',
// fit: BoxFit.cover,
// ),
);
}
Widget getIconBtnSizeX(
{@required text,
width = 233,
height = 116,
onTop,
Color color = Colors.black,
double circular = 10,
double textSize = 18}) {
return InkWell(
onTap: onTop,
child: Container(
alignment: Alignment(0, 0),
margin: EdgeInsets.all(0),
padding: EdgeInsets.all(0),
width: ScreenUtil().setWidth(width),
height: ScreenUtil().setHeight(height),
decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(circular)),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(width: ScreenUtil().setWidth(12)),
Icon(Icons.play_arrow, color: Colors.white, size: ScreenUtil().setWidth(56)),
Text(
text,
style: TextStyle(color: Colors.white, fontSize: textSize),
)
],
),
),
);
}