283 lines
8.4 KiB
Dart
283 lines
8.4 KiB
Dart
import 'dart:io';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
<<<<<<< HEAD
|
|
import 'package:file_picker/file_picker.dart';
|
|
import '../models/saf_permission_state.dart';
|
|
|
|
/// 使用 file_picker 实现文件夹访问
|
|
=======
|
|
import 'package:flutter_saf/flutter_saf.dart';
|
|
import '../models/saf_permission_state.dart';
|
|
|
|
/// SAF 存储服务
|
|
/// 负责管理通过 SAF 授权的文件夹访问
|
|
>>>>>>> c5a85e05a3bb50cd4ea7de0da2db94c867eb7ddd
|
|
class SafStorageService {
|
|
static final SafStorageService _instance = SafStorageService._internal();
|
|
factory SafStorageService() => _instance;
|
|
SafStorageService._internal();
|
|
|
|
<<<<<<< HEAD
|
|
static const String _prefKeySafPath = 'saf_storage_path';
|
|
String? _cachedPath;
|
|
|
|
Future<void> init() async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
_cachedPath = prefs.getString(_prefKeySafPath);
|
|
if (kDebugMode) {
|
|
print('[SAF] 初始化,缓存路径: $_cachedPath');
|
|
}
|
|
}
|
|
|
|
Future<SafPermissionState> getPermissionState() async {
|
|
if (_cachedPath == null || _cachedPath!.isEmpty) {
|
|
return SafPermissionState.unauthorized;
|
|
}
|
|
try {
|
|
final dir = Directory(_cachedPath!);
|
|
if (!await dir.exists()) {
|
|
=======
|
|
static const String _prefKeySafUri = 'saf_storage_uri';
|
|
static const String _prefKeySafPermission = 'saf_permission_uri';
|
|
|
|
/// 存储的授权 URI
|
|
String? _cachedUriString;
|
|
|
|
/// 初始化,从 SharedPreferences 恢复授权状态
|
|
Future<void> init() async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
_cachedUriString = prefs.getString(_prefKeySafUri);
|
|
if (kDebugMode) {
|
|
print('[SAF] 初始化,缓存 URI: $_cachedUriString');
|
|
}
|
|
}
|
|
|
|
/// 获取当前授权状态
|
|
Future<SafPermissionState> getPermissionState() async {
|
|
if (_cachedUriString == null || _cachedUriString!.isEmpty) {
|
|
return SafPermissionState.unauthorized;
|
|
}
|
|
|
|
try {
|
|
final uri = Uri.parse(_cachedUriString!);
|
|
// 检查 Uri 是否仍然有效
|
|
final isValid = await FlutterSaf.isDirectory(uri);
|
|
if (!isValid) {
|
|
>>>>>>> c5a85e05a3bb50cd4ea7de0da2db94c867eb7ddd
|
|
_clearCache();
|
|
return SafPermissionState.expired;
|
|
}
|
|
return SafPermissionState.authorized;
|
|
} catch (e) {
|
|
_clearCache();
|
|
return SafPermissionState.expired;
|
|
}
|
|
}
|
|
|
|
<<<<<<< HEAD
|
|
Future<SafAuthorizationResult> requestPermission() async {
|
|
try {
|
|
// 使用 file_picker 选择文件夹
|
|
String? selectedPath = await FilePicker.platform.getDirectoryPath();
|
|
|
|
if (selectedPath == null || selectedPath.isEmpty) {
|
|
return SafAuthorizationResult.denied();
|
|
}
|
|
|
|
// 验证路径是否包含 mbattery_charger(可选,提高容错)
|
|
if (!selectedPath.contains('mbattery_charger')) {
|
|
return SafAuthorizationResult.error('请选择 mbattery_charger 文件夹');
|
|
}
|
|
|
|
_cachedPath = selectedPath;
|
|
await _savePath(selectedPath);
|
|
|
|
if (kDebugMode) {
|
|
print('[SAF] 授权成功,路径: $selectedPath');
|
|
}
|
|
|
|
return SafAuthorizationResult.success(selectedPath);
|
|
=======
|
|
/// 请求 SAF 授权(引导用户选择文件夹)
|
|
/// 返回授权结果
|
|
Future<SafAuthorizationResult> requestPermission() async {
|
|
try {
|
|
// 调用系统文件夹选择器
|
|
// 引导用户选择 /storage/emulated/0/mbattery_charger/
|
|
// 或者用户可以选择任何目录,但我们建议选择具体路径
|
|
final uri = await FlutterSaf.openDocumentTree();
|
|
|
|
if (uri == null) {
|
|
return SafAuthorizationResult.denied();
|
|
}
|
|
|
|
// 获取持久化 URI 权限
|
|
await FlutterSaf.takePersistableUriPermission(uri);
|
|
|
|
// 验证是否为目录
|
|
final isValid = await FlutterSaf.isDirectory(uri);
|
|
if (!isValid) {
|
|
return SafAuthorizationResult.error('选择的路径不是有效目录');
|
|
}
|
|
|
|
// 保存 URI
|
|
final uriString = uri.toString();
|
|
_cachedUriString = uriString;
|
|
await _saveUri(uriString);
|
|
|
|
if (kDebugMode) {
|
|
print('[SAF] 授权成功,URI: $uriString');
|
|
}
|
|
|
|
return SafAuthorizationResult.success(uriString);
|
|
>>>>>>> c5a85e05a3bb50cd4ea7de0da2db94c867eb7ddd
|
|
} catch (e) {
|
|
if (kDebugMode) {
|
|
print('[SAF] 授权失败: $e');
|
|
}
|
|
return SafAuthorizationResult.error('授权失败: $e');
|
|
}
|
|
}
|
|
|
|
<<<<<<< HEAD
|
|
Future<bool> logFileExists(String fileName) async {
|
|
final state = await getPermissionState();
|
|
if (state != SafPermissionState.authorized) return false;
|
|
try {
|
|
final file = File('${_cachedPath!}/$fileName');
|
|
return await file.exists();
|
|
=======
|
|
/// 检查指定日期的日志文件是否存在
|
|
Future<bool> logFileExists(String fileName) async {
|
|
final state = await getPermissionState();
|
|
if (state != SafPermissionState.authorized) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
final uri = Uri.parse(_cachedUriString!);
|
|
final fileUri = await FlutterSaf.getFile(uri, fileName);
|
|
return fileUri != null && await FlutterSaf.isFile(fileUri);
|
|
>>>>>>> c5a85e05a3bb50cd4ea7de0da2db94c867eb7ddd
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
<<<<<<< HEAD
|
|
Future<List<String>> readLogFile(String fileName) async {
|
|
final state = await getPermissionState();
|
|
if (state != SafPermissionState.authorized) return [];
|
|
try {
|
|
final file = File('${_cachedPath!}/$fileName');
|
|
if (!await file.exists()) return [];
|
|
return await file.readAsLines();
|
|
=======
|
|
/// 读取日志文件内容
|
|
/// 返回文件行列表,如果文件不存在或读取失败返回空列表
|
|
Future<List<String>> readLogFile(String fileName) async {
|
|
final state = await getPermissionState();
|
|
if (state != SafPermissionState.authorized) {
|
|
return [];
|
|
}
|
|
|
|
try {
|
|
final uri = Uri.parse(_cachedUriString!);
|
|
final fileUri = await FlutterSaf.getFile(uri, fileName);
|
|
if (fileUri == null || !await FlutterSaf.isFile(fileUri)) {
|
|
return [];
|
|
}
|
|
|
|
final content = await FlutterSaf.readTextFile(fileUri);
|
|
return content.split('\n');
|
|
>>>>>>> c5a85e05a3bb50cd4ea7de0da2db94c867eb7ddd
|
|
} catch (e) {
|
|
if (kDebugMode) {
|
|
print('[SAF] 读取文件失败: $e');
|
|
}
|
|
return [];
|
|
}
|
|
}
|
|
|
|
<<<<<<< HEAD
|
|
Future<List<String>> listFiles() async {
|
|
final state = await getPermissionState();
|
|
if (state != SafPermissionState.authorized) return [];
|
|
try {
|
|
final dir = Directory(_cachedPath!);
|
|
if (!await dir.exists()) return [];
|
|
final entities = await dir.list().toList();
|
|
return entities
|
|
.where((e) => e is File)
|
|
.map((e) => e.path.split(Platform.pathSeparator).last)
|
|
.toList();
|
|
} catch (e) {
|
|
if (kDebugMode) {
|
|
print('[SAF] 列出文件失败: $e');
|
|
}
|
|
=======
|
|
/// 获取文件夹中的文件列表
|
|
Future<List<String>> listFiles() async {
|
|
final state = await getPermissionState();
|
|
if (state != SafPermissionState.authorized) {
|
|
return [];
|
|
}
|
|
|
|
try {
|
|
final uri = Uri.parse(_cachedUriString!);
|
|
final files = await FlutterSaf.listFiles(uri);
|
|
return files.where((f) => f.isFile).map((f) => f.name).toList();
|
|
} catch (e) {
|
|
>>>>>>> c5a85e05a3bb50cd4ea7de0da2db94c867eb7ddd
|
|
return [];
|
|
}
|
|
}
|
|
|
|
<<<<<<< HEAD
|
|
=======
|
|
/// 检查授权是否有效,如果失效则清除缓存
|
|
>>>>>>> c5a85e05a3bb50cd4ea7de0da2db94c867eb7ddd
|
|
Future<bool> validatePermission() async {
|
|
final state = await getPermissionState();
|
|
return state == SafPermissionState.authorized;
|
|
}
|
|
|
|
<<<<<<< HEAD
|
|
void _clearCache() {
|
|
_cachedPath = null;
|
|
_savePath(null);
|
|
}
|
|
|
|
Future<void> _savePath(String? path) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
if (path != null && path.isNotEmpty) {
|
|
await prefs.setString(_prefKeySafPath, path);
|
|
} else {
|
|
await prefs.remove(_prefKeySafPath);
|
|
}
|
|
}
|
|
|
|
String? get cachedPath => _cachedPath;
|
|
=======
|
|
/// 清除授权缓存
|
|
void _clearCache() {
|
|
_cachedUriString = null;
|
|
_saveUri(null);
|
|
}
|
|
|
|
/// 保存 URI 到 SharedPreferences
|
|
Future<void> _saveUri(String? uriString) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
if (uriString != null && uriString.isNotEmpty) {
|
|
await prefs.setString(_prefKeySafUri, uriString);
|
|
} else {
|
|
await prefs.remove(_prefKeySafUri);
|
|
}
|
|
}
|
|
|
|
/// 获取缓存的 URI(用于调试)
|
|
String? get cachedUri => _cachedUriString;
|
|
>>>>>>> c5a85e05a3bb50cd4ea7de0da2db94c867eb7ddd
|
|
}
|