diff --git a/android/app/build.gradle b/android/app/build.gradle
index af31424..1e6f864 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -41,6 +41,9 @@ android {
targetSdkVersion 29
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
+ ndk {
+ abiFilters "arm64-v8a", "armeabi", "armeabi-v7a", "mips" // 不支持"x86", "x86_64"模拟器
+ }
}
buildTypes {
diff --git a/android/app/release/output.json b/android/app/release/output.json
index 940283b..02a09d3 100644
--- a/android/app/release/output.json
+++ b/android/app/release/output.json
@@ -1 +1 @@
-[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":20220620,"versionName":"1.5.3","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
\ No newline at end of file
+[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":20250521,"versionName":"1.6.4","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
\ No newline at end of file
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index c132438..3004b3f 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -36,6 +36,9 @@
+
+
+
-1) {
+ if (mapKey.length == 0 || key.length < mapKey.length) {
+ mapKey = key;
+ }
+ }
+ }
+
+ _mapChsName = mapChsName[mapKey];
+
+ if (_mapChsName == null) {
+ _mapChsName = mapName + (mapName.length > 0 ? '地图' : '');
+ }
+ return _mapChsName;
+}
+
+// key 全部小写
+Map mapChsName = {
+ 'apple': '苹果地图',
+ 'google': '谷歌地图',
+ 'googlego': '谷歌地图轻量版',
+ 'amap': '高德地图',
+ 'baidu': '百度地图',
+ 'waze': '位智地图',
+ 'yandexmaps': 'Yandex地图',
+ 'yandexnavi': 'Yandex导航地图',
+ 'citymapper': '城市地图',
+ 'mapswithme': '离线地图',
+ 'osmand': 'OsmAnd地图',
+ 'doubleGis': 'doubleGis地图',
+ 'tencent': '腾讯地图',
+};
+
// Timer g_remindTimer; //定时提醒变量
//
// // 设置定时提醒
@@ -187,6 +228,7 @@ String copyright_info_PinYin = '';
// 区县中心地址
double center_latitude = -1; // 区县中心纬度
double center_longitude = -1; // 区县中心经度
+String official_seal = ''; // 区县单位公章
clear_user_info() {
qx_code = -1;
@@ -887,7 +929,7 @@ Widget getImageWidget() {
color: Color.fromRGBO(49, 216, 123, 1),
fontWeight: FontWeight.bold)),
),
- SizedBox(height: ScreenUtil().setHeight(copyright_info.contains('\n') ? 25 : 90)),
+ SizedBox(height: ScreenUtil().setHeight(copyright_info.contains('\n') ? 25 : 70)),
Container(
alignment: Alignment.center,
child: Text(copyright_info,
diff --git a/lib/components/dioFun.dart b/lib/components/dioFun.dart
index dd6e120..fd6c83f 100644
--- a/lib/components/dioFun.dart
+++ b/lib/components/dioFun.dart
@@ -2078,6 +2078,7 @@ Future playUrl({@required int index, String url, BuildContext context}) {
id: index + 1,
dwip: listDwinfoGetList2[index]['dwip'],
url: urlnew,
+ urlType: 'rtmp',
title: '点位视频\n${(index + 1)}、${listDwinfoGetList2[index]['dwmc']}',
)));
diff --git a/lib/main.dart b/lib/main.dart
index e24d0d1..d4253fc 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -91,7 +91,7 @@ class _MyAppState extends State {
// g_bVoiceRemind = (null == g_bVoiceRemind) ? false : g_bVoiceRemind; // 默认关闭
g_bVoiceRemind = (null == g_bVoiceRemind) ? true : g_bVoiceRemind; // 默认开启
// print('g_bVoiceRemind = $g_bVoiceRemind');
- g_remindGap = await Storage.getInt('nRemindGap');
+ g_remindGap = await Storage.getInt('nRemindGap');
g_remindGap = (null == g_remindGap) ? 60 : g_remindGap; // 提醒间隔默认为60S
eventBus.fire(VoiceRemindUpdate('g_bVoiceRemind 数据已更新'));
diff --git a/lib/my_fijkPanel_fix/my_fijkvalue.dart b/lib/my_fijkPanel_fix/my_fijkvalue.dart
new file mode 100644
index 0000000..f9cc64c
--- /dev/null
+++ b/lib/my_fijkPanel_fix/my_fijkvalue.dart
@@ -0,0 +1,50 @@
+//MIT License
+//
+//Copyright (c) [2019] [Befovy]
+//
+//Permission is hereby granted, free of charge, to any person obtaining a copy
+//of this software and associated documentation files (the "Software"), to deal
+//in the Software without restriction, including without limitation the rights
+//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//copies of the Software, and to permit persons to whom the Software is
+//furnished to do so, subject to the following conditions:
+//
+//The above copyright notice and this permission notice shall be included in all
+//copies or substantial portions of the Software.
+//
+//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+//SOFTWARE.
+
+//r:\Flutter\FlutterSDK\flutter\.pub-cache\hosted\pub.flutter-io.cn\fijkplayer-0.8.4\lib\core\MyFijkValue.dart
+//part of fijkplayer;
+
+import 'dart:core';
+
+//新增的,为变私有成员为公有成员
+class MyFijkData {
+ static String fijkViewPanelVolume = "__fijkview_panel_init_volume";
+ static String fijkViewPanelBrightness = "__fijkview_panel_init_brightness";
+ static String fijkViewPanelSeekto = "__fijkview_panel_sekto_position";
+}
+
+//新增的,为变私有成员为公有成员
+String mYduration2String(Duration duration) {
+ if (duration.inMilliseconds < 0) return "-: negtive";
+
+ String twoDigits(int n) {
+ if (n >= 10) return "$n";
+ return "0$n";
+ }
+
+ String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
+ String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
+ int inHours = duration.inHours;
+ return inHours > 0
+ ? "$inHours:$twoDigitMinutes:$twoDigitSeconds"
+ : "$twoDigitMinutes:$twoDigitSeconds";
+}
diff --git a/lib/my_fijkPanel_fix/my_panel3.dart b/lib/my_fijkPanel_fix/my_panel3.dart
new file mode 100644
index 0000000..c4225a3
--- /dev/null
+++ b/lib/my_fijkPanel_fix/my_panel3.dart
@@ -0,0 +1,828 @@
+import 'dart:async';
+import 'dart:core';
+import 'dart:math';
+import 'dart:ui';
+import 'dart:typed_data';
+
+import 'package:fijkplayer/fijkplayer.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/rendering.dart';
+import 'package:flutter/widgets.dart';
+import 'my_fijkvalue.dart';
+import '../components/commonFun.dart';
+import 'package:provider/provider.dart';
+import '../provider/player_ratio.dart';
+import 'my_slider.dart';
+import '../my_extended_image/common/image_picker/_image_picker_io.dart';
+import '../services/Storage.dart';
+
+// class MyFijkPanelWidgetBuilder extends StatefulWidget {
+// const MyFijkPanelWidgetBuilder({Key key, this.path}) : super(key: key);
+// final path;
+// @override
+// State createState() {
+// return MyFijkPanelWidgetBuilderState();
+// }
+// }
+
+// snapshot
+ImageProvider myImageProvider;
+//ImageProvider _imageProvider;
+//Timer _snapshotTimer;
+
+FijkPanelWidgetBuilder fijkPanel2Builder3(
+ {Key key,
+ final FijkPlayer player,
+ final bool fill = false,
+ final int duration = 4000,
+ final bool doubleTap = true,
+ final bool snapShot = false,
+ final VoidCallback onBack}) {
+ return (FijkPlayer player, FijkData data, BuildContext context, Size viewSize,
+ Rect texturePos) {
+ return MyFijkPanelWidgetBuilder(
+ key: key,
+ player: player,
+ data: data,
+ onBack: onBack,
+ viewSize: viewSize,
+ texPos: texturePos,
+ fill: fill,
+ doubleTap: doubleTap,
+ snapShot: snapShot,
+ hideDuration: duration,
+ );
+ };
+}
+
+class MyFijkPanelWidgetBuilder extends StatefulWidget {
+ final FijkPlayer player;
+ final FijkData data;
+ final VoidCallback onBack;
+ final Size viewSize;
+ final Rect texPos;
+ final bool fill;
+ final bool doubleTap;
+ final bool snapShot;
+ final int hideDuration;
+
+ const MyFijkPanelWidgetBuilder(
+ {Key key,
+ @required this.player,
+ this.data,
+ this.fill,
+ this.onBack,
+ this.viewSize,
+ this.hideDuration,
+ this.doubleTap,
+ this.snapShot,
+ this.texPos})
+ : assert(player != null),
+ assert(
+ hideDuration != null && hideDuration > 0 && hideDuration < 10000),
+ super(key: key);
+
+ // @override
+ // FijkPanel2State createState() => FijkPanel2State();
+ // @override
+ //State createState() {
+ MyFijkPanelWidgetBuilderState createState() {
+ return MyFijkPanelWidgetBuilderState(player);
+ }
+}
+
+class MyFijkPanelWidgetBuilderState extends State
+ with SingleTickerProviderStateMixin {
+ FijkPlayer player;
+
+ MyFijkPanelWidgetBuilderState(@required this.player) {
+ _oldFullScreen = player.value.fullScreen;
+ }
+
+ PlayerRatioProvide playerRatioProvide;
+ AnimationController _controller;
+ Animation _animation;
+ Offset _normalizedOffset;
+ double _previousScale;
+ double _kMinFlingVelocity = 600.0;
+
+ Offset _offset = Offset.zero;
+ double _scale = 1.0;
+ Offset _focalPoint = Offset.zero;
+ Offset _deltaPoint = Offset.zero;
+
+ bool _oldFullScreen;
+ bool _bScaleing = false;
+
+ //FijkPlayer get player => widget.player;
+
+ Timer _hideTimer;
+ bool _hideStuff = true;
+
+ Timer _statelessTimer;
+ bool _prepared = false;
+ bool _playing = false;
+
+ //bool _dragLeft;
+ int _nDrag; //0 Left, 1 Center, 2 Right
+ double _volume;
+ double _brightness;
+ double _deltaX = 0;
+ double _deltaY = 0;
+
+ double _seekPos = -1.0;
+ Duration _duration = Duration();
+ Duration _currentPos = Duration();
+ Duration _bufferPos = Duration();
+
+ StreamSubscription _currentPosSubs;
+ StreamSubscription _bufferPosSubs;
+
+ StreamController _valController;
+
+ // snapshot
+ //ImageProvider _imageProvider;
+ Timer _snapshotTimer;
+
+ // Is it needed to clear seek data in FijkData (widget.data)
+ bool _needClearSeekData = true;
+
+ static const MyFijkSliderColors sliderColors = MyFijkSliderColors();
+
+ @override
+ void initState() {
+ super.initState();
+
+ _controller = AnimationController(vsync: this);
+ _controller.addListener(() {
+ setState(() {
+ _offset = _animation.value;
+ });
+ });
+
+ _valController = StreamController.broadcast();
+ _prepared = player.state.index >= FijkState.prepared.index;
+ _playing = player.state == FijkState.started;
+ _duration = player.value.duration;
+ _currentPos = player.currentPos;
+ _bufferPos = player.bufferPos;
+
+ _currentPosSubs = player.onCurrentPosUpdate.listen((v) {
+ if (_hideStuff == false) {
+ setState(() {
+ _currentPos = v;
+ });
+ } else {
+ _currentPos = v;
+ }
+ if (_needClearSeekData) {
+ widget.data.clearValue(MyFijkData.fijkViewPanelSeekto);
+ }
+ _needClearSeekData = false;
+ });
+
+ if (widget.data.contains(MyFijkData.fijkViewPanelSeekto)) {
+ var pos = widget.data.getValue(MyFijkData.fijkViewPanelSeekto) as double;
+ _currentPos = Duration(milliseconds: pos.toInt());
+ }
+
+ _bufferPosSubs = player.onBufferPosUpdate.listen((v) {
+ if (_hideStuff == false) {
+ setState(() {
+ _bufferPos = v;
+ });
+ } else {
+ _bufferPos = v;
+ }
+ });
+ player.addListener(_playerValueChanged);
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ _controller.dispose();
+ _valController?.close();
+ _hideTimer?.cancel();
+ _statelessTimer?.cancel();
+ _snapshotTimer?.cancel();
+ _currentPosSubs?.cancel();
+ _bufferPosSubs?.cancel();
+ player.removeListener(_playerValueChanged);
+ }
+
+ double dura2double(Duration d) {
+ return d != null ? d.inMilliseconds.toDouble() : 0.0;
+ }
+
+ void _playerValueChanged() {
+ FijkValue value = player.value;
+
+ if (value.duration != _duration) {
+ if (_hideStuff == false) {
+ setState(() {
+ _duration = value.duration;
+ });
+ } else {
+ _duration = value.duration;
+ }
+ }
+ bool playing = (value.state == FijkState.started);
+ bool prepared = value.prepared;
+ if (playing != _playing ||
+ prepared != _prepared ||
+ value.state == FijkState.asyncPreparing) {
+ setState(() {
+ _playing = playing;
+ _prepared = prepared;
+ });
+ }
+ }
+
+ void _restartHideTimer() {
+ _hideTimer?.cancel();
+ _hideTimer = Timer(Duration(milliseconds: widget.hideDuration), () {
+ setState(() {
+ _hideStuff = true;
+ });
+ });
+ }
+
+ void onTapFun() {
+ if (_hideStuff == true) {
+ _restartHideTimer();
+ }
+ setState(() {
+ _hideStuff = !_hideStuff;
+ });
+ }
+
+ void playOrPause() {
+ if (player.isPlayable() || player.state == FijkState.asyncPreparing) {
+ if (player.state == FijkState.started) {
+ //bPlaying = false;
+ playerRegionProvide.changePlayerState(false);
+ Storage.setString('bPlaying', 'false');
+ player.pause();
+ } else {
+ //bPlaying = true;
+ playerRegionProvide.changePlayerState(true);
+ Storage.setString('bPlaying', 'true');
+ player.start();
+ }
+ //setState(() {});
+ } else {
+ FijkLog.w("Invalid state ${player.state} ,can't perform play or pause");
+ }
+ }
+
+ void onVerticalDragStartFun(DragStartDetails d) {
+ // if (_bScaleing) {
+ // return;
+ // }
+ if (d.localPosition.dx > panelWidth() * 3 / 4) {
+ // right, volume
+ //_dragLeft = false;
+ _nDrag = 2; //0 Left, 1 Center, 2 Right
+
+ //https://fijkplayer.befovy.com/docs/zh/system-volume.html#gsc.tab=0
+ /// never show system volume changed UI.
+ int neverShowUI = 2;
+ FijkVolume.setUIMode(neverShowUI);
+
+ FijkVolume.getVol().then((v) {
+ if (widget.data != null &&
+ !widget.data.contains(MyFijkData.fijkViewPanelVolume)) {
+ widget.data.setValue(MyFijkData.fijkViewPanelVolume, v);
+ }
+ setState(() {
+ _volume = v;
+ _valController.add(v);
+ });
+ });
+ } else if (d.localPosition.dx < panelWidth() / 4) {
+ // left, brightness
+ //_dragLeft = true;
+ _nDrag = 0; //0 Left, 1 Center, 2 Right
+ FijkPlugin.screenBrightness().then((v) {
+ if (widget.data != null &&
+ !widget.data.contains(MyFijkData.fijkViewPanelBrightness)) {
+ widget.data.setValue(MyFijkData.fijkViewPanelBrightness, v);
+ }
+ setState(() {
+ _brightness = v;
+ _valController.add(v);
+ });
+ });
+ } else {
+ _nDrag = 1; //0 Left, 1 Center, 2 Right
+ // setState(() {
+ // if (_oldFullScreen != player.value.fullScreen) {
+ // //全屏和窗口之间切换,便初始化相关变量
+ // _oldFullScreen = player.value.fullScreen;
+ // // _offset = Offset.zero;
+ // // _scale = 1.0;
+ // //_focalPoint = Offset.zero;
+ // //_deltaPoint = Offset.zero;
+ // }
+ // // _bScaleing = true;
+ // // _previousScale = _scale;
+ // // _normalizedOffset = (d.localPosition - _offset) / _scale;
+ // // // 计算图片放大后的位置
+ // // _controller.stop();
+ // });
+ }
+ _statelessTimer?.cancel();
+ _statelessTimer = Timer(const Duration(milliseconds: 2000), () {
+ setState(() {});
+ });
+ }
+
+ void onVerticalDragUpdateFun(DragUpdateDetails d) {
+ // if (_bScaleing) {
+ // return;
+ // }
+
+ double delta = d.primaryDelta / panelHeight();
+ print("d.primaryDelta = ${d.primaryDelta}, delta = {$delta}");
+
+ delta = -delta.clamp(-1.0, 1.0);
+ //if (_dragLeft != null && _dragLeft == false) {
+ if (_nDrag != null && _nDrag == 2) {
+ if (_volume != null) {
+ _volume += delta;
+ _volume = _volume.clamp(0.0, 1.0);
+ FijkVolume.setVol(_volume);
+ setState(() {
+ _valController.add(_volume);
+ });
+ }
+ //} else if (_dragLeft != null && _dragLeft == true) {
+ } else if (_nDrag != null && _nDrag == 0) {
+ if (_brightness != null) {
+ _brightness += delta;
+ _brightness = _brightness.clamp(0.0, 1.0);
+ FijkPlugin.setScreenBrightness(_brightness);
+ setState(() {
+ _valController.add(_brightness);
+ });
+ }
+ } else {
+ setState(() {
+ //_scale = (_previousScale * details.scale).clamp(1.0, 10.0);
+ // 限制放大倍数 1~10倍
+ // _offset = _clampOffset(d.localPosition - _normalizedOffset * _scale);
+ // playerRatioProvide.changeOffset(_offset);
+
+ _deltaY -= 2 * d.primaryDelta / panelHeight();
+ _deltaY = _deltaY.clamp(-1.0, 1.0);
+ playerRatioProvide.changeDeltaY(_deltaY);
+ // 更新当前位置
+ });
+ }
+ }
+
+ void onVerticalDragEndFun(DragEndDetails e) {
+ _volume = null;
+ _brightness = null;
+ }
+
+ Widget buildPlayButton(BuildContext context, double height) {
+ Icon icon = (player.state == FijkState.started)
+ ? Icon(Icons.pause)
+ : Icon(Icons.play_arrow);
+ bool fullScreen = player.value.fullScreen;
+ return IconButton(
+ padding: EdgeInsets.all(0),
+ iconSize: fullScreen ? height : height * 0.8,
+ color: Color(0xFFFFFFFF),
+ icon: icon,
+ onPressed: playOrPause,
+ );
+ }
+
+ Widget buildFullScreenButton(BuildContext context, double height) {
+ Icon icon = player.value.fullScreen
+ ? Icon(Icons.fullscreen_exit)
+ : Icon(Icons.fullscreen);
+ bool fullScreen = player.value.fullScreen;
+ return IconButton(
+ padding: EdgeInsets.all(0),
+ iconSize: fullScreen ? height : height * 0.8,
+ color: Color(0xFFFFFFFF),
+ icon: icon,
+ onPressed: () {
+ player.value.fullScreen
+ ? player.exitFullScreen()
+ : player.enterFullScreen();
+ },
+ );
+ }
+
+ Widget buildTimeText(BuildContext context, double height) {
+ String text = "${mYduration2String(_currentPos)}" +
+ "/${mYduration2String(_duration)}";
+ return Text(text, style: TextStyle(fontSize: 12, color: Color(0xFFFFFFFF)));
+ }
+
+ Widget buildSlider(BuildContext context) {
+ double duration = dura2double(_duration);
+
+ double currentValue = _seekPos > 0 ? _seekPos : dura2double(_currentPos);
+ currentValue = currentValue.clamp(0.0, duration);
+
+ double bufferPos = dura2double(_bufferPos);
+ bufferPos = bufferPos.clamp(0.0, duration);
+
+ return Padding(
+ padding: EdgeInsets.only(left: 0),
+ child: MyFijkSlider(
+ colors: sliderColors,
+ value: currentValue,
+ cacheValue: bufferPos,
+ min: 0.0,
+ max: duration,
+ onChanged: (v) {
+ _restartHideTimer();
+ setState(() {
+ _seekPos = v;
+ });
+ },
+ onChangeEnd: (v) {
+ setState(() {
+ player.seekTo(v.toInt());
+ _currentPos = Duration(milliseconds: _seekPos.toInt());
+ widget.data.setValue(MyFijkData.fijkViewPanelSeekto, _seekPos);
+ _needClearSeekData = true;
+ _seekPos = -1.0;
+ });
+ },
+ ),
+ );
+ }
+
+ Widget buildBottom(BuildContext context, double height) {
+ if (_duration != null && _duration.inMilliseconds > 0) {
+ return Row(
+ children: [
+ buildPlayButton(context, height),
+ buildTimeText(context, height),
+ Expanded(child: buildSlider(context)),
+ buildFullScreenButton(context, height),
+ ],
+ );
+ } else {
+ return Row(
+ children: [
+ buildPlayButton(context, height),
+ Expanded(child: Container()),
+ buildFullScreenButton(context, height),
+ ],
+ );
+ }
+ }
+
+ void takeSnapshot() {
+ player.takeSnapShot().then((v) {
+ var provider = MemoryImage(v);
+ precacheImage(provider, context).then((_) {
+ setState(() {
+ myImageProvider = provider;
+ });
+ });
+ FijkLog.d("get snapshot succeed");
+
+ //Uint8List fileData;
+ String fileFath;
+ ImageSaver.save('extended_image_cropped_image.jpg', v).then((value) {
+ fileFath = value;
+ // var fileFath = await ImagePickerSaver.saveFile(fileData: fileData);
+ print('my save fileFath : $fileFath');
+ });
+ }).catchError((e) {
+ FijkLog.d("get snapshot failed");
+ });
+ }
+
+ Widget buildPanel(BuildContext context) {
+ double height = panelHeight();
+
+ bool fullScreen = player.value.fullScreen;
+ Widget centerWidget = Container(
+ color: Color(0x00000000),
+ );
+
+ Widget centerChild = Container(
+ color: Color(0x00000000),
+ );
+
+ if (fullScreen && widget.snapShot) {
+ centerWidget = Row(
+ children: [
+ Expanded(child: centerChild),
+ Padding(
+ padding: EdgeInsets.only(left: 10, right: 10, top: 8, bottom: 8),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ IconButton(
+ padding: EdgeInsets.all(0),
+ color: Color(0xFFFFFFFF),
+ icon: Icon(Icons.camera_alt),
+ onPressed: () {
+ takeSnapshot();
+ },
+ ),
+ ],
+ ),
+ )
+ ],
+ );
+ }
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Container(
+ height: height > 200 ? 80 : height / 5,
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ colors: [Color(0x88000000), Color(0x00000000)],
+ begin: Alignment.topCenter,
+ end: Alignment.bottomCenter,
+ ),
+ ),
+ ),
+ Expanded(
+ child: centerWidget,
+ ),
+ Container(
+ height: height > 80 ? 80 : height / 2,
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ colors: [Color(0x88000000), Color(0x00000000)],
+ end: Alignment.topCenter,
+ begin: Alignment.bottomCenter,
+ ),
+ ),
+ alignment: Alignment.bottomCenter,
+ child: Container(
+ height: height > 80 ? 45 : height / 2,
+ padding: EdgeInsets.only(left: 8, right: 8, bottom: 5),
+ child: buildBottom(context, height > 80 ? 40 : height / 2),
+ // child: CustomFijkWidgetBottom(
+ // player: player,
+ // buildContext: context,
+ // viewSize:
+ // Size(widget.viewSize.width, widget.viewSize.height - 50),
+ // texturePos: Rect.fromLTRB(widget.texPos.left, widget.texPos.top,
+ // widget.texPos.width, widget.texPos.height - 50),
+ //),
+ ),
+ )
+ ],
+ );
+ }
+
+ Rect panelRect() {
+ Rect rect = player.value.fullScreen || (true == widget.fill)
+ ? Rect.fromLTWH(0, 0, widget.viewSize.width, widget.viewSize.height)
+ : Rect.fromLTRB(
+ max(0.0, widget.texPos.left),
+ max(0.0, widget.texPos.top),
+ min(widget.viewSize.width, widget.texPos.right),
+ min(widget.viewSize.height, widget.texPos.bottom));
+ return rect;
+ }
+
+ double panelHeight() {
+ if (player.value.fullScreen || (true == widget.fill)) {
+ return widget.viewSize.height;
+ } else {
+ return min(widget.viewSize.height, widget.texPos.bottom) -
+ max(0.0, widget.texPos.top);
+ }
+ }
+
+ double panelWidth() {
+ if (player.value.fullScreen || (true == widget.fill)) {
+ return widget.viewSize.width;
+ } else {
+ return min(widget.viewSize.width, widget.texPos.right) -
+ max(0.0, widget.texPos.left);
+ }
+ }
+
+ Widget buildBack(BuildContext context) {
+ return IconButton(
+ padding: EdgeInsets.only(left: 5),
+ icon: Icon(
+ Icons.arrow_back_ios,
+ color: Color(0xDDFFFFFF),
+ ),
+ onPressed: widget.onBack,
+ );
+ }
+
+ Widget buildStateless() {
+ if (_volume != null || _brightness != null) {
+ Widget toast = _volume == null
+ ? defaultFijkBrightnessToast(_brightness, _valController.stream)
+ : defaultFijkVolumeToast(_volume, _valController.stream);
+ return IgnorePointer(
+ child: AnimatedOpacity(
+ opacity: 1,
+ duration: Duration(milliseconds: 500),
+ child: toast,
+ ),
+ );
+ } else if (player.state == FijkState.asyncPreparing) {
+ return Container(
+ alignment: Alignment.center,
+ child: SizedBox(
+ width: 30,
+ height: 30,
+ child: CircularProgressIndicator(
+ valueColor: AlwaysStoppedAnimation(Colors.white)),
+ ),
+ );
+ } else if (player.state == FijkState.error) {
+ return Container(
+ alignment: Alignment.center,
+ child: Icon(
+ Icons.error,
+ size: 30,
+ color: Color(0x99FFFFFF),
+ ),
+ );
+ } else if (myImageProvider != null) {
+ _snapshotTimer?.cancel();
+ _snapshotTimer = Timer(Duration(milliseconds: 1500), () {
+ if (mounted) {
+ setState(() {
+ myImageProvider = null;
+ });
+ }
+ });
+ return Center(
+ child: IgnorePointer(
+ child: Container(
+ decoration: BoxDecoration(
+ border: Border.all(color: Colors.yellowAccent, width: 3)),
+ child:
+ Image(height: 200, fit: BoxFit.contain, image: myImageProvider),
+ ),
+ ),
+ );
+ } else {
+ return Container();
+ }
+ }
+
+ GestureDetector buildGestureDetector(BuildContext context) {
+ return GestureDetector(
+ onScaleStart: _handleOnScaleStart,
+ onScaleUpdate: _handleOnScaleUpdate,
+ onScaleEnd: _handleOnScaleEnd,
+ onDoubleTap: () {
+ //自定义 FijkView 的双击响应
+ print('My onDoubleTap');
+ if (1.0 == playerRatioProvide.scale) {
+ playOrPause();
+ } else {
+ _handleScaleBack();
+ }
+ },
+
+ onTap: onTapFun,
+ //onDoubleTap: widget.doubleTap ? onDoubleTapFun : null,
+ onVerticalDragUpdate: onVerticalDragUpdateFun,
+ onVerticalDragStart: onVerticalDragStartFun,
+ onVerticalDragEnd: onVerticalDragEndFun,
+ //onHorizontalDragUpdate: (d) {},
+ child: AbsorbPointer(
+ absorbing: _hideStuff,
+ child: AnimatedOpacity(
+ opacity: _hideStuff ? 0 : 1,
+ duration: Duration(milliseconds: 300),
+ child: buildPanel(context),
+ ),
+ ),
+ );
+ }
+
+ void _handleOnScaleStart(ScaleStartDetails details) {
+ setState(() {
+ // if (_oldFullScreen != player.value.fullScreen) {
+ // //全屏和窗口之间切换,便初始化相关变量
+ // _oldFullScreen = player.value.fullScreen;
+ // // _offset = Offset.zero;
+ // // _scale = 1.0;
+ // //_focalPoint = Offset.zero;
+ // //_deltaPoint = Offset.zero;
+ // }
+
+ _bScaleing = true;
+ _previousScale = _scale;
+ _normalizedOffset = (details.focalPoint - _offset) / _scale;
+ // 计算图片放大后的位置
+ _controller.stop();
+ _focalPoint = details.focalPoint;
+ });
+ }
+
+ void _handleScaleBack() {
+ // 更新当前位置
+ playerRatioProvide.changeScale(1.0);
+ playerRatioProvide.changeOffset(Offset(0, 0));
+ playerRatioProvide.changeDeltaX(0.0);
+ playerRatioProvide.changeDeltaY(0.0);
+ }
+
+ void _handleOnScaleUpdate(ScaleUpdateDetails details) {
+ setState(() {
+ print('details.scale = ${details.scale}');
+ //print('_scale = $_scale, offset.dx = ${_offset.dx}, offset.dy = ${_offset.dy}');
+ //print('details.focalPoint = (${details.focalPoint.dx}, ${details.focalPoint.dy})');
+ //print('details.horizontalScale = ${details.horizontalScale}; details.verticalScale = ${details.verticalScale})');
+
+ if (1.0 != details.scale) {
+ _scale = (_previousScale * details.scale).clamp(1.0, 10.0);
+ playerRatioProvide.changeScale(_scale);
+ // 限制放大倍数 1~10倍
+ _offset = _clampOffset(details.focalPoint - _normalizedOffset * _scale);
+ } else {
+ _deltaPoint = _clampdeltaPoint(details.focalPoint - _focalPoint);
+ _focalPoint = details.focalPoint;
+ print('_deltaPoint = (${_deltaPoint.dx}, ${_deltaPoint.dy})');
+ playerRatioProvide.changeDeltaX(_deltaPoint.dx);
+ playerRatioProvide.changeDeltaY(_deltaPoint.dy);
+ }
+
+ // 更新当前位置
+ playerRatioProvide.changeOffset(_offset);
+ });
+ }
+
+ Offset _clampdeltaPoint(Offset delta) {
+ final Size size = context.size; // widget的屏幕尺寸
+ double rate = 2.0;
+ Offset deltaPoint =
+ Offset((rate * delta.dx / size.width), (rate * delta.dy / size.height));
+ _deltaPoint -= deltaPoint;
+ return Offset(
+ _deltaPoint.dx.clamp(-1.0, 1.0), _deltaPoint.dy.clamp(-1.0, 1.0));
+ }
+
+ Offset _clampOffset(Offset offset) {
+ final Size size = context.size;
+ // widget的屏幕宽度
+ final Offset minOffset = Offset(size.width, size.height) * (1.0 - _scale);
+ // 限制他的最小尺寸
+ return Offset(
+ offset.dx.clamp(minOffset.dx, 0.0), offset.dy.clamp(minOffset.dy, 0.0));
+ }
+
+ void _handleOnScaleEnd(ScaleEndDetails details) {
+ final double magnitude = details.velocity.pixelsPerSecond.distance;
+ if (magnitude < _kMinFlingVelocity) return;
+ final Offset direction = details.velocity.pixelsPerSecond / magnitude;
+ // 计算当前的方向
+ final double distance = (Offset.zero & context.size).shortestSide;
+ // 计算放大倍速,并相应的放大宽和高,比如原来是600*480的图片,放大后倍数为1.25倍时,宽和高是同时变化的
+ _animation = _controller.drive(Tween(
+ begin: _offset, end: _clampOffset(_offset + direction * distance)));
+ _controller
+ ..value = 0.0
+ ..fling(velocity: magnitude / 1000.0);
+ _bScaleing = false;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ playerRatioProvide = Provider.of(context);
+ Rect rect = panelRect();
+
+ List ws = [];
+
+ if (_statelessTimer != null && _statelessTimer.isActive) {
+ ws.add(buildStateless());
+ } else if (player.state == FijkState.asyncPreparing) {
+ ws.add(buildStateless());
+ } else if (player.state == FijkState.error) {
+ ws.add(buildStateless());
+ } else if (myImageProvider != null) {
+ ws.add(buildStateless());
+ }
+ ws.add(buildGestureDetector(context));
+ if (widget.onBack != null) {
+ ws.add(buildBack(context));
+ }
+ return Positioned.fromRect(
+ rect: rect,
+ child: Stack(children: ws),
+ );
+ }
+
+}
diff --git a/lib/my_fijkPanel_fix/my_slider.dart b/lib/my_fijkPanel_fix/my_slider.dart
new file mode 100644
index 0000000..46e4c2d
--- /dev/null
+++ b/lib/my_fijkPanel_fix/my_slider.dart
@@ -0,0 +1,244 @@
+//MIT License
+//
+//Copyright (c) [2019] [Befovy]
+//
+//Permission is hereby granted, free of charge, to any person obtaining a copy
+//of this software and associated documentation files (the "Software"), to deal
+//in the Software without restriction, including without limitation the rights
+//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//copies of the Software, and to permit persons to whom the Software is
+//furnished to do so, subject to the following conditions:
+//
+//The above copyright notice and this permission notice shall be included in all
+//copies or substantial portions of the Software.
+//
+//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+//SOFTWARE.
+
+//part of fijkplayer;
+import 'package:flutter/material.dart';
+import 'dart:core';
+import 'dart:math';
+import 'dart:ui';
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/rendering.dart';
+import 'package:flutter/widgets.dart';
+
+/// MyFijkSlider is like Slider in Flutter SDK.
+/// MyFijkSlider support [cacheValue] which can be used
+/// to show the player's cached buffer.
+/// The [colors] is used to make colorful painter to draw the line and circle.
+class MyFijkSlider extends StatefulWidget {
+ final double value;
+ final double cacheValue;
+
+ final ValueChanged onChanged;
+ final ValueChanged onChangeStart;
+ final ValueChanged onChangeEnd;
+
+ final double min;
+ final double max;
+
+ final MyFijkSliderColors colors;
+
+ const MyFijkSlider({
+ Key key,
+ @required this.value,
+ @required this.onChanged,
+ this.cacheValue = 0.0,
+ this.onChangeStart,
+ this.onChangeEnd,
+ this.min = 0.0,
+ this.max = 1.0,
+ this.colors = const MyFijkSliderColors(),
+ }) : assert(value != null),
+ assert(cacheValue != null),
+ assert(min != null),
+ assert(max != null),
+ assert(min <= max),
+ assert(value >= min && value <= max),
+ super(key: key);
+
+ @override
+ State createState() {
+ return _MyFijkSliderState();
+ }
+}
+
+class _MyFijkSliderState extends State {
+ bool dragging = false;
+
+ double dragValue;
+
+ static const double margin = 2.0;
+
+ @override
+ Widget build(BuildContext context) {
+ double v = widget.value / (widget.max - widget.min);
+ double cv = widget.cacheValue / (widget.max - widget.min);
+
+ return GestureDetector(
+ child: Container(
+ margin: EdgeInsets.only(left: margin, right: margin),
+ height: double.infinity,
+ width: double.infinity,
+ color: Colors.transparent,
+ child: CustomPaint(
+ painter: _MySliderPainter(v, cv, dragging, colors: widget.colors),
+ ),
+ ),
+ onHorizontalDragStart: (DragStartDetails details) {
+ setState(() {
+ dragging = true;
+ });
+ dragValue = widget.value;
+ if (widget.onChangeStart != null) {
+ widget.onChangeStart(dragValue);
+ }
+ },
+ onHorizontalDragUpdate: (DragUpdateDetails details) {
+ final box = context.findRenderObject() as RenderBox;
+ final dx = details.localPosition.dx;
+ dragValue = (dx - margin) / (box.size.width - 2 * margin);
+ dragValue = max(0, min(1, dragValue));
+ dragValue = dragValue * (widget.max - widget.min) + widget.min;
+ if (widget.onChanged != null) {
+ widget.onChanged(dragValue);
+ }
+ },
+ onHorizontalDragEnd: (DragEndDetails details) {
+ setState(() {
+ dragging = false;
+ });
+ if (widget.onChangeEnd != null) {
+ widget.onChangeEnd(dragValue);
+ }
+ },
+ );
+ }
+}
+
+/// Colors for the MyFijkSlider
+class MyFijkSliderColors {
+ const MyFijkSliderColors({
+ this.playedColor = const Color.fromRGBO(255, 0, 0, 0.6),
+ this.bufferedColor = const Color.fromRGBO(50, 50, 100, 0.4),
+ this.cursorColor = const Color.fromRGBO(255, 0, 0, 0.8),
+ this.baselineColor = const Color.fromRGBO(200, 200, 200, 0.5),
+ });
+
+ final Color playedColor;
+ final Color bufferedColor;
+ final Color cursorColor;
+ final Color baselineColor;
+
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ other is MyFijkSliderColors &&
+ runtimeType == other.runtimeType &&
+ hashCode == other.hashCode;
+
+ @override
+ int get hashCode =>
+ hashValues(playedColor, bufferedColor, cursorColor, baselineColor);
+}
+
+class _MySliderPainter extends CustomPainter {
+ final double v;
+ final double cv;
+
+ final bool dragging;
+ final Paint pt = Paint();
+
+ final MyFijkSliderColors colors;
+
+ _MySliderPainter(this.v, this.cv, this.dragging,
+ {this.colors = const MyFijkSliderColors()})
+ : assert(colors != null),
+ assert(v != null),
+ assert(cv != null);
+
+ @override
+ void paint(Canvas canvas, Size size) {
+ double lineHeight = min(size.height / 2, 1);
+ pt.color = colors.baselineColor;
+
+ double radius = min(size.height / 2, 4);
+ // draw background
+ canvas.drawRRect(
+ RRect.fromRectAndRadius(
+ Rect.fromPoints(
+ Offset(0, size.height / 2 - lineHeight),
+ Offset(size.width, size.height / 2 + lineHeight),
+ ),
+ Radius.circular(radius),
+ ),
+ pt,
+ );
+
+ final double value = v * size.width;
+
+ // draw played part
+ pt.color = colors.playedColor;
+ canvas.drawRRect(
+ RRect.fromRectAndRadius(
+ Rect.fromPoints(
+ Offset(0, size.height / 2 - lineHeight),
+ Offset(value, size.height / 2 + lineHeight),
+ ),
+ Radius.circular(radius),
+ ),
+ pt,
+ );
+
+ // draw cached part
+ final double cacheValue = cv * size.width;
+ if (cacheValue > value && cacheValue > 0) {
+ pt.color = colors.bufferedColor;
+ canvas.drawRRect(
+ RRect.fromRectAndRadius(
+ Rect.fromPoints(
+ Offset(value, size.height / 2 - lineHeight),
+ Offset(cacheValue, size.height / 2 + lineHeight),
+ ),
+ Radius.circular(radius),
+ ),
+ pt,
+ );
+ }
+
+ //注意:改变拖动圆形光标,必须按Q退出App,再重新flutter run才能生效
+ // draw circle cursor
+ // pt.color = colors.cursorColor;
+ // pt.color = pt.color.withAlpha(max(0, pt.color.alpha - 50));
+ //radius = min(size.height / 2, dragging ? 10 : 5);
+ pt.color = Colors.red;
+ //radius = 10;
+ radius = min(size.height / 2, 10);
+ canvas.drawCircle(Offset(value, size.height / 2), radius, pt);
+ //pt.color = colors.cursorColor;
+ //radius = min(size.height / 2, dragging ? 6 : 3);
+ //canvas.drawCircle(Offset(value, size.height / 2), radius, pt);
+ }
+
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ other is _MySliderPainter && hashCode == other.hashCode;
+
+ @override
+ int get hashCode => hashValues(v, cv, dragging, colors);
+
+ @override
+ bool shouldRepaint(_MySliderPainter oldDelegate) {
+ return hashCode != oldDelegate.hashCode;
+ }
+}
diff --git a/lib/my_flutter_drag_scale/example/test/widget_test.dart b/lib/my_flutter_drag_scale/example/test/widget_test.dart
index 0fb031a..be5e3af 100644
--- a/lib/my_flutter_drag_scale/example/test/widget_test.dart
+++ b/lib/my_flutter_drag_scale/example/test/widget_test.dart
@@ -8,12 +8,12 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
-import 'package:flutter_drag_scale_example/main.dart';
+// import 'package:flutter_drag_scale_example/main.dart';
void main() {
testWidgets('Verify Platform version', (WidgetTester tester) async {
// Build our app and trigger a frame.
- await tester.pumpWidget(MyApp());
+ // await tester.pumpWidget(MyApp());
// Verify that platform version is retrieved.
expect(
diff --git a/lib/my_flutter_superplayer/android/src/main/java/com/tencent/liteav/demo/superplayer/model/SuperPlayerImpl.java b/lib/my_flutter_superplayer/android/src/main/java/com/tencent/liteav/demo/superplayer/model/SuperPlayerImpl.java
index 7fc5c74..1bfaa32 100644
--- a/lib/my_flutter_superplayer/android/src/main/java/com/tencent/liteav/demo/superplayer/model/SuperPlayerImpl.java
+++ b/lib/my_flutter_superplayer/android/src/main/java/com/tencent/liteav/demo/superplayer/model/SuperPlayerImpl.java
@@ -103,7 +103,7 @@ public class SuperPlayerImpl implements SuperPlayer, ITXVodPlayListener, ITXLive
case TXLiveConstants.PLAY_ERR_NET_DISCONNECT:
case TXLiveConstants.PLAY_EVT_PLAY_END:
if (mCurrentPlayType == SuperPlayerDef.PlayerType.LIVE_SHIFT) { // 直播时移失败,返回直播
- mLivePlayer.resumeLive();
+ // mLivePlayer.resumeLive();
updatePlayerType(SuperPlayerDef.PlayerType.LIVE);
onError(SuperPlayerCode.LIVE_SHIFT_FAIL, "时移失败,返回直播");
updatePlayerState(SuperPlayerDef.PlayerState.PLAYING);
@@ -398,7 +398,10 @@ public class SuperPlayerImpl implements SuperPlayer, ITXVodPlayListener, ITXLive
mCurrentPlayVideoURL = url;
if (mLivePlayer != null) {
mLivePlayer.setPlayListener(this);
- int result = mLivePlayer.startPlay(url, playType); // result返回值:0 success; -1 empty url; -2 invalid url; -3 invalid playType;
+ // 由于腾讯播放器SDK在2022-10-11进行更新,导致hyzp_ybqx项目编译出现下面报错。将下面文件
+ //\hyzp_ybqx\lib\my_flutter_superplayer\android\src\main\java\com\tencent\liteav\demo\superplayer\model\SuperPlayerImpl.java
+ //中的TXLivePlayer 的 startPlay 变更为 startLivePlay,将TXVodPlayer 的 startPlay 变更为 startVodPlay,问题解决。
+ int result = mLivePlayer.startLivePlay(url, playType); // result返回值:0 success; -1 empty url; -2 invalid url; -3 invalid playType;
if (result != 0) {
TXCLog.e(TAG, "playLiveURL videoURL:" + url + ",result:" + result);
} else {
@@ -449,9 +452,9 @@ public class SuperPlayerImpl implements SuperPlayer, ITXVodPlayListener, ITXLive
query += "spfileid=" + mFileId + "&spdrmtype=" + drmType + "&spappid=" + mAppId;
Uri newUri = uri.buildUpon().query(query).build();
TXCLog.i(TAG, "playVodURL: newurl = " + Uri.decode(newUri.toString()) + " ;url= " + url);
- ret = mVodPlayer.startPlay(Uri.decode(newUri.toString()));
+ ret = mVodPlayer.startVodPlay(Uri.decode(newUri.toString()));
} else {
- ret = mVodPlayer.startPlay(url);
+ ret = mVodPlayer.startVodPlay(url);
}
if (ret == 0) {
@@ -498,7 +501,7 @@ public class SuperPlayerImpl implements SuperPlayer, ITXVodPlayListener, ITXLive
e.printStackTrace();
TXCLog.e(TAG, "playTimeShiftLiveURL: bizidNum error = " + bizid);
}
- mLivePlayer.prepareLiveSeek(domian, bizidNum);
+ // mLivePlayer.prepareLiveSeek(domian, bizidNum);
}
/**
@@ -730,7 +733,7 @@ public class SuperPlayerImpl implements SuperPlayer, ITXVodPlayListener, ITXLive
@Override
public void resumeLive() {
if (mCurrentPlayType == SuperPlayerDef.PlayerType.LIVE_SHIFT) {
- mLivePlayer.resumeLive();
+ // mLivePlayer.resumeLive();
}
updatePlayerType(SuperPlayerDef.PlayerType.LIVE);
}
@@ -805,7 +808,7 @@ public class SuperPlayerImpl implements SuperPlayer, ITXVodPlayListener, ITXLive
updatePlayerType(SuperPlayerDef.PlayerType.LIVE_SHIFT);
LogReport.getInstance().uploadLogs(LogReport.ELK_ACTION_TIMESHIFT, 0, 0);
if (mLivePlayer != null) {
- mLivePlayer.seek(position);
+ // mLivePlayer.seek(position);
}
}
if (mObserver != null) {
@@ -856,7 +859,7 @@ public class SuperPlayerImpl implements SuperPlayer, ITXVodPlayListener, ITXLive
mVodPlayer.stopPlay(true);
TXCLog.i(TAG, "onQualitySelect quality.url:" + quality.url);
mVodPlayer.setStartTime(currentTime);
- mVodPlayer.startPlay(quality.url);
+ mVodPlayer.startVodPlay(quality.url);
} else { //br!=0;index!=-1;url=null
TXCLog.i(TAG, "setBitrateIndex quality.index:" + quality.index);
// 说明是多bitrate的m3u8子流,会自动无缝seek
diff --git a/lib/pages/Works/DWDT/basic_map.dart b/lib/pages/Works/DWDT/basic_map.dart
index a23d116..84bf989 100644
--- a/lib/pages/Works/DWDT/basic_map.dart
+++ b/lib/pages/Works/DWDT/basic_map.dart
@@ -4,8 +4,10 @@ import 'package:flutter_bmfmap/BaiduMap/bmfmap_map.dart';
import 'package:flutter_screenutil/screen_util.dart';
import 'package:hyzp_ybqx/components/commonFun.dart';
import 'package:hyzp_ybqx/components/hyxx_data_handle.dart';
+import 'package:map_launcher/map_launcher.dart';
import '../../../components/dioFun.dart';
+import '../../../services/Storage.dart';
import 'dwInfoDialog.dart';
import 'dwInfo_data.dart';
@@ -20,6 +22,11 @@ class BasicMap extends StatefulWidget {
}
class _BasicMapState extends State {
+ // 导航相关代码
+ double destinationLatitude = 28.45382237207785;
+ double destinationLongitude = 104.7506958256658;
+ String destinationTitle = '珙县大坪上';
+
Size screenSize;
BMFMapOptions mapOptions;
BMFMapController myMapController;
@@ -32,9 +39,18 @@ class _BasicMapState extends State {
}
}
+ List availableMaps;
+
+ void init() async {
+ // 获取用户选择的默认地图
+ availableMaps = await MapLauncher.installedMaps;
+ }
+
@override
void initState() {
super.initState();
+ init();
+
mapOptions = BMFMapOptions(
//center: BMFCoordinate(39.965, 116.404),//北京市
//30 116.395645038,39.9299857781 北京-北京市
@@ -291,8 +307,17 @@ class _BasicMapState extends State {
.push(
PageRouteBuilder(
opaque: false,
- pageBuilder: (context, animation, secondaryAnimation) =>
- dwInfoDialog(id: id, dwIndex: dwIndex, title: title, content: content),
+ pageBuilder: (context, animation, secondaryAnimation) => dwInfoDialog(
+ id: id,
+ dwIndex: dwIndex,
+ title: title,
+ content: content,
+ parentContext: context,
+ destinationLatitude: double.parse(listCoordinate[1]),
+ destinationLongitude: double.parse(listCoordinate[0]),
+ destinationTitle: listDwinfoGetList2[dwIndex]["dwmc"],
+ availableMaps: availableMaps,
+ ),
),
)
.then((value) async {
diff --git a/lib/pages/Works/DWDT/dwInfoDialog.dart b/lib/pages/Works/DWDT/dwInfoDialog.dart
index 7437318..6594dd5 100644
--- a/lib/pages/Works/DWDT/dwInfoDialog.dart
+++ b/lib/pages/Works/DWDT/dwInfoDialog.dart
@@ -1,21 +1,38 @@
import 'package:flutter/material.dart';
+import 'package:geolocator/geolocator.dart';
import 'package:hyzp_ybqx/components/dioFun.dart';
+import 'package:map_launcher/map_launcher.dart';
//import 'package:hyzp_ybqx/widget/player_pro.dart';
import '../../../components/commonFun.dart';
+import '../../../services/Storage.dart';
+import 'maps_sheet.dart';
//确认对话框
class dwInfoDialog extends Dialog {
- dwInfoDialog({@required this.id, this.title = "", @required this.dwIndex, this.content});
+ dwInfoDialog({
+ @required this.id,
+ this.title = "",
+ @required this.dwIndex,
+ this.content,
+ // 导航相关参数
+ this.parentContext,
+ this.destinationLatitude,
+ this.destinationLongitude,
+ this.destinationTitle,
+ this.availableMaps,
+ });
int dwIndex;
String id;
String title;
String content;
bool ret = false;
+ BuildContext parentContext;
@override
Widget build(BuildContext context) {
+ getCurrentPosition();
Size mediaSize = MediaQuery.of(context).size;
return WillPopScope(
child: Material(
@@ -90,9 +107,9 @@ class dwInfoDialog extends Dialog {
onPressed: () async {
ret = true;
getingDwVideo = false;
- Navigator.pop(context, ret); //关闭弹框,返回sRet
+ navigationMap(context);
},
- child: Text("确认"),
+ child: Text("导航"),
),
RaisedButton(
child: Text("取消"),
@@ -115,4 +132,102 @@ class dwInfoDialog extends Dialog {
},
);
}
+
+ // 导航相关代码
+ double destinationLatitude = 28.45382237207785;
+ double destinationLongitude = 104.7506958256658;
+ String destinationTitle = '珙县大坪上';
+
+ double originLatitude;
+ double originLongitude;
+ String originTitle = '我的位置';
+
+ List waypoints = [
+ // Coords(37.7705112, -122.4108267),
+ // Coords(37.6988984, -122.4830961),
+ // Coords(37.7935754, -122.483654),
+ ];
+
+ DirectionsMode directionsMode = DirectionsMode.driving;
+
+ List availableMaps;
+
+ // String defaultMapName = 'Amap';
+ String defaultMapName = g_defaultMapName;
+ AvailableMap defalutMap;
+
+ void getCurrentPosition() async {
+ print('getCurrentPosition begin');
+
+ // 是否保存默认地图
+ g_bSaveDefaultMap = await Storage.getBool('bSaveDefaultMap');
+ g_bSaveDefaultMap = (null == g_bSaveDefaultMap) ? false : g_bSaveDefaultMap; // 默认不保存
+ // 用户选择的默认地图名称
+ g_defaultMapName = await Storage.getString('defaultMapName');
+ g_defaultMapName = (null == g_defaultMapName) ? '' : g_defaultMapName; // 默认为空字符串
+ defaultMapName = g_defaultMapName;
+
+ // 获取用户选择的默认地图
+ // availableMaps = await MapLauncher.installedMaps; // 为避免延迟错乱,该变量由父组件传入
+ if (defaultMapName != null && defaultMapName.length > 0) {
+ for (var map in availableMaps) {
+ if (defaultMapName.toLowerCase() == map.mapName.toLowerCase()) {
+ defalutMap = map;
+ break;
+ }
+ }
+ }
+
+ await Geolocator.getCurrentPosition().then((Position value) {
+ originLatitude = value.latitude;
+ originLongitude = value.longitude;
+ print('value = ${value.toString()}');
+ // value = Latitude: 28.796201, Longitude: 104.607751
+ print('getCurrentPosition end');
+ });
+ }
+
+ navigationMap(BuildContext context) {
+ print('this.defalutMap = ${defalutMap}');
+ if (defalutMap != null) {
+ defalutMap.showDirections(
+ destination: Coords(
+ destinationLatitude,
+ destinationLongitude,
+ ),
+ destinationTitle: destinationTitle,
+ origin: originLatitude == null || originLongitude == null
+ ? null
+ : Coords(originLatitude, originLongitude),
+ originTitle: originTitle,
+ waypoints: waypoints,
+ directionsMode: directionsMode,
+ );
+ } else {
+ MapsSheet.show(
+ context: parentContext,
+ onMapTap: (map) {
+ if (g_bSaveDefaultMap) {
+ g_defaultMapName = map.mapName;
+ Storage.setString('defaultMapName', g_defaultMapName);
+ }
+
+ map.showDirections(
+ destination: Coords(
+ destinationLatitude,
+ destinationLongitude,
+ ),
+ destinationTitle: destinationTitle,
+ origin: originLatitude == null || originLongitude == null
+ ? null
+ : Coords(originLatitude, originLongitude),
+ originTitle: originTitle,
+ waypoints: waypoints,
+ directionsMode: directionsMode,
+ );
+ },
+ );
+ }
+ Navigator.pop(context, ret); //关闭弹框,返回sRet
+ }
}
diff --git a/lib/pages/Works/DWDT/maps_sheet.dart b/lib/pages/Works/DWDT/maps_sheet.dart
new file mode 100644
index 0000000..a2bda47
--- /dev/null
+++ b/lib/pages/Works/DWDT/maps_sheet.dart
@@ -0,0 +1,49 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:map_launcher/map_launcher.dart';
+
+class MapsSheet {
+ static show({
+ @required BuildContext context,
+ @required Function(AvailableMap map) onMapTap,
+ }) async {
+ final availableMaps = await MapLauncher.installedMaps;
+
+ showModalBottomSheet(
+ context: context,
+ builder: (BuildContext context) {
+ return SafeArea(
+ child: Column(
+ children: [
+ Expanded(
+ child: SingleChildScrollView(
+ child: Container(
+ child: Wrap(
+ children: [
+ for (var map in availableMaps)
+ ListTile(
+ onTap: () {
+ print('map.mapName = ${map.mapName}');
+ // map.mapName = Amap
+ Navigator.pop(context);
+ onMapTap(map);
+ },
+ title: Text(map.mapName),
+ leading: SvgPicture.asset(
+ map.icon,
+ height: 30.0,
+ width: 30.0,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/pages/Works/HYSH/tsjj_content_new.dart b/lib/pages/Works/HYSH/tsjj_content_new.dart
index 868b669..776ac0f 100644
--- a/lib/pages/Works/HYSH/tsjj_content_new.dart
+++ b/lib/pages/Works/HYSH/tsjj_content_new.dart
@@ -13,6 +13,7 @@ import 'package:keyboard_avoider/keyboard_avoider.dart';
//
import '../../../components/commonFun.dart';
+
//import 'package:hyzp_ybqx/widget/player_pro_new.dart';
import '../../../components/dioFun.dart';
import '../../../components/doJSON.dart';
@@ -75,6 +76,8 @@ class _LoginPageState extends State with SingleTickerProviderSta
try_setState(); //避免如下异常报错
});
+ print('official_seal = $official_seal');
+
_widthLeft = _screenWidth / 2;
getListFlields();
@@ -123,7 +126,8 @@ class _LoginPageState extends State with SingleTickerProviderSta
print('_mapTsjjGetTsStatus = $_mapTsjjGetTsStatus');
// 获取网络图片尺寸,getMediaUrl(_mapGetTsjjGetData['pic_url'])
- await flustars.WidgetUtil.getImageWH(url: getMediaUrl(_mapGetTsjjGetData['pic_url'])).then((rect) {
+ await flustars.WidgetUtil.getImageWH(url: getMediaUrl(_mapGetTsjjGetData['pic_url']))
+ .then((rect) {
if (null != rect) {
_radioImage = rect.height / rect.width;
print("rect = $rect,_radioImage = $_radioImage");
@@ -915,8 +919,13 @@ class _LoginPageState extends State with SingleTickerProviderSta
//color: Colors.black12,
decoration: BoxDecoration(
//color: Colors.white,
+ // image: DecorationImage(
+ // image: AssetImage("assets/images/jkzx_stamp.png"), fit: BoxFit.contain),
+ // image: DecorationImage(
+ // image: AssetImage("assets/images/宜宾市长宁生态环境局.png"), fit: BoxFit.contain),
image: DecorationImage(
- image: AssetImage("assets/images/jkzx_stamp.png"), fit: BoxFit.contain),
+ image: AssetImage("assets/images/" + official_seal), fit: BoxFit.contain),
+
),
//child:
),
diff --git a/lib/pages/tabs/page4_myMsics_new.dart b/lib/pages/tabs/page4_myMsics_new.dart
index 346c738..c88de0c 100644
--- a/lib/pages/tabs/page4_myMsics_new.dart
+++ b/lib/pages/tabs/page4_myMsics_new.dart
@@ -16,6 +16,7 @@ import 'package:hyzp_ybqx/pages/Works/TJXX/tj_data.dart';
import 'package:hyzp_ybqx/pages/tabs/page5_userManager.dart';
import 'package:hyzp_ybqx/pages/tabs/page6_download.dart';
import 'package:hyzp_ybqx/pages/tabs/page7_setRemind.dart';
+import 'package:hyzp_ybqx/pages/tabs/page8_defaultMap.dart';
import 'package:hyzp_ybqx/services/EventBus.dart';
import 'package:hyzp_ybqx/widget/JdButton.dart';
import 'package:package_info/package_info.dart';
@@ -111,35 +112,35 @@ class _Page4_MyMsicsNewState extends State
static onNullFun() {}
Widget _getListTile(
- title, {
- String leadPath = '',
- Color leadColor,
- Color textColor,
- onTapFun = onNullFun,
- onLongPressFun = onNullFun,
- size = 16.0,
- bool bBadge = false,
- Widget trailWidget = const Icon(Icons.arrow_forward_ios),
- }) {
+ title, {
+ String leadPath = '',
+ Color leadColor,
+ Color textColor,
+ onTapFun = onNullFun,
+ onLongPressFun = onNullFun,
+ size = 16.0,
+ bool bBadge = false,
+ Widget trailWidget = const Icon(Icons.arrow_forward_ios),
+ }) {
// print("_getListTile bVoiceRemind = $bVoiceRemind"); // _getListTile bVoiceRemind = false
return Column(
children: [
ListTile(
leading: bBadge
? Badge(
- position: BadgePosition.topEnd(top: -7, end: -12),
- badgeContent: null,
- child: Image.asset(
- leadPath,
- height: ScreenUtil().setHeight(78),
- fit: BoxFit.fitHeight,
- ),
- )
+ position: BadgePosition.topEnd(top: -7, end: -12),
+ badgeContent: null,
+ child: Image.asset(
+ leadPath,
+ height: ScreenUtil().setHeight(78),
+ fit: BoxFit.fitHeight,
+ ),
+ )
: Image.asset(
- leadPath,
- height: ScreenUtil().setHeight(78),
- fit: BoxFit.fitHeight,
- ),
+ leadPath,
+ height: ScreenUtil().setHeight(78),
+ fit: BoxFit.fitHeight,
+ ),
title: Text(title, style: TextStyle(fontSize: size, color: textColor)),
trailing: trailWidget,
contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 0),
@@ -202,11 +203,13 @@ class _Page4_MyMsicsNewState extends State
leadPath: 'assets/images/账户管理.png',
leadColor: _deepBlueColor,
onTapFun: OnTap_user_manager),
+ _getListTile('默认导航',
+ leadPath: 'assets/images/默认地图3.png',
+ leadColor: _deepBlueColor,
+ onTapFun: OnTap_DefaultMap),
//bNewVer:是否发现新版本
_getListTile('提醒设置',
- leadPath: 'assets/images/语音提醒.png',
- leadColor: _deepGreyColor,
- onTapFun: OnTap_Remind),
+ leadPath: 'assets/images/语音提醒.png', leadColor: _deepGreyColor, onTapFun: OnTap_Remind),
_getListTile('关于',
leadPath: 'assets/images/关于.png', leadColor: _deepBlueColor, onTapFun: OnTap_MyAbout)
@@ -511,6 +514,10 @@ class _Page4_MyMsicsNewState extends State
Navigator.of(context).push(MaterialPageRoute(builder: (context) => page5_userManager()));
}
+ OnTap_DefaultMap() async {
+ Navigator.of(context).push(MaterialPageRoute(builder: (context) => page8_defaultMap()));
+ }
+
OnTap_download() {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => page6_download()));
}
diff --git a/lib/pages/tabs/page8_defaultMap.dart b/lib/pages/tabs/page8_defaultMap.dart
new file mode 100644
index 0000000..7f8723c
--- /dev/null
+++ b/lib/pages/tabs/page8_defaultMap.dart
@@ -0,0 +1,284 @@
+import 'package:badges/badges.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:hyzp_ybqx/pages/Login/FaceReg.dart';
+import 'package:hyzp_ybqx/pages/Login/ModifyPassword.dart';
+import 'package:hyzp_ybqx/services/Storage.dart';
+
+import '../../components/commonFun.dart';
+import '../../widget/JdButton.dart';
+
+class page8_defaultMap extends StatefulWidget {
+ page8_defaultMap({Key key}) : super(key: key);
+
+ _LoginPageState createState() => _LoginPageState();
+}
+
+class _LoginPageState extends State {
+ bool bSaveDefaultMap = false;
+ String defaultMapName = '';
+
+ dispose() {
+ super.dispose();
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ init();
+ }
+
+ void init() async {
+ // 从磁盘读取变量
+ // 是否保存默认地图
+ g_bSaveDefaultMap = await Storage.getBool('bSaveDefaultMap');
+ g_bSaveDefaultMap = (null == g_bSaveDefaultMap) ? false : g_bSaveDefaultMap; // 默认不保存
+ // 用户选择的默认地图名称
+ g_defaultMapName = await Storage.getString('defaultMapName');
+ g_defaultMapName = (null == g_defaultMapName) ? '' : g_defaultMapName; // 默认为空字符串
+
+ bSaveDefaultMap = g_bSaveDefaultMap;
+ // bSaveDefaultMap = false;
+ // defaultMapName = g_defaultMapName;
+ // defaultMapName = '高德地图';
+ // defaultMapName = getMapChsName('amap');
+ defaultMapName = getMapChsName(g_defaultMapName);
+ setState(() {});
+ }
+
+ ////////
+ static onNullFun() {}
+
+ Widget _getListTile(
+ title, {
+ String leadPath = '',
+ Color leadColor,
+ Color textColor,
+ onTapFun = onNullFun,
+ onLongPressFun = onNullFun,
+ size = 16.0,
+ bool bBadge = false,
+ Widget trailWidget = const Icon(Icons.arrow_forward_ios),
+ }) {
+ // print("_getListTile bSaveDefaultMap = $bSaveDefaultMap "); // _getListTile bSaveDefaultMap = false
+ return Column(
+ children: [
+ ListTile(
+ leading: bBadge
+ ? Badge(
+ position: BadgePosition.topEnd(top: -7, end: -12),
+ badgeContent: null,
+ child: Image.asset(
+ leadPath,
+ height: ScreenUtil().setHeight(78),
+ fit: BoxFit.fitHeight,
+ // color: leadColor, // 无效
+ ),
+ )
+ : Image.asset(
+ leadPath,
+ height: ScreenUtil().setHeight(78),
+ fit: BoxFit.fitHeight,
+ ),
+ title: Text(title, style: TextStyle(fontSize: size, color: textColor)),
+ trailing: trailWidget,
+ contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 0),
+ enabled: true,
+ onTap: onTapFun,
+ onLongPress: onLongPressFun,
+ ),
+ Divider(
+ height: 1.0,
+ ),
+ ],
+ );
+ }
+
+ List _listViewUser = [];
+
+ Color _greenColor = Color.fromRGBO(36, 206, 192, 1); //绿色
+ Color _deepBlueColor = Color.fromRGBO(79, 118, 230, 1); //深蓝
+ Color _deepGreyColor = Color.fromRGBO(116, 139, 161, 1); //深灰
+ Color _ligthBlueColor = Color.fromRGBO(80, 159, 245, 1); //亮蓝
+
+ OnTap_FaceReg() async {
+ Navigator.of(context).push(MaterialPageRoute(builder: (context) => FaceReg()));
+ }
+
+ OnTap_modify_password() {
+ Navigator.of(context).push(MaterialPageRoute(builder: (context) => ModifyPassword()));
+ }
+
+ OnTap_Remind() {
+ setState(() {
+ bSaveDefaultMap = !bSaveDefaultMap;
+ print("bSaveDefaultMap = $bSaveDefaultMap");
+ });
+ }
+
+ Widget getTextField() {
+ return Container(
+ width: ScreenUtil().setWidth(400),
+ child: TextField(
+ readOnly: !bSaveDefaultMap,
+ focusNode: FocusNode(),
+ textAlignVertical: TextAlignVertical(y: 1.0),
+ controller: TextEditingController.fromValue(TextEditingValue(
+ text: defaultMapName.toString(),
+ // 保持光标在最后
+ selection: TextSelection.fromPosition(TextPosition(
+ affinity: TextAffinity.downstream, offset: defaultMapName.toString().length)))),
+ maxLines: 1,
+ keyboardType: TextInputType.text,
+ decoration: InputDecoration(
+ //contentPadding: EdgeInsets.only(bottom: 16),
+ // hintText: widget.text,
+ // border: OutlineInputBorder(
+ // borderRadius: BorderRadius.circular(30), borderSide: BorderSide.none),
+ border: UnderlineInputBorder(borderSide: BorderSide(color: Colors.lightBlue)),
+ focusedBorder: UnderlineInputBorder(borderSide: BorderSide(color: Colors.lightBlue)),
+ enabledBorder: UnderlineInputBorder(borderSide: BorderSide(color: Colors.lightBlue)),
+ ),
+ onChanged: (v) {
+ defaultMapName = v;
+ },
+ ),
+ );
+ }
+
+ Widget getText(String text) {
+ return Container(
+ child: Text(text,
+ style: TextStyle(
+ fontSize: 16,
+ color: Colors.blueAccent,
+ fontWeight: FontWeight.bold,
+ decoration: TextDecoration.underline,
+ )),
+ );
+ }
+
+ ////////
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: PreferredSize(
+ preferredSize: Size.fromHeight(ScreenUtil().setHeight(173)), // 设置appBar高度
+ // 设置appBar高度
+ child: AppBar(
+ automaticallyImplyLeading: false,
+ centerTitle: true,
+ titleSpacing: 0.0,
+ //设置title的左边距
+ flexibleSpace: Container(
+ //SizedBox(height: ScreenUtil().statusBarHeight), //显示顶部状态栏
+ // SizedBox(height: ScreenUtil().setHeight(10)), //显示顶部状态栏
+ padding: EdgeInsets.only(top: ScreenUtil().statusBarHeight), //留出顶部状态栏高度
+ child: Container(
+ //height: ScreenUtil().setHeight(173),
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ colors: [
+ Color.fromRGBO(12, 186, 156, 1),
+ Color.fromRGBO(39, 127, 235, 1),
+ ],
+ ),
+ ),
+ // decoration: BoxDecoration(
+ // gradient: LinearGradient(colors: [
+ // Color(0xFF0018EB),
+ // Color(0xFF01C1D9),
+ // ], begin: Alignment.bottomCenter, end: Alignment.topCenter),
+ // ),
+ ),
+ ),
+ title: Padding(
+ padding: EdgeInsets.only(left: 0, right: 0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ getIconAndTextButton(
+ iconColor: Colors.white,
+ iconData: Icons.chevron_left_outlined,
+ onPress: () {
+ Navigator.pop(context);
+ },
+ ),
+ Expanded(
+ child: Text("默认导航设置",
+ style: TextStyle(color: Colors.white, fontSize: 20),
+ textAlign: TextAlign.center,
+ overflow: TextOverflow.ellipsis),
+ ),
+ SizedBox(width: 50),
+ ],
+ ),
+ ),
+ ),
+ ),
+ body: Container(
+ padding: EdgeInsets.only(top: 30, bottom: 20, left: 20, right: 20),
+ child: ListView(
+ children: [
+ Center(
+ child: Container(
+ margin: EdgeInsets.only(top: 30),
+ height: ScreenUtil().setWidth(160),
+ width: ScreenUtil().setWidth(160),
+ //child: Image.asset('assets/images/user.png', fit: BoxFit.cover),
+ child: Image.asset('assets/images/ybsthbj.png', fit: BoxFit.fitHeight),
+ ),
+ ),
+ SizedBox(height: 50),
+ _getListTile('保存默认导航地图',
+ leadPath: 'assets/images/地图选中.png',
+ leadColor: _deepGreyColor,
+ // textColor: bSaveDefaultMap ? Colors.blue : null,
+ onTapFun: OnTap_Remind,
+ trailWidget: bSaveDefaultMap
+ ? Icon(Icons.check_box, color: Colors.blue)
+ : Icon(Icons.check_box_outline_blank, color: Colors.blueAccent)),
+ _getListTile('已选默认导航地图:',
+ leadPath: 'assets/images/用户选择.png',
+ leadColor: _deepBlueColor,
+ trailWidget: getText(defaultMapName)),
+ SizedBox(height: 60),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ JdButton(
+ height: 128,
+ width: 282,
+ //height: 126,
+ text: "确认",
+ color: Colors.blueAccent,
+ onTop: () async {
+ g_bSaveDefaultMap = bSaveDefaultMap;
+ await Storage.setBool('bSaveDefaultMap', g_bSaveDefaultMap);
+ if (!g_bSaveDefaultMap) {
+ await Storage.setString('defaultMapName', '');
+ }
+ Navigator.pop(context);
+ },
+ ),
+ JdButton(
+ height: 128,
+ width: 282,
+ //height: 126,
+ text: "取消",
+ color: Colors.blueAccent,
+ onTop: () {
+ Navigator.pop(context);
+ },
+ )
+ ],
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/widget/my_superplayer-0.0.3.dart b/lib/widget/my_superplayer-0.0.3.dart
new file mode 100644
index 0000000..9323294
--- /dev/null
+++ b/lib/widget/my_superplayer-0.0.3.dart
@@ -0,0 +1,739 @@
+import 'dart:async';
+import 'dart:convert';
+import 'dart:ui';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_screenutil/screen_util.dart';
+import 'package:flutter_superplayer/flutter_superplayer.dart';
+import 'package:flutterptcontrol/flutterptcontrol.dart';
+import 'package:hyzp_ybqx/components/commonFun.dart';
+import 'package:hyzp_ybqx/components/dioFun.dart';
+import 'package:hyzp_ybqx/provider/player_ratio.dart';
+import 'package:hyzp_ybqx/provider/player_region.dart';
+import 'package:provider/provider.dart';
+
+import '../components/commonFun.dart';
+import '../services/Storage.dart';
+
+const _kControlViewTypes = [kControlViewTypeDefault, kControlViewTypeWithout];
+
+class SuperPlayerPage extends StatefulWidget {
+ SuperPlayerPage(
+ {@required this.url,
+ this.id = -2, // 播放点位视频的点位编号,-2 表示播放违章视频
+ this.dwip = '', // 点位IP,用于点位视频控制球机方向
+ this.loop = 1,
+ this.title = 'Tencent Player',
+ Key key})
+ : super(key: key);
+ String dwip;
+ String url;
+ String title;
+ int loop; //设置播放循环,默认播放器的循环次数是1, 即不循环播放。如果设置循环次数0,表示无限循环。
+ int id;
+
+ @override
+ _SuperPlayerPageState createState() => _SuperPlayerPageState();
+}
+
+class _SuperPlayerPageState extends State with SuperPlayerListener {
+ SuperPlayerController _playerController = SuperPlayerController();
+
+ String _sdkVersion = 'Unknown';
+ List _logs = [];
+ bool bFullScreen = false;
+
+ String _controlViewType = _kControlViewTypes.first;
+
+ @override
+ void dispose() {
+ Playing = false;
+ // 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小
+ setSphericalCameraDio(id: widget.id, dwip: widget.dwip, cmdCode: 1);
+ super.dispose();
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ //initPlatformState();
+ // Future.delayed(const Duration(milliseconds: 1000), () {
+ // _playerController.playWithModel(SuperPlayerModel(url: widget.url));
+ // setState(() {
+ // });
+ // });
+ init();
+ }
+
+ Future init() async {
+ await _playerController.addListener(this);
+ await initPlatformState();
+ if (!mounted) return;
+ print('mounted = ${mounted}');
+ // 开启调试日志
+ //await FTXPlayerController.setConsoleEnabled(true);
+ // 初始化播放器
+ //await _controller.initialize(onlyAudio: true);
+
+ await _playerController.uiHideDanmu(); // 隐藏弹幕
+ //设置播放循环,默认播放器的循环次数是1, 即不循环播放。如果设置循环次数0,表示无限循环。
+ if (0 == widget.loop) {
+ await _playerController.setLoop(true);
+ }
+
+ await _playerController.playWithModel(testSuperPlayerModel);
+ //_controller.play("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4");
+ // _controller
+ // .play('rtmp://125.64.218.67:9901/rtp/gb_play_34020000001320003016_34020000001320003016');
+ // 设置循环播放
+ //await _controller.setLoop(true);
+ // 开始播放
+ //await _controller.play("http://125.64.218.67:9908/video/2_6063_20210409_140608_川Q31715.mp4");
+ }
+
+ SuperPlayerModel get testSuperPlayerModel {
+ // int appId = 1252463788;
+ // String fileId = "5285890781763144364";
+
+ SuperPlayerModel superPlayerModel = SuperPlayerModel(
+ url: widget.url,
+ // appId: appId,
+ // videoId: SuperPlayerVideoId(fileId: fileId),
+ );
+ return superPlayerModel;
+ }
+
+ // Platform messages are asynchronous, so we initialize in an async method.
+ Future initPlatformState() async {
+ String sdkVersion;
+ // Platform messages may fail, so we use a try/catch PlatformException.
+ try {
+ sdkVersion = await FlutterSuperPlayer.sdkVersion;
+ } on PlatformException {
+ sdkVersion = 'Failed to get platform version.';
+ }
+ print('sdkVersion = ${sdkVersion}');
+ print('mounted = ${mounted}');
+
+ // If the widget was removed from the tree while the asynchronous platform
+ // message was in flight, we want to discard the reply rather than calling
+ // setState to update our non-existent appearance.
+ if (!mounted) return;
+
+ setState(() {
+ _sdkVersion = sdkVersion;
+ });
+ }
+
+ void _addLog(String method, dynamic data) {
+ _logs.add('>>>$method');
+ if (data != null) {
+ _logs.add(data is Map ? json.encode(data) : data);
+ }
+ _logs.add(' ');
+
+ setState(() {});
+ }
+
+ PlayerRatioProvide playerRatioProvide;
+
+ @override
+ Widget build(BuildContext context) {
+ playerRegionProvide = Provider.of(context);
+ playerRatioProvide = Provider.of(context);
+ // List listData = getDataListControl2();
+ double btnHeight1 = 70; //第一按钮行高度
+ double btnHeight2 = 160; //第二按钮行高度
+ int btnCount = 4; //每行按钮个数
+ // int btnCount3 = listData.length; //每行按钮个数
+ var mediaSize = MediaQuery.of(context).size;
+
+ // widget.id:播放点位视频的点位编号,-2 表示播放违章视频
+ double btn_left = -2 == widget.id ? 347 : 70; //第一按钮行高度
+ double btn_gap = -2 == widget.id ? 104 : 70; //第一按钮行高度
+
+ //远程控制球机方向按钮外半径和内半径
+ double _outerRadius = 270;
+ double _innerRadius = _outerRadius / 2;
+
+ //double barHeight = bFullScreen ? 0 : MediaQueryData.fromWindow(window).padding.top;
+ return Scaffold(
+ appBar: bFullScreen
+ ? null
+ : PreferredSize(
+ preferredSize: Size.fromHeight(ScreenUtil().setHeight(173)), // 设置appBar高度
+ // 设置appBar高度
+ child: AppBar(
+ automaticallyImplyLeading: false,
+ centerTitle: true,
+ titleSpacing: 0.0,
+ //设置title的左边距
+ flexibleSpace: Container(
+ //SizedBox(height: ScreenUtil().statusBarHeight), //显示顶部状态栏
+ // SizedBox(height: ScreenUtil().setHeight(10)), //显示顶部状态栏
+ padding: EdgeInsets.only(top: ScreenUtil().statusBarHeight), //留出顶部状态栏高度
+ child: Container(
+ //height: ScreenUtil().setHeight(173),
+ decoration: BoxDecoration(
+ gradient: LinearGradient(
+ begin: Alignment.centerLeft,
+ end: Alignment.centerRight,
+ colors: [
+ Color.fromRGBO(12, 186, 156, 1),
+ Color.fromRGBO(39, 127, 235, 1),
+ ],
+ ),
+ ),
+ // decoration: BoxDecoration(
+ // gradient: LinearGradient(colors: [
+ // Color(0xFF0018EB),
+ // Color(0xFF01C1D9),
+ // ], begin: Alignment.bottomCenter, end: Alignment.topCenter),
+ // ),
+ ),
+ ),
+ title: Padding(
+ padding: EdgeInsets.only(left: 0, right: 0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ getIconAndTextButton(
+ iconColor: Colors.white,
+ iconData: Icons.chevron_left_outlined,
+ onPress: () {
+ getingDwVideo = false;
+ Navigator.pop(context);
+ },
+ ),
+ Expanded(
+ child: Text(widget.title,
+ style: TextStyle(color: Colors.white, fontSize: 18),
+ textAlign: TextAlign.center,
+ overflow: TextOverflow.ellipsis),
+ ),
+ SizedBox(width: 50),
+ ],
+ ),
+ ),
+ ),
+ ),
+ body: WillPopScope(
+ child: Container(
+ // height: ScreenUtil().screenHeight -
+ // ScreenUtil().statusBarHeight -
+ // ScreenUtil().bottomBarHeight,
+ color: Color.fromRGBO(224, 224, 224, 1),
+ child: Column(
+ children: [
+ //第2行组件,视频播放区
+ Center(
+ child: Container(
+ //padding: EdgeInsets.only(top: barHeight),
+ alignment: Alignment(0, -1),
+ width: MediaQuery.of(context).size.width,
+ height: MediaQuery.of(context).size.width * (9 / 16),
+ color: Colors.black,
+ child: Stack(
+ children: [
+ _playState <= 2 ? getMoreWidget(strokeWidth: 3.0) : SizedBox.shrink(),
+ SuperPlayerView(
+ controller: _playerController,
+ controlViewType: _kControlViewTypes[0],
+ ),
+ //_playState < 3 ? SizedBox.shrink() : getMoreWidget(strokeWidth: 3.0),
+ ],
+ ),
+ ),
+ ),
+ //第3.1行组件,控制按钮区
+ bFullScreen ? SizedBox.shrink() : SizedBox(height: ScreenUtil().setHeight(69)),
+ bFullScreen
+ ? SizedBox.shrink()
+ : Row(
+ children: [
+ SizedBox(width: ScreenUtil().setWidth(btn_left)),
+ getRoundButton(
+ //(bPlaying) ? '暂停' : '播放',
+ text: playerRegionProvide.playerText,
+ icon: playerRegionProvide.playerIcon,
+ diameter: 130,
+ onPress: playOrPause,
+ ),
+ SizedBox(width: ScreenUtil().setWidth(btn_gap)),
+ getRoundButton(
+ text: '刷新',
+ icon: Icons.autorenew,
+ diameter: 130,
+ onPress: () {
+ restartPlay(urlnew);
+ },
+ ),
+ // widget.id:播放点位视频的点位编号,-2 表示播放违章视频
+ -2 == widget.id
+ ? SizedBox.shrink()
+ : SizedBox(width: ScreenUtil().setWidth(btn_gap)),
+ -2 == widget.id
+ ? SizedBox.shrink()
+ : getRoundButton_image(
+ text: '雨刷',
+ image_path: 'assets/images/wiper.png',
+ diameter: 130,
+ onPress: () {
+ // 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小
+ setSphericalCameraDio(
+ id: widget.id, dwip: widget.dwip, cmdCode: 3);
+ },
+ ),
+ -2 == widget.id
+ ? SizedBox.shrink()
+ : SizedBox(width: ScreenUtil().setWidth(btn_gap)),
+ -2 == widget.id
+ ? SizedBox.shrink()
+ : getRoundButton_image(
+ text: '放大',
+ image_path: 'assets/images/zoom_in.png',
+ imageSize: 72,
+ diameter: 130,
+ onPress: () {
+ // 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小
+ setSphericalCameraDio(
+ id: widget.id, dwip: widget.dwip, cmdCode: 11);
+ },
+ ),
+ -2 == widget.id
+ ? SizedBox.shrink()
+ : SizedBox(width: ScreenUtil().setWidth(btn_gap)),
+ -2 == widget.id
+ ? SizedBox.shrink()
+ : getRoundButton_image(
+ text: '缩小',
+ image_path: 'assets/images/zoom_out.png',
+ imageSize: 72,
+ diameter: 130,
+ onPress: () {
+ // 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小
+ setSphericalCameraDio(
+ id: widget.id, dwip: widget.dwip, cmdCode: 12);
+ },
+ ),
+ ],
+ ),
+ bFullScreen ? SizedBox.shrink() : SizedBox(height: ScreenUtil().setHeight(79)),
+ bFullScreen
+ ? SizedBox.shrink()
+ : Container(
+ height: ScreenUtil().setHeight(2 * _outerRadius),
+ width: ScreenUtil().setWidth(2 * _outerRadius),
+ child: PtControlWidget(
+ // innerRadius: _innerRadius,
+ // outerRadius: _outerRadius,
+ // 进行像素单位转换,解决按钮响应错乱问题
+ innerRadius: _innerRadius / ScreenUtil().pixelRatio,
+ outerRadius: _outerRadius / ScreenUtil().pixelRatio,
+ callback: -2 == widget.id // 播放点位视频的点位编号,-2 表示播放违章视频
+ ? null
+ : (status) {
+ ///点击回调
+ print('status = $status');
+ switch (status) {
+
+ /// status == -1 超出范围
+ /// status == 0 右
+ case 0:
+ setSphericalCameraDio(
+ id: widget.id, dwip: widget.dwip, cmdCode: 24);
+ break;
+
+ /// status == 1 右上
+ case 1:
+ setSphericalCameraDio(
+ id: widget.id, dwip: widget.dwip, cmdCode: 26);
+ break;
+
+ ///三、球机位移接口方向代码说明:
+ // 上:8 下:4 左:2 右:1 左上:10 左下:6 右上:9 右下:5
+
+ // 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小
+ // 21:上移
+ // 22:下移
+ // 23:左移
+ // 24:右移
+ // 25:左上移动
+ // 26:右上移动
+ // 27:左下移动
+ // 28:右下移动
+ /// status == 2 上
+ case 2:
+ setSphericalCameraDio(
+ id: widget.id, dwip: widget.dwip, cmdCode: 21);
+ break;
+
+ /// status == 3 左上
+ case 3:
+ setSphericalCameraDio(
+ id: widget.id, dwip: widget.dwip, cmdCode: 25);
+ break;
+
+ /// status == 4 左
+ case 4:
+ setSphericalCameraDio(
+ id: widget.id, dwip: widget.dwip, cmdCode: 23);
+ break;
+
+ /// status == 5 左下
+ case 5:
+ setSphericalCameraDio(
+ id: widget.id, dwip: widget.dwip, cmdCode: 27);
+ break;
+
+ /// status == 6 下
+ case 6:
+ setSphericalCameraDio(
+ id: widget.id, dwip: widget.dwip, cmdCode: 22);
+ break;
+
+ /// status == 7 右下
+ case 7:
+ setSphericalCameraDio(
+ id: widget.id, dwip: widget.dwip, cmdCode: 28);
+ break;
+
+ /// status == 8 还原
+ case 8:
+ break;
+ default:
+ break;
+ }
+ },
+ ),
+ // child: GridView.custom(
+ // // padding: EdgeInsets.only(
+ // // left: ScreenUtil().setWidth(35), right: ScreenUtil().setWidth(35)),
+ // gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
+ // crossAxisCount: btnCount3,
+ // mainAxisSpacing: 0,
+ // crossAxisSpacing: 1,
+ // childAspectRatio: ratio3,
+ // ),
+ // childrenDelegate: SliverChildBuilderDelegate((context, position) {
+ // return getItemContainer(listData[position]);
+ // }, childCount: btnCount3)),
+ ),
+ //SizedBox(height: ScreenUtil().setHeight(49)),
+ //Divider(color: Colors.blue),
+ //第4行组件,分隔栏
+ // Container(
+ // //height: 11,
+ // height: ScreenUtil().setHeight(28),
+ // color: Color.fromRGBO(224, 224, 224, 1),
+ // ),
+ ],
+ ),
+ ),
+ onWillPop: () {
+ Playing = false;
+ getingDwVideo = false;
+ // 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小
+ setSphericalCameraDio(id: widget.id, dwip: widget.dwip, cmdCode: 1);
+ Navigator.pop(context); //关闭弹框,播放输入视频地址
+ },
+ ),
+ );
+ }
+
+ @override
+ void onClickFloatCloseBtn() {
+ _addLog('onClickFloatCloseBtn', {});
+ }
+
+ @override
+ void onClickSmallReturnBtn() {
+ _addLog('onClickSmallReturnBtn', {});
+ Navigator.maybePop(context);
+ }
+
+ @override
+ void onFullScreenChange(bool isFullScreen) {
+ _addLog('onFullScreenChange', {'isFullScreen': isFullScreen});
+ bFullScreen = !bFullScreen;
+ setState(() {});
+ }
+
+ @override
+ void onPlayProgressChange(int current, int duration) {
+ _addLog('onPlayProgressChange', {'current': current, 'duration': duration});
+ }
+
+ int _playState = 4;
+ int i = 0;
+
+ @override
+ void onPlayStateChange(int playState) {
+ _playState = playState;
+ i++;
+ print('$i、playState = $playState');
+ _addLog('onPlayStateChange', {'playState': playState});
+ setPlayOrPauseIcon(playState);
+ }
+
+ void setPlayOrPauseIcon(int state) {
+ //state : 1 播放状态,2 暂停状态
+ print('state = $state');
+ if (1 == state) {
+ bPlaying = true;
+ } else {
+ bPlaying = false;
+ }
+ playerRegionProvide.changePlayerState(bPlaying);
+ Storage.setString('bPlaying', bPlaying ? 'true' : 'false');
+ setState(() {});
+ }
+
+ @override
+ void onStartFloatWindowPlay() {
+ _addLog('onStartFloatWindowPlay', {});
+ }
+
+ //生成圆形按钮部件,基于图标
+ Widget getRoundButton(
+ {double diameter = 144,
+ double marginVer = 10,
+ String text,
+ IconData icon,
+ double fontSize = 16,
+ double iconSize = 90,
+ Color color = const Color.fromRGBO(52, 157, 237, 1),
+ var onPress}) {
+ return InkWell(
+ onTap: onPress,
+ child: Column(
+ children: [
+ Container(
+ width: ScreenUtil().setWidth(diameter),
+ height: ScreenUtil().setHeight(diameter),
+ alignment: Alignment.center,
+ child: Icon(
+ icon,
+ size: ScreenUtil().setWidth(iconSize),
+ color: Color.fromRGBO(52, 157, 237, 1),
+ ),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.all(Radius.circular(200)),
+ border: Border.all(width: 0, style: BorderStyle.none),
+ ),
+ ),
+ SizedBox(height: ScreenUtil().setHeight(marginVer)),
+ Text(text, style: TextStyle(fontSize: fontSize, color: Color.fromRGBO(139, 139, 139, 1))),
+ ],
+ ),
+ );
+ }
+
+ //生成圆形按钮部件,基于图片
+ Widget getRoundButton_image(
+ {double diameter = 144,
+ double marginVer = 10,
+ String text,
+ String image_path,
+ double fontSize = 16,
+ double imageSize = 90,
+ Color color = const Color.fromRGBO(52, 157, 237, 1),
+ Color color_bkg = Colors.white,
+ var onPress}) {
+ return InkWell(
+ onTap: onPress,
+ child: Column(
+ children: [
+ Container(
+ width: ScreenUtil().setWidth(diameter),
+ height: ScreenUtil().setHeight(diameter),
+ alignment: Alignment.center,
+ child: Image.asset(image_path,
+ fit: BoxFit.fitWidth,
+ width: ScreenUtil().setWidth(imageSize),
+ //height: ScreenUtil().setWidth(iconSize),
+ color: Color.fromRGBO(52, 157, 237, 1)),
+ // child: Icon(
+ // icon,
+ // size: ScreenUtil().setWidth(iconSize),
+ // color: Color.fromRGBO(52, 157, 237, 1),
+ // ),
+ decoration: BoxDecoration(
+ color: color_bkg,
+ borderRadius: BorderRadius.all(Radius.circular(200)),
+ border: Border.all(width: 0, style: BorderStyle.none),
+ ),
+ ),
+ SizedBox(height: ScreenUtil().setHeight(marginVer)),
+ Text(text, style: TextStyle(fontSize: fontSize, color: Color.fromRGBO(139, 139, 139, 1))),
+ ],
+ ),
+ );
+ }
+
+ bool bPlaying = true;
+
+ void playOrPause() {
+ //state : 1 播放状态,2 暂停状态
+ _playerController.getPlayState().then((state) {
+ print('state = $state');
+ if (1 == state) {
+ bPlaying = false;
+ _playerController.pause();
+ } else {
+ bPlaying = true;
+ _playerController.resume();
+ }
+ playerRegionProvide.changePlayerState(bPlaying);
+ Storage.setString('bPlaying', bPlaying ? 'true' : 'false');
+ setState(() {});
+ });
+ }
+
+ void restartPlay(String url) async {
+ _playState = 4;
+ bPlaying = true;
+ _playerController.resetPlayer();
+ _playerController.resume();
+ // //writeCurrentPosFile();
+ // await player.stop();
+ // await player.reset();
+ // await player.setOption(FijkOption.playerCategory, "mediacodec-all-videos", 1);
+ // await player.setOption(FijkOption.hostCategory, "enable-snapshot", 1);
+ // await player.setOption(FijkOption.hostCategory, "request-screen-on", 1);
+ // await player.setOption(FijkOption.hostCategory, "request-audio-focus", 1);
+ // await player.setOption(FijkOption.hostCategory, "enable-accurate-seek", 1);
+ // await player.setOption(FijkOption.hostCategory, "max-buffer-size", 500 * 1024);
+ // await player.setDataSource(url, autoPlay: true).catchError((e) {
+ // print("setDataSource error: $e");
+ // });
+ // await player.setLoop(widget.loop); //设置播放循环,默认播放器的循环次数是1, 即不循环播放。如果设置循环次数0,表示无限循环。
+ // bPlaying = true;
+ // setState(() {});
+ // playerRegionProvide.changePlayerState(bPlaying);
+ }
+
+ //生成播放控制区第2行按钮List
+// List getDataListControl2() {
+// double _diameter = 100;
+// double _iconSize = 70;
+// double _fontSize = 14;
+// double _marginVer = 8;
+//
+// List list = [
+// // getRoundButton(
+// // diameter: _diameter,
+// // iconSize: _iconSize,
+// // text: '快退',
+// // icon: Icons.fast_rewind,
+// // onPress: () {
+// // fastSeek(false);
+// // },
+// // ),
+// // getRoundButton(
+// // diameter: _diameter,
+// // iconSize: _iconSize,
+// // text: '快进',
+// // icon: Icons.fast_forward,
+// // onPress: () {
+// // fastSeek(true);
+// // },
+// // ),
+// getRoundButton(
+// diameter: _diameter,
+// iconSize: _iconSize,
+// fontSize: _fontSize,
+// marginVer: _marginVer,
+// text: '放大',
+// icon: Icons.zoom_in,
+// onPress: () {
+// //print('Icons.videocam');
+// //_inputDialog(context2);
+// if (10 >= playerRatioProvide.scale) {
+// playerRatioProvide.changeScale(playerRatioProvide.scale + 0.5);
+// }
+// },
+// ),
+// getRoundButton(
+// diameter: _diameter,
+// iconSize: _iconSize,
+// fontSize: _fontSize,
+// marginVer: _marginVer,
+// text: '缩小',
+// icon: Icons.zoom_out,
+// onPress: () {
+// //print('Icons.videocam');
+// //_getFileDialog(context2);
+// if (1 < playerRatioProvide.scale) {
+// playerRatioProvide.changeScale(playerRatioProvide.scale - 0.5);
+// }
+// },
+// ),
+// // _getIconAndTextButton(
+// // '还原',
+// // Icons.reply,
+// // Colors.orange,
+// // () {
+// // //print('Icons.videocam');
+// // //_getFileDialog(context2);
+// // // 更新当前位置
+// // playerRatioProvide.changeScale(1.0);
+// // playerRatioProvide.changeOffset(Offset(0, 0));
+// // playerRatioProvide.changeDeltaX(0.0);
+// // playerRatioProvide.changeDeltaY(0.0);
+// // },
+// // ),
+// getRoundButton(
+// diameter: _diameter,
+// iconSize: _iconSize,
+// fontSize: _fontSize,
+// marginVer: _marginVer,
+// text: '截图',
+// icon: Icons.camera_alt,
+// onPress: () {
+// //通过上面定义的key,才能准确调用该类型的该对象的方法
+// //_myFijkPanelWidgetBuilderStateKey.currentState.takeSnapshot();
+// //_fijkPanelWidgetBuilder.currentState..takeSnapshot();
+// takeSnapshot();
+// },
+// ),
+// getRoundButton(
+// diameter: _diameter,
+// iconSize: _iconSize,
+// fontSize: _fontSize,
+// marginVer: _marginVer,
+// text: '全屏',
+// icon: Icons.fullscreen,
+// onPress: () {
+// //player.enterFullScreen();
+// _playerController.toFullScreen();
+// },
+// ),
+// ];
+// return list;
+// }
+
+ void takeSnapshot() {
+ // player.takeSnapShot().then((v) {
+ // var provider = MemoryImage(v);
+ // precacheImage(provider, context).then((_) {
+ // setState(() {
+ // myImageProvider = provider;
+ // });
+ // });
+ // FijkLog.d("get snapshot succeed");
+ //
+ // //Uint8List fileData;
+ // String fileFath;
+ // ImageSaver.save('extended_image_cropped_image.jpg', v).then((value) {
+ // fileFath = value;
+ // // var fileFath = await ImagePickerSaver.saveFile(fileData: fileData);
+ // print('my save fileFath : $fileFath');
+ // });
+ // }).catchError((e) {
+ // FijkLog.d("get snapshot failed");
+ // });
+ }
+}
diff --git a/lib/widget/my_superplayer.dart b/lib/widget/my_superplayer.dart
index 48d0749..9713dc1 100644
--- a/lib/widget/my_superplayer.dart
+++ b/lib/widget/my_superplayer.dart
@@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:ui';
import 'dart:io';
+import 'package:fijkplayer/fijkplayer.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/screen_util.dart';
@@ -17,34 +18,38 @@ import 'package:fijkplayer/fijkplayer.dart';
import '../components/commonFun.dart';
import '../services/Storage.dart';
+import '../my_fijkPanel_fix/my_panel3.dart';
class SuperPlayerPage extends StatefulWidget {
SuperPlayerPage(
{@required this.url,
+ this.urlType = 'mp4', // 视频类型:mp4,rtmp
this.id = -2, // 播放点位视频的点位编号,-2 表示播放违章视频
this.dwip = '', // 点位IP,用于点位视频控制球机方向
this.loop = 1,
this.title = 'Tencent Player',
Key key})
: super(key: key);
- String dwip;
String url;
- String title;
- int loop; //设置播放循环,默认播放器的循环次数是1, 即不循环播放。如果设置循环次数0,表示无限循环。
+ String urlType;
int id;
+ String dwip;
+ int loop; //设置播放循环,默认播放器的循环次数是1, 即不循环播放。如果设置循环次数0,表示无限循环。
+ String title;
@override
_SuperPlayerPageState createState() => _SuperPlayerPageState();
}
-class _SuperPlayerPageState extends State with SuperPlayerListener {
- final SuperPlayerController _playerController = SuperPlayerController();
- final FijkPlayer _ijkPlayer = (){
- var player = FijkPlayer();
- player.setOption(FijkOption.playerCategory, "packet-buffering", 0);
- player.setOption(FijkOption.formatCategory, "probesize", 1024);
- return player;
- }();
+class _SuperPlayerPageState extends State
+ with WidgetsBindingObserver, AutomaticKeepAliveClientMixin {
+ // SuperPlayerController _playerController = SuperPlayerController();
+
+ @override
+ // TODO: implement wantKeepAlive
+ bool get wantKeepAlive => true;
+
+ final FijkPlayer _playerController = FijkPlayer();
String _sdkVersion = 'Unknown';
List _logs = [];
@@ -55,6 +60,7 @@ class _SuperPlayerPageState extends State with SuperPlayerListe
Playing = false;
// 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小
setSphericalCameraDio(id: widget.id, dwip: widget.dwip, cmdCode: 1);
+ _playerController.release(); // 必须显示释放视频播放资源,否则即使退出视频播放页面后台还在获取视频流
super.dispose();
_ijkPlayer.release();
_playerController.resetPlayer();
@@ -65,56 +71,113 @@ class _SuperPlayerPageState extends State with SuperPlayerListe
@override
void initState() {
super.initState();
- init();
+ //initPlatformState();
+ // Future.delayed(const Duration(milliseconds: 1000), () {
+ // _playerController.playWithModel(SuperPlayerModel(url: widget.url));
+ // setState(() {
+ // });
+ // });
+ // init();
+
+ WidgetsBinding.instance.addObserver(this);
+
+ _playerController.setOption(FijkOption.hostCategory, "enable-snapshot", 1);
+ _playerController.setOption(FijkOption.playerCategory, "mediacodec-all-videos", 1);
+ startPlay();
}
- Future init() async {
- await _playerController.addListener(this);
- await initPlatformState();
+ void startPlay() async {
+ // await _playerController.addListener(() {});
+
if (!mounted) return;
+ print('mounted = ${mounted}');
- if (_useIJKPlayer) {
- await _playerController.removeListener(this);
- _ijkPlayer.addListener(_fijkValueListener);
- _ijkPlayer.setDataSource(widget.url, autoPlay: true);
- } else {
- await _playerController.uiHideDanmu();
- if (0 == widget.loop) {
- await _playerController.setLoop(true);
- }
- await _playerController.playWithModel(testSuperPlayerModel);
+ await _playerController.setLoop(widget.loop); // 0无限循环,1循环一次,2循环两次,以此类推
+ await _playerController.setOption(FijkOption.playerCategory, "mediacodec-all-videos", 1);
+ await _playerController.setOption(FijkOption.hostCategory, "enable-snapshot", 1);
+ await _playerController.setOption(FijkOption.hostCategory, "request-screen-on", 1);
+ await _playerController.setOption(FijkOption.hostCategory, "request-audio-focus", 1);
+ await _playerController.setOption(FijkOption.hostCategory, "enable-accurate-seek", 1);
+ // 播放“rmtp”等网络视频设置
+ if (widget.urlType != 'mp4') {
+ /// fijkplayer播放点位视频延迟比较大优化-OK,改完后约1秒钟就能打开 - Being
+ // 是否开启预缓冲,一般直播项目会开启,达到秒开的效果,不过带来了播放丢帧卡顿的体验
+ await _playerController.setOption(FijkOption.playerCategory, "packet-buffering", 0);
+ // 播放前的探测Size,默认是1024K(1M), 改小一点会出画面更快
+ // await player.setOption(FijkOption.formatCategory, "probesize", 200); // 1.3S打开
+ await _playerController.setOption(FijkOption.formatCategory, "probesize", 1024); // 避免第一帧花屏
+ await _playerController.setOption(FijkOption.formatCategory, 'http-detect-range-support', 0);
+ // 设置播放前的探测时间 1,达到首屏秒开效果
+ await _playerController.setOption(FijkOption.formatCategory, "analyzeduration", 1);
+ // 缩短播放的rtmp视频延迟在1s内
+ await _playerController.setOption(FijkOption.formatCategory, "fflags", "nobuffer");
+ // 支持硬解: 1 开启, O 关闭
+ await _playerController.setOption(FijkOption.playerCategory, "mediacodec-hevc", 1);
+
+ /// fijkplayer播放点位视频延迟比较大优化-OK,改完后半秒钟就能打开 - End
+
+ // await _playerController.setOption(FijkOption.hostCategory, "request-screen-on", 1);
+ // await _playerController.setOption(FijkOption.hostCategory, "request-audio-focus", 1);
}
}
- bool get _useIJKPlayer {
- return Platform.isIOS && widget.url.startsWith("rtmp");
+ await _playerController.setDataSource(widget.url, autoPlay: true).catchError((e) {
+ print("setDataSource error: $e");
+ });
+ playerRegionProvide.changePlayerState(bPlaying);
}
+ // Future init() async {
+ // await _playerController.addListener(this);
+ // await initPlatformState();
+ // if (!mounted) return;
+ // print('mounted = ${mounted}');
+ // // 开启调试日志
+ // //await FTXPlayerController.setConsoleEnabled(true);
+ // // 初始化播放器
+ // //await _controller.initialize(onlyAudio: true);
+ //
+ // await _playerController.uiHideDanmu(); // 隐藏弹幕
+ // //设置播放循环,默认播放器的循环次数是1, 即不循环播放。如果设置循环次数0,表示无限循环。
+ // if (0 == widget.loop) {
+ // await _playerController.setLoop(true);
+ // }
+ //
+ // await _playerController.playWithModel(testSuperPlayerModel);
+ // //_controller.play("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4");
+ // // _controller
+ // // .play('rtmp://125.64.218.67:9901/rtp/gb_play_34020000001320003016_34020000001320003016');
+ // // 设置循环播放
+ // //await _controller.setLoop(true);
+ // // 开始播放
+ // //await _controller.play("http://125.64.218.67:9908/video/2_6063_20210409_140608_川Q31715.mp4");
+ // }
+
SuperPlayerModel get testSuperPlayerModel {
return SuperPlayerModel(url: widget.url);
}
// Platform messages are asynchronous, so we initialize in an async method.
- Future initPlatformState() async {
- String sdkVersion;
- // Platform messages may fail, so we use a try/catch PlatformException.
- try {
- sdkVersion = await FlutterSuperPlayer.sdkVersion;
- } on PlatformException {
- sdkVersion = 'Failed to get platform version.';
- }
- print('sdkVersion = ${sdkVersion}');
- print('mounted = ${mounted}');
-
- // If the widget was removed from the tree while the asynchronous platform
- // message was in flight, we want to discard the reply rather than calling
- // setState to update our non-existent appearance.
- if (!mounted) return;
-
- setState(() {
- _sdkVersion = sdkVersion;
- });
- }
+ // Future initPlatformState() async {
+ // String sdkVersion;
+ // // Platform messages may fail, so we use a try/catch PlatformException.
+ // try {
+ // sdkVersion = await FlutterSuperPlayer.sdkVersion;
+ // } on PlatformException {
+ // sdkVersion = 'Failed to get platform version.';
+ // }
+ // print('sdkVersion = ${sdkVersion}');
+ // print('mounted = ${mounted}');
+ //
+ // // If the widget was removed from the tree while the asynchronous platform
+ // // message was in flight, we want to discard the reply rather than calling
+ // // setState to update our non-existent appearance.
+ // if (!mounted) return;
+ //
+ // setState(() {
+ // _sdkVersion = sdkVersion;
+ // });
+ // }
void _addLog(String method, dynamic data) {
_logs.add('>>>$method');
@@ -128,16 +191,20 @@ class _SuperPlayerPageState extends State with SuperPlayerListe
PlayerRatioProvide playerRatioProvide;
+ FijkPanelWidgetBuilder _fijkPanelWidgetBuilder;
+
@override
Widget build(BuildContext context) {
+ _fijkPanelWidgetBuilder = fijkPanel2Builder3(snapShot: true, player: _playerController);
playerRegionProvide = Provider.of(context);
playerRatioProvide = Provider.of(context);
- // List listData = getDataListControl2();
- double btnHeight1 = 70; //第一按钮行高度
- double btnHeight2 = 160; //第二按钮行高度
- int btnCount = 4; //每行按钮个数
- // int btnCount3 = listData.length; //每行按钮个数
- var mediaSize = MediaQuery.of(context).size;
+
+ // // List listData = getDataListControl2();
+ // double btnHeight1 = 70; //第一按钮行高度
+ // double btnHeight2 = 160; //第二按钮行高度
+ // int btnCount = 4; //每行按钮个数
+ // // int btnCount3 = listData.length; //每行按钮个数
+ // var mediaSize = MediaQuery.of(context).size;
// widget.id:播放点位视频的点位编号,-2 表示播放违章视频
double btn_left = -2 == widget.id ? 347 : 70; //第一按钮行高度
@@ -212,7 +279,30 @@ class _SuperPlayerPageState extends State with SuperPlayerListe
child: Stack(
children: [
_playState <= 2 ? getMoreWidget(strokeWidth: 3.0) : SizedBox.shrink(),
- _useIJKPlayer ? FijkView(player: _ijkPlayer, color: Colors.black) : SuperPlayerView(controller: _playerController)
+ // SuperPlayerView(
+ // controller: _playerController,
+ // controlViewType: _kControlViewTypes[0],
+ // ),
+
+ FijkView(
+ //设置视频区域背景颜色-OK
+ color: Colors.black,
+ player: _playerController,
+ // panelBuilder: fijkPanel2Builder(snapShot: true),
+ panelBuilder: _fijkPanelWidgetBuilder,
+ fsFit: FijkFit.fill,
+ // panelBuilder: simplestUI,
+ // panelBuilder: (FijkPlayer player, BuildContext context,
+ // Size viewSize, Rect texturePos) {
+ // return CustomFijkPanel(
+ // player: player,
+ // buildContext: context,
+ // viewSize: viewSize,
+ // texturePos: texturePos);
+ // },
+ ),
+
+ //_playState < 3 ? SizedBox.shrink() : getMoreWidget(strokeWidth: 3.0),
],
),
),
@@ -532,21 +622,26 @@ class _SuperPlayerPageState extends State with SuperPlayerListe
bool bPlaying = true;
- Future playOrPause() async {
+ void playOrPause() {
+ // playerRegionProvide.changePlayerState(bPlaying);
+ //
+ // if (bPlaying) {
+ // _playerController.start();
+ // } else {
+ // _playerController.pause();
+ // }
+ //
+ // setState(() {
+ // bPlaying = !bPlaying;
+ // });
+
//state : 1 播放状态,2 暂停状态
- int state;
- if (_useIJKPlayer) {
- state = _ijkPlayer.state == FijkState.started ? 1 : 2;
- } else {
- state = await _playerController.getPlayState();
- }
-
- if (1 == state) {
+ if (FijkState.started == _playerController.state) {
bPlaying = false;
- _useIJKPlayer ? _ijkPlayer.pause() : _playerController.pause();
+ _playerController.pause();
} else {
bPlaying = true;
- _useIJKPlayer ? _ijkPlayer.start() : _playerController.resume();
+ _playerController.start();
}
playerRegionProvide.changePlayerState(bPlaying);
Storage.setString('bPlaying', bPlaying ? 'true' : 'false');
@@ -556,13 +651,30 @@ class _SuperPlayerPageState extends State with SuperPlayerListe
void restartPlay(String url) async {
_playState = 4;
bPlaying = true;
- if (_useIJKPlayer) {
- await _ijkPlayer.reset();
- _ijkPlayer.setDataSource(widget.url, autoPlay: true);
- } else {
- _playerController.resetPlayer();
- _playerController.resume();
- }
+
+ await _playerController.stop();
+ await _playerController.reset();
+ startPlay();
+
+ // _playerController.resetPlayer();
+ // _playerController.resume();
+
+ // //writeCurrentPosFile();
+ // await player.stop();
+ // await player.reset();
+ // await player.setOption(FijkOption.playerCategory, "mediacodec-all-videos", 1);
+ // await player.setOption(FijkOption.hostCategory, "enable-snapshot", 1);
+ // await player.setOption(FijkOption.hostCategory, "request-screen-on", 1);
+ // await player.setOption(FijkOption.hostCategory, "request-audio-focus", 1);
+ // await player.setOption(FijkOption.hostCategory, "enable-accurate-seek", 1);
+ // await player.setOption(FijkOption.hostCategory, "max-buffer-size", 500 * 1024);
+ // await player.setDataSource(url, autoPlay: true).catchError((e) {
+ // print("setDataSource error: $e");
+ // });
+ // await player.setLoop(widget.loop); //设置播放循环,默认播放器的循环次数是1, 即不循环播放。如果设置循环次数0,表示无限循环。
+ // bPlaying = true;
+ // setState(() {});
+ // playerRegionProvide.changePlayerState(bPlaying);
}
//生成播放控制区第2行按钮List
diff --git a/pubspec.lock b/pubspec.lock
index 5eab507..16234e5 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -356,6 +356,13 @@ packages:
relative: true
source: path
version: "0.0.3"
+ flutter_svg:
+ dependency: "direct main"
+ description:
+ name: flutter_svg
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "0.19.1"
flutter_swiper:
dependency: "direct main"
description:
@@ -387,6 +394,27 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.1"
+ geolocator:
+ dependency: "direct main"
+ description:
+ name: geolocator
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "6.2.1"
+ geolocator_platform_interface:
+ dependency: transitive
+ description:
+ name: geolocator_platform_interface
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.0.9"
+ geolocator_web:
+ dependency: transitive
+ description:
+ name: geolocator_web
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.0.1"
get_it:
dependency: "direct main"
description:
@@ -457,6 +485,13 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.1"
+ map_launcher:
+ dependency: "direct main"
+ description:
+ name: map_launcher
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.1.3+1"
matcher:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index f47a770..67b6d86 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -21,7 +21,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
-version: 1.4.33+20220515
+version: 1.6.5+20250527
environment:
sdk: ">=2.7.0 <3.0.0"
@@ -36,7 +36,7 @@ dependencies:
cupertino_icons: ^1.0.0
# hyzp_ybqx00_yibin Project Adds
- fijkplayer: ^0.8.7
+ fijkplayer: ^0.8.8
path_provider: ^1.6.14
permission_handler: ^5.0.1+1
@@ -108,6 +108,11 @@ dependencies:
# 添加水印插件
disable_screenshots: ^0.1.0
+ # 导航相关插件
+ map_launcher: ^1.1.3+1
+ flutter_svg: ^0.19.1
+ geolocator: ^6.2.1
+
dev_dependencies:
flutter_test:
sdk: flutter