From 82097e9df2ebd575bcfaf5709617014c16128302 Mon Sep 17 00:00:00 2001 From: Nippy Date: Sun, 8 Nov 2026 22:48:54 +0100 Subject: update center app --- .../raveos_center/oldalak/visszajelzes.py | 203 ++++++++++++++++++--- 1 file changed, 181 insertions(+), 22 deletions(-) (limited to 'raveos-center/raveos_center/oldalak') diff --git a/raveos-center/raveos_center/oldalak/visszajelzes.py b/raveos-center/raveos_center/oldalak/visszajelzes.py index fcfcbdd..dc0e366 100644 --- a/raveos-center/raveos_center/oldalak/visszajelzes.py +++ b/raveos-center/raveos_center/oldalak/visszajelzes.py @@ -1,9 +1,15 @@ from datetime import datetime -from PyQt6.QtCore import Qt, QTimer -from PyQt6.QtGui import QTextCursor +import re +import shutil +import subprocess + +from PyQt6.QtCore import Qt, QTimer, QUrl +from PyQt6.QtGui import QDesktopServices, QTextCursor from PyQt6.QtWidgets import ( QCheckBox, + QApplication, + QComboBox, QDialog, QHBoxLayout, QLineEdit, @@ -134,6 +140,12 @@ class Urlap(QWidget): self.szoveg_mezo = QPlainTextEdit() self.szoveg_mezo.setMinimumHeight(160) doboz.addWidget(self.szoveg_mezo) + self.link_cimke = cimke(tr("Link (nem kötelező)"), "kartyacim") + doboz.addWidget(self.link_cimke) + self.link_mezo = QLineEdit() + self.link_mezo.setMaxLength(500) + self.link_mezo.setPlaceholderText("https://") + doboz.addWidget(self.link_mezo) self.diag = Kartya(terkoz=8, margo=16) self.diag_jelolo = QCheckBox(tr("Diagnosztika csatolása (ajánlott, segít megtalálni a hibát)")) @@ -181,6 +193,9 @@ class Urlap(QWidget): self.tipus = tipus self.cim_mezo.clear() self.szoveg_mezo.clear() + self.link_mezo.clear() + self.link_cimke.setVisible(tipus == "otlet") + self.link_mezo.setVisible(tipus == "otlet") self.diag_jelolo.setChecked(False) self.hiba.hide() self.kuld.setEnabled(True) @@ -197,7 +212,9 @@ class Urlap(QWidget): "ahol mások is támogathatják.") ) self.cim_mezo.setPlaceholderText(tr("Például: Sötét és világos téma váltó")) - self.szoveg_mezo.setPlaceholderText(tr("Mit szeretnél, és miért lenne hasznos?")) + self.szoveg_mezo.setPlaceholderText( + tr("Írd le 1-2 mondatban: mit szeretnél, és miért lenne hasznos? Egy link önmagában nem elég.") + ) self.diag.hide() self.cim_mezo.setFocus() @@ -215,10 +232,19 @@ class Urlap(QWidget): def _kuld(self): cim = self.cim_mezo.text().strip() szoveg = self.szoveg_mezo.toPlainText().strip() + link = self.link_mezo.text().strip() if self.tipus == "otlet" else "" if len(cim) < 3 or len(szoveg) < 10: self.hiba.setText(tr("Adj meg egy legalább 3 karakteres címet és egy legalább 10 karakteres leírást.")) self.hiba.show() return + if self.tipus == "otlet" and len(re.sub(r"https?://\S+", "", szoveg).strip()) < OTLET_MIN_LEIRAS: + self.hiba.setText(tr("Az ötlethez írj 1-2 mondatos leírást, ne csak egy linket.")) + self.hiba.show() + return + if link and not link.startswith(("http://", "https://")): + self.hiba.setText(jegyek_api.HIBAUZENETEK["rossz_link"]) + self.hiba.show() + return self.hiba.hide() self.kuld.setEnabled(False) self.kuld.setText(tr("Küldés...")) @@ -227,7 +253,7 @@ class Urlap(QWidget): def munka(): naplo = jegyek_api.naplo_feltolt(diagnosztika.jelentes()) if csatol else None - return jegyek_api.uj_jegy(tipus, cim, szoveg, diagnosztika.rendszer_osszegzes(), naplo) + return jegyek_api.uj_jegy(tipus, cim, szoveg, diagnosztika.rendszer_osszegzes(), naplo, link or None) hatterben(munka, kesz=self._kuldve, hiba=self._kuldes_hiba) @@ -247,6 +273,7 @@ class Reszletek(QWidget): super().__init__() self.oldal = oldal self.jegy_id = None + self.frissitve = None doboz = QVBoxLayout(self) doboz.setContentsMargins(0, 0, 0, 0) doboz.setSpacing(12) @@ -284,8 +311,10 @@ class Reszletek(QWidget): vd.addLayout(sor) doboz.addWidget(self.valasz_doboz) - def betolt(self, jegy): + def betolt(self, jegy, piszkozat_marad=False): + piszkozat = self.valasz_mezo.toPlainText() if piszkozat_marad and self.jegy_id == jegy["id"] else "" self.jegy_id = jegy["id"] + self.frissitve = jegy.get("frissitve") self.cim.setText(jegy["cim"]) while self.meta.count(): w = self.meta.takeAt(0).widget() @@ -318,7 +347,7 @@ class Reszletek(QWidget): self.szal.addWidget(Uzenet(u)) self.szal.addStretch(1) self.hiba.hide() - self.valasz_mezo.clear() + self.valasz_mezo.setPlainText(piszkozat) def _kuld(self): szoveg = self.valasz_mezo.toPlainText().strip() @@ -492,7 +521,9 @@ class ErtekelesLap(QWidget): hatterben(jegyek_api.ertekel, csillag, szoveg, kesz=kesz, hiba=hiba) -ELFOGADAS_VERZIO = 3 +ELFOGADAS_VERZIO = 4 +OTLET_MIN_LEIRAS = 10 +FRISSITES_MS = 60000 ISMERTETO = [ (tr("Mire jó?"), "", [ @@ -520,6 +551,12 @@ ISMERTETO = [ tr("A Visszajelzés csak hibák jelzésére és ötletek beküldésére való."), tr("Egy hibáról egy jegyet nyiss. Ha már van róla jegyed, abba írj, ne nyiss újat."), tr("Ötlet beküldése előtt nézd meg az Ötletek listát. Ha van hasonló, támogasd azt, ne küldj újat."), + tr("Az ötlethez kötelező 1-2 mondatos leírás: mit szeretnél, és miért lenne hasznos. Egy link önmagában " + "nem elég, ezeket nem hagyjuk jóvá."), + tr("Az ötletekhez csatolt linkeken található tartalomért (például egy GitHub-alkalmazás vagy annak " + "forráskódja) nem vállalunk felelősséget. Nincs lehetőségünk minden forrást egyenként átnézni, ezért " + "ha a linkelt tartalom kártékony kódot tartalmaz, azért a RaveOS fejlesztői nem felelnek. " + "Csak megbízható forrásból telepíts."), tr("Ne írj a jegybe vagy az értékelésbe személyes vagy titkos adatot: jelszót, e-mail-címet, telefonszámot vagy más emberek " "adatait. A diagnosztikát kitakarjuk, a beírt szöveget nem."), tr("Kulturált hangnemet kérünk. Sértő, fenyegető vagy trágár üzenet tiltással jár."), @@ -602,13 +639,31 @@ class IsmertetoAblak(QDialog): class OtletKartya(Kartya): def __init__(self, otlet, szavaz): super().__init__(terkoz=8, margo=18) + if otlet.get("kiemelt"): + self.setProperty("kiemelt", True) + self.elrendezes.addWidget(cimke(tr("KIEMELT"), "monozold")) felso = QHBoxLayout() cim = cimke(otlet["cim"], tordel=True) cim.setStyleSheet("font-size: 15px; font-weight: 600;") felso.addWidget(cim, 1) - felso.addWidget(allapotcimke(otlet["allapot"]), 0, Qt.AlignmentFlag.AlignTop) + if otlet.get("link"): + link = gomb(tr("Link megnyitása"), kicsi=True) + link.setToolTip(otlet["link"]) + link.clicked.connect(lambda: QDesktopServices.openUrl(QUrl(otlet["link"]))) + felso.addWidget(link, 0, Qt.AlignmentFlag.AlignTop) + if otlet["allapot"] != "uj": + felso.addWidget(allapotcimke(otlet["allapot"]), 0, Qt.AlignmentFlag.AlignTop) self.elrendezes.addLayout(felso) self.elrendezes.addWidget(cimke(otlet.get("leiras") or "", "masodlagos", True)) + if otlet.get("szerkesztette"): + self.elrendezes.addWidget( + cimke( + tr("Szerkesztve: {0} által, {1}", otlet["szerkesztette"], ido(otlet["szerkesztve"])) + if otlet.get("szerkesztve") + else tr("Szerkesztve: {0} által", otlet["szerkesztette"]), + "halvany", + ) + ) also = QHBoxLayout() also.addWidget(cimke(tr("{0} támogató", otlet['szavazat']), "monohalvany")) if otlet.get("sajat"): @@ -621,6 +676,18 @@ class OtletKartya(Kartya): self.elrendezes.addLayout(also) +def rendez(otletek, mod): + kulcs = (lambda o: o["letrehozva"]) if mod == "uj" else (lambda o: (o["szavazat"], o["letrehozva"])) + kiemelt = sorted((o for o in otletek if o.get("kiemelt")), key=kulcs, reverse=True) + tobbi = sorted((o for o in otletek if not o.get("kiemelt")), key=kulcs, reverse=True) + return kiemelt + tobbi + + +def ertesit(cim, szoveg): + if shutil.which("notify-send"): + subprocess.Popen(["notify-send", "-a", "RaveOS Center", "-i", "raveos-center", cim, szoveg]) + + class Visszajelzes(Oldal): def __init__(self, kozpont): super().__init__(kozpont, tr("HIBÁK ÉS ÖTLETEK"), tr("Visszajelzés"), kitolt=True) @@ -628,7 +695,9 @@ class Visszajelzes(Oldal): self.uj_hiba.clicked.connect(lambda: self.urlap_nyit("hiba")) self.uj_otlet = self.fejlec_gomb(gomb(tr("Új ötlet"))) self.uj_otlet.clicked.connect(lambda: self.urlap_nyit("otlet")) - sugo = self.fejlec_gomb(gomb(tr("Hogyan működik?"))) + sugo = gomb(tr("Hogyan működik?")) + sugo.setProperty("sarga", True) + sugo = self.fejlec_gomb(sugo) sugo.clicked.connect(self.ismerteto) self.elfogadas_sav = QWidget() @@ -700,6 +769,17 @@ class Visszajelzes(Oldal): True, ) ) + rendezo = QHBoxLayout() + rendezo.addWidget(cimke(tr("Rendezés:"), "halvany")) + self.rendezes = QComboBox() + self.rendezes.addItem(tr("Legtöbb támogató"), "tamogato") + self.rendezes.addItem(tr("Legújabb"), "uj") + self.rendezes.setCurrentIndex(max(0, self.rendezes.findData(beallitasok.ertek("otletek_rendezes", "tamogato")))) + self.rendezes.currentIndexChanged.connect(self._rendezes_valtozott) + rendezo.addWidget(self.rendezes) + rendezo.addStretch(1) + od.addLayout(rendezo) + self.otletek_adat = [] self.otlet_doboz = QVBoxLayout() self.otlet_doboz.setSpacing(12) od.addLayout(self.otlet_doboz) @@ -710,12 +790,77 @@ class Visszajelzes(Oldal): self.ertekeles_lap = ErtekelesLap(self) ertekeles_gorgeto.setWidget(self.ertekeles_lap) self.fulek.addWidget(ertekeles_gorgeto) + self.frissito = QTimer(self) + self.frissito.setInterval(FRISSITES_MS) + self.frissito.timeout.connect(self.idoszakos) + self.frissito.start() + QApplication.instance().applicationStateChanged.connect(self._allapot_valtozott) self.jegyek = [] + self.uj_otletek = 0 + self.uj_valaszok = 0 self.lista_betoltve = False self.ful("jegyeim") def indulaskor(self): - hatterben(jegyek_api.jegyeim, kesz=self._jelveny_frissit) + def munka(): + return jegyek_api.jegyeim(), (jegyek_api.otletek() if self.elfogadva() else []) + + def kesz(eredmeny): + jegyek, otletek = eredmeny + self._uj_otletek_szamol(otletek) + self._jelveny_frissit(jegyek) + valaszok = sum(1 for j in jegyek if j["uj_valasz"]) + if valaszok: + ertesit(tr("Új válasz a jegyedre"), tr("{0} jegyedre érkezett válasz a Visszajelzésben.", valaszok)) + if self.uj_otletek: + ertesit(tr("Új ötletek"), tr("{0} új ötlet érkezett az utolsó megnézés óta.", self.uj_otletek)) + + hatterben(munka, kesz=kesz) + + def _allapot_valtozott(self, allapot): + if allapot == Qt.ApplicationState.ApplicationActive: + self.idoszakos() + + def idoszakos(self): + if not self.elfogadva() or self.kitiltva: + return + def kesz(jegyek): + self._jelveny_frissit(jegyek) + if not self.isVisible() or self.fulek.currentIndex() != 0 or self.jobb.currentWidget() is self.urlap_gorgeto: + return + if jegyek != self.jegyek: + self.lista_frissit() + nyitott = self.reszletek.jegy_id + regi = next((j for j in self.jegyek if j["id"] == nyitott), None) + uj = next((j for j in jegyek if j["id"] == nyitott), None) + if nyitott and uj and (not regi or uj.get("frissitve") != self.reszletek.frissitve): + hatterben( + jegyek_api.jegy, + nyitott, + kesz=lambda jegy: self.reszletek.jegy_id == jegy["id"] and self.reszletek.betolt(jegy, True), + hiba=self._jegy_hiba, + ) + + hatterben(jegyek_api.jegyeim, kesz=kesz) + if self.isVisible() and self.fulek.currentIndex() == 1: + self._otletek_frissit() + + def _uj_otletek_szamol(self, otletek): + if not otletek: + return + legujabb = max(o["letrehozva"] for o in otletek) + latott = beallitasok.ertek("otletek_latott", None) + if latott is None: + beallitasok.beallit("otletek_latott", legujabb) + latott = legujabb + self.uj_otletek = sum(1 for o in otletek if o["letrehozva"] > latott and not o.get("sajat")) + + def _fulcimkek(self): + jegyeim = tr("Jegyeim") + (f" ({self.uj_valaszok})" if self.uj_valaszok else "") + otletek = tr("Ötletek") + (f" ({self.uj_otletek})" if self.uj_otletek else "") + self.fulsor.gombok["jegyeim"].setText(jegyeim) + self.fulsor.gombok["otletek"].setText(otletek) + self.kozpont.jelveny(AZON, self.uj_valaszok + self.uj_otletek) def elfogadva(self): return (beallitasok.ertek("visszajelzes_elfogadva", 0) or 0) >= ELFOGADAS_VERZIO @@ -799,7 +944,8 @@ class Visszajelzes(Oldal): self.hiba.show() def _jelveny_frissit(self, jegyek): - self.kozpont.jelveny(AZON, sum(1 for j in jegyek if j["uj_valasz"])) + self.uj_valaszok = sum(1 for j in jegyek if j["uj_valasz"]) + self._fulcimkek() def lista_frissit(self, kivalaszt=None): def kesz(jegyek): @@ -875,20 +1021,33 @@ class Visszajelzes(Oldal): hiba=self._jegy_hiba, ) + def _rendezes_valtozott(self, _index): + beallitasok.beallit("otletek_rendezes", self.rendezes.currentData()) + self._otletek_mutat() + + def _otletek_mutat(self): + while self.otlet_doboz.count(): + w = self.otlet_doboz.takeAt(0).widget() + if w: + w.deleteLater() + if not self.otletek_adat: + self.otlet_doboz.addWidget(cimke(tr("Még nincs közzétett ötlet."), "halvany")) + for o in rendez(self.otletek_adat, self.rendezes.currentData()): + kartya = OtletKartya(o, self._szavaz) + for g in kartya.findChildren(QPushButton): + g.setEnabled(self.szabad() or g.text() == tr("Link megnyitása")) + self.otlet_doboz.addWidget(kartya) + def _otletek_frissit(self): def kesz(otletek): self.hiba.hide() - while self.otlet_doboz.count(): - w = self.otlet_doboz.takeAt(0).widget() - if w: - w.deleteLater() - if not otletek: - self.otlet_doboz.addWidget(cimke(tr("Még nincs közzétett ötlet."), "halvany")) - for o in otletek: - kartya = OtletKartya(o, self._szavaz) - for g in kartya.findChildren(QPushButton): - g.setEnabled(self.szabad()) - self.otlet_doboz.addWidget(kartya) + self.otletek_adat = otletek + if otletek: + latott = beallitasok.ertek("otletek_latott", 0) or 0 + beallitasok.beallit("otletek_latott", max([latott] + [o["letrehozva"] for o in otletek])) + self.uj_otletek = 0 + self._fulcimkek() + self._otletek_mutat() hatterben(jegyek_api.otletek, kesz=kesz, hiba=self._hibat_mutat) -- cgit v1.3