From da16a66d412d68b0f58686327c0226c36be0a317 Mon Sep 17 00:00:00 2001 From: Kibi Kelburton Date: Tue, 11 Aug 2026 22:44:55 +0200 Subject: [PATCH] Quality of life notification enhancement --- gui.py | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 9 deletions(-) diff --git a/gui.py b/gui.py index 2cbca3d..db6f0f4 100644 --- a/gui.py +++ b/gui.py @@ -23,8 +23,8 @@ def normalize_file_path(path_str: str) -> str: else: path_str = urllib.parse.unquote(path_str[7:]) return os.path.abspath(path_str) -from PySide6.QtCore import Qt, QThread, QObject, Signal, QUrl, QFile, QIODevice -from PySide6.QtGui import QIcon, QAction, QPixmap, QPainter, QColor, QFont, QPen, QImage, QDesktopServices +from PySide6.QtCore import Qt, QThread, QObject, Signal, QUrl, QFile, QIODevice, QTimer, QMimeData +from PySide6.QtGui import QIcon, QAction, QPixmap, QPainter, QColor, QFont, QPen, QImage, QDesktopServices, QDrag from PySide6.QtNetwork import QNetworkAccessManager, QNetworkRequest, QHttpMultiPart, QHttpPart, QNetworkReply, QLocalServer, QLocalSocket from PySide6.QtWidgets import ( QApplication, QSystemTrayIcon, QMenu, QDialog, QVBoxLayout, QHBoxLayout, @@ -533,6 +533,39 @@ class SettingsDialog(QDialog): else: QMessageBox.critical(self, "Error", "Failed to save configuration file.") +# ========================================== +# Draggable File Label Widget +# ========================================== +class DraggableImageLabel(QLabel): + def __init__(self, file_path, parent=None): + super().__init__(parent) + self.file_path = file_path + self.drag_start_pos = None + + def mousePressEvent(self, event): + if event.button() == Qt.MouseButton.LeftButton: + self.drag_start_pos = event.pos() + super().mousePressEvent(event) + + def mouseMoveEvent(self, event): + if not (event.buttons() & Qt.MouseButton.LeftButton): + return + if self.drag_start_pos is None: + return + if (event.pos() - self.drag_start_pos).manhattanLength() < QApplication.startDragDistance(): + return + + if self.file_path and os.path.exists(self.file_path): + drag = QDrag(self) + mime_data = QMimeData() + mime_data.setUrls([QUrl.fromLocalFile(self.file_path)]) + drag.setMimeData(mime_data) + + if self.pixmap() and not self.pixmap().isNull(): + drag.setPixmap(self.pixmap().scaled(80, 80, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) + + drag.exec(Qt.DropAction.CopyAction) + # ========================================== # Upload Gallery Window & Components # ========================================== @@ -559,10 +592,13 @@ class GalleryCard(QFrame): layout.setContentsMargins(8, 8, 8, 8) layout.setSpacing(6) - # Thumbnail - self.thumb_label = QLabel() + # Thumbnail with Drag & Drop support + file_path = item.get("file_path", "") + self.thumb_label = DraggableImageLabel(file_path) self.thumb_label.setFixedSize(160, 100) self.thumb_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.thumb_label.setCursor(Qt.CursorShape.OpenHandCursor) + self.thumb_label.setToolTip("Click & Drag to drop file into other apps") self.thumb_label.setStyleSheet("background-color: #121216; border-radius: 4px;") thumb_path = item.get("thumbnail_path", "") @@ -1238,14 +1274,48 @@ class SystemTrayApp(QObject): if not config.get("enable_notifications", True): return - thumb_path = generate_thumbnail(file_path) - if thumb_path and os.path.exists(thumb_path): - body_text = f'


{item_url}' + abs_path = os.path.abspath(file_path) + ext = os.path.splitext(abs_path)[1].lower() + if ext in [".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", ".avif"]: + img_path = abs_path else: - body_text = f'Upload Successful: {item_url}' + img_path = generate_thumbnail(abs_path) or abs_path + file_url = "file://" + abs_path + + body_text = f'{item_url}' + + # Direct DBus Notification for Spectacle-style centered image preview & file drag-and-drop try: - subprocess.run(["notify-send", "-a", "f0ckm", "Upload Successful", body_text], check=False) + import dbus + bus = dbus.SessionBus() + notify_obj = bus.get_object('org.freedesktop.Notifications', '/org/freedesktop/Notifications') + notify_iface = dbus.Interface(notify_obj, 'org.freedesktop.Notifications') + + hints = { + 'urls': dbus.Array([dbus.String(file_url)], signature='s', variant_level=1), + 'x-kde-urls': dbus.Array([dbus.String(file_url)], signature='s', variant_level=1), + 'desktop-entry': dbus.String('', variant_level=1), + 'x-kde-app-icon': dbus.String('', variant_level=1) + } + notify_iface.Notify('f0ckm Uploader', dbus.UInt32(0), '', '', body_text, [], hints, -1) + return + except Exception as e: + print(f"DBus notification error: {e}") + + # Fallback to notify-send + try: + cmd = [ + "notify-send", + "-a", "f0ckm Uploader", + "-h", f"string:x-kde-urls:{file_url}", + "-h", f"string:urls:{file_url}", + "-h", "string:desktop-entry:", + "-h", "string:x-kde-app-icon:", + "", + body_text + ] + subprocess.run(cmd, check=False) except Exception as e: print(f"Notification error: {e}")