style: 改为ios 风格
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||
|
||||
import 'config/ice_servers.dart';
|
||||
@@ -16,12 +17,9 @@ class MyApp extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
return CupertinoApp(
|
||||
title: 'WebRTC 控制端',
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
|
||||
useMaterial3: true,
|
||||
),
|
||||
theme: const CupertinoThemeData(primaryColor: CupertinoColors.activeBlue),
|
||||
home: const ControllerHome(),
|
||||
);
|
||||
}
|
||||
@@ -35,17 +33,15 @@ class ControllerHome extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _ControllerHomeState extends State<ControllerHome> {
|
||||
final _serverUrlController =
|
||||
TextEditingController(text: kDefaultSignalServer);
|
||||
final _serverUrlController = TextEditingController(
|
||||
text: kDefaultSignalServer,
|
||||
);
|
||||
final _deviceIdController = TextEditingController();
|
||||
final _targetController = TextEditingController(text: '981964879');
|
||||
|
||||
RemoteController? _controller;
|
||||
RTCVideoRenderer? _renderer;
|
||||
|
||||
/// 用于在任意位置(含回调中)弹出提示。
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
bool _connected = false;
|
||||
String _status = '状态: 已停止';
|
||||
String _stats = '';
|
||||
@@ -76,6 +72,23 @@ class _ControllerHomeState extends State<ControllerHome> {
|
||||
|
||||
void _setStatus(String status) => setState(() => _status = status);
|
||||
|
||||
/// 以 iOS 风格弹窗提示用户(替代原 Material 的 SnackBar)。
|
||||
void _showAlert(String message) {
|
||||
if (!mounted) return;
|
||||
showCupertinoDialog<void>(
|
||||
context: context,
|
||||
builder: (ctx) => CupertinoAlertDialog(
|
||||
content: Text(message),
|
||||
actions: [
|
||||
CupertinoDialogAction(
|
||||
child: const Text('确定'),
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _connect() async {
|
||||
final serverUrl = _serverUrlController.text.trim();
|
||||
final deviceId = _deviceIdController.text.trim();
|
||||
@@ -132,43 +145,19 @@ class _ControllerHomeState extends State<ControllerHome> {
|
||||
|
||||
/// ICE 断开:提示用户并自动返回连接设置面板。
|
||||
Future<void> _onIceDisconnected(String message) async {
|
||||
final scaffoldCtx = _scaffoldKey.currentState?.context;
|
||||
if (mounted && scaffoldCtx != null) {
|
||||
ScaffoldMessenger.of(scaffoldCtx).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(message),
|
||||
duration: const Duration(seconds: 3),
|
||||
),
|
||||
);
|
||||
}
|
||||
_showAlert(message);
|
||||
await _disconnect();
|
||||
}
|
||||
|
||||
/// 目标被控端不在线:提示用户并复位到连接设置面板。
|
||||
Future<void> _onTargetOffline(String message) async {
|
||||
final scaffoldCtx = _scaffoldKey.currentState?.context;
|
||||
if (mounted && scaffoldCtx != null) {
|
||||
ScaffoldMessenger.of(scaffoldCtx).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(message),
|
||||
duration: const Duration(seconds: 3),
|
||||
),
|
||||
);
|
||||
}
|
||||
_showAlert(message);
|
||||
setState(() => _connected = false);
|
||||
}
|
||||
|
||||
/// 被控端拒绝连接请求:提示用户并复位到连接设置面板。
|
||||
Future<void> _onConnectionRejected(String message) async {
|
||||
final scaffoldCtx = _scaffoldKey.currentState?.context;
|
||||
if (mounted && scaffoldCtx != null) {
|
||||
ScaffoldMessenger.of(scaffoldCtx).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(message),
|
||||
duration: const Duration(seconds: 3),
|
||||
),
|
||||
);
|
||||
}
|
||||
_showAlert(message);
|
||||
setState(() => _connected = false);
|
||||
}
|
||||
|
||||
@@ -186,15 +175,21 @@ class _ControllerHomeState extends State<ControllerHome> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
key: _scaffoldKey,
|
||||
appBar: AppBar(title: const Text('WebRTC 控制端')),
|
||||
body: _connected ? _buildControlPanel() : _buildSetupPanel(),
|
||||
return CupertinoPageScaffold(
|
||||
// 控制模式(已连接)下隐藏导航栏,避免其半透明浮层遮挡顶部的
|
||||
// 状态/统计信息浮层;连接设置面板再显示标题栏。
|
||||
navigationBar: _connected
|
||||
? null
|
||||
: const CupertinoNavigationBar(
|
||||
middle: Text('WebRTC 控制端'),
|
||||
),
|
||||
child: _connected ? _buildControlPanel() : _buildSetupPanel(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSetupPanel() {
|
||||
return SingleChildScrollView(
|
||||
return SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -205,23 +200,27 @@ class _ControllerHomeState extends State<ControllerHome> {
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const Text('信令服务器地址:', style: TextStyle(fontSize: 14)),
|
||||
TextField(
|
||||
const SizedBox(height: 8),
|
||||
CupertinoTextField(
|
||||
controller: _serverUrlController,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'ws://175.178.213.60:8088/ws/signal',
|
||||
),
|
||||
placeholder: 'ws://175.178.213.60:8088/ws/signal',
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 12),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text('本机设备ID:', style: TextStyle(fontSize: 14)),
|
||||
TextField(
|
||||
const SizedBox(height: 8),
|
||||
CupertinoTextField(
|
||||
controller: _deviceIdController,
|
||||
decoration: const InputDecoration(hintText: '设备ID'),
|
||||
placeholder: '设备ID',
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 12),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text('目标被控设备ID:', style: TextStyle(fontSize: 14)),
|
||||
TextField(
|
||||
const SizedBox(height: 8),
|
||||
CupertinoTextField(
|
||||
controller: _targetController,
|
||||
decoration: const InputDecoration(hintText: '被控端设备ID'),
|
||||
placeholder: '被控端设备ID',
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 12),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
@@ -231,18 +230,26 @@ class _ControllerHomeState extends State<ControllerHome> {
|
||||
const SizedBox(height: 24),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
child: CupertinoButton.filled(
|
||||
onPressed: _connect,
|
||||
child: const Text('连接被控设备'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildControlPanel() {
|
||||
return Stack(
|
||||
return SafeArea(
|
||||
// 仅保留顶部安全区(避开系统状态栏),底部/左右保持全屏,
|
||||
// 以便右下角的断开按钮贴近屏幕边缘。
|
||||
top: true,
|
||||
bottom: false,
|
||||
left: false,
|
||||
right: false,
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(color: Colors.black),
|
||||
if (_renderer != null)
|
||||
@@ -263,10 +270,12 @@ class _ControllerHomeState extends State<ControllerHome> {
|
||||
onTouch: (x, y) {},
|
||||
onSwipe: (x1, y1, x2, y2, d) {},
|
||||
onLongPress: (x, y) {},
|
||||
onKey: (k, a) => _controller
|
||||
?.sendControlCommand(ControlCommands.key(k, a)),
|
||||
onMotionEvent: (a, x, y) => _controller
|
||||
?.sendControlCommand(ControlCommands.motionEvent(a, x, y)),
|
||||
onKey: (k, a) => _controller?.sendControlCommand(
|
||||
ControlCommands.key(k, a),
|
||||
),
|
||||
onMotionEvent: (a, x, y) => _controller?.sendControlCommand(
|
||||
ControlCommands.motionEvent(a, x, y),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -281,14 +290,10 @@ class _ControllerHomeState extends State<ControllerHome> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
_status,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
Text(_status, style: const TextStyle(color: Colors.white)),
|
||||
Text(
|
||||
_stats,
|
||||
style:
|
||||
const TextStyle(color: Colors.white, fontSize: 12),
|
||||
style: const TextStyle(color: Colors.white, fontSize: 12),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -297,13 +302,26 @@ class _ControllerHomeState extends State<ControllerHome> {
|
||||
Positioned(
|
||||
bottom: 16,
|
||||
right: 16,
|
||||
child: FloatingActionButton(
|
||||
child: CupertinoButton(
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: _disconnect,
|
||||
tooltip: '断开连接',
|
||||
child: const Icon(Icons.close),
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user