diff --git a/flutter/lib/models/file_model.dart b/flutter/lib/models/file_model.dart index 6be69aa85..c77afcbb4 100644 --- a/flutter/lib/models/file_model.dart +++ b/flutter/lib/models/file_model.dart @@ -104,10 +104,11 @@ class FileModel { // If `skip == true`, it means to skip this file without showing dialog. // Because `resp` may be null after the user operation or the last remembered operation, // and we should distinguish them. - final resp = overrideConfirm ?? (!skip - ? await showFileConfirmDialog( - translate("Overwrite"), "${evt['read_path']}", true) - : null); + final resp = overrideConfirm ?? + (!skip + ? await showFileConfirmDialog(translate("Overwrite"), + "${evt['read_path']}", true, evt['is_identical'] == "true") + : null); final id = int.tryParse(evt['id']) ?? 0; if (false == resp) { final jobIndex = jobController.getJob(id); @@ -147,7 +148,7 @@ class FileModel { bool fileConfirmCheckboxRemember = false; Future showFileConfirmDialog( - String title, String content, bool showCheckbox) async { + String title, String content, bool showCheckbox, bool isIdentical) async { fileConfirmCheckboxRemember = false; return await parent.target?.dialogManager.show( (setState, Function(bool? v) close) { @@ -172,6 +173,17 @@ class FileModel { style: const TextStyle(fontWeight: FontWeight.bold)), const SizedBox(height: 5), Text(content), + Offstage( + offstage: !isIdentical, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 12), + Text(translate("This file is identical with the peer's one"), + style: const TextStyle(fontWeight: FontWeight.w500)) + ], + ), + ), showCheckbox ? CheckboxListTile( contentPadding: const EdgeInsets.all(0), @@ -1242,7 +1254,8 @@ class FileDialogEventLoop var event = evt as _FileDialogEvent; event.setOverrideConfirm(_overrideConfirm); event.setSkip(_skip); - debugPrint("FileDialogEventLoop: consuming"); + debugPrint( + "FileDialogEventLoop: consuming"); } @override diff --git a/libs/hbb_common/protos/message.proto b/libs/hbb_common/protos/message.proto index be3a1e51e..0c29a5f19 100644 --- a/libs/hbb_common/protos/message.proto +++ b/libs/hbb_common/protos/message.proto @@ -301,6 +301,7 @@ message FileTransferDigest { uint64 last_modified = 3; uint64 file_size = 4; bool is_upload = 5; + bool is_identical = 6; } message FileTransferBlock { diff --git a/libs/hbb_common/src/fs.rs b/libs/hbb_common/src/fs.rs index 8ebfffc0a..41160f49d 100644 --- a/libs/hbb_common/src/fs.rs +++ b/libs/hbb_common/src/fs.rs @@ -821,20 +821,21 @@ pub fn is_write_need_confirmation( if path.exists() && path.is_file() { let metadata = std::fs::metadata(path)?; let modified_time = metadata.modified()?; - // let remote_mt = Duration::from_secs(digest.last_modified); + let remote_mt = Duration::from_secs(digest.last_modified); let local_mt = modified_time.duration_since(UNIX_EPOCH)?; // [Note] - // We decide not to compare the file with peers, + // We decide to give the decision whether to override the existing file to users, // which obey the behavior of the file manager in our system. - // - // if remote_mt == local_mt && digest.file_size == metadata.len() { - // return Ok(DigestCheckResult::IsSame); - // } + let mut is_identical = false; + if remote_mt == local_mt && digest.file_size == metadata.len() { + is_identical = true; + } Ok(DigestCheckResult::NeedConfirm(FileTransferDigest { id: digest.id, file_num: digest.file_num, last_modified: local_mt.as_secs(), file_size: metadata.len(), + is_identical, ..Default::default() })) } else { diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 1c7788193..c37f235c0 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -954,6 +954,7 @@ impl Remote { digest.file_num, read_path, true, + digest.is_identical ); } } @@ -997,6 +998,7 @@ impl Remote { digest.file_num, write_path, false, + digest.is_identical ); } } diff --git a/src/flutter.rs b/src/flutter.rs index 354e418eb..2262df660 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -420,7 +420,7 @@ impl InvokeUiSession for FlutterHandler { // unused in flutter // TEST flutter fn confirm_delete_files(&self, _id: i32, _i: i32, _name: String) {} - fn override_file_confirm(&self, id: i32, file_num: i32, to: String, is_upload: bool) { + fn override_file_confirm(&self, id: i32, file_num: i32, to: String, is_upload: bool, is_identical: bool) { self.push_event( "override_file_confirm", vec![ @@ -428,6 +428,7 @@ impl InvokeUiSession for FlutterHandler { ("file_num", &file_num.to_string()), ("read_path", &to), ("is_upload", &is_upload.to_string()), + ("is_identical", &is_identical.to_string()) ], ); } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 93d9c76fe..72d52ffd2 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index bdc2257b3..8807d5454 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "此文件与对方的一致") ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 651043850..ae7df823d 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 31ca52c11..ebd55d44f 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", "Tom brugernavn"), ("Empty Password", "Tom adgangskode"), ("Me", "Mig"), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 09fad80eb..26235b2af 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", "Leerer Benutzername"), ("Empty Password", "Leeres Passwort"), ("Me", "Ich"), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index 923d4b64e..bec769f22 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", "Κενό όνομα χρήστη"), ("Empty Password", "Κενός κωδικός πρόσβασης"), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 57a519338..9dd2e50b4 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index d15061286..8cf50154e 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", "Nombre de usuario vacío"), ("Empty Password", "Contraseña vacía"), ("Me", "Yo"), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index be9821083..2c820ea21 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 5798253ad..4617335de 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 672c65bbb..36080f5be 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index a6272dbd3..08f54500f 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 2333e23dd..3ff073c9c 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", "Nome Utente Vuoto"), ("Empty Password", "Password Vuota"), ("Me", "Io"), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 5b1bcec4c..bf15afb47 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 3b31b631b..0d4ea8e00 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index ccce435fc..0b0416f50 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 9574581e5..4aef1587d 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", "Gebruikersnaam Leeg"), ("Empty Password", "Wachtwoord Leeg"), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 5534bbe1b..cb96687cc 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 780bc46c6..ad430635d 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 5cfc2e5a3..83b84e6d9 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index c354c4685..804ee83ee 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 3abea8029..8f7b66f71 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 820b7a7db..8b3f29ac1 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index e81124d5c..5f3bdf93f 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index d237b8895..f5d24d604 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index 8e7ecf824..1d510b107 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index e0807d892..7345edb9c 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 085ed025d..fb3a341d9 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index 6b3e34e48..3e50acf66 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index c92044e39..19006c7d1 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index a16bf26b8..3269963db 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 302dd9166..f4eb574f0 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index e72be8ea5..9bdcb743e 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -477,5 +477,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Username", ""), ("Empty Password", ""), ("Me", ""), + ("This file is identical with the peer's one", "") ].iter().cloned().collect(); } diff --git a/src/ui/file_transfer.tis b/src/ui/file_transfer.tis index f69f6d323..21c0562a1 100644 --- a/src/ui/file_transfer.tis +++ b/src/ui/file_transfer.tis @@ -778,12 +778,14 @@ handler.confirmDeleteFiles = function(id, i, name) { }); } -handler.overrideFileConfirm = function(id, file_num, to, is_upload) { +handler.overrideFileConfirm = function(id, file_num, to, is_upload, is_identical) { var jt = file_transfer.job_table; + var identical_msg = is_identical ? translate("This file is identical with the peer's one"): ""; msgbox("custom-skip", "Confirm Write Strategy", "
\ -
" + translate('Overwrite') + translate('files') + ".
\ +
" + translate('Overwrite') + " " + translate('files') + ".
\
" + translate('This file exists, skip or overwrite this file?') + "
\ " + to + "
\ +
" + identical_msg + "
\
" + translate('Do this for all conflicts') + "
\ ", "", function(res=null) { if (!res) { diff --git a/src/ui/remote.rs b/src/ui/remote.rs index ed16f1e0e..68decf955 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -197,10 +197,10 @@ impl InvokeUiSession for SciterHandler { self.call("confirmDeleteFiles", &make_args!(id, i, name)); } - fn override_file_confirm(&self, id: i32, file_num: i32, to: String, is_upload: bool) { + fn override_file_confirm(&self, id: i32, file_num: i32, to: String, is_upload: bool, is_identical: bool) { self.call( "overrideFileConfirm", - &make_args!(id, file_num, to, is_upload), + &make_args!(id, file_num, to, is_upload, is_identical), ); } diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 11bcff925..b90f5fbea 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -872,7 +872,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default { only_count: bool, ); fn confirm_delete_files(&self, id: i32, i: i32, name: String); - fn override_file_confirm(&self, id: i32, file_num: i32, to: String, is_upload: bool); + fn override_file_confirm(&self, id: i32, file_num: i32, to: String, is_upload: bool, is_identical: bool); fn update_block_input_state(&self, on: bool); fn job_progress(&self, id: i32, file_num: i32, speed: f64, finished_size: f64); fn adapt_size(&self);