from PyQt6.QtCore import Qt from PyQt6.QtWidgets import ( QCheckBox, QFrame, QHBoxLayout, QLineEdit, QMessageBox, QPushButton, QVBoxLayout, QWidget, ) from raveos_center import katalogus from raveos_center.elemek import Kartya, Oldal, cimke, frissit_stilus, gomb from raveos_center.folyamat import FolyamatAblak from raveos_center.hatter import gyorsitott AZON = "alkalmazasok" MENU = "Alkalmazások" IKON = "alkalmazasok" CSAK_TELEPITETT = "telepitett" class KattinthatoSor(QWidget): def __init__(self, jelolo): super().__init__() self.jelolo = jelolo self.setCursor(Qt.CursorShape.PointingHandCursor) def mouseReleaseEvent(self, esemeny): if esemeny.button() == Qt.MouseButton.LeftButton and self.rect().contains(esemeny.position().toPoint()): self.jelolo.toggle() super().mouseReleaseEvent(esemeny) class AppSor(QWidget): def __init__(self, app, oldal): super().__init__() self.app = app self.oldal = oldal self.telepitve = False self.setObjectName("appsor") self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True) doboz = QVBoxLayout(self) doboz.setContentsMargins(16, 12, 16, 12) doboz.setSpacing(8) felso = QHBoxLayout() felso.setSpacing(14) self.jelolo = QCheckBox() self.jelolo.setVisible(app["type"] != "message") self.jelolo.toggled.connect(self._sor_jelolve) felso.addWidget(self.jelolo) betu = cimke(app["name"][:1].upper(), "kezdobetu") betu.setAlignment(Qt.AlignmentFlag.AlignCenter) betu.setFixedSize(36, 36) felso.addWidget(betu) szovegek = QVBoxLayout() szovegek.setSpacing(2) nevsor = QHBoxLayout() nevsor.setSpacing(10) nev = cimke(app["name"]) nev.setStyleSheet("font-size: 14px; font-weight: 600;") nevsor.addWidget(nev) nevsor.addWidget(cimke(katalogus.forras(app), "monohalvany")) self.allapot = cimke("TELEPÍTVE", "allapotcimke") self.allapot.setProperty("szin", "zold") self.allapot.hide() nevsor.addWidget(self.allapot) nevsor.addStretch(1) szovegek.addLayout(nevsor) leiras = katalogus.loc(app.get("desc")) self.leiras = cimke(leiras, "halvany") self.leiras.setToolTip(leiras) self.leiras.setMinimumWidth(80) szovegek.addWidget(self.leiras) felso.addLayout(szovegek, 1) self.eltavolit_gomb = None if app["type"] == "choice": self.eltavolit_gomb = gomb("Eltávolítás", kicsi=True) self.eltavolit_gomb.clicked.connect(lambda: self._opcio_muvelet(False)) felso.addWidget(self.eltavolit_gomb) self.gomb = gomb("", kicsi=True) self.gomb.setMinimumWidth(110) self.gomb.clicked.connect(self._kattint) felso.addWidget(self.gomb) doboz.addLayout(felso) self.opciok = [] if app["type"] == "choice": self._opcio_lista(doboz) elif app["type"] != "message": self.setCursor(Qt.CursorShape.PointingHandCursor) self.frissit(oldal.index) def mouseReleaseEvent(self, esemeny): if ( esemeny.button() == Qt.MouseButton.LeftButton and self.app["type"] not in ("choice", "message") and self.rect().contains(esemeny.position().toPoint()) ): self.jelolo.toggle() super().mouseReleaseEvent(esemeny) def resizeEvent(self, esemeny): super().resizeEvent(esemeny) teljes = self.leiras.toolTip() self.leiras.setText( self.leiras.fontMetrics().elidedText(teljes, Qt.TextElideMode.ElideRight, max(80, self.leiras.width())) ) def _opcio_lista(self, doboz): lista = QVBoxLayout() lista.setContentsMargins(82, 4, 0, 0) lista.setSpacing(6) fej = QHBoxLayout() fej.addWidget(cimke("VÁLASSZ, AKÁR TÖBBET IS", "monohalvany")) fej.addStretch(1) mind = gomb("Mind kijelölése", kicsi=True) mind.clicked.connect(self._mind) fej.addWidget(mind) lista.addLayout(fej) for o in self.app.get("options", []): jelolo = QCheckBox(o["name"]) jelolo.setMinimumWidth(130) jelolo.toggled.connect(lambda _: self._gombok_opcio()) kontener = KattinthatoSor(jelolo) sor = QHBoxLayout(kontener) sor.setContentsMargins(0, 2, 0, 2) sor.setSpacing(10) sor.addWidget(jelolo) leiras = cimke(katalogus.loc(o.get("desc")), "halvany") sor.addWidget(leiras, 1) allapot = cimke("TELEPÍTVE", "allapotcimke") allapot.setProperty("szin", "zold") sor.addWidget(allapot) lista.addWidget(kontener) self.opciok.append((jelolo, allapot, o)) doboz.addLayout(lista) def _mind(self): mind = all(j.isChecked() for j, _, _ in self.opciok) for j, _, _ in self.opciok: j.setChecked(not mind) def _sor_jelolve(self, jelolve): if self.opciok: for j, _, _ in self.opciok: j.blockSignals(True) j.setChecked(jelolve) j.blockSignals(False) self._gombok_opcio() self.oldal.kijeles_valtozott() def torol_kijeles(self): self.jelolo.setChecked(False) def telepitendo(self): if self.app["type"] == "choice": opciok = self._kijelolt(False) return (self.app, opciok) if opciok else None if self.jelolo.isChecked() and not self.telepitve and self.app["type"] != "message": return (self.app, None) return None def eltavolitando(self): if self.app["type"] == "choice": opciok = self._kijelolt(True) return (self.app, opciok) if opciok else None if self.jelolo.isChecked() and self.telepitve and katalogus.eltavolithato(self.app): return (self.app, None) return None def _kijelolt(self, telepitett): return [ o["id"] for j, _, o in self.opciok if j.isChecked() and katalogus.opcio_telepitve(o, self.oldal.index) == telepitett ] def _gombok_opcio(self): uj = self._kijelolt(False) regi = self._kijelolt(True) self.jelolo.blockSignals(True) self.jelolo.setChecked(any(j.isChecked() for j, _, _ in self.opciok)) self.jelolo.blockSignals(False) self.oldal.kijeles_valtozott() self.gomb.setText(f"Telepítés ({len(uj)})" if uj else "Telepítés") self.gomb.setEnabled(bool(uj)) self.gomb.setProperty("fo", True) frissit_stilus(self.gomb) self.eltavolit_gomb.setText(f"Eltávolítás ({len(regi)})" if regi else "Eltávolítás") self.eltavolit_gomb.setEnabled(bool(regi)) def _opcio_muvelet(self, telepites): kijelolt = self._kijelolt(not telepites) if kijelolt: self.oldal.muvelet(self.app, telepites, kijelolt) def frissit(self, index): if self.app["type"] == "choice": db = 0 for _, allapot, o in self.opciok: fent = katalogus.opcio_telepitve(o, index) allapot.setVisible(fent) db += fent self.telepitve = db > 0 self.allapot.setText(f"{db} / {len(self.opciok)} TELEPÍTVE") self.allapot.setVisible(db > 0) self._gombok_opcio() return if self.app["type"] == "message": self.gomb.setText("Tudnivalók") self.gomb.setProperty("fo", False) else: self.telepitve = katalogus.telepitve(self.app, index) self.allapot.setVisible(self.telepitve) if self.telepitve: self.gomb.setText("Eltávolítás") self.gomb.setEnabled(katalogus.eltavolithato(self.app)) self.gomb.setProperty("fo", False) else: self.gomb.setText("Telepítés") self.gomb.setEnabled(True) self.gomb.setProperty("fo", True) frissit_stilus(self.gomb) def _kattint(self): if self.app["type"] == "message": QMessageBox.information(self, self.app["name"], katalogus.loc(self.app.get("message"))) return if self.app["type"] == "choice": self._opcio_muvelet(True) return self.oldal.muvelet(self.app, not self.telepitve) class Csoport(QWidget): def __init__(self, nev): super().__init__() self.nev = nev doboz = QVBoxLayout(self) doboz.setContentsMargins(0, 0, 0, 0) doboz.setSpacing(10) self.fejlec = cimke("", "h2") doboz.addWidget(self.fejlec) self.lista = Kartya(terkoz=0, margo=0) doboz.addWidget(self.lista) self.sorok = [] def hozzaad(self, sor): self.sorok.append(sor) self.lista.elrendezes.addWidget(sor) def szur(self, lathatok): db = 0 utolso = None for sor in self.sorok: lathato = sor in lathatok sor.setVisible(lathato) sor.setProperty("utolso", False) if lathato: db += 1 utolso = sor if utolso: utolso.setProperty("utolso", True) for sor in self.sorok: frissit_stilus(sor) self.fejlec.setText(f"{self.nev.upper()} · {db}") self.setVisible(db > 0) return db class Alkalmazasok(Oldal): def __init__(self, kozpont): super().__init__(kozpont, "PACMAN · AUR · FLATPAK", "Alkalmazások") self.katalogus = [] self.index = {"pacman": set(), "flatpak": set()} self.sorok = [] self.csoportok = {} self.kategoria = "all" self.kereso = QLineEdit() self.kereso.setPlaceholderText("Keresés, pl. Steam, OBS, Discord") self.kereso.setClearButtonEnabled(True) self.kereso.setMinimumWidth(220) self.kereso.setMaximumWidth(340) self.kereso.textChanged.connect(self._szur) self.fejlec_gomb(self.kereso) pillek = QHBoxLayout() pillek.setSpacing(8) self.pillek = {} for azon, nev in katalogus.KATEGORIAK + [(CSAK_TELEPITETT, "Csak telepítettek")]: p = QPushButton(nev) p.setObjectName("pill") p.setCursor(Qt.CursorShape.PointingHandCursor) p.clicked.connect(lambda _=False, a=azon: self._kategoria(a)) self.pillek[azon] = p if azon == CSAK_TELEPITETT: pillek.addStretch(1) pillek.addWidget(p) self.torzs.addLayout(pillek) self.kiemelt = Kartya(terkoz=8, margo=24) self.kiemelt.setObjectName("kiemelt") ks = QHBoxLayout() ks.setSpacing(24) kszoveg = QVBoxLayout() kszoveg.setSpacing(6) kszoveg.addWidget(cimke("CSOMAG · GAMING ALAPOK", "eyebrow")) kszoveg.addWidget(cimke("EGY KATTINTÁS, MINDEN AMI JÁTÉKHOZ KELL", "h2", True)) kszoveg.addWidget( cimke("Steam (Proton-GE-vel), Lutris, Heroic, GameMode és MangoHud egyben, előre beállítva.", "masodlagos", True) ) ks.addLayout(kszoveg, 1) self.kiemelt_gomb = gomb("Csomag telepítése", fo=True) self.kiemelt_gomb.clicked.connect(self._gaming_alapok) ks.addWidget(self.kiemelt_gomb, 0, Qt.AlignmentFlag.AlignVCenter) self.kiemelt.elrendezes.addLayout(ks) self.torzs.addWidget(self.kiemelt) self.hiba = cimke("", "figyelem", True) self.hiba.hide() self.torzs.addWidget(self.hiba) self._kijeles_sav() self.lista = QVBoxLayout() self.lista.setSpacing(28) self.torzs.addLayout(self.lista) self.ures = cimke("Nincs találat.", "halvany") self.ures.hide() self.torzs.addWidget(self.ures) self.torzs.addStretch(1) self._betolt() self._kategoria("all") def _kijeles_sav(self): self.sav = QFrame(self) self.sav.setObjectName("kijelessav") s = QHBoxLayout(self.sav) s.setContentsMargins(48, 12, 48, 12) s.setSpacing(8) self.sav_szoveg = cimke("", "mono") s.addWidget(self.sav_szoveg) s.addStretch(1) torles = gomb("Kijelölés törlése", kicsi=True) torles.clicked.connect(self._kijeles_torles) s.addWidget(torles) self.sav_eltavolit = gomb("Kijelöltek eltávolítása") self.sav_eltavolit.clicked.connect(lambda: self._tomeges(False)) s.addWidget(self.sav_eltavolit) self.sav_telepit = gomb("Kijelöltek telepítése", fo=True) self.sav_telepit.clicked.connect(lambda: self._tomeges(True)) s.addWidget(self.sav_telepit) self.sav.hide() def resizeEvent(self, esemeny): super().resizeEvent(esemeny) magassag = self.sav.sizeHint().height() self.sav.setGeometry(0, self.height() - magassag, self.width(), magassag) def kijeles_valtozott(self): if not hasattr(self, "sav"): return uj = [x for x in (s.telepitendo() for s in self.sorok) if x] regi = [x for x in (s.eltavolitando() for s in self.sorok) if x] kijelolt = sum(1 for s in self.sorok if s.jelolo.isChecked()) latszik = kijelolt > 0 self.sav.setVisible(latszik) self.setViewportMargins(0, 0, 0, self.sav.sizeHint().height() if latszik else 0) self.sav_szoveg.setText(f"{kijelolt} KIJELÖLVE") self.sav_telepit.setText(f"Kijelöltek telepítése ({len(uj)})") self.sav_telepit.setEnabled(bool(uj)) self.sav_eltavolit.setText(f"Kijelöltek eltávolítása ({len(regi)})") self.sav_eltavolit.setEnabled(bool(regi)) if latszik: self.sav.raise_() magassag = self.sav.sizeHint().height() self.sav.setGeometry(0, self.height() - magassag, self.width(), magassag) def _kijeles_torles(self): for s in self.sorok: s.torol_kijeles() def _nev(self, app, opciok): if opciok: return ", ".join(f"{app['name']}: {o['name']}" for o in app.get("options", []) if o["id"] in opciok) return app["name"] def _tomeges(self, telepites): tetelek = [x for x in ((s.telepitendo() if telepites else s.eltavolitando()) for s in self.sorok) if x] if not tetelek: return nevek = [self._nev(app, opciok) for app, opciok in tetelek] if not telepites: valasz = QMessageBox.question( self, "Eltávolítás", "Biztosan eltávolítod ezeket?\n\n" + "\n".join(nevek), QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No, ) if valasz != QMessageBox.StandardButton.Yes: return lepesek = [] for app, opciok in tetelek: for lepes in katalogus.lepesek(app, telepites, opciok): lepes.kotelezo = False lepesek.append(lepes) if not lepesek: return cim = f"{'Telepítés' if telepites else 'Eltávolítás'}: {len(tetelek)} alkalmazás" FolyamatAblak(self, cim, lepesek, "Minden lépés sikeresen lefutott.", "Nem minden lépés sikerült.").exec() self._kijeles_torles() self.megjelenik() def _betolt(self): try: self.katalogus = katalogus.betolt() except (OSError, ValueError, RuntimeError) as e: self.hiba.setText(f"Az alkalmazáskatalógus nem tölthető be: {e}") self.hiba.show() return for azon, nev in katalogus.KATEGORIAK[1:]: csoport = Csoport(nev) self.csoportok[azon] = csoport self.lista.addWidget(csoport) for app in self.katalogus: csoport = self.csoportok.get(app["category"]) or self.csoportok["System"] sor = AppSor(app, self) self.sorok.append(sor) csoport.hozzaad(sor) def megjelenik(self, *_): gyorsitott("telepitett", katalogus.telepitett_index, kesz=self._index_kesz, kor=30) def _index_kesz(self, index): if index == self.index: return self.index = index for s in self.sorok: s.frissit(index) alap = [a for a in self.katalogus if a["id"] in katalogus.GAMING_ALAPOK] hianyzik = [a for a in alap if not katalogus.telepitve(a, index)] self.kiemelt_gomb.setEnabled(bool(hianyzik)) self.kiemelt_gomb.setText("Csomag telepítése" if hianyzik else "Minden telepítve") self._szur() def _kategoria(self, azon): self.kategoria = azon for a, p in self.pillek.items(): p.setProperty("aktiv", a == azon) frissit_stilus(p) self._szur() def _szur(self): szoveg = self.kereso.text().strip().lower() lathatok = set() for s in self.sorok: app = s.app if self.kategoria == CSAK_TELEPITETT: jo = s.telepitve else: jo = self.kategoria == "all" or app["category"] == self.kategoria if jo and (not szoveg or szoveg in app["name"].lower() or szoveg in katalogus.loc(app.get("desc")).lower()): lathatok.add(s) osszes = sum(c.szur(lathatok) for c in self.csoportok.values()) self.ures.setText( "Még nincs telepítve egyetlen alkalmazás sem a listából." if self.kategoria == CSAK_TELEPITETT and not szoveg else "Nincs találat." ) self.ures.setVisible(osszes == 0) self.kiemelt.setVisible(self.kategoria in ("all", "Games") and not szoveg) def muvelet(self, app, telepites, opciok=None): if not telepites: nevek = ", ".join(o["name"] for o in app.get("options", []) if o["id"] in (opciok or [])) or app["name"] valasz = QMessageBox.question( self, "Eltávolítás", f"Biztosan eltávolítod: {nevek}?", QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No, ) if valasz != QMessageBox.StandardButton.Yes: return lepesek = katalogus.lepesek(app, telepites, opciok) if not lepesek: return cim = f"{'Telepítés' if telepites else 'Eltávolítás'}: {app['name']}" FolyamatAblak(self, cim, lepesek, f"{app['name']} {'telepítve' if telepites else 'eltávolítva'}.").exec() self.megjelenik() def _gaming_alapok(self): lepesek = [] for app in self.katalogus: if app["id"] in katalogus.GAMING_ALAPOK and not katalogus.telepitve(app, self.index): lepesek += katalogus.lepesek(app, True) if not lepesek: return FolyamatAblak(self, "Gaming alapok telepítése", lepesek, "A Gaming alapok telepítve.").exec() self.megjelenik() OLDAL = Alkalmazasok