mirror of
https://github.com/TagStudioDev/TagStudio.git
synced 2026-02-02 08:09:13 +00:00
feat: sort by "date added" to library (#674)
* ui: add sorting mode dropdown * feat: pass sorting mode to Library.search_library * feat: implement sorting by creation date * ui: add dropdown for sorting direction * ui: update shown entries after changing sorting mode / direction * docs: mark sorting by "Date Created" as completed * fix: remove sorting options that have not been implemented * fix: rename sorting mode to "Date Added" * fix: check off the right item on the roadmap * feat: translate sorting UI * fix: address review comments
This commit is contained in:
@@ -99,6 +99,7 @@ Features are broken up into the following priority levels, with nested prioritie
|
||||
- [ ] Fuzzy Search [LOW] [#400](https://github.com/TagStudioDev/TagStudio/issues/400)
|
||||
- [ ] Sortable results [HIGH] [#68](https://github.com/TagStudioDev/TagStudio/issues/68)
|
||||
- [ ] Sort by relevance [HIGH]
|
||||
- [x] Sort by date added [HIGH]
|
||||
- [ ] Sort by date created [HIGH]
|
||||
- [ ] Sort by date modified [HIGH]
|
||||
- [ ] Sort by date taken (photos) [MEDIUM]
|
||||
@@ -182,6 +183,7 @@ These version milestones are rough estimations for when the previous core featur
|
||||
- [ ] Field content search [HIGH]
|
||||
- [ ] Sortable results [HIGH]
|
||||
- [ ] Sort by relevance [HIGH]
|
||||
- [x] Sort by date added [HIGH]
|
||||
- [ ] Sort by date created [HIGH]
|
||||
- [ ] Sort by date modified [HIGH]
|
||||
- [ ] Sort by date taken (photos) [MEDIUM]
|
||||
|
||||
@@ -212,5 +212,7 @@
|
||||
"view.size.4": "Extra Large",
|
||||
"window.message.error_opening_library": "Error opening library.",
|
||||
"window.title.error": "Error",
|
||||
"window.title.open_create_library": "Open/Create Library"
|
||||
"window.title.open_create_library": "Open/Create Library",
|
||||
"sorting.direction.ascending": "Ascending",
|
||||
"sorting.direction.descending": "Descending"
|
||||
}
|
||||
|
||||
@@ -59,6 +59,10 @@ class ItemType(enum.Enum):
|
||||
TAG_GROUP = 2
|
||||
|
||||
|
||||
class SortingModeEnum(enum.Enum):
|
||||
DATE_ADDED = "file.date_added"
|
||||
|
||||
|
||||
@dataclass
|
||||
class FilterState:
|
||||
"""Represent a state of the Library grid view."""
|
||||
@@ -66,6 +70,8 @@ class FilterState:
|
||||
# these should remain
|
||||
page_index: int | None = 0
|
||||
page_size: int | None = 500
|
||||
sorting_mode: SortingModeEnum = SortingModeEnum.DATE_ADDED
|
||||
ascending: bool = True
|
||||
|
||||
# these should be erased on update
|
||||
# Abstract Syntax Tree Of the current Search Query
|
||||
@@ -110,6 +116,12 @@ class FilterState:
|
||||
def with_page_size(self, page_size: int) -> "FilterState":
|
||||
return replace(self, page_size=page_size)
|
||||
|
||||
def with_sorting_mode(self, mode: SortingModeEnum) -> "FilterState":
|
||||
return replace(self, sorting_mode=mode)
|
||||
|
||||
def with_sorting_direction(self, ascending: bool) -> "FilterState":
|
||||
return replace(self, ascending=ascending)
|
||||
|
||||
|
||||
class FieldTypeEnum(enum.Enum):
|
||||
TEXT_LINE = "Text Line"
|
||||
|
||||
@@ -14,11 +14,14 @@ import structlog
|
||||
from humanfriendly import format_timespan
|
||||
from sqlalchemy import (
|
||||
URL,
|
||||
ColumnExpressionArgument,
|
||||
Engine,
|
||||
NullPool,
|
||||
and_,
|
||||
asc,
|
||||
create_engine,
|
||||
delete,
|
||||
desc,
|
||||
exists,
|
||||
func,
|
||||
or_,
|
||||
@@ -42,7 +45,7 @@ from ...constants import (
|
||||
)
|
||||
from ...enums import LibraryPrefs
|
||||
from .db import make_tables
|
||||
from .enums import FieldTypeEnum, FilterState, TagColor
|
||||
from .enums import FieldTypeEnum, FilterState, SortingModeEnum, TagColor
|
||||
from .fields import (
|
||||
BaseField,
|
||||
DatetimeField,
|
||||
@@ -576,6 +579,13 @@ class Library:
|
||||
query_count = select(func.count()).select_from(statement.alias("entries"))
|
||||
count_all: int = session.execute(query_count).scalar()
|
||||
|
||||
sort_on: ColumnExpressionArgument = Entry.id
|
||||
match search.sorting_mode:
|
||||
case SortingModeEnum.DATE_ADDED:
|
||||
sort_on = Entry.id
|
||||
|
||||
statement = statement.order_by(asc(sort_on) if search.ascending else desc(sort_on))
|
||||
|
||||
statement = statement.limit(search.limit).offset(search.offset)
|
||||
|
||||
logger.info(
|
||||
|
||||
@@ -72,6 +72,15 @@ class Ui_MainWindow(QMainWindow):
|
||||
spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
self.horizontalLayout_3.addItem(spacerItem)
|
||||
|
||||
# Sorting Dropdowns
|
||||
self.sorting_mode_combobox = QComboBox(self.centralwidget)
|
||||
self.sorting_mode_combobox.setObjectName(u"sortingModeComboBox")
|
||||
self.horizontalLayout_3.addWidget(self.sorting_mode_combobox)
|
||||
|
||||
self.sorting_direction_combobox = QComboBox(self.centralwidget)
|
||||
self.sorting_direction_combobox.setObjectName(u"sortingDirectionCombobox")
|
||||
self.horizontalLayout_3.addWidget(self.sorting_direction_combobox)
|
||||
|
||||
# Thumbnail Size placeholder
|
||||
self.thumb_size_combobox = QComboBox(self.centralwidget)
|
||||
self.thumb_size_combobox.setObjectName(u"thumbSizeComboBox")
|
||||
|
||||
@@ -65,6 +65,7 @@ from src.core.library.alchemy.enums import (
|
||||
FieldTypeEnum,
|
||||
FilterState,
|
||||
ItemType,
|
||||
SortingModeEnum,
|
||||
)
|
||||
from src.core.library.alchemy.fields import _FieldID
|
||||
from src.core.library.alchemy.library import Entry, LibraryStatus
|
||||
@@ -551,16 +552,40 @@ class QtDriver(DriverMixin, QObject):
|
||||
search_button.clicked.connect(
|
||||
lambda: self.filter_items(
|
||||
FilterState.from_search_query(self.main_window.searchField.text())
|
||||
.with_sorting_mode(self.sorting_mode)
|
||||
.with_sorting_direction(self.sorting_direction)
|
||||
)
|
||||
)
|
||||
# Search Field
|
||||
search_field: QLineEdit = self.main_window.searchField
|
||||
search_field.returnPressed.connect(
|
||||
# TODO - parse search field for filters
|
||||
lambda: self.filter_items(
|
||||
FilterState.from_search_query(self.main_window.searchField.text())
|
||||
.with_sorting_mode(self.sorting_mode)
|
||||
.with_sorting_direction(self.sorting_direction)
|
||||
)
|
||||
)
|
||||
# Sorting Dropdowns
|
||||
sort_mode_dropdown: QComboBox = self.main_window.sorting_mode_combobox
|
||||
for sort_mode in SortingModeEnum:
|
||||
sort_mode_dropdown.addItem(Translations[sort_mode.value], sort_mode)
|
||||
sort_mode_dropdown.setCurrentIndex(
|
||||
list(SortingModeEnum).index(self.filter.sorting_mode)
|
||||
) # set according to self.filter
|
||||
sort_mode_dropdown.currentIndexChanged.connect(self.sorting_mode_callback)
|
||||
|
||||
sort_dir_dropdown: QComboBox = self.main_window.sorting_direction_combobox
|
||||
sort_dir_dropdown.addItem("Ascending", userData=True)
|
||||
sort_dir_dropdown.addItem("Descending", userData=False)
|
||||
Translations.translate_with_setter(
|
||||
lambda text: sort_dir_dropdown.setItemText(0, text), "sorting.direction.ascending"
|
||||
)
|
||||
Translations.translate_with_setter(
|
||||
lambda text: sort_dir_dropdown.setItemText(1, text), "sorting.direction.descending"
|
||||
)
|
||||
sort_dir_dropdown.setCurrentIndex(0) # Default: Ascending
|
||||
sort_dir_dropdown.currentIndexChanged.connect(self.sorting_direction_callback)
|
||||
|
||||
# Thumbnail Size ComboBox
|
||||
thumb_size_combobox: QComboBox = self.main_window.thumb_size_combobox
|
||||
for size in self.thumb_sizes:
|
||||
@@ -880,6 +905,24 @@ class QtDriver(DriverMixin, QObject):
|
||||
content=strip_web_protocol(field.value),
|
||||
)
|
||||
|
||||
@property
|
||||
def sorting_direction(self) -> bool:
|
||||
"""Whether to Sort the results in ascending order."""
|
||||
return self.main_window.sorting_direction_combobox.currentData()
|
||||
|
||||
def sorting_direction_callback(self):
|
||||
logger.info("Sorting Direction Changed", ascending=self.sorting_direction)
|
||||
self.filter_items()
|
||||
|
||||
@property
|
||||
def sorting_mode(self) -> SortingModeEnum:
|
||||
"""What to sort by."""
|
||||
return self.main_window.sorting_mode_combobox.currentData()
|
||||
|
||||
def sorting_mode_callback(self):
|
||||
logger.info("Sorting Mode Changed", mode=self.sorting_mode)
|
||||
self.filter_items()
|
||||
|
||||
def thumb_size_callback(self, index: int):
|
||||
"""Perform actions needed when the thumbnail size selection is changed.
|
||||
|
||||
@@ -1192,6 +1235,9 @@ class QtDriver(DriverMixin, QObject):
|
||||
|
||||
if filter:
|
||||
self.filter = dataclasses.replace(self.filter, **dataclasses.asdict(filter))
|
||||
else:
|
||||
self.filter.sorting_mode = self.sorting_mode
|
||||
self.filter.ascending = self.sorting_direction
|
||||
|
||||
# inform user about running search
|
||||
self.main_window.statusbar.showMessage(Translations["status.library_search_query"])
|
||||
|
||||
Reference in New Issue
Block a user