← back to lwj1994__clipboard_ai

Function bodies 677 total

All specs Real LLM only Function bodies
SqlDbRepo class · dart · L72-L245 (174 LOC)
lib/module/history/sql_db_repo.dart
class SqlDbRepo extends StateViewModel<SqlDbRepoState> {
  SqlDbRepo({int pageSize = 500})
    : _pageSize = pageSize,
      super(state: SqlDbRepoState.initial);

  DriftHistoryRepository get _repository =>
      viewModelBinding.read(historyRepositorySpec);
  final int _pageSize;

  int _reloadToken = 0;
  bool _loadingMoreInternal = false;
  HistoryPageCursor? _nextPageCursor;

  @override
  void onCreate(InstanceArg arg) {
    super.onCreate(arg);
    unawaited(refresh());
  }

  Future<void> refresh() async {
    final token = ++_reloadToken;
    setState(state.copyWith(loading: true, clearError: true));
    try {
      final groups = await _repository.loadGroups();
      final selectedGroupId = _sanitizeGroupId(state.selectedGroupId, groups);
      final page = await _repository.queryPage(
        query: state.query,
        groupId: selectedGroupId,
        pageSize: _pageSize,
      );
      if (token != _reloadToken) {
        return;
      }
      _nextPageCursor = page.nextC
QuickPanelAutoPasteService class · dart · L8-L60 (53 LOC)
lib/module/hotkey/quick_panel_auto_paste_service.dart
class QuickPanelAutoPasteService with ViewModel {
  QuickPanelAutoPasteService();

  static const String _enabledKey = 'quick_panel_auto_paste_enabled_v1';
  static const String _firstLaunchGuideShownKey =
      'quick_panel_accessibility_guide_shown_v1';
  static const String _quickPanelGuideShownKey =
      'quick_panel_shortcut_guide_shown_v1';
  static const String _logScope = 'auto_paste.service';

  AppLogService get _log => viewModelBinding.read(appLogServiceSpec);

  Future<bool> isEnabled() async {
    final enabled =
        await AppKvRepository.instance.getBool(_enabledKey) ?? false;
    unawaited(
      _log.info(_logScope, 'is_enabled_read', fields: {'enabled': enabled}),
    );
    return enabled;
  }

  Future<void> setEnabled(bool enabled) async {
    await AppKvRepository.instance.setBool(_enabledKey, enabled);
    unawaited(
      _log.info(_logScope, 'set_enabled', fields: {'enabled': enabled}),
    );
  }

  /// 首次启动时消费快捷面板引导标记,返回 true 表示需要展示引导。
  Future<bool> cons
QuickPanelShortcutService class · dart · L15-L407 (393 LOC)
lib/module/hotkey/quick_panel_shortcut_service.dart
class QuickPanelShortcutService with ViewModel {
  QuickPanelShortcutService._();

  static const String _storageKey = 'quick_panel_hotkey_v1';
  static const String _searchStorageKey = 'quick_panel_search_hotkey_v1';

  static final HotKey defaultHotKey = HotKey(
    key: PhysicalKeyboardKey.keyV,
    modifiers: <HotKeyModifier>[
      defaultTargetPlatform == TargetPlatform.macOS
          ? HotKeyModifier.meta
          : HotKeyModifier.control,
      HotKeyModifier.shift,
    ],
    scope: HotKeyScope.system,
  );

  static final HotKey defaultSearchHotKey = HotKey(
    key: PhysicalKeyboardKey.keyF,
    modifiers: <HotKeyModifier>[HotKeyModifier.alt, HotKeyModifier.shift],
    scope: HotKeyScope.system,
  );

  static const List<HotKeyModifier> _allowedModifiers = <HotKeyModifier>[
    HotKeyModifier.meta,
    HotKeyModifier.control,
    HotKeyModifier.alt,
    HotKeyModifier.shift,
  ];

  final StreamController<void> _triggerController =
      StreamController<void>.broadcast();
ShortcutRegistrationException class · dart · L409-L411 (3 LOC)
lib/module/hotkey/quick_panel_shortcut_service.dart
class ShortcutRegistrationException implements Exception {
  const ShortcutRegistrationException();
}
AppShutdownViewModel class · dart · L7-L35 (29 LOC)
lib/module/init/app_shutdown_view_model.dart
class AppShutdownViewModel with ViewModel {
  DriftHistoryRepository get _historyRepository =>
      viewModelBinding.read(historyRepositorySpec);
  AppLogService get _appLogService => viewModelBinding.read(appLogServiceSpec);

  Future<void>? _shutdownFuture;

  Future<void> shutdown() {
    return _shutdownFuture ??= _shutdown();
  }

  Future<void> _shutdown() async {
    try {
      await _historyRepository.close();
    } catch (_) {
      // 应用即将退出时优先继续收尾,避免单点失败阻断后续关闭。
    }
    try {
      await AppKvRepository.instance.close();
    } catch (_) {
      // Ignore shutdown errors during app exit.
    }
    try {
      await _appLogService.shutdown();
    } catch (_) {
      // Ignore shutdown errors during app exit.
    }
  }
}
StartInit class · dart · L13-L56 (44 LOC)
lib/module/init/start_init.dart
class StartInit with ViewModelBinding {
  StartInit._();

  static final StartInit instance = StartInit._();

  QuickPanelShortcutService get _quickPanelShortcutService =>
      viewModelBinding.read(quickPanelShortcutServiceSpec);
  AppLogService get _appLogService =>
      viewModelBinding.read(appLogServiceSpec);
  MainWindowViewModel get _mainWindowViewModel =>
      viewModelBinding.read(mainWindowViewModelSpec);
  ClipboardIngestionService get _clipboardIngestionService =>
      viewModelBinding.read(clipboardIngestionServiceSpec);
  PanelCoordinatorViewModel get _panelCoordinator =>
      viewModelBinding.read(panelCoordinatorViewModelSpec);

  @override
  Future<void> init() async {
    WidgetsFlutterBinding.ensureInitialized();

    if (!kIsWeb && isDesktopPlatform(defaultTargetPlatform)) {
      await windowManager.ensureInitialized();
      final options = _mainWindowViewModel.initialWindowOptions;
      await windowManager.waitUntilReadyToShow(options, () async {
        aw
AppLogExportSaveLocationPicker class · dart · L23-L87 (65 LOC)
lib/module/log/app_log_export_save_location_picker.dart
class AppLogExportSaveLocationPicker with ViewModel {
  AppLogExportSaveLocationPicker({
    GetSaveLocationCallback? getSaveLocationCallback,
    PrepareWindowForDialogCallback? prepareWindowForDialogCallback,
  }) : _getSaveLocation = getSaveLocationCallback ?? getSaveLocation,
       _prepareWindowForDialog =
           prepareWindowForDialogCallback ?? _focusWindowForDialog;

  static const XTypeGroup _logTypeGroup = XTypeGroup(
    label: 'Log files',
    extensions: <String>['log'],
  );

  final GetSaveLocationCallback _getSaveLocation;
  final PrepareWindowForDialogCallback _prepareWindowForDialog;

  Future<String?> pickSaveLocation({String? lastExportPath}) async {
    await _prepareWindowForDialogSafely();
    final location = await _getSaveLocation(
      acceptedTypeGroups: const <XTypeGroup>[_logTypeGroup],
      initialDirectory: _resolveInitialDirectory(lastExportPath),
      suggestedName: buildAppLogExportFileName(),
      confirmButtonText: 'Export',
      canCreateD
Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
AppLogExportResult class · dart · L15-L23 (9 LOC)
lib/module/log/app_log_service.dart
class AppLogExportResult {
  const AppLogExportResult({
    required this.exportPath,
    required this.revealedInFinder,
  });

  final String exportPath;
  final bool revealedInFinder;
}
DiagnosticLogs class · dart · L10-L24 (15 LOC)
lib/module/log/data/app_log_database.dart
class DiagnosticLogs extends Table {
  IntColumn get id => integer().autoIncrement()();

  IntColumn get createdAtMs => integer()();

  TextColumn get level => text()();

  TextColumn get origin => text()();

  TextColumn get scope => text()();

  TextColumn get message => text()();

  TextColumn get fieldsJson => text().nullable()();
}
AppLogDatabase class · dart · L27-L50 (24 LOC)
lib/module/log/data/app_log_database.dart
class AppLogDatabase extends _$AppLogDatabase {
  AppLogDatabase() : super(_openConnection());

  @override
  int get schemaVersion => 1;

  @override
  MigrationStrategy get migration => MigrationStrategy(
    onCreate: (Migrator m) async {
      await m.createAll();
      await _createIndexes();
    },
    onUpgrade: (Migrator m, int from, int to) async {
      await _createIndexes();
    },
  );

  Future<void> _createIndexes() async {
    await customStatement(
      'CREATE INDEX IF NOT EXISTS idx_diagnostic_logs_created_at '
      'ON diagnostic_logs(created_at_ms DESC, id DESC)',
    );
  }
}
DiagnosticLog class · dart · L205-L341 (137 LOC)
lib/module/log/data/app_log_database.g.dart
class DiagnosticLog extends DataClass implements Insertable<DiagnosticLog> {
  final int id;
  final int createdAtMs;
  final String level;
  final String origin;
  final String scope;
  final String message;
  final String? fieldsJson;
  const DiagnosticLog({
    required this.id,
    required this.createdAtMs,
    required this.level,
    required this.origin,
    required this.scope,
    required this.message,
    this.fieldsJson,
  });
  @override
  Map<String, Expression> toColumns(bool nullToAbsent) {
    final map = <String, Expression>{};
    map['id'] = Variable<int>(id);
    map['created_at_ms'] = Variable<int>(createdAtMs);
    map['level'] = Variable<String>(level);
    map['origin'] = Variable<String>(origin);
    map['scope'] = Variable<String>(scope);
    map['message'] = Variable<String>(message);
    if (!nullToAbsent || fieldsJson != null) {
      map['fields_json'] = Variable<String>(fieldsJson);
    }
    return map;
  }

  DiagnosticLogsCompanion toCompanion(bool n
DiagnosticLogsCompanion class · dart · L343-L453 (111 LOC)
lib/module/log/data/app_log_database.g.dart
class DiagnosticLogsCompanion extends UpdateCompanion<DiagnosticLog> {
  final Value<int> id;
  final Value<int> createdAtMs;
  final Value<String> level;
  final Value<String> origin;
  final Value<String> scope;
  final Value<String> message;
  final Value<String?> fieldsJson;
  const DiagnosticLogsCompanion({
    this.id = const Value.absent(),
    this.createdAtMs = const Value.absent(),
    this.level = const Value.absent(),
    this.origin = const Value.absent(),
    this.scope = const Value.absent(),
    this.message = const Value.absent(),
    this.fieldsJson = const Value.absent(),
  });
  DiagnosticLogsCompanion.insert({
    this.id = const Value.absent(),
    required int createdAtMs,
    required String level,
    required String origin,
    required String scope,
    required String message,
    this.fieldsJson = const Value.absent(),
  }) : createdAtMs = Value(createdAtMs),
       level = Value(level),
       origin = Value(origin),
       scope = Value(scope),
       mes
_ class · dart · L455-L464 (10 LOC)
lib/module/log/data/app_log_database.g.dart
abstract class _$AppLogDatabase extends GeneratedDatabase {
  _$AppLogDatabase(QueryExecutor e) : super(e);
  $AppLogDatabaseManager get managers => $AppLogDatabaseManager(this);
  late final $DiagnosticLogsTable diagnosticLogs = $DiagnosticLogsTable(this);
  @override
  Iterable<TableInfo<Table, Object?>> get allTables =>
      allSchemaEntities.whereType<TableInfo<Table, Object?>>();
  @override
  List<DatabaseSchemaEntity> get allSchemaEntities => [diagnosticLogs];
}
StoredDiagnosticLogEntry class · dart · L8-L24 (17 LOC)
lib/module/log/data/app_log_repository.dart
class StoredDiagnosticLogEntry {
  const StoredDiagnosticLogEntry({
    required this.createdAtMs,
    required this.level,
    required this.origin,
    required this.scope,
    required this.message,
    required this.fieldsJson,
  });

  final int createdAtMs;
  final String level;
  final String origin;
  final String scope;
  final String message;
  final String? fieldsJson;
}
DriftAppLogRepository class · dart · L26-L163 (138 LOC)
lib/module/log/data/app_log_repository.dart
class DriftAppLogRepository with ViewModel {
  DriftAppLogRepository({AppLogDatabase? database})
    : _db = database ?? AppLogDatabase();

  final AppLogDatabase _db;
  bool _closed = false;

  Future<void> close() async {
    if (_closed) {
      return;
    }
    _closed = true;
    await _db.close();
  }

  Future<void> insert({
    required int createdAtMs,
    required String level,
    required String origin,
    required String scope,
    required String message,
    Map<String, Object?> fields = const <String, Object?>{},
  }) {
    return _db
        .into(_db.diagnosticLogs)
        .insert(
          DiagnosticLogsCompanion.insert(
            createdAtMs: createdAtMs,
            level: level,
            origin: origin,
            scope: scope,
            message: message,
            fieldsJson: Value(fields.isEmpty ? null : jsonEncode(fields)),
          ),
        );
  }

  Future<int> count() async {
    final countExpression = _db.diagnosticLogs.id.count();
    fin
Want this analysis on your repo? https://repobility.com/scan/
ToggleInAppPanelEvent class · dart · L7-L11 (5 LOC)
lib/module/panel/panel_coordinator_event.dart
class ToggleInAppPanelEvent extends PanelCoordinatorEvent {
  const ToggleInAppPanelEvent({required this.minimizeWindowOnDismiss});

  final bool minimizeWindowOnDismiss;
}
ShowErrorToastEvent class · dart · L14-L18 (5 LOC)
lib/module/panel/panel_coordinator_event.dart
class ShowErrorToastEvent extends PanelCoordinatorEvent {
  const ShowErrorToastEvent(this.message);

  final String message;
}
RequestMainRefreshEvent class · dart · L22-L24 (3 LOC)
lib/module/panel/panel_coordinator_event.dart
class RequestMainRefreshEvent extends PanelCoordinatorEvent {
  const RequestMainRefreshEvent();
}
TogglePanelWithSearchEvent class · dart · L28-L30 (3 LOC)
lib/module/panel/panel_coordinator_event.dart
class TogglePanelWithSearchEvent extends PanelCoordinatorEvent {
  const TogglePanelWithSearchEvent();
}
_ResolvedPanelRequest class · dart · L751-L767 (17 LOC)
lib/module/panel/panel_coordinator_view_model.dart
class _ResolvedPanelRequest {
  const _ResolvedPanelRequest({
    required this.key,
    required this.groups,
    required this.requestedGroupId,
    required this.selectedGroupId,
    required this.query,
    required this.pageSize,
  });

  final _PanelRequestKey key;
  final List<ClipboardGroup> groups;
  final String? requestedGroupId;
  final String? selectedGroupId;
  final String query;
  final int pageSize;
}
_PanelRequestKey class · dart · L769-L784 (16 LOC)
lib/module/panel/panel_coordinator_view_model.dart
class _PanelRequestKey {
  const _PanelRequestKey({required this.groupId, required this.query});

  final String? groupId;
  final String query;

  @override
  bool operator ==(Object other) {
    return other is _PanelRequestKey &&
        other.groupId == groupId &&
        other.query == query;
  }

  @override
  int get hashCode => Object.hash(groupId, query);
}
_PanelPageCacheEntry class · dart · L786-L886 (101 LOC)
lib/module/panel/panel_coordinator_view_model.dart
class _PanelPageCacheEntry {
  const _PanelPageCacheEntry({
    required this.key,
    required this.groups,
    required this.items,
    required this.requestedGroupId,
    required this.selectedGroupId,
    required this.query,
    required this.pageSize,
    required this.totalCount,
  });

  final _PanelRequestKey key;
  final List<ClipboardGroup> groups;
  final List<ClipboardItem> items;
  final String? requestedGroupId;
  final String? selectedGroupId;
  final String query;
  final int pageSize;
  final int totalCount;

  _PanelPageCacheEntry copyWith({
    _PanelRequestKey? key,
    List<ClipboardGroup>? groups,
    List<ClipboardItem>? items,
    String? requestedGroupId,
    bool clearRequestedGroupId = false,
    String? selectedGroupId,
    bool clearSelectedGroupId = false,
    String? query,
    int? pageSize,
    int? totalCount,
  }) {
    return _PanelPageCacheEntry(
      key: key ?? this.key,
      groups: groups ?? this.groups,
      items: items ?? this.items,
    
_PanelActionFlutterHandler class · dart · L905-L923 (19 LOC)
lib/module/panel/panel_coordinator_view_model.dart
class _PanelActionFlutterHandler implements QuickPanelActionFlutterApi {
  _PanelActionFlutterHandler({
    required this.onItemPicked,
    required this.onItemAction,
  });

  final Future<void> Function(PanelItemPickedMessage payload) onItemPicked;
  final Future<bool> Function(PanelItemActionMessage action) onItemAction;

  @override
  void onPanelItemPicked(PanelItemPickedMessage payload) {
    unawaited(onItemPicked(payload));
  }

  @override
  Future<bool> onPanelItemAction(PanelItemActionMessage action) {
    return onItemAction(action);
  }
}
Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
_PanelDataFlutterHandler class · dart · L925-L945 (21 LOC)
lib/module/panel/panel_coordinator_view_model.dart
class _PanelDataFlutterHandler implements QuickPanelDataFlutterApi {
  _PanelDataFlutterHandler({
    required this.onRequestPage,
    required this.onRequestItemContent,
  });

  final Future<PanelPageMessage> Function(PanelPageRequestMessage request)
  onRequestPage;
  final Future<PanelItemContentMessage> Function(String itemId)
  onRequestItemContent;

  @override
  Future<PanelPageMessage> requestPanelPage(PanelPageRequestMessage request) {
    return onRequestPage(request);
  }

  @override
  Future<PanelItemContentMessage> requestPanelItemContent(String itemId) {
    return onRequestItemContent(itemId);
  }
}
_PanelSettingsFlutterHandler class · dart · L947-L956 (10 LOC)
lib/module/panel/panel_coordinator_view_model.dart
class _PanelSettingsFlutterHandler implements QuickPanelSettingsFlutterApi {
  _PanelSettingsFlutterHandler({required this.onRequestWindowSettings});

  final Future<PanelWindowSettingsMessage> Function() onRequestWindowSettings;

  @override
  Future<PanelWindowSettingsMessage> requestPanelWindowSettings() {
    return onRequestWindowSettings();
  }
}
MacosAccessibilityService class · dart · L9-L100 (92 LOC)
lib/module/permission/macos_accessibility_service.dart
class MacosAccessibilityService with ViewModel {
  MacosAccessibilityService();

  static final pigeon.AccessibilityHostApi _hostApi =
      pigeon.AccessibilityHostApi();

  static bool get isSupported => isNativeBridgePlatform;

  AppLogService get _appLogService =>
      viewModelBinding.read(appLogServiceSpec);

  Future<bool> isAccessibilityGranted() {
    return _invokeBool(
      () => _hostApi.isAccessibilityGranted(),
      method: 'isAccessibilityGranted',
      scope: 'accessibility.bridge',
    );
  }

  Future<bool> requestAccessibilityPermission() {
    return _invokeBool(
      () => _hostApi.requestAccessibilityPermission(),
      method: 'requestAccessibilityPermission',
      scope: 'accessibility.permission',
    );
  }

  Future<bool> openAccessibilitySettings() {
    return _invokeBool(
      () => _hostApi.openAccessibilitySettings(),
      method: 'openAccessibilitySettings',
      scope: 'accessibility.permission',
    );
  }

  Future<bool> performQuickPanelAut
FileTypeInfo class · dart · L6-L22 (17 LOC)
lib/module/recognition/file_type_detector.dart
class FileTypeInfo {
  const FileTypeInfo({
    required this.mimeType,
    required this.extension,
    required this.fileSizeBytes,
    required this.isTextLike,
    this.textPreview,
  });

  final String mimeType;
  final String extension;
  final int fileSizeBytes;
  final bool isTextLike;

  /// 文本类文件的前 N 个字符预览。
  final String? textPreview;
}
FileTypeDetector class · dart · L24-L301 (278 LOC)
lib/module/recognition/file_type_detector.dart
class FileTypeDetector {
  const FileTypeDetector._();

  /// 文本预览最大字符数。
  static const int _maxPreviewChars = 500;

  /// 检测文件类型,优先用后缀,后缀不可识别时用 magic number 兜底。
  static Future<FileTypeInfo> detect(String filePath) async {
    final file = File(filePath);
    final sizeBytes = await file.length();
    final ext = _extractExtension(filePath);

    // 后缀优先查找。
    final mimeByExt = _extensionToMime[ext];
    if (mimeByExt != null) {
      final isText = _textLikeExtensions.contains(ext);
      final preview = isText ? await _readTextPreview(file) : null;
      return FileTypeInfo(
        mimeType: mimeByExt,
        extension: ext,
        fileSizeBytes: sizeBytes,
        isTextLike: isText,
        textPreview: preview,
      );
    }

    // Magic number 兜底。
    final magicMime = await _detectByMagicNumber(filePath);
    if (magicMime != null) {
      return FileTypeInfo(
        mimeType: magicMime,
        extension: ext,
        fileSizeBytes: sizeBytes,
        isTextLike: false,
RecognitionResult class · dart · L3-L13 (11 LOC)
lib/module/recognition/recognition_service.dart
class RecognitionResult {
  const RecognitionResult({
    required this.type,
    required this.confidence,
    required this.normalizedText,
  });

  final SmartCardType type;
  final double confidence;
  final String normalizedText;
}
RecognitionService class · dart · L15-L17 (3 LOC)
lib/module/recognition/recognition_service.dart
abstract class RecognitionService {
  Future<RecognitionResult> recognize(String rawInput);
}
RuleBasedRecognitionService class · dart · L8-L170 (163 LOC)
lib/module/recognition/rule_based_recognition_service.dart
class RuleBasedRecognitionService with ViewModel implements RecognitionService {
  RuleBasedRecognitionService();

  static final RegExp _emailRegExp = RegExp(
    r'^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$',
  );
  static final RegExp _urlRegExp = RegExp(
    r'^(https?:\/\/)?([A-Za-z0-9-]+\.)+[A-Za-z]{2,}(:\d+)?(\/\S*)?$',
  );
  static final RegExp _phoneRegExp = RegExp(r'^(\+?\d[\d -]{6,}\d)$');
  static final RegExp _identityRegExp = RegExp(r'^(\d{15}|\d{17}[\dXx])$');
  static final RegExp _bankRegExp = RegExp(r'^\d{16,19}$');
  static final RegExp _shipmentRegExp = RegExp(
    r'^[A-Z]{0,2}\d{8,20}[A-Z]{0,2}$',
  );
  static final RegExp _englishAddressMarkerRegExp = RegExp(
    r'\b(Street|St\.?|Road|Rd\.?|Avenue|Ave\.?|Lane|Ln\.?|Boulevard|Blvd\.?)\b',
    caseSensitive: false,
  );
  static final RegExp _chineseAddressMarkerRegExp = RegExp(
    r'(省|市|区(?!域)|县|路|街|道|号|镇|乡|村)',
  );
  static final RegExp _addressNumberRegExp = RegExp(
    r'\d{1,5}\s*(号|弄|室|单元|楼|栋|#)?'
Repobility · open methodology · https://repobility.com/research/
RecommendationContext class · dart · L3-L11 (9 LOC)
lib/module/recommendation/recommendation_service.dart
class RecommendationContext {
  const RecommendationContext({
    required this.currentApp,
    required this.currentHour,
  });

  final String currentApp;
  final int currentHour;
}
RecommendationItem class · dart · L13-L23 (11 LOC)
lib/module/recommendation/recommendation_service.dart
class RecommendationItem {
  const RecommendationItem({
    required this.card,
    required this.score,
    required this.reason,
  });

  final SmartCard card;
  final double score;
  final String reason;
}
RecommendationService class · dart · L25-L31 (7 LOC)
lib/module/recommendation/recommendation_service.dart
abstract class RecommendationService {
  Future<List<RecommendationItem>> recommend({
    required RecommendationContext context,
    required List<SmartCard> candidates,
    int limit = 5,
  });
}
AliyunOssProvider class · dart · L11-L136 (126 LOC)
lib/module/s3_store/aliyun_oss_provider.dart
class AliyunOssProvider extends S3Provider {
  AliyunOssProvider(this._config) {
    _initClient();
  }

  final S3StoreConfig _config;
  late final oss.Client _client;

  @override
  S3StoreConfig get config => _config;

  void _initClient() {
    oss.Client.init(
      ossEndpoint: _config.endpoint,
      bucketName: _config.bucket,
      authGetter: _authGetter,
    );
    _client = oss.Client();
  }

  Future<oss.Auth> _authGetter() async {
    return oss.Auth(
      accessKey: _config.accessKeyId,
      accessSecret: _config.secretAccessKey,
      // 非 STS 场景:expire 设远期,secureToken 留空。
      expire: '2099-12-31T23:59:59Z',
      secureToken: '',
    );
  }

  @override
  Future<void> testConnection() async {
    // 列举根前缀下最多 1 个对象来验证连接。
    await _client.listObjects({
      'prefix': config.prefix.isEmpty ? '' : '${config.prefix}/',
      'max-keys': '1',
    });
  }

  @override
  Future<void> putObject({
    required String key,
    required Uint8List data,
    String? contentTyp
S3BackupConfig class · dart · L15-L33 (19 LOC)
lib/module/s3_store/s3_backup_service.dart
class S3BackupConfig {
  const S3BackupConfig({
    required this.endpoint,
    required this.bucket,
    required this.region,
    required this.accessKeyId,
    required this.secretAccessKey,
    required this.enabled,
  });

  final String endpoint;
  final String bucket;
  final String region;
  final String accessKeyId;
  final String secretAccessKey;
  final bool enabled;

  bool get hasConfig => endpoint.isNotEmpty && bucket.isNotEmpty;
}
S3StoreConfig class · dart · L6-L42 (37 LOC)
lib/module/s3_store/s3_provider.dart
class S3StoreConfig {
  const S3StoreConfig({
    required this.endpoint,
    required this.bucket,
    required this.accessKeyId,
    required this.secretAccessKey,
    this.region = '',
    this.prefix = 'AcopyBackup',
  });

  /// 服务端点,如 `https://s3.amazonaws.com`、`https://oss-cn-hangzhou.aliyuncs.com`。
  final String endpoint;

  /// 存储桶名称。
  final String bucket;

  final String accessKeyId;
  final String secretAccessKey;

  /// 区域,部分服务商签名需要(如 AWS)。
  final String region;

  /// 对象 key 前缀,默认 `AcopyBackup`。
  final String prefix;

  bool get isValid =>
      endpoint.isNotEmpty &&
      bucket.isNotEmpty &&
      accessKeyId.isNotEmpty &&
      secretAccessKey.isNotEmpty;

  /// 拼接完整 object key:`{prefix}/{path}`。
  String objectKey(String path) {
    if (prefix.isEmpty) return path;
    return '$prefix/$path';
  }
}
S3Provider class · dart · L47-L72 (26 LOC)
lib/module/s3_store/s3_provider.dart
abstract class S3Provider {
  /// 当前使用的配置。
  S3StoreConfig get config;

  /// 测试连接是否可用(通常 HEAD bucket 或 list 一个空前缀)。
  Future<void> testConnection();

  /// 上传对象。
  Future<void> putObject({
    required String key,
    required Uint8List data,
    String? contentType,
  });

  /// 下载对象,不存在时返回 null。
  Future<Uint8List?> getObject(String key);

  /// 列出指定前缀下的所有对象 key。
  Future<List<String>> listObjects(String prefix);

  /// 删除对象(可选实现,同步场景暂不需要)。
  Future<void> deleteObject(String key) async {}

  /// 释放资源(HTTP client 等)。
  void dispose() {}
}
LocalSearchService class · dart · L6-L31 (26 LOC)
lib/module/search/local_search_service.dart
class LocalSearchService implements SearchService {
  const LocalSearchService({required CardSource source}) : _source = source;

  final CardSource _source;

  @override
  Future<List<SmartCard>> search(String query, {int limit = 30}) async {
    final normalized = query.trim().toLowerCase();
    final cards = _source();
    if (normalized.isEmpty) {
      return cards.take(limit).toList(growable: false);
    }
    final matched = cards.where((card) {
      if (card.title.toLowerCase().contains(normalized)) {
        return true;
      }
      if (card.content.toLowerCase().contains(normalized)) {
        return true;
      }
      return card.fields.values.any(
        (value) => value.toLowerCase().contains(normalized),
      );
    });
    return matched.take(limit).toList(growable: false);
  }
}
Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
SearchService class · dart · L3-L5 (3 LOC)
lib/module/search/search_service.dart
abstract class SearchService {
  Future<List<SmartCard>> search(String query, {int limit = 30});
}
SecureSecretStore class · dart · L7-L13 (7 LOC)
lib/module/security/secure_secret_store.dart
abstract class SecureSecretStore {
  Future<String?> read(String key);

  Future<void> write(String key, String value);

  Future<void> delete(String key);
}
KeychainSecureSecretStore class · dart · L23-L49 (27 LOC)
lib/module/security/secure_secret_store.dart
class KeychainSecureSecretStore implements SecureSecretStore {
  KeychainSecureSecretStore({SecureStorageHostApi? hostApi})
    : _hostApi = hostApi ?? SecureStorageHostApi();

  final SecureStorageHostApi _hostApi;

  @override
  Future<String?> read(String key) {
    return _hostApi.readSecret(key);
  }

  @override
  Future<void> write(String key, String value) async {
    final ok = await _hostApi.writeSecret(key, value);
    if (!ok) {
      throw StateError('写入安全存储失败: $key');
    }
  }

  @override
  Future<void> delete(String key) async {
    final ok = await _hostApi.deleteSecret(key);
    if (!ok) {
      throw StateError('删除安全存储失败: $key');
    }
  }
}
AppKvSecureSecretStore class · dart · L51-L72 (22 LOC)
lib/module/security/secure_secret_store.dart
class AppKvSecureSecretStore implements SecureSecretStore {
  const AppKvSecureSecretStore();

  static const String _keyPrefix = 'secure_secret.';

  String _storageKey(String key) => '$_keyPrefix$key';

  @override
  Future<void> delete(String key) {
    return AppKvRepository.instance.remove(_storageKey(key));
  }

  @override
  Future<String?> read(String key) {
    return AppKvRepository.instance.getString(_storageKey(key));
  }

  @override
  Future<void> write(String key, String value) {
    return AppKvRepository.instance.setString(_storageKey(key), value);
  }
}
SensitiveMasker class · dart · L1-L13 (13 LOC)
lib/module/security/sensitive_masker.dart
class SensitiveMasker {
  const SensitiveMasker._();

  static String mask(String input, {int keepLast = 4}) {
    if (input.length <= keepLast) {
      return '*' * input.length;
    }

    final visible = input.substring(input.length - keepLast);
    final hidden = '*' * (input.length - keepLast);
    return '$hidden$visible';
  }
}
TaskDag class · dart · L13-L79 (67 LOC)
lib/module/shared/task_dag.dart
class TaskDag {
  final Map<String, _DagNode> _nodes = {};

  /// 添加任务。[dependsOn] 列出必须先完成的任务名。
  void add<T>(
    String name,
    Future<T> Function() task, {
    List<String> dependsOn = const [],
  }) {
    if (_nodes.containsKey(name)) {
      throw ArgumentError('任务 "$name" 已存在');
    }
    _nodes[name] = _DagNode(name: name, task: task, dependsOn: dependsOn);
  }

  /// 执行所有任务,返回 {任务名: 返回值} 的结果 Map。
  /// 无依赖的任务并行执行,有依赖的等上游完成后立即开始。
  Future<Map<String, Object?>> execute() async {
    // 验证依赖关系。
    for (final node in _nodes.values) {
      for (final dep in node.dependsOn) {
        if (!_nodes.containsKey(dep)) {
          throw StateError('任务 "${node.name}" 依赖不存在的任务 "$dep"');
        }
      }
    }
    _detectCycle();

    final results = <String, Object?>{};
    final futures = <String, Future<void>>{};

    Future<void> run(String name) {
      return futures.putIfAbsent(name, () async {
        final node = _nodes[name]!;
        // 等待所有上游任务完成。
        await Future.wait([f
_DagNode class · dart · L81-L91 (11 LOC)
lib/module/shared/task_dag.dart
class _DagNode {
  _DagNode({
    required this.name,
    required this.task,
    required this.dependsOn,
  });

  final String name;
  final Future<Object?> Function() task;
  final List<String> dependsOn;
}
DailyFileStore class · dart · L10-L74 (65 LOC)
lib/module/sync/daily_file_store.dart
abstract class DailyFileStore {
  /// 已成功写入的 payload hash 缓存,key 为 dateKey。
  /// 写入前比较 hash,内容未变更时跳过实际 I/O;仅在写入成功后缓存。
  final Map<String, String> _writeCache = {};

  /// 存储后端是否可用。
  Future<bool> isAvailable();

  /// 将某天的 payload 写入 days/{dateKey}.json。
  /// 内置 hash 去重:内容未变更时直接返回 true,跳过实际 I/O。
  Future<bool> writeDailyFile(String dateKey, String payload) async {
    final digest = sha256.convert(utf8.encode(payload)).toString();
    if (_writeCache[dateKey] == digest) return true;
    final ok = await doWriteDailyFile(dateKey, payload);
    if (ok) _writeCache[dateKey] = digest;
    return ok;
  }

  /// 子类实现的实际写入逻辑。
  @protected
  Future<bool> doWriteDailyFile(String dateKey, String payload);

  /// 读取某天的 payload。
  Future<String?> readDailyFile(String dateKey);

  /// 列出所有已存储的日期 key。
  Future<List<String>> listDailyFiles();

  /// 将图片文件写入 images/ 子目录。
  Future<bool> writeImageFile(String filename, Uint8List data);

  /// 从 images/ 子目录读取图片文件。
  Future<Uint8List?> readImageFile(Str
Want this analysis on your repo? https://repobility.com/scan/
LocalBackupService class · dart · L9-L144 (136 LOC)
lib/module/sync/local_backup_service.dart
class LocalBackupService extends DailyFileStore with ViewModel {
  LocalBackupService({LocalBackupHostApi? hostApi})
    : _hostApi = hostApi ?? LocalBackupHostApi();

  final LocalBackupHostApi _hostApi;

  String? _resolvedPath;

  /// 当前已配置的备份文件夹路径,未配置时为 null。
  String? get backupPath => _resolvedPath;

  /// 是否已配置备份文件夹位置。
  bool get hasBackupLocation => _resolvedPath != null;

  /// 尝试从已保存的 bookmark 恢复文件路径。
  Future<String?> resolveLocation() async {
    final previousPath = _resolvedPath;
    try {
      _resolvedPath = await _hostApi.resolveBookmarkedBackupLocation();
    } catch (_) {
      _resolvedPath = null;
    }
    if (_resolvedPath != previousPath) {
      clearWriteCache();
    }
    return _resolvedPath;
  }

  /// 弹出选择文件夹面板让用户选择备份文件夹,成功后持久化 bookmark。
  Future<String?> pickLocation() async {
    final previousPath = _resolvedPath;
    final path = await _hostApi.pickAndBookmarkBackupLocation(
      'clipboard-backup.json',
    );
    _resolvedPath = path;
    if (_reso
LocalHistoryStore class · dart · L3-L16 (14 LOC)
lib/module/sync/local_history_store.dart
class LocalHistoryStore {
  const LocalHistoryStore();

  static const String _historyPayloadKey =
      'quickvault.clipboard.history.local.payload.v1';

  Future<String?> loadPayload() async {
    return AppKvRepository.instance.getString(_historyPayloadKey);
  }

  Future<void> savePayload(String payload) async {
    await AppKvRepository.instance.setString(_historyPayloadKey, payload);
  }
}
SyncSignal class · dart · L5-L46 (42 LOC)
lib/module/sync/sync_signal.dart
class SyncSignal {
  const SyncSignal({
    required this.version,
    required this.timestamp,
    required this.deviceId,
    this.changedDateKeys = const <String>[],
  }) : assert(version >= 0),
       assert(timestamp > 0),
       assert(deviceId != '');

  /// 单调递增的版本号。
  final int version;

  /// 推送时的毫秒时间戳。
  final int timestamp;

  /// 推送设备的唯一标识。
  final String deviceId;

  /// 本次推送变更的日期 key 列表(如 `["2026-03-30Z"]`)。
  /// 拉取端可据此只拉变更的天,不用全量遍历。为空时回退到全量拉取。
  final List<String> changedDateKeys;

  Map<String, Object> toJson() => {
    'v': version,
    't': timestamp,
    'd': deviceId,
    if (changedDateKeys.isNotEmpty) 'k': changedDateKeys,
  };

  static SyncSignal? tryParse(Map<String, Object?> json) {
    final v = json['v'];
    final t = json['t'];
    final d = json['d'];
    if (v is! int || t is! int || d is! String) return null;
    final k = json['k'];
    final keys = k is List
        ? k.whereType<String>().toList(growable: false)
        : const <String>[];
    retu
‹ prevpage 2 / 14next ›