Implemented sorting by track title, artist name etc...

(Sorting order is not getting saved.)
This commit is contained in:
The Wobbler 2025-02-23 16:38:56 +01:00
parent 1b69321c05
commit 3dd9123332
3 changed files with 100 additions and 21 deletions

View file

@ -22,7 +22,15 @@ class Playlist:
# no other playlist can be created using the same name # no other playlist can be created using the same name
self.app.utils.unique_names.append(self.title) self.app.utils.unique_names.append(self.title)
self.sorting: list[Qt.SortOrder] | None = None # Custom sort order if None # the number is the index of the header section,
# the bool is the sorting order (True = ascending, False = descending)
self.sorting: list[tuple[int, bool]] = [
(0, True),
(1, True),
(2, True),
(3, True),
(4, True)
]
self.tracks: list[Track] = [] self.tracks: list[Track] = []
self.current_track_index = 0 self.current_track_index = 0
self.current_track: Track | None = None self.current_track: Track | None = None
@ -128,6 +136,30 @@ class Playlist:
def load_from_wbz(self, path): def load_from_wbz(self, path):
self.load_from_m3u(path) # placeholder self.load_from_m3u(path) # placeholder
def sync(self, view, user_sort: bool=False):
num_tracks = view.topLevelItemCount()
i = 0
while i < num_tracks:
track_item = view.topLevelItem(i)
track = track_item.track
track_item.index = i
if user_sort:
track_item.index_user_sort = i
self.tracks[i] = track
track.set_occurrences()
i += 1
# make sure the next track is cached (could be moved by user)
if self.app.player.current_playlist == self and self.has_tracks():
self.app.player.cache_next_track()
def has_tracks(self): def has_tracks(self):
return len(self.tracks) > 0 return len(self.tracks) > 0
@ -169,7 +201,12 @@ class Playlist:
return self.current_track.sound, self.current_track.duration return self.current_track.sound, self.current_track.duration
def save(self): def save(self):
wbz_data = ""
first_view = list(self.views.values())[0]
first_view.sortItems(4, Qt.SortOrder.AscendingOrder)
self.sync(first_view)
wbz_data = "#WOBUZZM3U\n"
for track in self.tracks: for track in self.tracks:
wbz_data += f"{track.path}\n" wbz_data += f"{track.path}\n"

View file

@ -1,7 +1,7 @@
#!/usr/bin/python3 #!/usr/bin/python3
from PyQt6.QtCore import pyqtSignal from PyQt6.QtCore import Qt, pyqtSignal
from PyQt6.QtGui import QDropEvent, QIcon, QFont from PyQt6.QtGui import QDropEvent, QIcon
from PyQt6.QtWidgets import QTreeWidget, QAbstractItemView from PyQt6.QtWidgets import QTreeWidget, QAbstractItemView
from .track import TrackItem from .track import TrackItem
@ -20,6 +20,9 @@ class PlaylistView(QTreeWidget):
self.app = playlist.app self.app = playlist.app
self.header = self.header()
self.header.setSectionsClickable(True)
playlist.views[id(dock)] = self playlist.views[id(dock)] = self
self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
@ -37,30 +40,58 @@ class PlaylistView(QTreeWidget):
self.setHeaderLabels(headers) self.setHeaderLabels(headers)
self.itemActivated.connect(self.on_track_activation) self.itemActivated.connect(self.on_track_activation)
self.header.sectionClicked.connect(self.on_header_click)
def on_user_sort(self): def on_header_click(self, section_index: int):
if section_index == 0: # this would just invert the current sorting
return
sorting = self.playlist.sorting
last_sort_section_index, order = sorting[4]
if last_sort_section_index == section_index:
order = not order # invert order
self.playlist.sorting[4] = (section_index, order) # set sorting
# convert True/False to Qt.SortOrder.AscendingOrder/Qt.SortOrder.DescendingOrder
qorder = Qt.SortOrder.AscendingOrder if order else Qt.SortOrder.DescendingOrder
self.header.setSortIndicator(section_index, qorder)
else:
del sorting[0] # remove first sort
sorting.append((section_index, True)) # last sort is this section index, ascending
self.header.setSortIndicator(section_index, Qt.SortOrder.AscendingOrder)
self.sort()
def sort(self):
for index, order in self.playlist.sorting:
# convert True/False to Qt.SortOrder.AscendingOrder/Qt.SortOrder.DescendingOrder
qorder = Qt.SortOrder.AscendingOrder if order else Qt.SortOrder.DescendingOrder
self.sortItems(index, qorder)
self.on_sort()
def on_sort(self, user_sort: bool=False):
num_tracks = self.topLevelItemCount() num_tracks = self.topLevelItemCount()
i = 0 i = 0
while i < num_tracks: while i < num_tracks:
track_item = self.topLevelItem(i) track = self.topLevelItem(i)
track = track_item.track
track_item.index_user_sort = i
track_item.index = i
track_item.setText(5, str(i + 1))
self.playlist.tracks[i] = track
track.set_occurrences()
i += 1 i += 1
# make sure the next track is cached (could be moved by user) track.setText(0, str(i)) # 0 = index
if self.app.player.current_playlist == self.playlist and self.app.player.current_playlist.has_tracks():
self.app.player.cache_next_track() if user_sort:
track.setText(4, str(i)) # 4 = user sort index
self.playlist.sync(self, user_sort) # sync playlist to this view
def dropEvent(self, event: QDropEvent): def dropEvent(self, event: QDropEvent):
# receive items that were dropped and create new items from its tracks (new items bc. widgets can only have # receive items that were dropped and create new items from its tracks (new items bc. widgets can only have
@ -88,7 +119,7 @@ class PlaylistView(QTreeWidget):
event.accept() event.accept()
self.on_user_sort() self.on_sort(True)
def dragEnterEvent(self, event): def dragEnterEvent(self, event):
# store dragged items in gui.dropped, so the other playlist can receive it # store dragged items in gui.dropped, so the other playlist can receive it

View file

@ -18,6 +18,7 @@ class TrackItem(QTreeWidgetItem):
self.track = track self.track = track
self.index_user_sort = index self.index_user_sort = index
self.index = index self.index = index
self.parent = parent
self.playlist = parent.playlist self.playlist = parent.playlist
@ -48,10 +49,20 @@ class TrackItem(QTreeWidgetItem):
self.setFont(2, self.bold_font) self.setFont(2, self.bold_font)
self.setFont(3, self.normal_font) self.setFont(3, self.normal_font)
def unmark(self): def unmark(self):
self.setIcon(0, QIcon(None)) self.setIcon(0, QIcon(None))
self.setFont(1, self.normal_font) self.setFont(1, self.normal_font)
self.setFont(2, self.normal_font) self.setFont(2, self.normal_font)
self.setFont(3, self.normal_font) self.setFont(3, self.normal_font)
def __lt__(self, other):
# make numeric strings get sorted the right way
column = self.parent.sortColumn()
if column == 0 or column == 4:
return int(self.text(column)) < int(other.text(column))
else:
return super().__lt__(other)