From 5cf41e86cf24902d938ef588d47149eea2b88821 Mon Sep 17 00:00:00 2001 From: Valeri Ochinski Date: Tue, 7 Nov 2023 01:35:19 +0300 Subject: [PATCH 1/2] Add basic speed/remaining time estimation I'm not exactly happy with it currently since it always overshoots. Something more complicated may be needed for decent UX. --- po/nxdumpclient.pot | 36 +++++++++++++++++++------------- src/UsbDeviceClient.vala | 3 +++ src/widgets/DeviceStatusRow.vala | 22 +++++++++++++++++-- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/po/nxdumpclient.pot b/po/nxdumpclient.pot index b53e0df..984be46 100644 --- a/po/nxdumpclient.pot +++ b/po/nxdumpclient.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: nxdumpclient\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-31 18:55+0300\n" +"POT-Creation-Date: 2023-11-06 20:42+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -194,50 +194,58 @@ msgstr "" msgid "Transfer progress" msgstr "" -#: src/widgets/DeviceStatusRow.vala:86 +#: src/widgets/DeviceStatusRow.vala:88 msgctxt "status" msgid "Uninitialized" msgstr "" -#: src/widgets/DeviceStatusRow.vala:89 +#: src/widgets/DeviceStatusRow.vala:91 msgctxt "status" msgid "Connected" msgstr "" -#: src/widgets/DeviceStatusRow.vala:92 +#: src/widgets/DeviceStatusRow.vala:94 msgctxt "status" msgid "Transferring file" msgstr "" -#: src/widgets/DeviceStatusRow.vala:95 +#: src/widgets/DeviceStatusRow.vala:97 msgctxt "status" msgid "Fatal error" msgstr "" -#: src/widgets/DeviceStatusRow.vala:121 +#. TODO: use StringBuilder.take on GLib >= 2.78 +#: src/widgets/DeviceStatusRow.vala:124 #, c-format msgctxt "file transfer progress" msgid "%s / %s" msgstr "" -#: src/widgets/DeviceStatusRow.vala:162 +#. FIXME: I18N +#: src/widgets/DeviceStatusRow.vala:136 +#, c-format +msgctxt "file transfer speed and min:sec remaining" +msgid "(%s/s, %02lld:%02lld remaining)" +msgstr "" + +#: src/widgets/DeviceStatusRow.vala:181 msgid "USB 1.1" msgstr "" -#: src/widgets/DeviceStatusRow.vala:165 +#: src/widgets/DeviceStatusRow.vala:184 msgid "USB 2.0" msgstr "" -#: src/widgets/DeviceStatusRow.vala:168 +#: src/widgets/DeviceStatusRow.vala:187 msgid "USB 3.0" msgstr "" -#: src/widgets/DeviceStatusRow.vala:171 +#: src/widgets/DeviceStatusRow.vala:190 msgctxt "speed string" msgid "N/A" msgstr "" -#: src/widgets/DeviceStatusRow.vala:179 +#: src/widgets/DeviceStatusRow.vala:198 msgctxt "version string" msgid "N/A" msgstr "" @@ -299,15 +307,15 @@ msgstr "" msgid "Not enough space for dump (%s required)" msgstr "" -#: src/UsbDeviceClient.vala:566 +#: src/UsbDeviceClient.vala:569 msgid "NCA checksum verification failed (non-standard dump options?)" msgstr "" -#: src/UsbDeviceClient.vala:600 +#: src/UsbDeviceClient.vala:603 msgid "NSP header" msgstr "" -#: src/UsbDeviceClient.vala:650 +#: src/UsbDeviceClient.vala:653 msgid "NCA checksum verification failed" msgstr "" diff --git a/src/UsbDeviceClient.vala b/src/UsbDeviceClient.vala index 814ca62..f9167d3 100644 --- a/src/UsbDeviceClient.vala +++ b/src/UsbDeviceClient.vala @@ -181,6 +181,7 @@ namespace NXDumpClient { public string transfer_file_name_inner { get; private set; default = ""; } // Used in NSP mode public int64 transfer_total_bytes { get; private set; default = 0; } public int64 transfer_current_bytes { get; private set; default = 0; } + public int64 transfer_started_time { get; private set; default = 0; } public uint16 max_packet_size { get { if (endpoint_input != null) { @@ -415,6 +416,7 @@ namespace NXDumpClient { transfer_file_name_inner = ""; transfer_total_bytes = file_size; transfer_current_bytes = 0; + transfer_started_time = get_monotonic_time(); status = TRANSFER; } finally { thaw_notify(); @@ -460,6 +462,7 @@ namespace NXDumpClient { transfer_file_name_inner = ""; transfer_total_bytes = file_size; transfer_current_bytes = 0; + transfer_started_time = get_monotonic_time(); } finally { thaw_notify(); } diff --git a/src/widgets/DeviceStatusRow.vala b/src/widgets/DeviceStatusRow.vala index 710b840..2e615b9 100644 --- a/src/widgets/DeviceStatusRow.vala +++ b/src/widgets/DeviceStatusRow.vala @@ -19,6 +19,8 @@ */ namespace NXDumpClient { + private const uint32 MIN_TRANSFER_SPEED_SIZE = 0x800000 * 5; + [GtkTemplate (ui = "/org/v1993/NXDumpClient/widgets/DeviceStatusRow.ui")] class DeviceStatusRow: Adw.Bin { protected UsbDeviceClient? device { get; set; default = null; } @@ -118,10 +120,26 @@ namespace NXDumpClient { requires(device != null) { transfer_fraction = ((double)device.transfer_current_bytes) / ((double)device.transfer_total_bytes); - transfer_text = C_("file transfer progress", "%s / %s").printf( + // TODO: use StringBuilder.take on GLib >= 2.78 + var builder = new StringBuilder(C_("file transfer progress", "%s / %s").printf( format_size(device.transfer_current_bytes), format_size(device.transfer_total_bytes) - ); + )); + + var time_passed = get_monotonic_time() - device.transfer_started_time; + if (device.transfer_current_bytes >= MIN_TRANSFER_SPEED_SIZE && time_passed > 0) { + var bytes_remaining = device.transfer_total_bytes - device.transfer_current_bytes; + var time_remaining = time_passed * bytes_remaining / device.transfer_current_bytes / 1000000; + var bytes_per_second = device.transfer_current_bytes * 1000000 / time_passed; + builder.append_c(' '); + builder.append_printf(C_("file transfer speed and min:sec remaining", "(%s/s, %02lld:%02lld remaining)"), + format_size(bytes_per_second), + time_remaining / 60, + time_remaining % 60 + ); + } + + transfer_text = builder.free_and_steal(); } private void transfer_started_cb(UsbDeviceClient client, File file, bool mass_transfer) { From eebfbc269807a0b30c811cb92440060b68d0a3fe Mon Sep 17 00:00:00 2001 From: Valeri Ochinski Date: Tue, 7 Nov 2023 03:54:08 +0300 Subject: [PATCH 2/2] Make remaining time estimation much better The initial estimate is pretty much 100% accurate now. --- po/nxdumpclient.pot | 26 +++++++++++++++----------- src/UsbDeviceClient.vala | 10 +++++++--- src/widgets/DeviceStatusRow.vala | 28 +++++++++++++++++----------- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/po/nxdumpclient.pot b/po/nxdumpclient.pot index 984be46..0b22360 100644 --- a/po/nxdumpclient.pot +++ b/po/nxdumpclient.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: nxdumpclient\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-06 20:42+0300\n" +"POT-Creation-Date: 2023-11-07 03:53+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -221,31 +221,35 @@ msgctxt "file transfer progress" msgid "%s / %s" msgstr "" -#. FIXME: I18N -#: src/widgets/DeviceStatusRow.vala:136 +#: src/widgets/DeviceStatusRow.vala:138 #, c-format msgctxt "file transfer speed and min:sec remaining" msgid "(%s/s, %02lld:%02lld remaining)" msgstr "" -#: src/widgets/DeviceStatusRow.vala:181 +#: src/widgets/DeviceStatusRow.vala:144 +msgctxt "file transfer speed and min:sec placeholder" +msgid "(-- B/s, --:-- remaining)" +msgstr "" + +#: src/widgets/DeviceStatusRow.vala:186 msgid "USB 1.1" msgstr "" -#: src/widgets/DeviceStatusRow.vala:184 +#: src/widgets/DeviceStatusRow.vala:189 msgid "USB 2.0" msgstr "" -#: src/widgets/DeviceStatusRow.vala:187 +#: src/widgets/DeviceStatusRow.vala:192 msgid "USB 3.0" msgstr "" -#: src/widgets/DeviceStatusRow.vala:190 +#: src/widgets/DeviceStatusRow.vala:195 msgctxt "speed string" msgid "N/A" msgstr "" -#: src/widgets/DeviceStatusRow.vala:198 +#: src/widgets/DeviceStatusRow.vala:203 msgctxt "version string" msgid "N/A" msgstr "" @@ -307,15 +311,15 @@ msgstr "" msgid "Not enough space for dump (%s required)" msgstr "" -#: src/UsbDeviceClient.vala:569 +#: src/UsbDeviceClient.vala:573 msgid "NCA checksum verification failed (non-standard dump options?)" msgstr "" -#: src/UsbDeviceClient.vala:603 +#: src/UsbDeviceClient.vala:607 msgid "NSP header" msgstr "" -#: src/UsbDeviceClient.vala:653 +#: src/UsbDeviceClient.vala:657 msgid "NCA checksum verification failed" msgstr "" diff --git a/src/UsbDeviceClient.vala b/src/UsbDeviceClient.vala index f9167d3..bb8e32d 100644 --- a/src/UsbDeviceClient.vala +++ b/src/UsbDeviceClient.vala @@ -65,7 +65,7 @@ namespace NXDumpClient { private const uint32 RESPONSE_SIZE = 0x10; private const uint DEFAULT_TIMEOUT = 5000; private const uint32 STATUS_SUCCESS = 0x0; - private const uint32 BLOCK_SIZE = 0x800000; + internal const uint32 BLOCK_SIZE = 0x800000; private const string NSP_MAGIC = "PFS0"; @@ -416,7 +416,7 @@ namespace NXDumpClient { transfer_file_name_inner = ""; transfer_total_bytes = file_size; transfer_current_bytes = 0; - transfer_started_time = get_monotonic_time(); + transfer_started_time = 0; status = TRANSFER; } finally { thaw_notify(); @@ -462,7 +462,7 @@ namespace NXDumpClient { transfer_file_name_inner = ""; transfer_total_bytes = file_size; transfer_current_bytes = 0; - transfer_started_time = get_monotonic_time(); + transfer_started_time = 0; } finally { thaw_notify(); } @@ -533,6 +533,10 @@ namespace NXDumpClient { checksum.update(incoming_data, incoming_data.length); } + if (transfer_started_time == 0) { + transfer_started_time = get_monotonic_time(); + } + transfer_progress.emit(); } diff --git a/src/widgets/DeviceStatusRow.vala b/src/widgets/DeviceStatusRow.vala index 2e615b9..f5d7ca5 100644 --- a/src/widgets/DeviceStatusRow.vala +++ b/src/widgets/DeviceStatusRow.vala @@ -19,7 +19,7 @@ */ namespace NXDumpClient { - private const uint32 MIN_TRANSFER_SPEED_SIZE = 0x800000 * 5; + private const uint32 MIN_TRANSFER_SPEED_SIZE = BLOCK_SIZE * 5; [GtkTemplate (ui = "/org/v1993/NXDumpClient/widgets/DeviceStatusRow.ui")] class DeviceStatusRow: Adw.Bin { @@ -126,17 +126,23 @@ namespace NXDumpClient { format_size(device.transfer_total_bytes) )); - var time_passed = get_monotonic_time() - device.transfer_started_time; - if (device.transfer_current_bytes >= MIN_TRANSFER_SPEED_SIZE && time_passed > 0) { - var bytes_remaining = device.transfer_total_bytes - device.transfer_current_bytes; - var time_remaining = time_passed * bytes_remaining / device.transfer_current_bytes / 1000000; - var bytes_per_second = device.transfer_current_bytes * 1000000 / time_passed; + if (device.transfer_total_bytes >= MIN_TRANSFER_SPEED_SIZE) { + var time_passed = get_monotonic_time() - device.transfer_started_time; + var current_bytes_adjusted = device.transfer_current_bytes - BLOCK_SIZE; builder.append_c(' '); - builder.append_printf(C_("file transfer speed and min:sec remaining", "(%s/s, %02lld:%02lld remaining)"), - format_size(bytes_per_second), - time_remaining / 60, - time_remaining % 60 - ); + if (current_bytes_adjusted > 0 && time_passed > 0) { + // Time is measured after the first transfer, so skip it + var bytes_remaining = device.transfer_total_bytes - current_bytes_adjusted; + var time_remaining = time_passed * bytes_remaining / current_bytes_adjusted / 1000000; + var bytes_per_second = current_bytes_adjusted * 1000000 / time_passed; + builder.append_printf(C_("file transfer speed and min:sec remaining", "(%s/s, %02lld:%02lld remaining)"), + format_size(bytes_per_second), + time_remaining / 60, + time_remaining % 60 + ); + } else { + builder.append(C_("file transfer speed and min:sec placeholder", "(-- B/s, --:-- remaining)")); + } } transfer_text = builder.free_and_steal();