From 16bb321f7131f3148925685b927c28f5348111d2 Mon Sep 17 00:00:00 2001 From: Ludvig Sandh Date: Sat, 17 Jan 2026 14:29:27 +0100 Subject: [PATCH 1/8] fix: faulty progress bar The progress bar UI element always showed 1 step ahead of what it supposed to, also causing the last step to display a visual glitch (empty window) --- src/tagstudio/qt/mixed/progress_bar.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tagstudio/qt/mixed/progress_bar.py b/src/tagstudio/qt/mixed/progress_bar.py index 9dba568a0..24d54711e 100644 --- a/src/tagstudio/qt/mixed/progress_bar.py +++ b/src/tagstudio/qt/mixed/progress_bar.py @@ -46,14 +46,17 @@ def update_progress(self, value: int): def _update_progress_unknown_iterable(self, value): if hasattr(value, "__getitem__"): - self.update_progress(value[0] + 1) + self.update_progress(value[0]) else: - self.update_progress(value + 1) + self.update_progress(value) def from_iterable_function( self, function: Callable, update_label_callback: Callable | None, *done_callbacks ): - """Display the progress widget from a threaded iterable function.""" + """Display the progress widget from a threaded iterable function. + + Method expects the iterable to yield the number of completed objects. + """ iterator = FunctionIterator(function) iterator.value.connect(lambda x: self._update_progress_unknown_iterable(x)) if update_label_callback: From cfe80f455f55b077c0a133465e27775adee1aea5 Mon Sep 17 00:00:00 2001 From: Ludvig Sandh Date: Sat, 17 Jan 2026 14:35:37 +0100 Subject: [PATCH 2/8] fix: corrected drop import progress bar text --- src/tagstudio/qt/mixed/drop_import_modal.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tagstudio/qt/mixed/drop_import_modal.py b/src/tagstudio/qt/mixed/drop_import_modal.py index 766ce6083..d57c0cb0d 100644 --- a/src/tagstudio/qt/mixed/drop_import_modal.py +++ b/src/tagstudio/qt/mixed/drop_import_modal.py @@ -168,9 +168,9 @@ def begin_transfer(self, choice: DuplicateChoice | None = None): def displayed_text(x): return Translations.format( "drop_import.progress.label.singular" - if x[0] + 1 == 1 + if x[0] == 1 else "drop_import.progress.label.plural", - count=x[0] + 1, + count=x[0], suffix=f" {x[1]} {self.choice.value}" if self.choice else "", ) @@ -194,6 +194,7 @@ def copy_files(self): file_count = 0 duplicated_files_progress = 0 for file in self.files: + yield [file_count, duplicated_files_progress] if file.is_dir(): continue @@ -214,7 +215,6 @@ def copy_files(self): shutil.copyfile(file, unwrap(self.driver.lib.library_dir) / dest_file) file_count += 1 - yield [file_count, duplicated_files_progress] def _get_relative_path(self, path: Path) -> Path: for dir in self.dirs_in_root: From 691bbd86e9adb2482ce6b6801a53dc45367268b1 Mon Sep 17 00:00:00 2001 From: Ludvig Sandh Date: Sat, 17 Jan 2026 14:41:44 +0100 Subject: [PATCH 3/8] fix: corrected relink progress bar Update progress bar at the beginning of the relink iteration instead of the end, which previously showed incorrect progress text and an empty window during the first iteration. --- .../core/library/alchemy/registries/unlinked_registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tagstudio/core/library/alchemy/registries/unlinked_registry.py b/src/tagstudio/core/library/alchemy/registries/unlinked_registry.py index 8058df85f..521a84f19 100644 --- a/src/tagstudio/core/library/alchemy/registries/unlinked_registry.py +++ b/src/tagstudio/core/library/alchemy/registries/unlinked_registry.py @@ -68,6 +68,7 @@ def fix_unlinked_entries(self) -> Iterator[int]: self.files_fixed_count = 0 matched_entries: list[Entry] = [] for i, entry in enumerate(self.unlinked_entries): + yield i item_matches = self.match_unlinked_file_entry(entry) if len(item_matches) == 1: logger.info( @@ -84,7 +85,6 @@ def fix_unlinked_entries(self) -> Iterator[int]: continue self.files_fixed_count += 1 matched_entries.append(entry) - yield i for entry in matched_entries: self.unlinked_entries.remove(entry) From 523decd6b984ef30e9432c8911c679b335cb7a76 Mon Sep 17 00:00:00 2001 From: Ludvig Sandh Date: Sat, 17 Jan 2026 15:29:58 +0100 Subject: [PATCH 4/8] fix: corrected 'refresh ignore entries' progress bar Update progress bar at the beginning of the refresh loop iteration instead of the end, which previously showed incorrect progress text and an empty window during the first iteration. --- .../core/library/alchemy/registries/ignored_registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tagstudio/core/library/alchemy/registries/ignored_registry.py b/src/tagstudio/core/library/alchemy/registries/ignored_registry.py index a864e248e..9e31b1e76 100644 --- a/src/tagstudio/core/library/alchemy/registries/ignored_registry.py +++ b/src/tagstudio/core/library/alchemy/registries/ignored_registry.py @@ -39,12 +39,12 @@ def refresh_ignored_entries(self) -> Iterator[int]: library_dir: Path = unwrap(self.lib.library_dir) for i, entry in enumerate(self.lib.all_entries()): + yield i if not Ignore.compiled_patterns: # If the compiled_patterns has malfunctioned, don't consider that a false positive yield i elif Ignore.compiled_patterns.match(library_dir / entry.path): self.ignored_entries.append(entry) - yield i def remove_ignored_entries(self) -> None: self.lib.remove_entries(list(map(lambda ignored: ignored.id, self.ignored_entries))) From 094c9206a4e0fe787a92dd9244416c615bab3c57 Mon Sep 17 00:00:00 2001 From: Ludvig Sandh Date: Sat, 17 Jan 2026 15:32:41 +0100 Subject: [PATCH 5/8] fix: corrected 'refresh unlinked' progress bar Update progress bar at the beginning of the refresh loop iteration instead of the end, which previously showed incorrect progress text and an empty window during the first iteration. --- .../core/library/alchemy/registries/unlinked_registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tagstudio/core/library/alchemy/registries/unlinked_registry.py b/src/tagstudio/core/library/alchemy/registries/unlinked_registry.py index 521a84f19..dfcbbddf8 100644 --- a/src/tagstudio/core/library/alchemy/registries/unlinked_registry.py +++ b/src/tagstudio/core/library/alchemy/registries/unlinked_registry.py @@ -34,10 +34,10 @@ def refresh_unlinked_files(self) -> Iterator[int]: self.unlinked_entries = [] for i, entry in enumerate(self.lib.all_entries()): + yield i full_path = unwrap(self.lib.library_dir) / entry.path if not full_path.exists() or not full_path.is_file(): self.unlinked_entries.append(entry) - yield i def match_unlinked_file_entry(self, match_entry: Entry) -> list[Path]: """Try and match unlinked file entries with matching results in the library directory. From 9cd0c45be8f08f46ccaafd1312fdd5c229fdb329 Mon Sep 17 00:00:00 2001 From: Ludvig Sandh Date: Sat, 17 Jan 2026 15:52:11 +0100 Subject: [PATCH 6/8] fix: corrected 'mirror entries' progress bar Same as last commit --- src/tagstudio/qt/mixed/mirror_entries_modal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tagstudio/qt/mixed/mirror_entries_modal.py b/src/tagstudio/qt/mixed/mirror_entries_modal.py index d67cf12ed..81adf521c 100644 --- a/src/tagstudio/qt/mixed/mirror_entries_modal.py +++ b/src/tagstudio/qt/mixed/mirror_entries_modal.py @@ -95,9 +95,9 @@ def mirror_entries_runnable(self): mirrored: list = [] lib = self.driver.lib for i, entries in enumerate(self.tracker.groups): + yield i lib.mirror_entry_fields(*entries) sleep(0.005) - yield i for d in mirrored: self.tracker.groups.remove(d) From 1df290fc23a06ac02d3f63bf5d12a6989eb76728 Mon Sep 17 00:00:00 2001 From: Ludvig Sandh Date: Sat, 17 Jan 2026 15:53:59 +0100 Subject: [PATCH 7/8] fix: Unknown key in 'mirror entries' progress bar text (translation formatting) --- src/tagstudio/qt/mixed/mirror_entries_modal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tagstudio/qt/mixed/mirror_entries_modal.py b/src/tagstudio/qt/mixed/mirror_entries_modal.py index 81adf521c..fc0f91a93 100644 --- a/src/tagstudio/qt/mixed/mirror_entries_modal.py +++ b/src/tagstudio/qt/mixed/mirror_entries_modal.py @@ -74,7 +74,7 @@ def refresh_list(self): def mirror_entries(self): def displayed_text(x): return Translations.format( - "entries.mirror.label", idx=x + 1, count=self.tracker.groups_count + "entries.mirror.label", idx=x, total=self.tracker.groups_count ) pw = ProgressWidget( From 003630d4f19acc86a4da3f279fde6ceb07f3b5f0 Mon Sep 17 00:00:00 2001 From: Ludvig Sandh Date: Sat, 17 Jan 2026 16:15:19 +0100 Subject: [PATCH 8/8] fix: corrected 'merge duplicates' progress bar Note: Seems like this bar is never used in the UI. But if it is in the future, this fixes it just like the other progress bars. --- .../core/library/alchemy/registries/dupe_files_registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tagstudio/core/library/alchemy/registries/dupe_files_registry.py b/src/tagstudio/core/library/alchemy/registries/dupe_files_registry.py index d99a4f498..d810e2467 100644 --- a/src/tagstudio/core/library/alchemy/registries/dupe_files_registry.py +++ b/src/tagstudio/core/library/alchemy/registries/dupe_files_registry.py @@ -80,7 +80,7 @@ def merge_dupe_entries(self): ) for i, entries in enumerate(self.groups): + yield i remove_ids = entries[1:] logger.info("Removing entries group", ids=remove_ids) self.library.remove_entries(remove_ids) - yield i - 1 # The -1 waits for the next step to finish