添加设备代码信息到 Android 和 iOS 平台信息;更新 Auth 页面以使用新的 TextEditingController 管理输入;重构推流测试页面以支持动态 RTMP URL 解析;删除不再需要的测试文件。

This commit is contained in:
2026-07-09 12:26:41 +08:00
parent 98a3381716
commit a1f6ea14cf
29 changed files with 267 additions and 1797 deletions
+16
View File
@@ -0,0 +1,16 @@
/// 获取 TOKEN 响应模型
class GetTokenResModel {
GetTokenResModel({required this.deviceAccessToken});
final String deviceAccessToken;
factory GetTokenResModel.fromJson(Map<String, dynamic> json) {
return GetTokenResModel(
deviceAccessToken: (json['deviceAccessToken'] ?? '').toString(),
);
}
Map<String, dynamic> toJson() {
return {'deviceAccessToken': deviceAccessToken};
}
}
+37 -6
View File
@@ -1,19 +1,37 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:recording_tool/app/router/app_navigator.dart';
import 'package:recording_tool/features/auth/view_model_auth/view_model_auth.dart';
import 'package:recording_tool/features/scan_qrcode/pages/page_scan_qrcode.dart';
import 'package:recording_tool/shared/widgets/widgets.dart';
class AuthPageWidget extends StatefulWidget {
class AuthPageWidget extends ConsumerStatefulWidget {
const AuthPageWidget({super.key});
@override
State<AuthPageWidget> createState() => _AuthPageWidgetState();
ConsumerState<AuthPageWidget> createState() => _AuthPageWidgetState();
}
class _AuthPageWidgetState extends State<AuthPageWidget> {
class _AuthPageWidgetState extends ConsumerState<AuthPageWidget> {
late TextEditingController? _controller;
@override
void initState() {
super.initState();
_controller = TextEditingController();
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final authState = ref.watch(authProvider);
return Center(
child: Column(
children: [
@@ -26,7 +44,7 @@ class _AuthPageWidgetState extends State<AuthPageWidget> {
SizedBox(
width: 280.w,
height: 80.h,
child: AppTextField(initialValue: 'hhh'),
child: AppTextField(initialValue: 'hhh', controller: _controller),
),
SizedBox(height: 20.h),
SizedBox(
@@ -34,8 +52,20 @@ class _AuthPageWidgetState extends State<AuthPageWidget> {
height: 80.h,
child: AppButton(
label: '确定',
onPressed: () {
AppNavigator.push(const ScanQrCodePage());
onPressed: () async {
final code = _controller?.text;
final success = await ref
.read(authProvider.notifier)
.auth(code ?? '');
if (!mounted) return;
if (success) {
AppNavigator.push(const ScanQrCodePage());
return;
}
final message = ref.read(authProvider).errorMessage;
if (message != null && message.isNotEmpty) {
AppToast.show(message);
}
// return;
// AppNavigator.push(
// const WebviewPage(
@@ -45,6 +75,7 @@ class _AuthPageWidgetState extends State<AuthPageWidget> {
// );
},
variant: AppButtonVariant.secondary,
isLoading: authState.isLoading,
),
),
],
+31
View File
@@ -0,0 +1,31 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:recording_tool/app/config/api_common.dart';
import 'package:recording_tool/core/cache/app_storage.dart';
import 'package:recording_tool/core/cache/storage_keys.dart';
import 'package:recording_tool/core/network/providers/dio_providers.dart';
import 'package:recording_tool/core/utils/device_utils.dart';
import 'package:recording_tool/features/auth/model/model_auth.dart';
class AuthServer {
/// [passCode] 口令码
static Future<GetTokenResModel> login(String passCode, Ref ref) async {
final deviceCode = await DeviceUtils.deviceCode();
if (deviceCode.isEmpty) {
throw const FormatException('无法获取设备标识');
}
final apiClient = ref.read(apiClientProvider);
final data = await apiClient.post<GetTokenResModel>(
AuthApi.getToken.path,
data: {'deviceCode': deviceCode, 'passCode': passCode},
parser: (json) => GetTokenResModel.fromJson(json as Map<String, dynamic>),
);
if (data.deviceAccessToken.isEmpty) {
throw const FormatException('登录响应缺少 TOKEN');
}
await AppStorage.setString(StorageKeys.authToken, data.deviceAccessToken);
return data;
}
}
+13
View File
@@ -0,0 +1,13 @@
class AuthState {
const AuthState({this.isLoading = false, this.errorMessage});
final bool isLoading;
final String? errorMessage;
AuthState copyWith({bool? isLoading, String? errorMessage}) {
return AuthState(
isLoading: isLoading ?? this.isLoading,
errorMessage: errorMessage,
);
}
}
@@ -0,0 +1,39 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_riverpod/legacy.dart';
import 'package:recording_tool/core/network/api_exception.dart';
import 'package:recording_tool/features/auth/server/server_auth.dart';
import 'package:recording_tool/features/auth/state/state_auth.dart';
final authProvider = StateNotifierProvider<AuthViewModel, AuthState>((ref) {
return AuthViewModel(ref);
});
class AuthViewModel extends StateNotifier<AuthState> {
AuthViewModel(this._ref) : super(const AuthState());
final Ref _ref;
/// 鉴权获取 token
Future<bool> auth(String code) async {
final passCode = code.trim();
if (passCode.isEmpty) {
state = const AuthState(errorMessage: '请输入执裁口令');
return false;
}
state = const AuthState(isLoading: true);
try {
await AuthServer.login(passCode, _ref);
state = const AuthState();
return true;
} on FormatException catch (error) {
state = AuthState(errorMessage: error.message);
return false;
} on ApiException catch (error) {
state = AuthState(errorMessage: error.message);
return false;
} catch (_) {
state = const AuthState(errorMessage: '认证失败,请重试');
return false;
}
}
}