import json import os import re from typing import Any, Dict, List, Optional, Self, Type, cast from PyQt6.QtCore import ( QCoreApplication, QLocale, QResource, Qt, QTranslator, pyqtSlot, ) from PyQt6.QtMultimedia import QMediaDevices from PyQt6.QtWidgets import QAbstractItemView, QDialog, QListWidgetItem, QWidget from ui.Preferences import Ui_Preferences class Preferences(QDialog, Ui_Preferences): translator: Optional[QTranslator] _instance = None preferences: Dict[str, str | List[str]] def __new__(cls: Type[Self]) -> Self: if cls._instance: return cls._instance cls._instance = super(Preferences, cls).__new__(cls) return cls._instance @pyqtSlot(int) def done(self, r: int) -> None: self.hide() super().done(r) return @pyqtSlot() def exec(self) -> int: self.show() return super().exec() @pyqtSlot() def open(self) -> None: self.show() super().open() return def __init__(self, *args: Any, **kwargs: Any) -> None: super(Preferences, self).__init__(*args, **kwargs) self.setupUi(self) self.hide() # # Overrides # self.alertList.setSelectionMode( QAbstractItemView.SelectionMode.MultiSelection ) self.playerList.setSelectionMode( QAbstractItemView.SelectionMode.MultiSelection ) self.readerCombo.setEditable(False) self.phoneticsCombo.setEditable(False) # # End OverRides # for index, output in enumerate(QMediaDevices.audioOutputs()): identifier = output.id().data().decode("utf-8") description = output.description() self.alertList.addItem(description) self.playerList.addItem(description) resource = QResource("/translate") translator = QTranslator() for child in resource.children(): fn = f":/translate/{child}" if translator.load(fn): locale = QLocale(translator.language()) lang_code = locale.language() language = QLocale.languageToString(lang_code) self.languageCombo.addItem(language, translator.language()) self.setCurrent() return def setCurrent(self) -> None: if os.path.exists("preferences.json"): with open("preferences.json", "r") as f: self.preferences = json.load(f) else: self.preferences = { "readerFont": "OpenDyslexic", "phoneticFont": "Gentium", "alertOutputs": ["default"], "playerOutputs": ["Feed for virtual microphone"], "language": "pt", } for output in self.preferences["alertOutputs"]: if output == "default": output = QMediaDevices.defaultAudioOutput().description() for item in self.alertList.findItems( output, Qt.MatchFlag.MatchExactly ): item.setSelected(True) for output in self.preferences["playerOutputs"]: if output == "default": output = QMediaDevices.defaultAudioOutput().description() for item in self.playerList.findItems( output, Qt.MatchFlag.MatchExactly ): item.setSelected(True) index = self.languageCombo.findData(self.preferences["language"]) if index >= 0: self.languageCombo.setCurrentIndex(index) self.translator = QTranslator() if self.translator.load( f":/translate/esl_reader_{self.preferences['language']}" ): assert self.translator is not None QCoreApplication.installTranslator(self.translator) else: self.translator = None index = self.readerCombo.findText(self.preferences["readerFont"]) if index >= 0: self.readerCombo.setCurrentIndex(index) index = self.phoneticsCombo.findText(self.preferences["phoneticFont"]) if index >= 0: self.phoneticsCombo.setCurrentIndex(index) return def get( self, name: Optional[str] = None ) -> str | List[str] | Dict[str, str | List[str]]: if not name: return self.preferences return self.preferences[name] def accept(self) -> None: self.preferences["readerFont"] = self.readerCombo.currentFont().family() self.preferences[ "phoneticFont" ] = self.phoneticsCombo.currentFont().family() self.preferences["language"] = self.languageCombo.currentData() self.preferences["alertOutputs"] = [ x.data(Qt.ItemDataRole.DisplayRole) for x in self.alertList.selectedItems() ] self.preferences["playerOutputs"] = [ x.data(Qt.ItemDataRole.DisplayRole) for x in self.playerList.selectedItems() ] with open("preferences.json", "w") as f: json.dump(self.preferences, f, indent=2) if self.translator: if self.translator.language() != self.preferences["language"]: full_code: str = cast(str, self.preferences["language"]) locale = QLocale(full_code) language = locale.language() code = QLocale.languageToCode( language, QLocale.LanguageCodeType.ISO639Part1 ) print(language, code) fn = f":/translate/esl_reader_{code}.qm" translator = QTranslator() if translator.load(fn): QCoreApplication.removeTranslator(self.translator) self.translator = translator QCoreApplication.installTranslator(self.translator) else: print(self.tr("Unable to load translation file ") + f"{fn}") super().accept() return