Refactor user interface: enhance sound playback functionality and integrate signature update process,

fix broken database calls by using the app_id instead of the previously used appnr
This commit is contained in:
2025-09-03 10:40:57 +02:00
parent 087b8753fb
commit c6f356fda4

View File

@@ -7,14 +7,14 @@ import time
import webbrowser
from datetime import datetime
from pathlib import Path
from typing import Any, Union
from typing import Any, List, Optional, Tuple, Union
import loguru
from natsort import natsorted
from PySide6 import QtCore, QtGui, QtWidgets
from PySide6.QtMultimedia import QAudioOutput, QMediaPlayer
from PySide6.QtCore import QThread
from PySide6.QtGui import QRegularExpressionValidator
from PySide6.QtMultimedia import QAudioOutput, QMediaPlayer
from src import LOG_DIR, Icon
from src.backend import (
@@ -59,7 +59,10 @@ from src.ui.widgets import (
FilePicker,
MessageCalendar,
NewEditionChecker,
NewEditionCheckSelector,
SearchStatisticPage,
UpdaterThread,
UpdateSignatures,
UserCreate,
)
@@ -76,13 +79,6 @@ log.add(
log.success("UI started")
valid_input = (0, 0, 0, 0, 0, 0)
def play_sound(sound_file:str):
player = QMediaPlayer()
audio_output = QAudioOutput()
player.setAudioOutput(audio_output)
player.setSource(f"sounds/{sound_file}")
player.play()
class Ui(Ui_Semesterapparat):
# use the Ui_MainWindow class from mainwindow.py
@@ -256,6 +252,7 @@ class Ui(Ui_Semesterapparat):
self.availChecker = None
self.mail_thread = None
self.autoGrabber = None
self.newEditionChecker = NewEditionCheckerThread()
self.elsatab.setLayout(QtWidgets.QVBoxLayout())
self.search_statistics.setLayout(QtWidgets.QVBoxLayout())
@@ -270,6 +267,9 @@ class Ui(Ui_Semesterapparat):
self.steps.hide()
self.player = QMediaPlayer()
self.audio_output = QAudioOutput()
self.valid_check_semester.clicked.connect(self.display_valid_semester) # type:ignore
def create_doc(self):
@@ -313,6 +313,9 @@ class Ui(Ui_Semesterapparat):
elif self.select_action_box.currentText() == "Lehrperson bearbeiten":
self.setWidget(EditProf())
self.admin_action.setTitle("Lehrperson bearbeiten")
elif self.select_action_box.currentText() == "Signaturen aktualisieren":
self.setWidget(UpdateSignatures())
self.admin_action.setTitle("Signaturen aktualisieren")
else:
self.hideWidget()
self.admin_action.setTitle("")
@@ -330,6 +333,12 @@ class Ui(Ui_Semesterapparat):
tempdelete()
sys.exit()
def play_sound(self, sound_file: str):
self.player.setAudioOutput(self.audio_output)
self.audio_output.setVolume(50)
self.player.setSource(QtCore.QUrl.fromLocalFile(f"src/sounds/{sound_file}"))
self.player.play()
def get_apparats(self):
alist = self.db.getAllAparats(deleted=0)
alist = natsorted(alist, key=lambda x: x.appnr, reverse=True)
@@ -417,7 +426,7 @@ class Ui(Ui_Semesterapparat):
else:
return f"WiSe {currentYear}/{currentYear + 1}"
def open_apparat(self, apparat):
def open_apparat(self, apparat: Union[int, str]):
if self.load_app_data(apparat):
# change tab focus to tab 0
self.tabWidget.setCurrentIndex(0)
@@ -626,17 +635,17 @@ class Ui(Ui_Semesterapparat):
self.prof_mail.setText(data.mail)
self.app_name.setFocus()
def get_index_of_value(self, table_widget, value):
def get_index_of_value(self, table_widget: QtWidgets.QTableWidget, value: str):
for i in range(table_widget.rowCount()):
for j in range(table_widget.columnCount()):
if (
table_widget.item(i, j) is not None
and table_widget.item(i, j).text() == value
and table_widget.item(i, j).text() == value # type: ignore
):
return i, j
return (None, None)
def load_app_data(self, app_id=None):
def load_app_data(self, app_id: Optional[Union[int, str]] = None):
self.cancel_active_selection.setEnabled(True)
self.add_medium.setEnabled(True)
for child in self.app_group_box.findChildren(QtWidgets.QToolButton):
@@ -866,8 +875,9 @@ class Ui(Ui_Semesterapparat):
def update_app_media_list(self):
deleted = 0 if not self.chkbx_show_del_media.isChecked() else 1
app_id = self.active_apparat
app_id = self.db.getId(self.app_name.text())
prof_id = self.db.getProfId(self.profdata)
print(app_id, prof_id)
books: list[dict[int, BookData, int]] = self.db.getBooks(
app_id, prof_id, deleted
)
@@ -1201,6 +1211,7 @@ class Ui(Ui_Semesterapparat):
for runner in self.bookGrabber:
if not runner.isRunning():
runner.deleteLater()
self.bookGrabber.remove(runner)
# #log.debug("Checking file")
# get active app_id and prof_id
self.tableWidget_apparate.setEnabled(False)
@@ -1497,22 +1508,34 @@ class Ui(Ui_Semesterapparat):
self.avail_status.setText("0/0")
def check_new_editions(self):
# create a dialog that asks "Prof oder Apparat" with a button for each. based on that either search through the books of the apparat, or all books associated with the prof
selector = NewEditionCheckSelector()
selector.exec()
pick = selector.selection
app_id = self.tableWidget_apparate.item(
self.tableWidget_apparate.currentRow(), 0
).text()
prof_id: int = self.db.getProfIDByApparat(app_id)
app_name = self.tableWidget_apparate.item(
self.tableWidget_apparate.currentRow(), 1
).text()
subject = self.tableWidget_apparate.item(
self.tableWidget_apparate.currentRow(), 4
).text()
prof_id: int = self.db.getProfIDByApparat(app_id)
books = self.db.getBooks(app_id, prof_id, deleted=0)
if pick == "professor":
books = self.db.getBooksByProfId(prof_id)
app_name = "Sammelmail"
app_id = ", ".join(
[str(app.appnr) for app in self.db.getApparatsByProf(prof_id)]
)
else:
books = self.db.getBooks(app_id, prof_id, deleted=0)
books = [book["bookdata"] for book in books]
log.info(f"Checking {len(books)} for new editions")
self.newEditionChecker = NewEditionCheckerThread(books)
self.newEditionChecker.finished.connect(self.newEditionChecker.deleteLater)
self.newEditionChecker.entries = books
self.newEditionChecker.finished.connect(self.newEditionChecker.reset)
self.progressBar.setMaximum(len(books))
self.newEditionChecker.updateSignal.connect(self.update_status)
@@ -1520,13 +1543,18 @@ class Ui(Ui_Semesterapparat):
self.newEditionChecker.start()
while self.newEditionChecker.isRunning():
QtWidgets.QApplication.processEvents()
play_sound("ding.mp3")
self.play_sound("ding.mp3")
results = self.newEditionChecker.results
if results == []:
return
log.info(f"Found {len(results)} possible new editions - opening dialog")
newEditionChecker = NewEditionChecker(results=results)
newEditionChecker.exec()
accepted_books = newEditionChecker.accepted_books
# print(accepted_books)
if accepted_books == []:
return
self.mail_thread = Mail_Dialog(
prof_name=self.db.getSpecificProfData(prof_id, ["fullname"]),
@@ -1535,7 +1563,7 @@ class Ui(Ui_Semesterapparat):
app_name=app_name,
app_subject=subject,
accepted_books=accepted_books,
default_mail="Neuauflagen für Semesterapparat"
default_mail="Neuauflagen für Semesterapparat",
)
self.mail_thread.show()
@@ -1625,8 +1653,45 @@ class Ui(Ui_Semesterapparat):
menu.exec(self.tableWidget_apparat_media.mapToGlobal(position)) # type: ignore
def update_data(self):
# TODO: use link in table, parse data and if needed, update location / signature
pass
signatures = [
self.tableWidget_apparat_media.item(row, 1).text()
for row in range(self.tableWidget_apparat_media.rowCount())
] # type: ignore
prof_id = self.db.getProfId(self.profdata) # type: ignore
app_id = self.active_apparat
books: List[Tuple[int, BookData]] = []
for signature in signatures:
book = self.db.getBookBasedOnSignature(
app_id=app_id,
signature=signature,
prof_id=prof_id,
)
book_id = self.db.getBookIdBasedOnSignature(
self.active_apparat,
prof_id,
signature,
)
books.append((book_id, book))
# self.autoUpdater.entries = books
# self.autoUpdater.finished.connect(self.autoUpdater.reset)
self.updater = UpdaterThread()
u_books = []
for book_id, book in books:
u_books.append({"id": book_id, "bookdata": book})
self.updater.books = u_books
self.progressBar.setMaximum(len(books))
self.updater.finished.connect(self.updater.deleteLater)
self.updater.finished.connect(self.update_app_media_list)
self.updater.currtot.connect(self.update_status)
self.updater.start()
# ppn = book.link.split("kid=")[-1]
# result = cat.get_book(ppn)
# if result:
# book.signature = result.signature
# book.in_apparat = True
# print(book)
# self.db.updateBookdata(book_id, book)
# self.update_app_media_list()
def copy_to_apparat(self):
selected_rows = self.tableWidget_apparat_media.selectionModel().selectedRows() # type: ignore
@@ -1724,12 +1789,12 @@ class Ui(Ui_Semesterapparat):
).text()
prof_id = self.db.getProfId(self.profdata)
data = self.db.getBookBasedOnSignature(
app_id=self.active_apparat,
app_id=self.db.getId(self.app_name.text()),
signature=book,
prof_id=prof_id,
)
book_id = self.db.getBookIdBasedOnSignature(
self.active_apparat,
self.db.getId(self.app_name.text()),
prof_id,
book,
)
@@ -1891,7 +1956,13 @@ class Ui(Ui_Semesterapparat):
if state == 1:
log.debug("Deleting apparat {}", selected_apparat_id)
pid = self.db.getProfIDByApparat(selected_apparat_id)
self.db.deleteApparat(selected_apparat_id, Semester().value)
apparat = Apparat(
appnr=int(selected_apparat_id),
name=self.tableWidget_apparate.item(
self.tableWidget_apparate.currentRow(), 1
).text(),
)
self.db.deleteApparat(apparat=apparat, semester=Semester().value)
# delete the corresponding entry from self.apparats
for apparat in self.apparats:
if apparat.appnr == int(selected_apparat_id):
@@ -1935,6 +2006,7 @@ def launch_gui():
) # if that thread uses an event loop
app.aboutToQuit.connect(aui.docu.terminate) # our new slot
app.aboutToQuit.connect(aui.docu.wait)
app.aboutToQuit.connect(aui.newEditionChecker.terminate)
atexit.register(tempdelete)
# atexit.register(aui.validate_thread.quit)
# atexit.register(aui.docu.quit)