feat: Windows增加分辨率适应,切换分辨率按钮修改

This commit is contained in:
2026-07-23 09:26:13 +08:00
parent 7de30eefa4
commit a1c29246d7
4 changed files with 218 additions and 44 deletions

View File

@@ -1,5 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'config/ice_servers.dart';
@@ -33,6 +35,12 @@ class ControllerHome extends StatefulWidget {
}
class _ControllerHomeState extends State<ControllerHome> {
/// 与 Windows 原生窗口通信的通道(用于按视频比例调整窗口高度)。
static const MethodChannel _windowChannel = MethodChannel('app/window');
/// 记录上一次已应用的视频宽高比,避免重复调整窗口。
double _lastResizedAspect = 0;
final _serverUrlController = TextEditingController(
text: kDefaultSignalServer,
);
@@ -217,10 +225,22 @@ class _ControllerHomeState extends State<ControllerHome> {
final w = _renderer?.value.width ?? 0;
final h = _renderer?.value.height ?? 0;
if (w > 0 && h > 0 && mounted) {
setState(() => _videoAspect = w / h);
final aspect = w / h;
setState(() => _videoAspect = aspect);
_resizeWindowToAspect(aspect);
}
}
/// Windows 端:保持窗口宽度不变,按视频宽高比调整窗口高度;
/// 若高度超出屏幕,由原生端改为合适的窗口大小。
void _resizeWindowToAspect(double aspect) {
if (kIsWeb || defaultTargetPlatform != TargetPlatform.windows) return;
if (aspect <= 0) return;
if ((aspect - _lastResizedAspect).abs() < 0.001) return;
_lastResizedAspect = aspect;
_windowChannel.invokeMethod('resizeToVideoAspect', aspect);
}
/// ICE 断开:提示用户并自动返回连接设置面板。
Future<void> _onIceDisconnected(String message) async {
_showAlert(message);
@@ -239,10 +259,52 @@ class _ControllerHomeState extends State<ControllerHome> {
setState(() => _connected = false);
}
/// 弹出分辨率选择菜单iOS 风格 ActionSheet
void _showResolutionMenu() {
showCupertinoModalPopup<void>(
context: context,
builder: (ctx) => CupertinoActionSheet(
title: const Text('切换分辨率'),
actions: [
for (int i = 0; i < _resolutionOptions.length; i++)
CupertinoActionSheetAction(
onPressed: () {
Navigator.of(ctx).pop();
setState(() => _selectedResolution = i);
final o = _resolutionOptions[i];
_controller?.sendResolutionChange(
o['width'] as int,
o['height'] as int,
o['fps'] as int,
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (i == _selectedResolution) ...[
const Icon(CupertinoIcons.check_mark,
size: 18, color: CupertinoColors.activeBlue),
const SizedBox(width: 8),
],
Text(_resolutionOptions[i]['label'] as String),
],
),
),
],
cancelButton: CupertinoActionSheetAction(
isDefaultAction: true,
onPressed: () => Navigator.of(ctx).pop(),
child: const Text('取消'),
),
),
);
}
Future<void> _disconnect() async {
await _controller?.disconnect();
_controller = null;
_renderer?.removeListener(_onRendererUpdate);
_lastResizedAspect = 0;
setState(() {
_connected = false;
_renderer = null;
@@ -319,6 +381,58 @@ class _ControllerHomeState extends State<ControllerHome> {
);
}
/// 右上角浮动顶部菜单栏:整合「分辨率切换」与「断开连接」。
Widget _buildTopMenuBar() {
return Container(
decoration: BoxDecoration(
color: Colors.black54,
borderRadius: BorderRadius.circular(22),
),
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
// 分辨率菜单按钮:显示当前分辨率标签
CupertinoButton(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
onPressed: _showResolutionMenu,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(CupertinoIcons.slider_horizontal_3,
color: CupertinoColors.white, size: 20),
const SizedBox(width: 6),
Text(
_resolutionOptions[_selectedResolution]['label'] as String,
style: const TextStyle(
color: CupertinoColors.white,
fontSize: 14,
),
),
],
),
),
// 分隔线
Container(
width: 1,
height: 22,
color: CupertinoColors.white.withValues(alpha: 0.3),
),
// 断开连接按钮
CupertinoButton(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
onPressed: _disconnect,
child: const Icon(
CupertinoIcons.xmark_circle_fill,
color: CupertinoColors.destructiveRed,
size: 24,
),
),
],
),
);
}
Widget _buildControlPanel() {
return SafeArea(
// 仅保留顶部安全区(避开系统状态栏),底部/左右保持全屏,
@@ -378,48 +492,9 @@ class _ControllerHomeState extends State<ControllerHome> {
),
),
Positioned(
bottom: 16,
right: 16,
child: CupertinoButton(
padding: EdgeInsets.zero,
onPressed: _disconnect,
child: Container(
width: 48,
height: 48,
decoration: BoxDecoration(
color: CupertinoColors.destructiveRed,
borderRadius: BorderRadius.circular(24),
),
alignment: Alignment.center,
child: const Icon(
CupertinoIcons.clear,
color: CupertinoColors.white,
),
),
),
),
Positioned(
bottom: 16,
left: 16,
child: CupertinoSegmentedControl<int>(
groupValue: _selectedResolution,
children: <int, Widget>{
for (int i = 0; i < _resolutionOptions.length; i++)
i: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
child: Text(_resolutionOptions[i]['label'] as String),
),
},
onValueChanged: (int idx) {
setState(() => _selectedResolution = idx);
final o = _resolutionOptions[idx];
_controller?.sendResolutionChange(
o['width'] as int,
o['height'] as int,
o['fps'] as int,
);
},
),
top: 8,
right: 8,
child: _buildTopMenuBar(),
),
],
),