Skip to content

Commit cf6c56c

Browse files
fix: restore page navigation state (#933)
* refactor: store browsing history for navigation purposes * refactor: remove page_size from FilterState * refactor: move on from the term "filter" in favor of "BrowsingState" * fix: refactors didn't propagate to the tests * fix: ruff complaints * fix: remaing refactoring errors * fix: navigation works again * fix: also store and restore query
1 parent 1e783a5 commit cf6c56c

File tree

12 files changed

+195
-154
lines changed

12 files changed

+195
-154
lines changed

src/tagstudio/core/library/alchemy/enums.py

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import structlog
66

7-
from tagstudio.core.query_lang.ast import AST, Constraint, ConstraintType
7+
from tagstudio.core.query_lang.ast import AST
88
from tagstudio.core.query_lang.parser import Parser
99

1010
MAX_SQL_VARIABLES = 32766 # 32766 is the max sql bind parameter count as defined here: https://github.com/sqlite/sqlite/blob/master/src/sqliteLimit.h#L140
@@ -72,59 +72,57 @@ class SortingModeEnum(enum.Enum):
7272

7373

7474
@dataclass
75-
class FilterState:
75+
class BrowsingState:
7676
"""Represent a state of the Library grid view."""
7777

78-
# these should remain
79-
page_size: int
8078
page_index: int = 0
8179
sorting_mode: SortingModeEnum = SortingModeEnum.DATE_ADDED
8280
ascending: bool = True
8381

84-
# these should be erased on update
85-
# Abstract Syntax Tree Of the current Search Query
86-
ast: AST | None = None
87-
88-
@property
89-
def limit(self):
90-
return self.page_size
82+
query: str | None = None
9183

84+
# Abstract Syntax Tree Of the current Search Query
9285
@property
93-
def offset(self):
94-
return self.page_size * self.page_index
86+
def ast(self) -> AST | None:
87+
if self.query is None:
88+
return None
89+
return Parser(self.query).parse()
9590

9691
@classmethod
97-
def show_all(cls, page_size: int) -> "FilterState":
98-
return FilterState(page_size=page_size)
92+
def show_all(cls) -> "BrowsingState":
93+
return BrowsingState()
9994

10095
@classmethod
101-
def from_search_query(cls, search_query: str, page_size: int) -> "FilterState":
102-
return cls(ast=Parser(search_query).parse(), page_size=page_size)
96+
def from_search_query(cls, search_query: str) -> "BrowsingState":
97+
return cls(query=search_query)
10398

10499
@classmethod
105-
def from_tag_id(cls, tag_id: int | str, page_size: int) -> "FilterState":
106-
return cls(ast=Constraint(ConstraintType.TagID, str(tag_id), []), page_size=page_size)
100+
def from_tag_id(cls, tag_id: int | str) -> "BrowsingState":
101+
return cls(query=f"tag_id:{str(tag_id)}")
107102

108103
@classmethod
109-
def from_path(cls, path: Path | str, page_size: int) -> "FilterState":
110-
return cls(ast=Constraint(ConstraintType.Path, str(path).strip(), []), page_size=page_size)
104+
def from_path(cls, path: Path | str) -> "BrowsingState":
105+
return cls(query=f'path:"{str(path).strip()}"')
111106

112107
@classmethod
113-
def from_mediatype(cls, mediatype: str, page_size: int) -> "FilterState":
114-
return cls(ast=Constraint(ConstraintType.MediaType, mediatype, []), page_size=page_size)
108+
def from_mediatype(cls, mediatype: str) -> "BrowsingState":
109+
return cls(query=f"mediatype:{mediatype}")
115110

116111
@classmethod
117-
def from_filetype(cls, filetype: str, page_size: int) -> "FilterState":
118-
return cls(ast=Constraint(ConstraintType.FileType, filetype, []), page_size=page_size)
112+
def from_filetype(cls, filetype: str) -> "BrowsingState":
113+
return cls(query=f"filetype:{filetype}")
119114

120115
@classmethod
121-
def from_tag_name(cls, tag_name: str, page_size: int) -> "FilterState":
122-
return cls(ast=Constraint(ConstraintType.Tag, tag_name, []), page_size=page_size)
116+
def from_tag_name(cls, tag_name: str) -> "BrowsingState":
117+
return cls(query=f'tag:"{tag_name}"')
118+
119+
def with_page_index(self, index: int) -> "BrowsingState":
120+
return replace(self, page_index=index)
123121

124-
def with_sorting_mode(self, mode: SortingModeEnum) -> "FilterState":
122+
def with_sorting_mode(self, mode: SortingModeEnum) -> "BrowsingState":
125123
return replace(self, sorting_mode=mode)
126124

127-
def with_sorting_direction(self, ascending: bool) -> "FilterState":
125+
def with_sorting_direction(self, ascending: bool) -> "BrowsingState":
128126
return replace(self, ascending=ascending)
129127

130128

src/tagstudio/core/library/alchemy/library.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@
6161
from tagstudio.core.library.alchemy.db import make_tables
6262
from tagstudio.core.library.alchemy.enums import (
6363
MAX_SQL_VARIABLES,
64+
BrowsingState,
6465
FieldTypeEnum,
65-
FilterState,
6666
SortingModeEnum,
6767
)
6868
from tagstudio.core.library.alchemy.fields import (
@@ -857,13 +857,14 @@ def get_paths(self, glob: str | None = None, limit: int = -1) -> list[str]:
857857

858858
def search_library(
859859
self,
860-
search: FilterState,
860+
search: BrowsingState,
861+
page_size: int,
861862
) -> SearchResult:
862863
"""Filter library by search query.
863864
864865
:return: number of entries matching the query and one page of results.
865866
"""
866-
assert isinstance(search, FilterState)
867+
assert isinstance(search, BrowsingState)
867868
assert self.engine
868869

869870
with Session(self.engine, expire_on_commit=False) as session:
@@ -902,7 +903,7 @@ def search_library(
902903
sort_on = func.lower(Entry.path)
903904

904905
statement = statement.order_by(asc(sort_on) if search.ascending else desc(sort_on))
905-
statement = statement.limit(search.limit).offset(search.offset)
906+
statement = statement.limit(page_size).offset(search.page_index * page_size)
906907

907908
logger.info(
908909
"searching library",

src/tagstudio/core/utils/dupe_files.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import structlog
66

7-
from tagstudio.core.library.alchemy.enums import FilterState
7+
from tagstudio.core.library.alchemy.enums import BrowsingState
88
from tagstudio.core.library.alchemy.library import Library
99
from tagstudio.core.library.alchemy.models import Entry
1010

@@ -52,7 +52,7 @@ def refresh_dupe_files(self, results_filepath: str | Path):
5252
continue
5353

5454
results = self.library.search_library(
55-
FilterState.from_path(path_relative, page_size=500),
55+
BrowsingState.from_path(path_relative), 500
5656
)
5757

5858
if not results:

src/tagstudio/qt/modals/fix_unlinked.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def __init__(self, library: "Library", driver: "QtDriver"):
6363
self.relink_class.done.connect(
6464
# refresh the grid
6565
lambda: (
66-
self.driver.filter_items(),
66+
self.driver.update_browsing_state(),
6767
self.refresh_missing_files(),
6868
)
6969
)
@@ -78,7 +78,7 @@ def __init__(self, library: "Library", driver: "QtDriver"):
7878
lambda: (
7979
self.set_missing_count(),
8080
# refresh the grid
81-
self.driver.filter_items(),
81+
self.driver.update_browsing_state(),
8282
)
8383
)
8484
self.delete_button.clicked.connect(self.delete_modal.show)

src/tagstudio/qt/modals/tag_search.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
)
2525

2626
from tagstudio.core.constants import RESERVED_TAG_END, RESERVED_TAG_START
27-
from tagstudio.core.library.alchemy.enums import FilterState, TagColorEnum
27+
from tagstudio.core.library.alchemy.enums import BrowsingState, TagColorEnum
2828
from tagstudio.core.library.alchemy.library import Library
2929
from tagstudio.core.library.alchemy.models import Tag
3030
from tagstudio.core.palette import ColorType, get_tag_color
@@ -292,9 +292,7 @@ def set_tag_widget(self, tag: Tag | None, index: int):
292292
tag_widget.search_for_tag_action.triggered.connect(
293293
lambda checked=False, tag_id=tag.id: (
294294
self.driver.main_window.searchField.setText(f"tag_id:{tag_id}"),
295-
self.driver.filter_items(
296-
FilterState.from_tag_id(tag_id, page_size=self.driver.settings.page_size)
297-
),
295+
self.driver.update_browsing_state(BrowsingState.from_tag_id(tag_id)),
298296
)
299297
)
300298
tag_widget.search_for_tag_action.setEnabled(True)

0 commit comments

Comments
 (0)