feat(sync): WebDAV vault sync
All checks were successful
CI / Windows build (push) Successful in 12m32s
All checks were successful
CI / Windows build (push) Successful in 12m32s
Two-way sync of the vault folder to a user-configured WebDAV server, so annotations (which travel with the file) sync with the file. - WebDavSyncService.syncNow: per-file decision — local-only uploads, remote-only downloads, and when BOTH sides changed since the last sync it keeps the loser as <file>.conflict-<mtime> on both sides (last-write-wins by mtime) so no data is ever lost. Creates dirs as needed; deletes are conservative. - The decision logic is pure and unit-tested against a fake WebDAV client; the real client is a thin http adapter (no dio dependency). - Settings: WebDAV URL / user / password / remote folder, Test connection, Sync now (with status + last-synced), and an auto-sync toggle (default OFF). Real server round-trips are device/server-validated. Credentials are in SharedPreferences for now (TODO secure-storage). analyze clean, 432 tests.
This commit is contained in:
@@ -376,4 +376,76 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get vaultUpdated => '笔记库文件夹已更新';
|
||||
|
||||
@override
|
||||
String get syncSection => '同步(WebDAV)';
|
||||
|
||||
@override
|
||||
String get syncServerUrl => '服务器地址';
|
||||
|
||||
@override
|
||||
String get syncServerUrlHint =>
|
||||
'https://dav.example.com/remote.php/dav/files/me';
|
||||
|
||||
@override
|
||||
String get syncUsername => '用户名';
|
||||
|
||||
@override
|
||||
String get syncPassword => '密码';
|
||||
|
||||
@override
|
||||
String get syncRemoteFolder => '远程文件夹';
|
||||
|
||||
@override
|
||||
String get syncRemoteFolderHint => 'BadNote';
|
||||
|
||||
@override
|
||||
String get syncSave => '保存';
|
||||
|
||||
@override
|
||||
String get syncSaved => '同步设置已保存';
|
||||
|
||||
@override
|
||||
String get syncTestConnection => '测试连接';
|
||||
|
||||
@override
|
||||
String get syncTestOk => '连接成功';
|
||||
|
||||
@override
|
||||
String syncTestFailed(String error) {
|
||||
return '连接失败:$error';
|
||||
}
|
||||
|
||||
@override
|
||||
String get syncNow => '立即同步';
|
||||
|
||||
@override
|
||||
String get syncRunning => '同步中…';
|
||||
|
||||
@override
|
||||
String get syncNeverRun => '尚未同步';
|
||||
|
||||
@override
|
||||
String syncLastRun(String when) {
|
||||
return '上次同步:$when';
|
||||
}
|
||||
|
||||
@override
|
||||
String syncResultSummary(int uploaded, int downloaded, int conflicts) {
|
||||
return '上传 $uploaded · 下载 $downloaded · 冲突 $conflicts';
|
||||
}
|
||||
|
||||
@override
|
||||
String syncFailed(String error) {
|
||||
return '同步失败:$error';
|
||||
}
|
||||
|
||||
@override
|
||||
String get syncAuto => '启动时自动同步';
|
||||
|
||||
@override
|
||||
String get syncCredentialsNote => '凭据以明文保存在本地,建议使用专用的应用密码。';
|
||||
|
||||
@override
|
||||
String get syncNotConfigured => '请输入服务器地址以启用同步。';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user