1020 lines
30 KiB
Dart
1020 lines
30 KiB
Dart
|
import 'dart:async';
|
|||
|
import 'dart:io';
|
|||
|
|
|||
|
import 'package:flutter/material.dart';
|
|||
|
import 'package:flutter/services.dart';
|
|||
|
import 'package:flutter_aliplayer/flutter_aliplayer.dart';
|
|||
|
import 'package:flutter_aliplayer/flutter_aliplayer_factory.dart';
|
|||
|
import 'package:flutter_aliplayer_example/config.dart';
|
|||
|
import 'package:flutter_aliplayer_example/page/player_fragment/cache_config_fragment.dart';
|
|||
|
import 'package:flutter_aliplayer_example/page/player_fragment/filter_fragment.dart';
|
|||
|
import 'package:flutter_aliplayer_example/page/player_fragment/options_fragment.dart';
|
|||
|
import 'package:flutter_aliplayer_example/page/player_fragment/play_config_fragment.dart';
|
|||
|
import 'package:flutter_aliplayer_example/page/player_fragment/track_fragment.dart';
|
|||
|
import 'package:flutter_aliplayer_example/util/formatter_utils.dart';
|
|||
|
import 'package:flutter_aliplayer_example/widget/aliyun_marqueeview.dart';
|
|||
|
import 'package:flutter_aliplayer_example/widget/aliyun_slider.dart';
|
|||
|
import 'package:fluttertoast/fluttertoast.dart';
|
|||
|
import 'package:path_provider/path_provider.dart';
|
|||
|
import 'package:connectivity/connectivity.dart';
|
|||
|
|
|||
|
class PlayerPage extends StatefulWidget {
|
|||
|
final ModeType playMode;
|
|||
|
final Map<String, dynamic> dataSourceMap;
|
|||
|
|
|||
|
PlayerPage({Key key, this.playMode, this.dataSourceMap})
|
|||
|
: assert(playMode != null),
|
|||
|
super(key: key);
|
|||
|
|
|||
|
@override
|
|||
|
_PlayerPageState createState() => _PlayerPageState();
|
|||
|
}
|
|||
|
|
|||
|
class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
|
|||
|
FlutterAliplayer fAliplayer;
|
|||
|
int bottomIndex;
|
|||
|
List<Widget> mFramePage;
|
|||
|
ModeType _playMode;
|
|||
|
Map<String, dynamic> _dataSourceMap;
|
|||
|
OptionsFragment mOptionsFragment;
|
|||
|
|
|||
|
//是否允许后台播放
|
|||
|
bool _mEnablePlayBack = false;
|
|||
|
|
|||
|
//当前播放进度
|
|||
|
int _currentPosition = 0;
|
|||
|
|
|||
|
//当前播放时间,用于Text展示
|
|||
|
int _currentPositionText = 0;
|
|||
|
|
|||
|
//当前buffer进度
|
|||
|
int _bufferPosition = 0;
|
|||
|
|
|||
|
//是否展示loading
|
|||
|
bool _showLoading = false;
|
|||
|
|
|||
|
//loading进度
|
|||
|
int _loadingPercent = 0;
|
|||
|
|
|||
|
//视频时长
|
|||
|
int _videoDuration = 1;
|
|||
|
|
|||
|
//截图保存路径
|
|||
|
String _snapShotPath;
|
|||
|
|
|||
|
//提示内容
|
|||
|
String _tipsContent;
|
|||
|
|
|||
|
//是否展示提示内容
|
|||
|
bool _showTipsWidget = false;
|
|||
|
|
|||
|
//是否有缩略图
|
|||
|
bool _thumbnailSuccess = false;
|
|||
|
|
|||
|
//缩略图
|
|||
|
// Uint8List _thumbnailBitmap;
|
|||
|
ImageProvider _imageProvider;
|
|||
|
|
|||
|
//当前网络状态
|
|||
|
ConnectivityResult _currentConnectivityResult;
|
|||
|
|
|||
|
///seek中
|
|||
|
bool _inSeek = false;
|
|||
|
|
|||
|
bool _isLock = false;
|
|||
|
|
|||
|
//网络状态
|
|||
|
bool _isShowMobileNetWork = false;
|
|||
|
|
|||
|
//当前播放器状态
|
|||
|
int _currentPlayerState = 0;
|
|||
|
|
|||
|
String extSubTitleText = '';
|
|||
|
|
|||
|
///封面图
|
|||
|
bool _showCoverImg = true;
|
|||
|
|
|||
|
//网络状态监听
|
|||
|
StreamSubscription _networkSubscription;
|
|||
|
|
|||
|
List<int> dotPositionList = [];
|
|||
|
|
|||
|
GlobalKey<TrackFragmentState> trackFragmentKey = GlobalKey();
|
|||
|
|
|||
|
int aliPlayerViewId;
|
|||
|
|
|||
|
@override
|
|||
|
void initState() {
|
|||
|
super.initState();
|
|||
|
fAliplayer = FlutterAliPlayerFactory.createAliPlayer();
|
|||
|
WidgetsBinding.instance.addObserver(this);
|
|||
|
bottomIndex = 0;
|
|||
|
_playMode = widget.playMode;
|
|||
|
_dataSourceMap = widget.dataSourceMap;
|
|||
|
|
|||
|
//开启混音模式
|
|||
|
if (Platform.isIOS) {
|
|||
|
FlutterAliplayer.setAudioSessionTypeForIOS(
|
|||
|
AliPlayerAudioSesstionType.mix);
|
|||
|
}
|
|||
|
|
|||
|
//设置播放器
|
|||
|
fAliplayer.setPreferPlayerName(GlobalSettings.mPlayerName);
|
|||
|
fAliplayer.setEnableHardwareDecoder(GlobalSettings.mEnableHardwareDecoder);
|
|||
|
|
|||
|
if (Platform.isAndroid) {
|
|||
|
getExternalStorageDirectories().then(
|
|||
|
(value) {
|
|||
|
if (value.length > 0) {
|
|||
|
_snapShotPath = value[0].path;
|
|||
|
return _snapShotPath;
|
|||
|
}
|
|||
|
},
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
mOptionsFragment = OptionsFragment(fAliplayer);
|
|||
|
mFramePage = [
|
|||
|
mOptionsFragment,
|
|||
|
PlayConfigFragment(fAliplayer),
|
|||
|
FilterFragment(fAliplayer),
|
|||
|
CacheConfigFragment(fAliplayer),
|
|||
|
TrackFragment(trackFragmentKey, fAliplayer),
|
|||
|
];
|
|||
|
|
|||
|
mOptionsFragment.setOnEnablePlayBackChanged(
|
|||
|
(mEnablePlayBack) {
|
|||
|
this._mEnablePlayBack = mEnablePlayBack;
|
|||
|
},
|
|||
|
);
|
|||
|
|
|||
|
_initListener();
|
|||
|
}
|
|||
|
|
|||
|
_initListener() {
|
|||
|
fAliplayer.setOnEventReportParams(
|
|||
|
(params, playerId) {
|
|||
|
print("EventReportParams=${params}");
|
|||
|
},
|
|||
|
);
|
|||
|
fAliplayer.setOnPrepared(
|
|||
|
(playerId) {
|
|||
|
Fluttertoast.showToast(msg: "OnPrepared ");
|
|||
|
fAliplayer.getPlayerName().then(
|
|||
|
(value) => print("getPlayerName==${value}"),
|
|||
|
);
|
|||
|
fAliplayer.getMediaInfo().then(
|
|||
|
(value) {
|
|||
|
_videoDuration = value['duration'];
|
|||
|
setState(() {});
|
|||
|
},
|
|||
|
);
|
|||
|
},
|
|||
|
);
|
|||
|
fAliplayer.setOnRenderingStart(
|
|||
|
(playerId) {
|
|||
|
Fluttertoast.showToast(msg: " OnFirstFrameShow ");
|
|||
|
setState(
|
|||
|
() {
|
|||
|
if (mounted) {
|
|||
|
_showCoverImg = false;
|
|||
|
}
|
|||
|
},
|
|||
|
);
|
|||
|
},
|
|||
|
);
|
|||
|
fAliplayer.setOnVideoSizeChanged((width, height, rotation, playerId) {});
|
|||
|
fAliplayer.setOnStateChanged(
|
|||
|
(newState, playerId) {
|
|||
|
_currentPlayerState = newState;
|
|||
|
switch (newState) {
|
|||
|
case FlutterAvpdef.AVPStatus_AVPStatusStarted:
|
|||
|
setState(
|
|||
|
() {
|
|||
|
_showTipsWidget = false;
|
|||
|
_showLoading = false;
|
|||
|
},
|
|||
|
);
|
|||
|
break;
|
|||
|
case FlutterAvpdef.AVPStatus_AVPStatusPaused:
|
|||
|
break;
|
|||
|
default:
|
|||
|
}
|
|||
|
},
|
|||
|
);
|
|||
|
fAliplayer.setOnLoadingStatusListener(
|
|||
|
loadingBegin: (playerId) {
|
|||
|
setState(
|
|||
|
() {
|
|||
|
_loadingPercent = 0;
|
|||
|
_showLoading = true;
|
|||
|
},
|
|||
|
);
|
|||
|
},
|
|||
|
loadingProgress: (percent, netSpeed, playerId) {
|
|||
|
_loadingPercent = percent;
|
|||
|
if (percent == 100) {
|
|||
|
_showLoading = false;
|
|||
|
}
|
|||
|
setState(() {});
|
|||
|
},
|
|||
|
loadingEnd: (playerId) {
|
|||
|
setState(
|
|||
|
() {
|
|||
|
_showLoading = false;
|
|||
|
},
|
|||
|
);
|
|||
|
},
|
|||
|
);
|
|||
|
fAliplayer.setOnSeekComplete(
|
|||
|
(playerId) {
|
|||
|
_inSeek = false;
|
|||
|
},
|
|||
|
);
|
|||
|
fAliplayer.setOnInfo(
|
|||
|
(infoCode, extraValue, extraMsg, playerId) {
|
|||
|
if (infoCode == FlutterAvpdef.CURRENTPOSITION) {
|
|||
|
if (_videoDuration != 0 && extraValue <= _videoDuration) {
|
|||
|
_currentPosition = extraValue;
|
|||
|
}
|
|||
|
if (!_inSeek) {
|
|||
|
setState(
|
|||
|
() {
|
|||
|
_currentPositionText = extraValue;
|
|||
|
},
|
|||
|
);
|
|||
|
}
|
|||
|
} else if (infoCode == FlutterAvpdef.BUFFEREDPOSITION) {
|
|||
|
_bufferPosition = extraValue;
|
|||
|
if (mounted) {
|
|||
|
setState(() {});
|
|||
|
}
|
|||
|
} else if (infoCode == FlutterAvpdef.AUTOPLAYSTART) {
|
|||
|
Fluttertoast.showToast(msg: "AutoPlay");
|
|||
|
} else if (infoCode == FlutterAvpdef.CACHESUCCESS) {
|
|||
|
Fluttertoast.showToast(msg: "Cache Success");
|
|||
|
} else if (infoCode == FlutterAvpdef.CACHEERROR) {
|
|||
|
Fluttertoast.showToast(msg: "Cache Error $extraMsg");
|
|||
|
} else if (infoCode == FlutterAvpdef.LOOPINGSTART) {
|
|||
|
Fluttertoast.showToast(msg: "Looping Start");
|
|||
|
} else if (infoCode == FlutterAvpdef.SWITCHTOSOFTWAREVIDEODECODER) {
|
|||
|
Fluttertoast.showToast(msg: "change to soft ware decoder");
|
|||
|
mOptionsFragment.switchHardwareDecoder();
|
|||
|
}
|
|||
|
},
|
|||
|
);
|
|||
|
fAliplayer.setOnCompletion(
|
|||
|
(playerId) {
|
|||
|
_showTipsWidget = true;
|
|||
|
_showLoading = false;
|
|||
|
_tipsContent = "播放完成";
|
|||
|
setState(
|
|||
|
() {
|
|||
|
_currentPosition = _videoDuration;
|
|||
|
},
|
|||
|
);
|
|||
|
},
|
|||
|
);
|
|||
|
fAliplayer.setOnTrackReady(
|
|||
|
(playerId) {
|
|||
|
fAliplayer.getMediaInfo().then(
|
|||
|
(value) {
|
|||
|
setState(() {});
|
|||
|
List thumbnails = value['thumbnails'];
|
|||
|
if (thumbnails != null && thumbnails.isNotEmpty) {
|
|||
|
fAliplayer.createThumbnailHelper(thumbnails[0]['url']);
|
|||
|
} else {
|
|||
|
_thumbnailSuccess = false;
|
|||
|
}
|
|||
|
},
|
|||
|
);
|
|||
|
trackFragmentKey.currentState.loadData();
|
|||
|
setState(() {});
|
|||
|
},
|
|||
|
);
|
|||
|
|
|||
|
fAliplayer.setOnSnapShot((path, playerId) {
|
|||
|
Fluttertoast.showToast(msg: "SnapShot Save : $path");
|
|||
|
});
|
|||
|
fAliplayer.setOnError(
|
|||
|
(errorCode, errorExtra, errorMsg, playerId) {
|
|||
|
_showTipsWidget = true;
|
|||
|
_showLoading = false;
|
|||
|
_tipsContent = "$errorCode \n $errorMsg";
|
|||
|
setState(() {});
|
|||
|
},
|
|||
|
);
|
|||
|
|
|||
|
fAliplayer.setOnTrackChanged(
|
|||
|
(value, playerId) {
|
|||
|
AVPTrackInfo info = AVPTrackInfo.fromJson(value);
|
|||
|
if (info != null && info.trackDefinition.length > 0) {
|
|||
|
trackFragmentKey.currentState.onTrackChanged(info);
|
|||
|
Fluttertoast.showToast(msg: "${info.trackDefinition}切换成功");
|
|||
|
}
|
|||
|
},
|
|||
|
);
|
|||
|
|
|||
|
fAliplayer.setOnThumbnailPreparedListener(
|
|||
|
preparedSuccess: (playerId) {
|
|||
|
_thumbnailSuccess = true;
|
|||
|
setState(() {
|
|||
|
/// 打点位置
|
|||
|
dotPositionList.add(30000);
|
|||
|
dotPositionList.add(65000);
|
|||
|
dotPositionList.add(125000);
|
|||
|
});
|
|||
|
},
|
|||
|
preparedFail: (playerId) {
|
|||
|
_thumbnailSuccess = false;
|
|||
|
},
|
|||
|
);
|
|||
|
|
|||
|
fAliplayer.setOnThumbnailGetListener(
|
|||
|
onThumbnailGetSuccess: (bitmap, range, playerId) {
|
|||
|
// _thumbnailBitmap = bitmap;
|
|||
|
var provider = MemoryImage(bitmap);
|
|||
|
precacheImage(provider, context).then(
|
|||
|
(_) {
|
|||
|
setState(
|
|||
|
() {
|
|||
|
_imageProvider = provider;
|
|||
|
},
|
|||
|
);
|
|||
|
},
|
|||
|
);
|
|||
|
},
|
|||
|
onThumbnailGetFail: (playerId) {});
|
|||
|
|
|||
|
this.fAliplayer.setOnSubtitleHide(
|
|||
|
(trackIndex, subtitleID, playerId) {
|
|||
|
if (mounted) {
|
|||
|
setState(
|
|||
|
() {
|
|||
|
extSubTitleText = '';
|
|||
|
},
|
|||
|
);
|
|||
|
}
|
|||
|
},
|
|||
|
);
|
|||
|
|
|||
|
this.fAliplayer.setOnSubtitleShow(
|
|||
|
(trackIndex, subtitleID, subtitle, playerId) {
|
|||
|
if (mounted) {
|
|||
|
setState(
|
|||
|
() {
|
|||
|
extSubTitleText = subtitle;
|
|||
|
},
|
|||
|
);
|
|||
|
}
|
|||
|
},
|
|||
|
);
|
|||
|
_setNetworkChangedListener();
|
|||
|
}
|
|||
|
|
|||
|
_setNetworkChangedListener() {
|
|||
|
_networkSubscription = Connectivity().onConnectivityChanged.listen(
|
|||
|
(ConnectivityResult result) {
|
|||
|
if (result == ConnectivityResult.mobile) {
|
|||
|
fAliplayer.pause();
|
|||
|
setState(
|
|||
|
() {
|
|||
|
_isShowMobileNetWork = true;
|
|||
|
},
|
|||
|
);
|
|||
|
} else if (result == ConnectivityResult.wifi) {
|
|||
|
//从4G网络或者无网络切换到wifi
|
|||
|
if (_currentConnectivityResult == ConnectivityResult.mobile ||
|
|||
|
_currentConnectivityResult == ConnectivityResult.none) {
|
|||
|
fAliplayer.play();
|
|||
|
}
|
|||
|
setState(
|
|||
|
() {
|
|||
|
_isShowMobileNetWork = false;
|
|||
|
},
|
|||
|
);
|
|||
|
}
|
|||
|
_currentConnectivityResult = result;
|
|||
|
},
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
@override
|
|||
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
|||
|
super.didChangeAppLifecycleState(state);
|
|||
|
switch (state) {
|
|||
|
case AppLifecycleState.inactive:
|
|||
|
break;
|
|||
|
case AppLifecycleState.resumed:
|
|||
|
if (_mEnablePlayBack && GlobalSettings.mEnabletPictureInPicture) {
|
|||
|
FlutterAliPlayerFactory.hideFloatViewForAndroid();
|
|||
|
}
|
|||
|
setState(() {});
|
|||
|
_setNetworkChangedListener();
|
|||
|
break;
|
|||
|
case AppLifecycleState.paused:
|
|||
|
if (!_mEnablePlayBack) {
|
|||
|
fAliplayer.pause();
|
|||
|
}
|
|||
|
if (_mEnablePlayBack && GlobalSettings.mEnabletPictureInPicture) {
|
|||
|
FlutterAliPlayerFactory.showFloatViewForAndroid(aliPlayerViewId);
|
|||
|
}
|
|||
|
if (_networkSubscription != null) {
|
|||
|
_networkSubscription.cancel();
|
|||
|
}
|
|||
|
break;
|
|||
|
case AppLifecycleState.detached:
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
@override
|
|||
|
void dispose() {
|
|||
|
SystemChrome.setPreferredOrientations(
|
|||
|
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
|
|||
|
if (Platform.isIOS) {
|
|||
|
FlutterAliplayer.setAudioSessionTypeForIOS(
|
|||
|
AliPlayerAudioSesstionType.sdkDefault);
|
|||
|
}
|
|||
|
|
|||
|
fAliplayer.stop();
|
|||
|
fAliplayer.destroy();
|
|||
|
super.dispose();
|
|||
|
WidgetsBinding.instance.removeObserver(this);
|
|||
|
if (_networkSubscription != null) {
|
|||
|
_networkSubscription.cancel();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
@override
|
|||
|
Widget build(BuildContext context) {
|
|||
|
var x = 0.0;
|
|||
|
var y = 0.0;
|
|||
|
Orientation orientation = MediaQuery.of(context).orientation;
|
|||
|
var width = MediaQuery.of(context).size.width;
|
|||
|
|
|||
|
var height;
|
|||
|
if (orientation == Orientation.portrait) {
|
|||
|
height = width * 9.0 / 16.0;
|
|||
|
} else {
|
|||
|
height = MediaQuery.of(context).size.height;
|
|||
|
}
|
|||
|
|
|||
|
AliPlayerView aliPlayerView = AliPlayerView(
|
|||
|
onCreated: onViewPlayerCreated,
|
|||
|
x: x,
|
|||
|
y: y,
|
|||
|
width: width,
|
|||
|
height: height,
|
|||
|
aliPlayerViewType: AliPlayerViewTypeForAndroid.surfaceview,
|
|||
|
);
|
|||
|
|
|||
|
return OrientationBuilder(
|
|||
|
builder: (BuildContext context, Orientation orientation) {
|
|||
|
return Scaffold(
|
|||
|
appBar: _buildAppBar(orientation),
|
|||
|
body: Column(
|
|||
|
children: [
|
|||
|
Stack(
|
|||
|
children: [
|
|||
|
Container(
|
|||
|
color: Colors.black,
|
|||
|
child: aliPlayerView,
|
|||
|
width: width,
|
|||
|
height: height),
|
|||
|
Container(
|
|||
|
width: width,
|
|||
|
height: height,
|
|||
|
// padding: EdgeInsets.only(bottom: 25.0),
|
|||
|
child: Offstage(
|
|||
|
offstage: _isLock,
|
|||
|
child: _buildContentWidget(orientation),
|
|||
|
),
|
|||
|
),
|
|||
|
_buildProgressBar(width, height),
|
|||
|
_buildTipsWidget(width, height),
|
|||
|
_buildThumbnail(width, height),
|
|||
|
_buildNetWorkTipsWidget(width, height),
|
|||
|
Align(
|
|||
|
alignment: Alignment.topCenter,
|
|||
|
child: Text(
|
|||
|
extSubTitleText,
|
|||
|
style: TextStyle(color: Colors.red),
|
|||
|
),
|
|||
|
),
|
|||
|
Positioned(
|
|||
|
left: 30,
|
|||
|
top: height / 2,
|
|||
|
child: Offstage(
|
|||
|
offstage: orientation == Orientation.portrait,
|
|||
|
child: InkWell(
|
|||
|
onTap: () {
|
|||
|
setState(
|
|||
|
() {
|
|||
|
_isLock = !_isLock;
|
|||
|
},
|
|||
|
);
|
|||
|
},
|
|||
|
child: Container(
|
|||
|
width: 40,
|
|||
|
height: 40,
|
|||
|
decoration: BoxDecoration(
|
|||
|
color: Colors.black.withAlpha(150),
|
|||
|
borderRadius: BorderRadius.circular(20),
|
|||
|
),
|
|||
|
child: Icon(
|
|||
|
_isLock ? Icons.lock : Icons.lock_open,
|
|||
|
color: Colors.white,
|
|||
|
),
|
|||
|
),
|
|||
|
),
|
|||
|
),
|
|||
|
),
|
|||
|
_buildCoverImg(),
|
|||
|
_buildMarqueeView(),
|
|||
|
],
|
|||
|
),
|
|||
|
_buildControlBtns(orientation),
|
|||
|
_buildFragmentPage(orientation),
|
|||
|
],
|
|||
|
),
|
|||
|
bottomNavigationBar: _buildBottomNavigationBar(orientation),
|
|||
|
);
|
|||
|
},
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
void onViewPlayerCreated(viewId) async {
|
|||
|
this.aliPlayerViewId = viewId;
|
|||
|
this.fAliplayer.setPlayerView(viewId);
|
|||
|
_generatePlayConfigGen();
|
|||
|
switch (_playMode) {
|
|||
|
case ModeType.URL:
|
|||
|
this.fAliplayer.setUrl(_dataSourceMap[DataSourceRelated.URL_KEY]);
|
|||
|
break;
|
|||
|
case ModeType.STS:
|
|||
|
FlutterAliplayer.generatePlayerConfig().then((value) {
|
|||
|
this.fAliplayer.setVidSts(
|
|||
|
vid: _dataSourceMap[DataSourceRelated.VID_KEY],
|
|||
|
region: _dataSourceMap[DataSourceRelated.REGION_KEY],
|
|||
|
accessKeyId: _dataSourceMap[DataSourceRelated.ACCESSKEYID_KEY],
|
|||
|
accessKeySecret:
|
|||
|
_dataSourceMap[DataSourceRelated.ACCESSKEYSECRET_KEY],
|
|||
|
securityToken:
|
|||
|
_dataSourceMap[DataSourceRelated.SECURITYTOKEN_KEY],
|
|||
|
definitionList: _dataSourceMap[DataSourceRelated.DEFINITION_LIST],
|
|||
|
playConfig: value);
|
|||
|
});
|
|||
|
|
|||
|
break;
|
|||
|
case ModeType.AUTH:
|
|||
|
FlutterAliplayer.generatePlayerConfig().then((value) {
|
|||
|
this.fAliplayer.setVidAuth(
|
|||
|
vid: _dataSourceMap[DataSourceRelated.VID_KEY],
|
|||
|
region: _dataSourceMap[DataSourceRelated.REGION_KEY],
|
|||
|
playAuth: _dataSourceMap[DataSourceRelated.PLAYAUTH_KEY],
|
|||
|
definitionList: _dataSourceMap[DataSourceRelated.DEFINITION_LIST],
|
|||
|
playConfig: value);
|
|||
|
});
|
|||
|
break;
|
|||
|
case ModeType.MPS:
|
|||
|
this.fAliplayer.setVidMps(_dataSourceMap);
|
|||
|
break;
|
|||
|
default:
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
_buildAppBar(Orientation orientation) {
|
|||
|
if (orientation == Orientation.portrait) {
|
|||
|
return AppBar(
|
|||
|
title: const Text('Plugin for aliplayer'),
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// MARK: 私有方法
|
|||
|
_buildControlBtns(Orientation orientation) {
|
|||
|
return Offstage(
|
|||
|
offstage: orientation == Orientation.landscape,
|
|||
|
child: Padding(
|
|||
|
padding: const EdgeInsets.only(top: 16),
|
|||
|
child: Row(
|
|||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|||
|
children: [
|
|||
|
InkWell(
|
|||
|
child: Text('准备'),
|
|||
|
onTap: () {
|
|||
|
_showTipsWidget = false;
|
|||
|
_showLoading = false;
|
|||
|
trackFragmentKey.currentState.prepared();
|
|||
|
setState(() {});
|
|||
|
fAliplayer.prepare();
|
|||
|
},
|
|||
|
),
|
|||
|
InkWell(
|
|||
|
child: Text('播放'),
|
|||
|
onTap: () {
|
|||
|
fAliplayer.play();
|
|||
|
},
|
|||
|
),
|
|||
|
InkWell(
|
|||
|
child: Text('停止'),
|
|||
|
onTap: () {
|
|||
|
fAliplayer.stop();
|
|||
|
},
|
|||
|
),
|
|||
|
InkWell(
|
|||
|
child: Text('暂停'),
|
|||
|
onTap: () {
|
|||
|
fAliplayer.pause();
|
|||
|
},
|
|||
|
),
|
|||
|
InkWell(
|
|||
|
child: Text('截图'),
|
|||
|
onTap: () {
|
|||
|
if (Platform.isIOS) {
|
|||
|
fAliplayer.snapshot(
|
|||
|
DateTime.now().millisecondsSinceEpoch.toString() +
|
|||
|
".png");
|
|||
|
} else {
|
|||
|
fAliplayer.snapshot(_snapShotPath +
|
|||
|
"/snapshot_" +
|
|||
|
new DateTime.now().millisecondsSinceEpoch.toString() +
|
|||
|
".png");
|
|||
|
}
|
|||
|
},
|
|||
|
),
|
|||
|
],
|
|||
|
),
|
|||
|
),
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
_buildFragmentPage(Orientation orientation) {
|
|||
|
return Expanded(
|
|||
|
child: Offstage(
|
|||
|
offstage: orientation == Orientation.landscape,
|
|||
|
child: IndexedStack(index: bottomIndex, children: mFramePage),
|
|||
|
)); //mFramePage
|
|||
|
}
|
|||
|
|
|||
|
///缩略图
|
|||
|
_buildThumbnail(double width, double height) {
|
|||
|
if (_inSeek && _thumbnailSuccess) {
|
|||
|
return Container(
|
|||
|
alignment: Alignment.center,
|
|||
|
width: width,
|
|||
|
height: height,
|
|||
|
child: Wrap(
|
|||
|
direction: Axis.vertical,
|
|||
|
crossAxisAlignment: WrapCrossAlignment.center,
|
|||
|
children: [
|
|||
|
Text("${FormatterUtils.getTimeformatByMs(_currentPosition)}",
|
|||
|
style: TextStyle(color: Colors.white),
|
|||
|
textAlign: TextAlign.center),
|
|||
|
_imageProvider == null
|
|||
|
? Container()
|
|||
|
: Image(
|
|||
|
width: width / 2,
|
|||
|
height: height / 2,
|
|||
|
image: _imageProvider,
|
|||
|
),
|
|||
|
],
|
|||
|
),
|
|||
|
);
|
|||
|
} else {
|
|||
|
return Container();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
///提示Widget
|
|||
|
_buildTipsWidget(double width, double height) {
|
|||
|
if (_showTipsWidget) {
|
|||
|
return Container(
|
|||
|
alignment: Alignment.center,
|
|||
|
width: width,
|
|||
|
height: height,
|
|||
|
child: Column(
|
|||
|
mainAxisAlignment: MainAxisAlignment.center,
|
|||
|
children: [
|
|||
|
Text(_tipsContent,
|
|||
|
maxLines: 3,
|
|||
|
style: TextStyle(color: Colors.red),
|
|||
|
textAlign: TextAlign.center),
|
|||
|
SizedBox(
|
|||
|
height: 5.0,
|
|||
|
),
|
|||
|
OutlinedButton(
|
|||
|
style: OutlinedButton.styleFrom(
|
|||
|
shape: BeveledRectangleBorder(
|
|||
|
side: BorderSide(
|
|||
|
style: BorderStyle.solid,
|
|||
|
color: Colors.blue,
|
|||
|
width: 5,
|
|||
|
),
|
|||
|
borderRadius: BorderRadius.circular(5),
|
|||
|
),
|
|||
|
),
|
|||
|
child: Text(
|
|||
|
"Replay",
|
|||
|
style: TextStyle(color: Colors.white),
|
|||
|
),
|
|||
|
onPressed: () {
|
|||
|
setState(
|
|||
|
() {
|
|||
|
_showTipsWidget = false;
|
|||
|
},
|
|||
|
);
|
|||
|
fAliplayer.prepare();
|
|||
|
fAliplayer.play();
|
|||
|
},
|
|||
|
),
|
|||
|
],
|
|||
|
),
|
|||
|
);
|
|||
|
} else {
|
|||
|
return Container();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//网络提示Widget
|
|||
|
_buildNetWorkTipsWidget(double widgetWidth, double widgetHeight) {
|
|||
|
return Offstage(
|
|||
|
offstage: !_isShowMobileNetWork,
|
|||
|
child: Container(
|
|||
|
alignment: Alignment.center,
|
|||
|
width: widgetWidth,
|
|||
|
height: widgetHeight,
|
|||
|
child: Wrap(
|
|||
|
direction: Axis.vertical,
|
|||
|
alignment: WrapAlignment.center,
|
|||
|
crossAxisAlignment: WrapCrossAlignment.center,
|
|||
|
children: [
|
|||
|
Text("当前为移动网络",
|
|||
|
style: TextStyle(color: Colors.white),
|
|||
|
textAlign: TextAlign.center),
|
|||
|
SizedBox(
|
|||
|
height: 30.0,
|
|||
|
),
|
|||
|
Wrap(
|
|||
|
direction: Axis.horizontal,
|
|||
|
children: [
|
|||
|
OutlinedButton(
|
|||
|
style: OutlinedButton.styleFrom(
|
|||
|
shape: BeveledRectangleBorder(
|
|||
|
side: BorderSide(
|
|||
|
style: BorderStyle.solid,
|
|||
|
color: Colors.blue,
|
|||
|
width: 5,
|
|||
|
),
|
|||
|
borderRadius: BorderRadius.circular(5),
|
|||
|
),
|
|||
|
),
|
|||
|
child: Text("继续播放", style: TextStyle(color: Colors.white)),
|
|||
|
onPressed: () {
|
|||
|
setState(() {
|
|||
|
_isShowMobileNetWork = false;
|
|||
|
});
|
|||
|
fAliplayer.play();
|
|||
|
},
|
|||
|
),
|
|||
|
SizedBox(
|
|||
|
width: 10.0,
|
|||
|
),
|
|||
|
OutlinedButton(
|
|||
|
style: OutlinedButton.styleFrom(
|
|||
|
shape: BeveledRectangleBorder(
|
|||
|
side: BorderSide(
|
|||
|
style: BorderStyle.solid,
|
|||
|
color: Colors.blue,
|
|||
|
width: 5,
|
|||
|
),
|
|||
|
borderRadius: BorderRadius.circular(5),
|
|||
|
),
|
|||
|
),
|
|||
|
child: Text("退出播放", style: TextStyle(color: Colors.white)),
|
|||
|
onPressed: () {
|
|||
|
setState(
|
|||
|
() {
|
|||
|
_isShowMobileNetWork = false;
|
|||
|
Navigator.pop(context);
|
|||
|
},
|
|||
|
);
|
|||
|
},
|
|||
|
),
|
|||
|
],
|
|||
|
),
|
|||
|
],
|
|||
|
),
|
|||
|
),
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
///Loading
|
|||
|
_buildProgressBar(double width, double height) {
|
|||
|
if (_showLoading) {
|
|||
|
return Positioned(
|
|||
|
left: width / 2 - 20,
|
|||
|
top: height / 2 - 20,
|
|||
|
child: Column(
|
|||
|
children: [
|
|||
|
CircularProgressIndicator(
|
|||
|
backgroundColor: Colors.white,
|
|||
|
strokeWidth: 3.0,
|
|||
|
),
|
|||
|
SizedBox(
|
|||
|
height: 10.0,
|
|||
|
),
|
|||
|
Text(
|
|||
|
"$_loadingPercent%",
|
|||
|
style: TextStyle(color: Colors.white),
|
|||
|
),
|
|||
|
],
|
|||
|
),
|
|||
|
);
|
|||
|
} else {
|
|||
|
return SizedBox();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
///播放进度和buffer
|
|||
|
_buildContentWidget(Orientation orientation) {
|
|||
|
return SafeArea(
|
|||
|
child: Column(
|
|||
|
mainAxisAlignment: MainAxisAlignment.end,
|
|||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|||
|
children: [
|
|||
|
Padding(
|
|||
|
padding: EdgeInsets.only(left: 5.0),
|
|||
|
child: Text(
|
|||
|
"buffer : ${FormatterUtils.getTimeformatByMs(_bufferPosition)}",
|
|||
|
style: TextStyle(color: Colors.white, fontSize: 11),
|
|||
|
),
|
|||
|
),
|
|||
|
Row(
|
|||
|
children: [
|
|||
|
SizedBox(
|
|||
|
width: 5.0,
|
|||
|
),
|
|||
|
Text(
|
|||
|
"${FormatterUtils.getTimeformatByMs(_currentPositionText)} / ${FormatterUtils.getTimeformatByMs(_videoDuration)}",
|
|||
|
style: TextStyle(color: Colors.white, fontSize: 11),
|
|||
|
),
|
|||
|
Expanded(
|
|||
|
child: AliyunSlider(
|
|||
|
max: _videoDuration == 0 ? 1 : _videoDuration.toDouble(),
|
|||
|
min: 0,
|
|||
|
dotList: dotPositionList,
|
|||
|
bufferColor: Colors.white,
|
|||
|
bufferValue: _bufferPosition.toDouble(),
|
|||
|
value: _currentPosition.toDouble(),
|
|||
|
onChangeStart: (value) {
|
|||
|
_inSeek = true;
|
|||
|
_showLoading = false;
|
|||
|
setState(() {});
|
|||
|
},
|
|||
|
onChangeEnd: (value) {
|
|||
|
_inSeek = false;
|
|||
|
setState(
|
|||
|
() {
|
|||
|
if (_currentPlayerState == FlutterAvpdef.completion &&
|
|||
|
_showTipsWidget) {
|
|||
|
setState(
|
|||
|
() {
|
|||
|
_showTipsWidget = false;
|
|||
|
},
|
|||
|
);
|
|||
|
}
|
|||
|
},
|
|||
|
);
|
|||
|
fAliplayer.seekTo(
|
|||
|
value.ceil(),
|
|||
|
GlobalSettings.mEnableAccurateSeek
|
|||
|
? FlutterAvpdef.ACCURATE
|
|||
|
: FlutterAvpdef.INACCURATE);
|
|||
|
},
|
|||
|
onTapDot: (value) {
|
|||
|
if (_thumbnailSuccess) {
|
|||
|
fAliplayer.requestBitmapAtPosition(value.ceil());
|
|||
|
}
|
|||
|
setState(
|
|||
|
() async {
|
|||
|
_inSeek = true;
|
|||
|
await Future.delayed(
|
|||
|
const Duration(milliseconds: 1500));
|
|||
|
_inSeek = false;
|
|||
|
},
|
|||
|
);
|
|||
|
},
|
|||
|
onChanged: (value) {
|
|||
|
if (_thumbnailSuccess) {
|
|||
|
fAliplayer.requestBitmapAtPosition(value.ceil());
|
|||
|
}
|
|||
|
setState(
|
|||
|
() {
|
|||
|
_currentPosition = value.ceil();
|
|||
|
},
|
|||
|
);
|
|||
|
},
|
|||
|
),
|
|||
|
),
|
|||
|
IconButton(
|
|||
|
icon: Icon(
|
|||
|
orientation == Orientation.portrait
|
|||
|
? Icons.fullscreen
|
|||
|
: Icons.fullscreen_exit,
|
|||
|
color: Colors.white,
|
|||
|
),
|
|||
|
onPressed: () {
|
|||
|
if (orientation == Orientation.portrait) {
|
|||
|
SystemChrome.setPreferredOrientations(
|
|||
|
[
|
|||
|
DeviceOrientation.landscapeLeft,
|
|||
|
DeviceOrientation.landscapeRight
|
|||
|
],
|
|||
|
);
|
|||
|
} else {
|
|||
|
SystemChrome.setPreferredOrientations(
|
|||
|
[
|
|||
|
DeviceOrientation.portraitUp,
|
|||
|
DeviceOrientation.portraitDown
|
|||
|
],
|
|||
|
);
|
|||
|
}
|
|||
|
},
|
|||
|
),
|
|||
|
],
|
|||
|
),
|
|||
|
],
|
|||
|
),
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//底部tab
|
|||
|
_buildBottomNavigationBar(Orientation orientation) {
|
|||
|
if (orientation == Orientation.portrait) {
|
|||
|
return BottomNavigationBar(
|
|||
|
type: BottomNavigationBarType.fixed,
|
|||
|
items: [
|
|||
|
BottomNavigationBarItem(
|
|||
|
label: "options", icon: Icon(Icons.control_point)),
|
|||
|
BottomNavigationBarItem(
|
|||
|
label: "config", icon: Icon(Icons.control_point)),
|
|||
|
BottomNavigationBarItem(
|
|||
|
label: "filter", icon: Icon(Icons.control_point)),
|
|||
|
BottomNavigationBarItem(
|
|||
|
label: "cache", icon: Icon(Icons.control_point)),
|
|||
|
BottomNavigationBarItem(
|
|||
|
label: "track", icon: Icon(Icons.control_point)),
|
|||
|
],
|
|||
|
currentIndex: bottomIndex,
|
|||
|
onTap: (index) {
|
|||
|
if (index != bottomIndex) {
|
|||
|
setState(
|
|||
|
() {
|
|||
|
bottomIndex = index;
|
|||
|
},
|
|||
|
);
|
|||
|
}
|
|||
|
},
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
_buildCoverImg() {
|
|||
|
if (_showCoverImg) {
|
|||
|
return Image.asset("images/background_push.png");
|
|||
|
} else {
|
|||
|
return SizedBox();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
_buildMarqueeView() {
|
|||
|
return Container(
|
|||
|
height: 36,
|
|||
|
decoration: BoxDecoration(),
|
|||
|
child: Row(
|
|||
|
children: <Widget>[
|
|||
|
Container(
|
|||
|
decoration: const BoxDecoration(),
|
|||
|
),
|
|||
|
Expanded(
|
|||
|
child: MarqueeView(
|
|||
|
child: Text(
|
|||
|
"阿里云播放器",
|
|||
|
style: TextStyle(color: Colors.blue),
|
|||
|
),
|
|||
|
),
|
|||
|
),
|
|||
|
],
|
|||
|
),
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
_generatePlayConfigGen() {
|
|||
|
FlutterAliplayer.createVidPlayerConfigGenerator();
|
|||
|
FlutterAliplayer.setPreviewTime(0);
|
|||
|
}
|
|||
|
}
|