This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
class AppUpdateInfo {
|
||||
final String version;
|
||||
final String title;
|
||||
final String? description;
|
||||
final Uri pageUrl;
|
||||
final Uri? downloadUrl;
|
||||
final String? fileName;
|
||||
final DateTime? publishedAt;
|
||||
|
||||
const AppUpdateInfo({
|
||||
required this.version,
|
||||
required this.title,
|
||||
required this.pageUrl,
|
||||
this.description,
|
||||
this.downloadUrl,
|
||||
this.fileName,
|
||||
this.publishedAt,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
import '../../src/rust/api/ffi_types.dart' as ffi;
|
||||
|
||||
class SyncConfigModel {
|
||||
final String baseUrl;
|
||||
final String accessToken;
|
||||
final String refreshToken;
|
||||
final String localRoot;
|
||||
final String remoteRoot;
|
||||
final String syncMode;
|
||||
final String conflictStrategy;
|
||||
final String wcfDeleteMode;
|
||||
final int maxConcurrentTransfers;
|
||||
final int bandwidthLimitKbps;
|
||||
final List<String> excludedPaths;
|
||||
final int maxWorkers;
|
||||
final String dataDir;
|
||||
final String clientId;
|
||||
final String logLevel;
|
||||
|
||||
const SyncConfigModel({
|
||||
required this.baseUrl,
|
||||
required this.accessToken,
|
||||
required this.refreshToken,
|
||||
required this.localRoot,
|
||||
required this.dataDir,
|
||||
required this.clientId,
|
||||
this.remoteRoot = 'cloudreve://my',
|
||||
this.syncMode = 'full',
|
||||
this.conflictStrategy = 'keep_both',
|
||||
this.wcfDeleteMode = 'wcf_delete_local_only',
|
||||
this.maxConcurrentTransfers = 3,
|
||||
this.bandwidthLimitKbps = 0,
|
||||
this.excludedPaths = const [],
|
||||
this.maxWorkers = 0,
|
||||
this.logLevel = 'info',
|
||||
});
|
||||
|
||||
SyncConfigModel copyWith({
|
||||
String? baseUrl,
|
||||
String? accessToken,
|
||||
String? refreshToken,
|
||||
String? localRoot,
|
||||
String? remoteRoot,
|
||||
String? syncMode,
|
||||
String? conflictStrategy,
|
||||
String? wcfDeleteMode,
|
||||
int? maxConcurrentTransfers,
|
||||
int? bandwidthLimitKbps,
|
||||
List<String>? excludedPaths,
|
||||
int? maxWorkers,
|
||||
String? dataDir,
|
||||
String? clientId,
|
||||
String? logLevel,
|
||||
}) {
|
||||
return SyncConfigModel(
|
||||
baseUrl: baseUrl ?? this.baseUrl,
|
||||
accessToken: accessToken ?? this.accessToken,
|
||||
refreshToken: refreshToken ?? this.refreshToken,
|
||||
localRoot: localRoot ?? this.localRoot,
|
||||
remoteRoot: remoteRoot ?? this.remoteRoot,
|
||||
syncMode: syncMode ?? this.syncMode,
|
||||
conflictStrategy: conflictStrategy ?? this.conflictStrategy,
|
||||
wcfDeleteMode: wcfDeleteMode ?? this.wcfDeleteMode,
|
||||
maxConcurrentTransfers:
|
||||
maxConcurrentTransfers ?? this.maxConcurrentTransfers,
|
||||
bandwidthLimitKbps: bandwidthLimitKbps ?? this.bandwidthLimitKbps,
|
||||
excludedPaths: excludedPaths ?? this.excludedPaths,
|
||||
maxWorkers: maxWorkers ?? this.maxWorkers,
|
||||
dataDir: dataDir ?? this.dataDir,
|
||||
clientId: clientId ?? this.clientId,
|
||||
logLevel: logLevel ?? this.logLevel,
|
||||
);
|
||||
}
|
||||
|
||||
ffi.SyncConfigFfi toFfi() {
|
||||
return ffi.SyncConfigFfi(
|
||||
baseUrl: baseUrl,
|
||||
accessToken: accessToken,
|
||||
refreshToken: refreshToken,
|
||||
localRoot: localRoot,
|
||||
remoteRoot: remoteRoot,
|
||||
syncMode: syncMode,
|
||||
conflictStrategy: conflictStrategy,
|
||||
wcfDeleteMode: wcfDeleteMode,
|
||||
maxConcurrentTransfers: maxConcurrentTransfers,
|
||||
bandwidthLimitKbps: BigInt.from(bandwidthLimitKbps),
|
||||
excludedPaths: excludedPaths,
|
||||
maxWorkers: maxWorkers,
|
||||
dataDir: dataDir,
|
||||
clientId: clientId,
|
||||
logLevel: logLevel,
|
||||
);
|
||||
}
|
||||
|
||||
static SyncConfigModel fromFfi(ffi.SyncConfigFfi ffi) {
|
||||
return SyncConfigModel(
|
||||
baseUrl: ffi.baseUrl,
|
||||
accessToken: ffi.accessToken,
|
||||
refreshToken: ffi.refreshToken,
|
||||
localRoot: ffi.localRoot,
|
||||
remoteRoot: ffi.remoteRoot,
|
||||
syncMode: ffi.syncMode,
|
||||
conflictStrategy: ffi.conflictStrategy,
|
||||
wcfDeleteMode: ffi.wcfDeleteMode,
|
||||
maxConcurrentTransfers: ffi.maxConcurrentTransfers,
|
||||
bandwidthLimitKbps: ffi.bandwidthLimitKbps.toInt(),
|
||||
excludedPaths: ffi.excludedPaths,
|
||||
maxWorkers: ffi.maxWorkers,
|
||||
dataDir: ffi.dataDir,
|
||||
clientId: ffi.clientId,
|
||||
logLevel: ffi.logLevel,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
import '../../src/rust/api/ffi_types.dart' as ffi;
|
||||
|
||||
sealed class SyncEventModel {}
|
||||
|
||||
class SyncStateChanged extends SyncEventModel {
|
||||
final String newState;
|
||||
SyncStateChanged(this.newState);
|
||||
}
|
||||
|
||||
class SyncProgress extends SyncEventModel {
|
||||
final int synced;
|
||||
final int total;
|
||||
final String currentFile;
|
||||
SyncProgress(this.synced, this.total, this.currentFile);
|
||||
}
|
||||
|
||||
class SyncFileUploaded extends SyncEventModel {
|
||||
final String localPath;
|
||||
final String remoteUri;
|
||||
SyncFileUploaded(this.localPath, this.remoteUri);
|
||||
}
|
||||
|
||||
class SyncFileDownloaded extends SyncEventModel {
|
||||
final String localPath;
|
||||
final String remoteUri;
|
||||
SyncFileDownloaded(this.localPath, this.remoteUri);
|
||||
}
|
||||
|
||||
class SyncConflictDetected extends SyncEventModel {
|
||||
final String localPath;
|
||||
final String conflictType;
|
||||
SyncConflictDetected(this.localPath, this.conflictType);
|
||||
}
|
||||
|
||||
class SyncError extends SyncEventModel {
|
||||
final String message;
|
||||
final bool recoverable;
|
||||
SyncError(this.message, this.recoverable);
|
||||
}
|
||||
|
||||
class SyncTokenExpired extends SyncEventModel {}
|
||||
|
||||
class SyncDiskSpaceWarning extends SyncEventModel {
|
||||
final int availableMb;
|
||||
SyncDiskSpaceWarning(this.availableMb);
|
||||
}
|
||||
|
||||
class SyncInitialSyncComplete extends SyncEventModel {
|
||||
final SyncSummaryModel summary;
|
||||
SyncInitialSyncComplete(this.summary);
|
||||
}
|
||||
|
||||
class SyncSummaryModel {
|
||||
final int uploaded;
|
||||
final int downloaded;
|
||||
final int renamed;
|
||||
final int moved;
|
||||
final int conflicts;
|
||||
final int failed;
|
||||
final int skipped;
|
||||
final int deletedLocal;
|
||||
final int deletedRemote;
|
||||
final int durationMs;
|
||||
|
||||
const SyncSummaryModel({
|
||||
this.uploaded = 0,
|
||||
this.downloaded = 0,
|
||||
this.renamed = 0,
|
||||
this.moved = 0,
|
||||
this.conflicts = 0,
|
||||
this.failed = 0,
|
||||
this.skipped = 0,
|
||||
this.deletedLocal = 0,
|
||||
this.deletedRemote = 0,
|
||||
this.durationMs = 0,
|
||||
});
|
||||
|
||||
static SyncSummaryModel fromFfi(ffi.SyncSummaryFfi f) {
|
||||
return SyncSummaryModel(
|
||||
uploaded: f.uploaded,
|
||||
downloaded: f.downloaded,
|
||||
renamed: f.renamed,
|
||||
moved: f.moved,
|
||||
conflicts: f.conflicts,
|
||||
failed: f.failed,
|
||||
skipped: f.skipped,
|
||||
deletedLocal: f.deletedLocal,
|
||||
deletedRemote: f.deletedRemote,
|
||||
durationMs: f.durationMs.toInt(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import '../../src/rust/api/ffi_types.dart' as ffi;
|
||||
|
||||
class SyncStatusModel {
|
||||
final String state;
|
||||
final int syncedFiles;
|
||||
final int totalFiles;
|
||||
final int uploadingCount;
|
||||
final int downloadingCount;
|
||||
final int conflictCount;
|
||||
final int errorCount;
|
||||
final String? lastSyncTime;
|
||||
final String? errorMessage;
|
||||
|
||||
const SyncStatusModel({
|
||||
this.state = 'idle',
|
||||
this.syncedFiles = 0,
|
||||
this.totalFiles = 0,
|
||||
this.uploadingCount = 0,
|
||||
this.downloadingCount = 0,
|
||||
this.conflictCount = 0,
|
||||
this.errorCount = 0,
|
||||
this.lastSyncTime,
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
bool get isIdle => state == 'idle';
|
||||
bool get isInitializing => state == 'initializing';
|
||||
bool get isInitialSync => state == 'initialSync';
|
||||
bool get isContinuous => state == 'continuous';
|
||||
bool get isPaused => state == 'paused';
|
||||
bool get isError => state == 'error';
|
||||
bool get isStopped => state == 'stopped';
|
||||
bool get isActive => isInitializing || isInitialSync || isContinuous;
|
||||
|
||||
static SyncStatusModel fromFfi(ffi.SyncStatusFfi f) {
|
||||
return SyncStatusModel(
|
||||
state: f.state,
|
||||
syncedFiles: f.syncedFiles.toInt(),
|
||||
totalFiles: f.totalFiles.toInt(),
|
||||
uploadingCount: f.uploadingCount,
|
||||
downloadingCount: f.downloadingCount,
|
||||
conflictCount: f.conflictCount,
|
||||
errorCount: f.errorCount,
|
||||
lastSyncTime: f.lastSyncTime,
|
||||
errorMessage: f.errorMessage,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
class SyncTaskModel {
|
||||
final String id;
|
||||
final String trigger;
|
||||
final int totalCount;
|
||||
final int completedCount;
|
||||
final int failedCount;
|
||||
final String status;
|
||||
final String createdAt;
|
||||
final String updatedAt;
|
||||
final String? finishedAt;
|
||||
|
||||
const SyncTaskModel({
|
||||
required this.id,
|
||||
required this.trigger,
|
||||
required this.totalCount,
|
||||
required this.completedCount,
|
||||
required this.failedCount,
|
||||
required this.status,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
this.finishedAt,
|
||||
});
|
||||
|
||||
String get shortId => id.length > 8 ? id.substring(0, 8) : id;
|
||||
|
||||
String get triggerLabel => switch (trigger) {
|
||||
'initial_sync' => '初始同步',
|
||||
'continuous' => '持续同步',
|
||||
'manual' => '手动同步',
|
||||
_ => trigger,
|
||||
};
|
||||
|
||||
String get statusLabel => switch (status) {
|
||||
'pending' => '等待中',
|
||||
'running' => '执行中',
|
||||
'completed' => '已完成',
|
||||
'failed' => '失败',
|
||||
'cancelled' => '已取消',
|
||||
_ => status,
|
||||
};
|
||||
|
||||
double get progress =>
|
||||
totalCount > 0 ? completedCount / totalCount : 0.0;
|
||||
}
|
||||
|
||||
class SyncTaskItemModel {
|
||||
final int id;
|
||||
final String taskId;
|
||||
final String relativePath;
|
||||
final String actionType;
|
||||
final String status;
|
||||
final int fileSize;
|
||||
final String? errorMessage;
|
||||
final String createdAt;
|
||||
final String updatedAt;
|
||||
|
||||
const SyncTaskItemModel({
|
||||
required this.id,
|
||||
required this.taskId,
|
||||
required this.relativePath,
|
||||
required this.actionType,
|
||||
required this.status,
|
||||
required this.fileSize,
|
||||
this.errorMessage,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
});
|
||||
|
||||
String get actionLabel => switch (actionType) {
|
||||
'upload' => '上传',
|
||||
'download' => '下载',
|
||||
'delete_local' => '删本地',
|
||||
'delete_remote' => '删远程',
|
||||
'rename' => '重命名',
|
||||
'move' => '移动',
|
||||
'mkdir_remote' => '创建远程目录',
|
||||
'mkdir_local' => '创建本地目录',
|
||||
'conflict_resolve' => '冲突解决',
|
||||
'create_placeholder' => '创建占位符',
|
||||
_ => actionType,
|
||||
};
|
||||
|
||||
String get statusLabel => switch (status) {
|
||||
'pending' => '未开始',
|
||||
'running' => '进行中',
|
||||
'completed' => '已完成',
|
||||
'failed' => '失败',
|
||||
'skipped' => '跳过',
|
||||
_ => status,
|
||||
};
|
||||
|
||||
String get filename {
|
||||
final parts = relativePath.split('/');
|
||||
return parts.isNotEmpty ? parts.last : relativePath;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user