1.开始录制、结束录制增加

2. 增加电量检测、内存检查,是否低于 10%
This commit is contained in:
2026-06-04 18:25:58 +08:00
parent 124b4c1882
commit f49d208042
9 changed files with 267 additions and 0 deletions

View File

@@ -1,6 +1,7 @@
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:recording_tool/core/platform/device_health_snapshot.dart';
class AppPackageInfo {
const AppPackageInfo({
@@ -75,4 +76,11 @@ class AppPlatformInfo {
);
return AppDeviceInfo.fromMap(result ?? const <Object?, Object?>{});
}
static Future<DeviceHealthSnapshot> deviceHealth() async {
final result = await _channel.invokeMapMethod<Object?, Object?>(
'deviceHealth',
);
return DeviceHealthSnapshot.fromMap(result ?? const <Object?, Object?>{});
}
}

View File

@@ -0,0 +1,25 @@
import 'package:recording_tool/core/platform/device_health_snapshot.dart';
class DeviceHealthChecker {
DeviceHealthChecker._();
static const int thresholdPercent = 10;
static const String lowBatteryMessage = '电量低于10%,请充电';
static const String lowStorageMessage = '内存低于10%,请清理内存';
static List<String> warningLines(DeviceHealthSnapshot snapshot) {
final lines = <String>[];
final battery = snapshot.batteryLevelPercent;
if (battery != null && battery < thresholdPercent) {
lines.add(lowBatteryMessage);
}
if (snapshot.storageAvailablePercent < thresholdPercent) {
lines.add(lowStorageMessage);
}
return lines;
}
}

View File

@@ -0,0 +1,30 @@
class DeviceHealthSnapshot {
const DeviceHealthSnapshot({
this.batteryLevelPercent,
required this.storageAvailablePercent,
});
factory DeviceHealthSnapshot.fromMap(Map<Object?, Object?> map) {
final batteryRaw = map['batteryLevelPercent'];
int? batteryLevelPercent;
if (batteryRaw is int) {
batteryLevelPercent = batteryRaw;
} else if (batteryRaw is num) {
batteryLevelPercent = batteryRaw.round();
}
final storageRaw = map['storageAvailablePercent'];
final storageAvailablePercent = switch (storageRaw) {
final num value => value.toDouble(),
_ => 100.0,
};
return DeviceHealthSnapshot(
batteryLevelPercent: batteryLevelPercent,
storageAvailablePercent: storageAvailablePercent,
);
}
final int? batteryLevelPercent;
final double storageAvailablePercent;
}

View File

@@ -6,6 +6,8 @@ import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:recording_tool/core/platform/app_platform_info.dart';
import 'package:recording_tool/core/platform/device_health_checker.dart';
import 'package:recording_tool/core/utils/date_time_formatter.dart';
import 'package:recording_tool/features/recording/model/model_recording.dart';
import 'package:recording_tool/features/recording/recording_display_name.dart';
@@ -33,7 +35,20 @@ class _RecordingPageState extends ConsumerState<RecordingPage> {
WidgetsBinding.instance.addPostFrameCallback((_) => _bootstrap());
}
Future<void> _checkAndShowDeviceHealthAlerts() async {
final snapshot = await AppPlatformInfo.deviceHealth();
if (!mounted) return;
final lines = DeviceHealthChecker.warningLines(snapshot);
if (lines.isEmpty) return;
await AppDialog.deviceHealthAlert(context, lines: lines);
}
Future<void> _bootstrap() async {
await _checkAndShowDeviceHealthAlerts();
if (!mounted) return;
final clipboardResult = await ref
.read(recordingViewModelProvider.notifier)
.getClipboardContent();
@@ -95,6 +110,8 @@ class _RecordingPageState extends ConsumerState<RecordingPage> {
await _showNoPlayerInfoDialog();
return;
}
await _checkAndShowDeviceHealthAlerts();
if (!mounted) return;
await ref.read(recordingSessionControllerProvider.notifier).startRecording();
}

View File

@@ -4,6 +4,7 @@ import 'dart:io';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:recording_tool/core/permission/permission_service.dart';
import 'package:recording_tool/core/utils/rate_limiter.dart';
import 'package:recording_tool/features/recording/recording_display_name.dart';
import 'package:recording_tool/features/recording/recording_platform.dart';
import 'package:recording_tool/features/recording/view-model/view_model_recording.dart';
@@ -95,7 +96,12 @@ final recordingSessionControllerProvider =
);
class RecordingSessionController extends Notifier<RecordingSessionState> {
static const Duration _recordingActionInterval = Duration(milliseconds: 300);
static const Object _startRecordingThrottleKey = 'recording.session.start';
static const Object _stopRecordingThrottleKey = 'recording.session.stop';
StreamSubscription<RecordingStatus>? _statusSubscription;
final _rateLimit = RateLimitHub();
@override
RecordingSessionState build() {
@@ -207,7 +213,21 @@ class RecordingSessionController extends Notifier<RecordingSessionState> {
return _galleryPermissions().isEmpty;
}
bool _tryAcquireRecordingAction(Object key) {
var executed = false;
_rateLimit.throttle<void>(
key: key,
value: null,
duration: _recordingActionInterval,
options: const ThrottleOptions(leading: true, trailing: false),
onCallback: (_) => executed = true,
);
return executed;
}
Future<void> startRecording({bool enableDoNotDisturb = true}) async {
if (!_tryAcquireRecordingAction(_startRecordingThrottleKey)) return;
if (!state.isPreviewReady ||
state.isRecording ||
state.isStartingRecording) {
@@ -239,6 +259,8 @@ class RecordingSessionController extends Notifier<RecordingSessionState> {
}
Future<void> stopRecording() async {
if (!_tryAcquireRecordingAction(_stopRecordingThrottleKey)) return;
if (!state.isRecording) return;
try {
@@ -302,6 +324,7 @@ class RecordingSessionController extends Notifier<RecordingSessionState> {
}
Future<void> _dispose() async {
_rateLimit.clear();
await _statusSubscription?.cancel();
}
}

View File

@@ -30,4 +30,24 @@ class AppDialog {
},
);
}
static Future<void> deviceHealthAlert(
BuildContext context, {
required List<String> lines,
}) {
return showDialog<void>(
context: context,
builder: (dialogContext) {
return AlertDialog(
content: Text(lines.join('\n')),
actions: [
TextButton(
onPressed: () => Navigator.of(dialogContext).pop(),
child: const Text('确定'),
),
],
);
},
);
}
}