diff --git a/ui/designer/components/chartSelector.ui b/ui/designer/components/chartSelector.ui index e92db98..62e85fe 100644 --- a/ui/designer/components/chartSelector.ui +++ b/ui/designer/components/chartSelector.ui @@ -6,8 +6,8 @@ 0 0 - 671 - 295 + 476 + 347 @@ -25,7 +25,68 @@ songIdSelector.title - + + + + + songIdSelector.quickActions + + + + + + + 100 + 0 + + + + songIdSelector.quickActions.nextPackageButton + + + + + + + + 100 + 0 + + + + songIdSelector.quickActions.nextSongIdButton + + + + + + + + 100 + 0 + + + + songIdSelector.quickActions.previousSongIdButton + + + + + + + + 100 + 0 + + + + songIdSelector.quickActions.previousPackageButton + + + + + + @@ -48,12 +109,12 @@ 0 - + true - fuzzySearch.lineEdit.placeholder + search.lineEdit.placeholder true @@ -74,7 +135,7 @@ - + @@ -82,66 +143,11 @@ - - - - songIdSelector.quickActions - - - - - - songIdSelector.quickActions.previousPackageButton - - - - - - - songIdSelector.quickActions.previousSongIdButton - - - - - - - songIdSelector.quickActions.nextSongIdButton - - - - - - - songIdSelector.quickActions.nextPackageButton - - - - - - - - - - 200 - 0 - - - - ratingClassSelector.title - - - - 0 - - - - - - + diff --git a/ui/designer/components/chartSelector_ui.py b/ui/designer/components/chartSelector_ui.py index b518c22..51a79de 100644 --- a/ui/designer/components/chartSelector_ui.py +++ b/ui/designer/components/chartSelector_ui.py @@ -25,7 +25,7 @@ class Ui_ChartSelector(object): def setupUi(self, ChartSelector): if not ChartSelector.objectName(): ChartSelector.setObjectName(u"ChartSelector") - ChartSelector.resize(671, 295) + ChartSelector.resize(476, 347) ChartSelector.setWindowTitle(u"ChartSelector") self.mainVerticalLayout = QVBoxLayout(ChartSelector) self.mainVerticalLayout.setObjectName(u"mainVerticalLayout") @@ -36,29 +36,60 @@ class Ui_ChartSelector(object): sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.songIdSelectorGroupBox.sizePolicy().hasHeightForWidth()) self.songIdSelectorGroupBox.setSizePolicy(sizePolicy) - self.horizontalLayout = QHBoxLayout(self.songIdSelectorGroupBox) + self.verticalLayout_3 = QVBoxLayout(self.songIdSelectorGroupBox) + self.verticalLayout_3.setObjectName(u"verticalLayout_3") + self.songIdSelectorQuickActionsGroupBox = QGroupBox(self.songIdSelectorGroupBox) + self.songIdSelectorQuickActionsGroupBox.setObjectName(u"songIdSelectorQuickActionsGroupBox") + self.horizontalLayout = QHBoxLayout(self.songIdSelectorQuickActionsGroupBox) self.horizontalLayout.setObjectName(u"horizontalLayout") + self.nextPackageButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) + self.nextPackageButton.setObjectName(u"nextPackageButton") + self.nextPackageButton.setMinimumSize(QSize(100, 0)) + + self.horizontalLayout.addWidget(self.nextPackageButton) + + self.nextSongIdButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) + self.nextSongIdButton.setObjectName(u"nextSongIdButton") + self.nextSongIdButton.setMinimumSize(QSize(100, 0)) + + self.horizontalLayout.addWidget(self.nextSongIdButton) + + self.previousSongIdButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) + self.previousSongIdButton.setObjectName(u"previousSongIdButton") + self.previousSongIdButton.setMinimumSize(QSize(100, 0)) + + self.horizontalLayout.addWidget(self.previousSongIdButton) + + self.previousPackageButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) + self.previousPackageButton.setObjectName(u"previousPackageButton") + self.previousPackageButton.setMinimumSize(QSize(100, 0)) + + self.horizontalLayout.addWidget(self.previousPackageButton) + + + self.verticalLayout_3.addWidget(self.songIdSelectorQuickActionsGroupBox) + self.widget = QWidget(self.songIdSelectorGroupBox) self.widget.setObjectName(u"widget") self.widget.setMinimumSize(QSize(300, 0)) self.verticalLayout = QVBoxLayout(self.widget) self.verticalLayout.setObjectName(u"verticalLayout") self.verticalLayout.setContentsMargins(0, 0, 0, 0) - self.fuzzySearchLineEdit = QLineEdit(self.widget) - self.fuzzySearchLineEdit.setObjectName(u"fuzzySearchLineEdit") - self.fuzzySearchLineEdit.setFrame(True) - self.fuzzySearchLineEdit.setClearButtonEnabled(True) + self.searchLineEdit = QLineEdit(self.widget) + self.searchLineEdit.setObjectName(u"searchLineEdit") + self.searchLineEdit.setFrame(True) + self.searchLineEdit.setClearButtonEnabled(True) - self.verticalLayout.addWidget(self.fuzzySearchLineEdit) + self.verticalLayout.addWidget(self.searchLineEdit) self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.verticalLayout.addItem(self.verticalSpacer) - self.packageComboBox = QComboBox(self.widget) - self.packageComboBox.setObjectName(u"packageComboBox") + self.packComboBox = QComboBox(self.widget) + self.packComboBox.setObjectName(u"packComboBox") - self.verticalLayout.addWidget(self.packageComboBox) + self.verticalLayout.addWidget(self.packComboBox) self.songIdComboBox = QComboBox(self.widget) self.songIdComboBox.setObjectName(u"songIdComboBox") @@ -66,51 +97,15 @@ class Ui_ChartSelector(object): self.verticalLayout.addWidget(self.songIdComboBox) - self.horizontalLayout.addWidget(self.widget) - - self.songIdSelectorQuickActionsGroupBox = QGroupBox(self.songIdSelectorGroupBox) - self.songIdSelectorQuickActionsGroupBox.setObjectName(u"songIdSelectorQuickActionsGroupBox") - self.verticalLayout_2 = QVBoxLayout(self.songIdSelectorQuickActionsGroupBox) - self.verticalLayout_2.setObjectName(u"verticalLayout_2") - self.previousPackageButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) - self.previousPackageButton.setObjectName(u"previousPackageButton") - - self.verticalLayout_2.addWidget(self.previousPackageButton) - - self.previousSongIdButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) - self.previousSongIdButton.setObjectName(u"previousSongIdButton") - - self.verticalLayout_2.addWidget(self.previousSongIdButton) - - self.nextSongIdButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) - self.nextSongIdButton.setObjectName(u"nextSongIdButton") - - self.verticalLayout_2.addWidget(self.nextSongIdButton) - - self.nextPackageButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) - self.nextPackageButton.setObjectName(u"nextPackageButton") - - self.verticalLayout_2.addWidget(self.nextPackageButton) - - - self.horizontalLayout.addWidget(self.songIdSelectorQuickActionsGroupBox) + self.verticalLayout_3.addWidget(self.widget) self.mainVerticalLayout.addWidget(self.songIdSelectorGroupBox) - self.ratingClassGroupBox = QGroupBox(ChartSelector) - self.ratingClassGroupBox.setObjectName(u"ratingClassGroupBox") - self.ratingClassGroupBox.setMinimumSize(QSize(200, 0)) - self.horizontalLayout_2 = QHBoxLayout(self.ratingClassGroupBox) - self.horizontalLayout_2.setSpacing(0) - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.ratingClassSelector = RatingClassSelector(self.ratingClassGroupBox) + self.ratingClassSelector = RatingClassSelector(ChartSelector) self.ratingClassSelector.setObjectName(u"ratingClassSelector") - self.horizontalLayout_2.addWidget(self.ratingClassSelector) - - - self.mainVerticalLayout.addWidget(self.ratingClassGroupBox) + self.mainVerticalLayout.addWidget(self.ratingClassSelector) self.resultsHorizontalLayout = QHBoxLayout() self.resultsHorizontalLayout.setObjectName(u"resultsHorizontalLayout") @@ -142,13 +137,12 @@ class Ui_ChartSelector(object): def retranslateUi(self, ChartSelector): self.songIdSelectorGroupBox.setTitle(QCoreApplication.translate("ChartSelector", u"songIdSelector.title", None)) - self.fuzzySearchLineEdit.setPlaceholderText(QCoreApplication.translate("ChartSelector", u"fuzzySearch.lineEdit.placeholder", None)) self.songIdSelectorQuickActionsGroupBox.setTitle(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions", None)) - self.previousPackageButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.previousPackageButton", None)) - self.previousSongIdButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.previousSongIdButton", None)) - self.nextSongIdButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.nextSongIdButton", None)) self.nextPackageButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.nextPackageButton", None)) - self.ratingClassGroupBox.setTitle(QCoreApplication.translate("ChartSelector", u"ratingClassSelector.title", None)) + self.nextSongIdButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.nextSongIdButton", None)) + self.previousSongIdButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.previousSongIdButton", None)) + self.previousPackageButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.previousPackageButton", None)) + self.searchLineEdit.setPlaceholderText(QCoreApplication.translate("ChartSelector", u"search.lineEdit.placeholder", None)) self.resetButton.setText(QCoreApplication.translate("ChartSelector", u"resetButton", None)) pass # retranslateUi diff --git a/ui/extends/components/chartSelector.py b/ui/extends/components/chartSelector.py index 3a3dbca..cda77e0 100644 --- a/ui/extends/components/chartSelector.py +++ b/ui/extends/components/chartSelector.py @@ -1,27 +1,35 @@ from arcaea_offline.database import Database from arcaea_offline.models import Chart +from arcaea_offline.searcher import Searcher from arcaea_offline.utils.rating import rating_class_to_short_text from PySide6.QtCore import Qt from PySide6.QtGui import QStandardItem, QStandardItemModel -class FuzzySearchCompleterModel(QStandardItemModel): - def fillDbFuzzySearchResults(self, db: Database, kw: str): +class SearchCompleterModel(QStandardItemModel): + def __init__(self, parent=None): + super().__init__(parent) + self.searcher = Searcher() + self.db = Database() + + def updateSearcherSongs(self): + with self.db.sessionmaker() as session: + self.searcher.import_songs(session) + + def getSearchResult(self, kw: str): self.clear() - results = db.fuzzy_search_song_id(kw, limit=10) - results = sorted(results, key=lambda r: r.confidence, reverse=True) - songIds = [r.song_id for r in results] + songIds = self.searcher.search(kw) + charts: list[Chart] = [] for songId in songIds: - dbChartRows = db.get_charts_by_song_id(songId) - _charts = [Chart.from_db_row(dbRow) for dbRow in dbChartRows] + _charts = self.db.get_charts_by_song_id(songId) _charts = sorted(_charts, key=lambda c: c.rating_class, reverse=True) charts += _charts for chart in charts: displayText = ( - f"{chart.name_en} [{rating_class_to_short_text(chart.rating_class)}]" + f"{chart.title} [{rating_class_to_short_text(chart.rating_class)}]" ) item = QStandardItem(kw) item.setData(kw) diff --git a/ui/implements/components/chartSelector.py b/ui/implements/components/chartSelector.py index db4bb2e..b1fe55e 100644 --- a/ui/implements/components/chartSelector.py +++ b/ui/implements/components/chartSelector.py @@ -1,17 +1,19 @@ +import logging import re from typing import Literal from arcaea_offline.database import Database -from arcaea_offline.models import Chart, Pack +from arcaea_offline.models import Chart from arcaea_offline.utils.rating import rating_class_to_text from PySide6.QtCore import QModelIndex, Qt, Signal, Slot -from PySide6.QtGui import QColor, QShowEvent +from PySide6.QtGui import QShowEvent from PySide6.QtWidgets import QCompleter, QWidget from ui.designer.components.chartSelector_ui import Ui_ChartSelector -from ui.extends.components.chartSelector import FuzzySearchCompleterModel +from ui.extends.components.chartSelector import SearchCompleterModel from ui.extends.shared.delegates.descriptionDelegate import DescriptionDelegate -from ui.implements.components.ratingClassRadioButton import RatingClassRadioButton + +logger = logging.getLogger(__name__) class ChartSelector(Ui_ChartSelector, QWidget): @@ -37,25 +39,25 @@ class ChartSelector(Ui_ChartSelector, QWidget): self.valueChanged.connect(self.updateResultLabel) - self.fillPackageComboBox() - self.packageComboBox.setCurrentIndex(-1) + self.fillPackComboBox() + self.packComboBox.setCurrentIndex(-1) self.songIdComboBox.setCurrentIndex(-1) - self.fuzzySearchCompleterModel = FuzzySearchCompleterModel() - self.fuzzySearchCompleter = QCompleter(self.fuzzySearchCompleterModel) - self.fuzzySearchCompleter.popup().setItemDelegate( - DescriptionDelegate(self.fuzzySearchCompleter.popup()) + self.searchCompleterModel = SearchCompleterModel() + self.searchCompleter = QCompleter(self.searchCompleterModel) + self.searchCompleter.popup().setItemDelegate( + DescriptionDelegate(self.searchCompleter.popup()) ) - self.fuzzySearchCompleter.activated[QModelIndex].connect( - self.fuzzySearchCompleterSetSelection + self.searchCompleter.activated[QModelIndex].connect( + self.searchCompleterSetSelection ) - self.fuzzySearchLineEdit.setCompleter(self.fuzzySearchCompleter) + self.searchLineEdit.setCompleter(self.searchCompleter) - self.packageComboBox.setItemDelegate(DescriptionDelegate(self.packageComboBox)) + self.packComboBox.setItemDelegate(DescriptionDelegate(self.packComboBox)) self.songIdComboBox.setItemDelegate(DescriptionDelegate(self.songIdComboBox)) self.ratingClassSelector.valueChanged.connect(self.valueChanged) - self.packageComboBox.currentIndexChanged.connect(self.valueChanged) + self.packComboBox.currentIndexChanged.connect(self.valueChanged) self.songIdComboBox.currentIndexChanged.connect(self.valueChanged) def quickSwitchSelection( @@ -65,12 +67,12 @@ class ChartSelector(Ui_ChartSelector, QWidget): ): minIndex = 0 if model == "package": - maxIndex = self.packageComboBox.count() - 1 - currentIndex = self.packageComboBox.currentIndex() + ( + maxIndex = self.packComboBox.count() - 1 + currentIndex = self.packComboBox.currentIndex() + ( 1 if direction == "next" else -1 ) currentIndex = max(min(maxIndex, currentIndex), minIndex) - self.packageComboBox.setCurrentIndex(currentIndex) + self.packComboBox.setCurrentIndex(currentIndex) elif model == "songId": maxIndex = self.songIdComboBox.count() - 1 currentIndex = self.songIdComboBox.currentIndex() + ( @@ -82,17 +84,31 @@ class ChartSelector(Ui_ChartSelector, QWidget): return def value(self): - packageId = self.packageComboBox.currentData() + packId = self.packComboBox.currentData() songId = self.songIdComboBox.currentData() ratingClass = self.ratingClassSelector.value() - if packageId and songId and isinstance(ratingClass, int): + if packId and songId and isinstance(ratingClass, int): return self.db.get_chart(songId, ratingClass) return None def showEvent(self, event: QShowEvent): # update database results when widget visible - self.fillPackageComboBox() + self.searchCompleterModel.updateSearcherSongs() + + # remember selection and restore later + pack = self.packComboBox.currentData() + songId = self.songIdComboBox.currentData() + ratingClass = self.ratingClassSelector.value() + + self.fillPackComboBox() + + if pack: + self.selectPack(pack) + if songId: + self.selectSongId(songId) + if ratingClass is not None: + self.ratingClassSelector.select(ratingClass) return super().showEvent(event) @Slot() @@ -116,8 +132,8 @@ class ChartSelector(Ui_ChartSelector, QWidget): else: self.resultLabel.setText("...") - def fillPackageComboBox(self): - self.packageComboBox.clear() + def fillPackComboBox(self): + self.packComboBox.clear() packs = self.db.get_packs() for pack in packs: isAppendPack = re.search(r"_append_.*$", pack.id) @@ -127,20 +143,20 @@ class ChartSelector(Ui_ChartSelector, QWidget): packName = f"{basePackName} - {pack.name}" else: packName = pack.name - self.packageComboBox.addItem(f"{packName} ({pack.id})", pack.id) - row = self.packageComboBox.count() - 1 - self.packageComboBox.setItemData( + self.packComboBox.addItem(f"{packName} ({pack.id})", pack.id) + row = self.packComboBox.count() - 1 + self.packComboBox.setItemData( row, packName, DescriptionDelegate.MainTextRole ) - self.packageComboBox.setItemData( + self.packComboBox.setItemData( row, pack.id, DescriptionDelegate.DescriptionTextRole ) - self.packageComboBox.setCurrentIndex(-1) + self.packComboBox.setCurrentIndex(-1) def fillSongIdComboBox(self): self.songIdComboBox.clear() - packId = self.packageComboBox.currentData() + packId = self.packComboBox.currentData() if packId: charts = self.db.get_charts_by_pack_id(packId) inserted_song_ids = [] @@ -160,7 +176,7 @@ class ChartSelector(Ui_ChartSelector, QWidget): self.songIdComboBox.setCurrentIndex(-1) @Slot() - def on_packageComboBox_activated(self): + def on_packComboBox_activated(self): self.fillSongIdComboBox() @Slot(int) @@ -173,38 +189,49 @@ class ChartSelector(Ui_ChartSelector, QWidget): @Slot() def on_resetButton_clicked(self): - self.packageComboBox.setCurrentIndex(-1) + self.packComboBox.setCurrentIndex(-1) self.songIdComboBox.setCurrentIndex(-1) @Slot(str) - def on_fuzzySearchLineEdit_textChanged(self, text: str): + def on_searchLineEdit_textChanged(self, text: str): if text: - self.fuzzySearchCompleterModel.fillDbFuzzySearchResults(self.db, text) + self.searchCompleterModel.getSearchResult(text) else: - self.fuzzySearchCompleterModel.clear() + self.searchCompleterModel.clear() - def selectChart(self, chart: Chart): - packageIdIndex = self.packageComboBox.findData(chart.set) - if packageIdIndex > -1: - self.packageComboBox.setCurrentIndex(packageIdIndex) + def selectPack(self, packId: str) -> bool: + packIdIndex = self.packComboBox.findData(packId) + if packIdIndex > -1: + self.packComboBox.setCurrentIndex(packIdIndex) + self.fillSongIdComboBox() + return True else: - # QMessageBox - return + logger.warning(f'Attempting to select an unknown pack "{packId}"') + return False - self.fillSongIdComboBox() - songIdIndex = self.songIdComboBox.findData(chart.song_id) + def selectSongId(self, songId: str) -> bool: + songIdIndex = self.songIdComboBox.findData(songId) if songIdIndex > -1: self.songIdComboBox.setCurrentIndex(songIdIndex) + return True else: - # QMessageBox - return + logger.warning( + f'Attempting to select an unknown song "{songId}", maybe try selecting a pack first?' + ) + return False + def selectChart(self, chart: Chart): + if not self.selectPack(chart.set): + return False + if not self.selectSongId(chart.song_id): + return False self.ratingClassSelector.select(chart.rating_class) + return True @Slot(QModelIndex) - def fuzzySearchCompleterSetSelection(self, index: QModelIndex): + def searchCompleterSetSelection(self, index: QModelIndex): chart = index.data(Qt.ItemDataRole.UserRole + 10) # type: Chart self.selectChart(chart) - self.fuzzySearchLineEdit.clear() - self.fuzzySearchLineEdit.clearFocus() + self.searchLineEdit.clear() + self.searchLineEdit.clearFocus()