diff --git a/flutter/lib/common/shared_state.dart b/flutter/lib/common/shared_state.dart index 5ae618dfe..ebac18dac 100644 --- a/flutter/lib/common/shared_state.dart +++ b/flutter/lib/common/shared_state.dart @@ -202,6 +202,28 @@ class RemoteCountState { static RxInt find() => Get.find(tag: tag()); } +class PeerBoolOption { + static String tag(String id, String opt) => 'peer_{$opt}_$id'; + + static void init(String id, String opt, bool Function() init_getter) { + final key = tag(id, opt); + if (!Get.isRegistered(tag: key)) { + final RxBool value = RxBool(init_getter()); + Get.put(value, tag: key); + } + } + + static void delete(String id, String opt) { + final key = tag(id, opt); + if (Get.isRegistered(tag: key)) { + Get.delete(tag: key); + } + } + + static RxBool find(String id, String opt) => + Get.find(tag: tag(id, opt)); +} + class PeerStringOption { static String tag(String id, String opt) => 'peer_{$opt}_$id'; diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index dae3fa612..117a0ab02 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -51,6 +51,7 @@ class _RemotePageState extends State String keyboardMode = "legacy"; final _cursorOverImage = false.obs; late RxBool _showRemoteCursor; + late RxBool _zoomCursor; late RxBool _remoteCursorMoved; late RxBool _keyboardEnabled; @@ -68,6 +69,10 @@ class _RemotePageState extends State KeyboardEnabledState.init(id); ShowRemoteCursorState.init(id); RemoteCursorMovedState.init(id); + final optZoomCursor = 'zoom-cursor'; + PeerBoolOption.init(id, optZoomCursor, + () => bind.sessionGetToggleOptionSync(id: id, arg: optZoomCursor)); + _zoomCursor = PeerBoolOption.find(id, optZoomCursor); _showRemoteCursor = ShowRemoteCursorState.find(id); _keyboardEnabled = KeyboardEnabledState.find(id); _remoteCursorMoved = RemoteCursorMovedState.find(id); @@ -216,6 +221,7 @@ class _RemotePageState extends State }); return ImagePaint( id: widget.id, + zoomCursor: _zoomCursor, cursorOverImage: _cursorOverImage, keyboardEnabled: _keyboardEnabled, remoteCursorMoved: _remoteCursorMoved, @@ -233,6 +239,7 @@ class _RemotePageState extends State visible: _showRemoteCursor.isTrue && _remoteCursorMoved.isTrue, child: CursorPaint( id: widget.id, + zoomCursor: _zoomCursor, )))); paints.add(QualityMonitor(_ffi.qualityMonitorModel)); paints.add(RemoteMenubar( @@ -253,6 +260,7 @@ class _RemotePageState extends State class ImagePaint extends StatefulWidget { final String id; + final Rx zoomCursor; final Rx cursorOverImage; final Rx keyboardEnabled; final Rx remoteCursorMoved; @@ -261,6 +269,7 @@ class ImagePaint extends StatefulWidget { ImagePaint( {Key? key, required this.id, + required this.zoomCursor, required this.cursorOverImage, required this.keyboardEnabled, required this.remoteCursorMoved, @@ -277,6 +286,7 @@ class _ImagePaintState extends State { final ScrollController _vertical = ScrollController(); String get id => widget.id; + Rx get zoomCursor => widget.zoomCursor; Rx get cursorOverImage => widget.cursorOverImage; Rx get keyboardEnabled => widget.keyboardEnabled; Rx get remoteCursorMoved => widget.remoteCursorMoved; @@ -357,7 +367,7 @@ class _ImagePaintState extends State { if (cache == null) { return MouseCursor.defer; } else { - final key = cache.updateGetKey(scale); + final key = cache.updateGetKey(scale, zoomCursor.value); cursor.addKey(key); return FlutterCustomMemoryImageCursor( pixbuf: cache.data, @@ -500,8 +510,13 @@ class _ImagePaintState extends State { class CursorPaint extends StatelessWidget { final String id; + final RxBool zoomCursor; - const CursorPaint({Key? key, required this.id}) : super(key: key); + const CursorPaint({ + Key? key, + required this.id, + required this.zoomCursor, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -516,13 +531,21 @@ class CursorPaint extends StatelessWidget { hoty = m.defaultImage!.height / 2; } } - return CustomPaint( - painter: ImagePainter( - image: m.image ?? m.defaultImage, - x: m.x - hotx + c.x / c.scale, - y: m.y - hoty + c.y / c.scale, - scale: c.scale), - ); + return zoomCursor.isTrue + ? CustomPaint( + painter: ImagePainter( + image: m.image ?? m.defaultImage, + x: m.x - hotx + c.x / c.scale, + y: m.y - hoty + c.y / c.scale, + scale: c.scale), + ) + : CustomPaint( + painter: ImagePainter( + image: m.image ?? m.defaultImage, + x: (m.x - hotx) * c.scale + c.x, + y: (m.y - hoty) * c.scale + c.y, + scale: 1.0), + ); } } diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index cdbeb0bed..6db5a7fb7 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -47,7 +47,8 @@ class MenubarState { } _initSet(bool s, bool p) { - show = RxBool(s); + // Show remubar when connection is established. + show = RxBool(true); _pin = RxBool(p); } @@ -1109,6 +1110,25 @@ class _RemoteMenubarState extends State { ); }()); + /// Show remote cursor + displayMenu.add(() { + final opt = 'zoom-cursor'; + final state = PeerBoolOption.find(widget.id, opt); + return MenuEntrySwitch2( + switchType: SwitchType.scheckbox, + text: translate('Zoom cursor'), + getter: () { + return state; + }, + setter: (bool v) async { + state.value = v; + await bind.sessionToggleOption(id: widget.id, value: opt); + }, + padding: padding, + dismissOnClicked: true, + ); + }()); + /// Show quality monitor displayMenu.add(MenuEntrySwitch( switchType: SwitchType.scheckbox, diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index a39bc7d08..a074bf266 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -696,6 +696,8 @@ class CursorData { final img2.Image? image; double scale; Uint8List? data; + final double hotxOrigin; + final double hotyOrigin; double hotx; double hoty; final int width; @@ -707,45 +709,53 @@ class CursorData { required this.image, required this.scale, required this.data, - required this.hotx, - required this.hoty, + required this.hotxOrigin, + required this.hotyOrigin, required this.width, required this.height, - }); + }) : hotx = hotxOrigin * scale, + hoty = hotxOrigin * scale; int _doubleToInt(double v) => (v * 10e6).round().toInt(); - double _checkUpdateScale(double scale) { - // Update data if scale changed. - if (Platform.isWindows) { - final tgtWidth = (width * scale).toInt(); - final tgtHeight = (width * scale).toInt(); - if (tgtWidth < kMinCursorSize || tgtHeight < kMinCursorSize) { - double sw = kMinCursorSize.toDouble() / width; - double sh = kMinCursorSize.toDouble() / height; - scale = sw < sh ? sh : sw; + double _checkUpdateScale(double scale, bool shouldScale) { + double oldScale = this.scale; + if (!shouldScale) { + scale = 1.0; + } else { + // Update data if scale changed. + if (Platform.isWindows) { + final tgtWidth = (width * scale).toInt(); + final tgtHeight = (width * scale).toInt(); + if (tgtWidth < kMinCursorSize || tgtHeight < kMinCursorSize) { + double sw = kMinCursorSize.toDouble() / width; + double sh = kMinCursorSize.toDouble() / height; + scale = sw < sh ? sh : sw; + } } - if (_doubleToInt(this.scale) != _doubleToInt(scale)) { + } + + if (Platform.isWindows) { + if (_doubleToInt(oldScale) != _doubleToInt(scale)) { data = img2 .copyResize( image!, width: (width * scale).toInt(), height: (height * scale).toInt(), + interpolation: img2.Interpolation.average, ) .getBytes(format: img2.Format.bgra); } } + this.scale = scale; - if (hotx > 0 && hoty > 0) { - // default cursor data - hotx = (width * scale) / 2; - hoty = (height * scale) / 2; - } + hotx = hotxOrigin * scale; + hoty = hotyOrigin * scale; return scale; } - String updateGetKey(double scale) { - scale = _checkUpdateScale(scale); + String updateGetKey(double scale, bool shouldScale) { + scale = _checkUpdateScale(scale, shouldScale); return '${peerId}_${id}_${_doubleToInt(width * scale)}_${_doubleToInt(height * scale)}'; } } @@ -811,8 +821,6 @@ class CursorModel with ChangeNotifier { if (_defaultCache == null) { Uint8List data; double scale = 1.0; - double hotx = (defaultCursorImage!.width * scale) / 2; - double hoty = (defaultCursorImage!.height * scale) / 2; if (Platform.isWindows) { data = defaultCursorImage!.getBytes(format: img2.Format.bgra); } else { @@ -825,8 +833,8 @@ class CursorModel with ChangeNotifier { image: defaultCursorImage?.clone(), scale: scale, data: data, - hotx: hotx, - hoty: hoty, + hotxOrigin: defaultCursorImage!.width / 2, + hotyOrigin: defaultCursorImage!.height / 2, width: defaultCursorImage!.width, height: defaultCursorImage!.height, ); @@ -996,10 +1004,8 @@ class CursorModel with ChangeNotifier { image: Platform.isWindows ? img2.Image.fromBytes(w, h, data) : null, scale: 1.0, data: data, - hotx: 0, - hoty: 0, - // hotx: _hotx, - // hoty: _hoty, + hotxOrigin: _hotx, + hotyOrigin: _hoty, width: w, height: h, ); diff --git a/libs/hbb_common/src/fs.rs b/libs/hbb_common/src/fs.rs index 6cc795a0d..dd8a7530e 100644 --- a/libs/hbb_common/src/fs.rs +++ b/libs/hbb_common/src/fs.rs @@ -380,7 +380,7 @@ impl TransferJob { } } - pub async fn write(&mut self, block: FileTransferBlock, raw: Option<&[u8]>) -> ResultType<()> { + pub async fn write(&mut self, block: FileTransferBlock) -> ResultType<()> { if block.id != self.id { bail!("Wrong id"); } @@ -402,20 +402,15 @@ impl TransferJob { let path = format!("{}.download", get_string(&path)); self.file = Some(File::create(&path).await?); } - let data = if let Some(data) = raw { - data - } else { - &block.data - }; if block.compressed { - let tmp = decompress(data); + let tmp = decompress(&block.data); self.file.as_mut().unwrap().write_all(&tmp).await?; self.finished_size += tmp.len() as u64; } else { - self.file.as_mut().unwrap().write_all(data).await?; - self.finished_size += data.len() as u64; + self.file.as_mut().unwrap().write_all(&block.data).await?; + self.finished_size += block.data.len() as u64; } - self.transferred += data.len() as u64; + self.transferred += block.data.len() as u64; Ok(()) } diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 6eb443103..86a9e2f2e 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -915,13 +915,8 @@ impl Remote { } } Some(file_response::Union::Block(block)) => { - log::info!( - "file response block, file id:{}, file num: {}", - block.id, - block.file_num - ); if let Some(job) = fs::get_job(block.id, &mut self.write_jobs) { - if let Err(_err) = job.write(block, None).await { + if let Err(_err) = job.write(block).await { // to-do: add "skip" for writing job } self.update_jobs_status(); diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 68c5dbf60..16bbdb590 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "或"), ("Continue with", "使用"), ("Elevate", "提权"), + ("Zoom cursor", "缩放鼠标"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 98bb9c5d3..0f262cd25 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index b98e5ba3f..c7362e26f 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 1e8083915..acc22a461 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 93394a91f..206229859 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index a00009b78..d0c569eff 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "o"), ("Continue with", "Continuar con"), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index b6c3d002b..b602bd404 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -388,5 +388,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "This PC"), ("or", "یا"), ("Continue with", "ادامه با"), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index ff4e2e083..f4ff46cdf 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "ou"), ("Continue with", "Continuer avec"), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 9bd5de216..aaad2e9f9 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "vagy"), ("Continue with", "Folytatás a következővel"), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 7d4ae1634..96e7d38f4 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 3490a9b77..fc6b936bf 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 2953f80cd..1ff301bba 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 2473ef2de..aa6c01e3d 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 1ce728db3..05055d1a3 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index ffe94432d..c62007778 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "albo"), ("Continue with", "Kontynuuj z"), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index e7bb0e73c..ca0fcead9 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index bc35cfcb2..41459404b 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "ou"), ("Continue with", "Continuar com"), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 9e9a60829..b5d747f9d 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "или"), ("Continue with", "Продолжить с"), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 3970ef3b9..0844c8442 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index d9fd7b9bb..9f1779119 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 01aa7ff07..6f3c9ba92 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "veya"), ("Continue with", "bununla devam et"), ("Elevate", "Yükseltme"), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index da57cf07c..900f25ccd 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", "提權"), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 10119d1e2..b336b1e36 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 8bb164a8f..c21fe8aa8 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -389,5 +389,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", ""), ("Continue with", ""), ("Elevate", ""), + ("Zoom cursor", ""), ].iter().cloned().collect(); } diff --git a/src/server/connection.rs b/src/server/connection.rs index 112d5f739..cb2ddc2c6 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1629,7 +1629,8 @@ async fn start_ipc( file_num, data, compressed}) = data { - stream.send(&Data::FS(ipc::FS::WriteBlock{id, file_num, data, compressed})).await?; + stream.send(&Data::FS(ipc::FS::WriteBlock{id, file_num, data: Bytes::new(), compressed})).await?; + stream.send_raw(data).await?; } else { stream.send(&data).await?; } diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 26b26bf92..5edf53507 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -1,3 +1,5 @@ +#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] +use std::iter::FromIterator; #[cfg(windows)] use std::sync::Arc; use std::{ @@ -8,8 +10,6 @@ use std::{ RwLock, }, }; -#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] -use std::iter::FromIterator; #[cfg(windows)] use clipboard::{cliprdr::CliprdrClientContext, empty_clipboard, set_conn_enabled, ContextSend}; @@ -343,8 +343,15 @@ impl IpcTaskRunner { Data::ChatMessage { text } => { self.cm.new_message(self.conn_id, text); } - Data::FS(fs) => { - handle_fs(fs, &mut write_jobs, &self.tx).await; + Data::FS(mut fs) => { + if let ipc::FS::WriteBlock { id, file_num, data: _, compressed } = fs { + if let Ok(bytes) = self.stream.next_raw().await { + fs = ipc::FS::WriteBlock{id, file_num, data:bytes.into(), compressed}; + handle_fs(fs, &mut write_jobs, &self.tx).await; + } + } else { + handle_fs(fs, &mut write_jobs, &self.tx).await; + } } #[cfg(windows)] Data::ClipbaordFile(_clip) => { @@ -597,16 +604,13 @@ async fn handle_fs(fs: ipc::FS, write_jobs: &mut Vec, tx: &Unbo } => { if let Some(job) = fs::get_job(id, write_jobs) { if let Err(err) = job - .write( - FileTransferBlock { - id, - file_num, - data, - compressed, - ..Default::default() - }, - None, - ) + .write(FileTransferBlock { + id, + file_num, + data, + compressed, + ..Default::default() + }) .await { send_raw(fs::new_error(id, err, file_num), &tx);