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 init() async { final prefs = await SharedPreferences.getInstance(); _cachedPath = prefs.getString(_prefKeySafPath); if (kDebugMode) { print('[SAF] 初始化,缓存路径: $_cachedPath'); } } Future 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 init() async { final prefs = await SharedPreferences.getInstance(); _cachedUriString = prefs.getString(_prefKeySafUri); if (kDebugMode) { print('[SAF] 初始化,缓存 URI: $_cachedUriString'); } } /// 获取当前授权状态 Future 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 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 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 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 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> 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> 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> 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> 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 validatePermission() async { final state = await getPermissionState(); return state == SafPermissionState.authorized; } <<<<<<< HEAD void _clearCache() { _cachedPath = null; _savePath(null); } Future _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 _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 }