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/PKGBUILD | 2 +- raveos-center/raveos_center/forditasok.json | 68 +++++++ raveos-center/raveos_center/jegyek_api.py | 5 +- .../raveos_center/oldalak/visszajelzes.py | 203 ++++++++++++++++++--- raveos-center/raveos_center/stilus.py | 12 ++ 5 files changed, 266 insertions(+), 24 deletions(-) (limited to 'raveos-center') diff --git a/raveos-center/PKGBUILD b/raveos-center/PKGBUILD index 348df76..bc2fdd1 100644 --- a/raveos-center/PKGBUILD +++ b/raveos-center/PKGBUILD @@ -2,7 +2,7 @@ pkgname=raveos-center pkgver=1.0.0 -pkgrel=5 +pkgrel=6 pkgdesc="RaveOS Center: apps, updates, drivers, gaming, snapshots and feedback in one place" arch=('any') url="https://git.rp1.hu/RaveOS/RaveOS-PKGBUILD" diff --git a/raveos-center/raveos_center/forditasok.json b/raveos-center/raveos_center/forditasok.json index df1a3d6..855bf53 100644 --- a/raveos-center/raveos_center/forditasok.json +++ b/raveos-center/raveos_center/forditasok.json @@ -1994,5 +1994,73 @@ "Uptime": { "en": "Uptime", "de": "Laufzeit" + }, + "Link (nem kötelező)": { + "en": "Link (optional)", + "de": "Link (optional)" + }, + "A link csak http:// vagy https:// kezdetű lehet.": { + "en": "The link must start with http:// or https://.", + "de": "Der Link muss mit http:// oder https:// beginnen." + }, + "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.": { + "en": "We take no responsibility for content behind links attached to ideas (for example a GitHub application or its source code). We cannot review every source one by one, so the RaveOS developers are not liable if linked content contains malicious code. Only install from trusted sources.", + "de": "Für Inhalte hinter Links, die an Ideen angehängt sind (zum Beispiel eine GitHub-Anwendung oder ihr Quellcode), übernehmen wir keine Verantwortung. Wir können nicht jede Quelle einzeln prüfen, daher haften die RaveOS-Entwickler nicht, wenn verlinkte Inhalte Schadcode enthalten. Installiere nur aus vertrauenswürdigen Quellen." + }, + "KIEMELT": { + "en": "PINNED", + "de": "HERVORGEHOBEN" + }, + "Link megnyitása": { + "en": "Open link", + "de": "Link öffnen" + }, + "Szerkesztve: {0} által, {1}": { + "en": "Edited by {0}, {1}", + "de": "Bearbeitet von {0}, {1}" + }, + "Szerkesztve: {0} által": { + "en": "Edited by {0}", + "de": "Bearbeitet von {0}" + }, + "Rendezés:": { + "en": "Sort:", + "de": "Sortieren:" + }, + "Legtöbb támogató": { + "en": "Most supporters", + "de": "Meiste Unterstützer" + }, + "Legújabb": { + "en": "Newest", + "de": "Neueste" + }, + "Új válasz a jegyedre": { + "en": "New reply to your ticket", + "de": "Neue Antwort auf dein Ticket" + }, + "{0} jegyedre érkezett válasz a Visszajelzésben.": { + "en": "{0} of your tickets got a reply in Feedback.", + "de": "{0} deiner Tickets hat eine Antwort im Feedback erhalten." + }, + "Új ötletek": { + "en": "New ideas", + "de": "Neue Ideen" + }, + "{0} új ötlet érkezett az utolsó megnézés óta.": { + "en": "{0} new ideas since you last looked.", + "de": "{0} neue Ideen seit deinem letzten Besuch." + }, + "Írd le 1-2 mondatban: mit szeretnél, és miért lenne hasznos? Egy link önmagában nem elég.": { + "en": "Describe in 1-2 sentences what you would like and why it would be useful. A link alone is not enough.", + "de": "Beschreibe in 1-2 Sätzen, was du dir wünschst und warum es nützlich wäre. Ein Link allein reicht nicht." + }, + "Az ötlethez írj 1-2 mondatos leírást, ne csak egy linket.": { + "en": "Write a 1-2 sentence description for your idea, not just a link.", + "de": "Schreibe zu deiner Idee eine Beschreibung von 1-2 Sätzen, nicht nur einen Link." + }, + "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á.": { + "en": "Every idea needs a 1-2 sentence description: what you would like and why it would be useful. A link alone is not enough, such ideas will not be approved.", + "de": "Jede Idee braucht eine Beschreibung von 1-2 Sätzen: was du dir wünschst und warum es nützlich wäre. Ein Link allein reicht nicht, solche Ideen werden nicht freigegeben." } } diff --git a/raveos-center/raveos_center/jegyek_api.py b/raveos-center/raveos_center/jegyek_api.py index db6cbc7..e76c07d 100644 --- a/raveos-center/raveos_center/jegyek_api.py +++ b/raveos-center/raveos_center/jegyek_api.py @@ -82,8 +82,10 @@ def jegy(jegy_id): return _hitelesitett("GET", f"/jegyek/{jegy_id}") -def uj_jegy(tipus, cim, szoveg, rendszer=None, naplo=None): +def uj_jegy(tipus, cim, szoveg, rendszer=None, naplo=None, link=None): adat = {"tipus": tipus, "cim": cim, "szoveg": szoveg} + if link: + adat["link"] = link if rendszer: adat["rendszer"] = rendszer if naplo: @@ -128,6 +130,7 @@ HIBAUZENETEK = { "nincs_jegy": tr("Ez a jegy már nem létezik."), "nincs_ilyen_naplo": tr("A megadott naplóazonosító nem létezik."), "kitiltva": tr("Ez a gép ki van tiltva a Visszajelzés használatából."), + "rossz_link": tr("A link csak http:// vagy https:// kezdetű lehet."), } 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) diff --git a/raveos-center/raveos_center/stilus.py b/raveos-center/raveos_center/stilus.py index 383e736..92a1c1e 100644 --- a/raveos-center/raveos_center/stilus.py +++ b/raveos-center/raveos_center/stilus.py @@ -181,6 +181,18 @@ QPushButton:disabled {{ color: {SZOVEG_HALVANY}; border-color: {KERET}; }} +QPushButton[sarga="true"] {{ + border: 1px solid {SARGA}; + color: {SARGA}; + background: {SARGA_PANEL}; +}} +QPushButton[sarga="true"]:hover {{ + background: {SARGA}; + color: {ZOLDON_SZOVEG}; +}} +#kartya[kiemelt="true"] {{ + border: 1px solid {ZOLD}; +}} QPushButton[fo="true"] {{ background: {ZOLD}; color: {ZOLDON_SZOVEG}; -- cgit v1.3