feat: 简单实现投屏
This commit is contained in:
111
lib/pages/dlna/index.dart
Normal file
111
lib/pages/dlna/index.dart
Normal file
@ -0,0 +1,111 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:dlna_dart/dlna.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LiveDlnaPage extends StatefulWidget {
|
||||
final String datasource;
|
||||
|
||||
const LiveDlnaPage({Key? key, required this.datasource}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<LiveDlnaPage> createState() => _LiveDlnaPageState();
|
||||
}
|
||||
|
||||
class _LiveDlnaPageState extends State<LiveDlnaPage> {
|
||||
final Map<String, DLNADevice> _deviceList = {};
|
||||
final DLNAManager searcher = DLNAManager();
|
||||
late final Timer stopSearchTimer;
|
||||
String selectDeviceKey = '';
|
||||
bool isSearching = true;
|
||||
|
||||
DLNADevice? get device => _deviceList[selectDeviceKey];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
stopSearchTimer = Timer(const Duration(seconds: 20), () {
|
||||
setState(() => isSearching = false);
|
||||
searcher.stop();
|
||||
});
|
||||
searcher.stop();
|
||||
startSearch();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
searcher.stop();
|
||||
stopSearchTimer.cancel();
|
||||
}
|
||||
|
||||
void startSearch() async {
|
||||
// clear old devices
|
||||
isSearching = true;
|
||||
selectDeviceKey = '';
|
||||
_deviceList.clear();
|
||||
setState(() {});
|
||||
// start search server
|
||||
final m = await searcher.start();
|
||||
m.devices.stream.listen((deviceList) {
|
||||
deviceList.forEach((key, value) {
|
||||
_deviceList[key] = value;
|
||||
});
|
||||
setState(() {});
|
||||
});
|
||||
// close the server, the closed server can be start by call searcher.start()
|
||||
}
|
||||
|
||||
void selectDevice(String key) {
|
||||
if (selectDeviceKey.isNotEmpty) device?.pause();
|
||||
|
||||
selectDeviceKey = key;
|
||||
device?.setUrl(widget.datasource);
|
||||
device?.play();
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget cur;
|
||||
if (isSearching && _deviceList.isEmpty) {
|
||||
cur = const Center(child: CircularProgressIndicator());
|
||||
} else if (_deviceList.isEmpty) {
|
||||
cur = Center(
|
||||
child: Text(
|
||||
'没有找到设备',
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
cur = ListView(
|
||||
children: _deviceList.keys
|
||||
.map<Widget>((key) => ListTile(
|
||||
contentPadding: const EdgeInsets.all(2),
|
||||
title: Text(_deviceList[key]!.info.friendlyName),
|
||||
subtitle: Text(key),
|
||||
onTap: () => selectDevice(key),
|
||||
))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
return AlertDialog(
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('查找设备'),
|
||||
IconButton(
|
||||
onPressed: startSearch,
|
||||
icon: const Icon(Icons.refresh_rounded),
|
||||
),
|
||||
],
|
||||
),
|
||||
content: SizedBox(
|
||||
height: 200,
|
||||
width: 200,
|
||||
child: cur,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ import 'package:ns_danmaku/ns_danmaku.dart';
|
||||
import 'package:pilipala/http/user.dart';
|
||||
import 'package:pilipala/models/video/play/quality.dart';
|
||||
import 'package:pilipala/models/video/play/url.dart';
|
||||
import 'package:pilipala/pages/dlna/index.dart';
|
||||
import 'package:pilipala/pages/video/detail/index.dart';
|
||||
import 'package:pilipala/pages/video/detail/introduction/widgets/menu_row.dart';
|
||||
import 'package:pilipala/plugin/pl_player/index.dart';
|
||||
@ -1209,6 +1210,22 @@ class _HeaderControlState extends State<HeaderControl> {
|
||||
// ),
|
||||
// fuc: () => _.screenshot(),
|
||||
// ),
|
||||
ComBtn(
|
||||
icon: const Icon(
|
||||
Icons.cast,
|
||||
size: 19,
|
||||
color: Colors.white,
|
||||
),
|
||||
fuc: () async {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return LiveDlnaPage(
|
||||
datasource: widget.videoDetailCtr!.videoUrl);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
if (isFullScreen.value) ...[
|
||||
SizedBox(
|
||||
width: 56,
|
||||
|
@ -409,6 +409,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
dlna_dart:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dlna_dart
|
||||
sha256: ae07c1c53077bbf58756fa589f936968719b0085441981d33e74f82f89d1d281
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.0.8"
|
||||
dynamic_color:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -144,6 +144,8 @@ dependencies:
|
||||
disable_battery_optimization: ^1.1.1
|
||||
# 展开/收起
|
||||
expandable: ^5.0.1
|
||||
# 投屏
|
||||
dlna_dart: ^0.0.8
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Reference in New Issue
Block a user