recent uploads
This commit is contained in:
249
gui.py
249
gui.py
@@ -24,17 +24,41 @@ def normalize_file_path(path_str: str) -> str:
|
||||
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
|
||||
from PySide6.QtGui import QIcon, QAction, QPixmap, QPainter, QColor, QFont, QPen, QImage, QDesktopServices
|
||||
from PySide6.QtNetwork import QNetworkAccessManager, QNetworkRequest, QHttpMultiPart, QHttpPart, QNetworkReply, QLocalServer, QLocalSocket
|
||||
from PySide6.QtWidgets import (
|
||||
QApplication, QSystemTrayIcon, QMenu, QDialog, QVBoxLayout, QHBoxLayout,
|
||||
QLabel, QLineEdit, QComboBox, QCheckBox, QPushButton, QGroupBox,
|
||||
QFormLayout, QMessageBox, QFileDialog, QSlider
|
||||
QFormLayout, QMessageBox, QFileDialog, QSlider, QScrollArea, QFrame, QGridLayout, QWidget
|
||||
)
|
||||
|
||||
# Configuration paths
|
||||
CONFIG_DIR = os.path.expanduser("~/.config/f0ckm-uploader")
|
||||
CONFIG_PATH = os.path.join(CONFIG_DIR, "config.json")
|
||||
HISTORY_PATH = os.path.join(CONFIG_DIR, "history.json")
|
||||
|
||||
def load_history():
|
||||
if not os.path.exists(HISTORY_PATH):
|
||||
return []
|
||||
try:
|
||||
with open(HISTORY_PATH, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
def save_history(history_list):
|
||||
try:
|
||||
os.makedirs(CONFIG_DIR, exist_ok=True)
|
||||
with open(HISTORY_PATH, "w", encoding="utf-8") as f:
|
||||
json.dump(history_list[:100], f, indent=2)
|
||||
except Exception as e:
|
||||
print(f"Error saving history: {e}")
|
||||
|
||||
def add_history_entry(entry):
|
||||
history = load_history()
|
||||
history = [h for h in history if h.get("url") != entry.get("url")]
|
||||
history.insert(0, entry)
|
||||
save_history(history)
|
||||
|
||||
DEFAULT_CONFIG = {
|
||||
"api_url": "",
|
||||
@@ -509,6 +533,201 @@ class SettingsDialog(QDialog):
|
||||
else:
|
||||
QMessageBox.critical(self, "Error", "Failed to save configuration file.")
|
||||
|
||||
# ==========================================
|
||||
# Upload Gallery Window & Components
|
||||
# ==========================================
|
||||
class GalleryCard(QFrame):
|
||||
def __init__(self, item, parent=None, on_delete=None):
|
||||
super().__init__(parent)
|
||||
self.item = item
|
||||
self.on_delete = on_delete
|
||||
self.setFrameShape(QFrame.StyledPanel)
|
||||
self.setFixedHeight(195)
|
||||
self.setStyleSheet("""
|
||||
GalleryCard {
|
||||
background-color: #1e1e24;
|
||||
border: 1px solid #333340;
|
||||
border-radius: 8px;
|
||||
}
|
||||
GalleryCard:hover {
|
||||
border: 1px solid #555575;
|
||||
background-color: #242430;
|
||||
}
|
||||
""")
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setContentsMargins(8, 8, 8, 8)
|
||||
layout.setSpacing(6)
|
||||
|
||||
# Thumbnail
|
||||
self.thumb_label = QLabel()
|
||||
self.thumb_label.setFixedSize(160, 100)
|
||||
self.thumb_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
self.thumb_label.setStyleSheet("background-color: #121216; border-radius: 4px;")
|
||||
|
||||
thumb_path = item.get("thumbnail_path", "")
|
||||
file_path = item.get("file_path", "")
|
||||
pixmap = None
|
||||
if thumb_path and os.path.exists(thumb_path):
|
||||
pixmap = QPixmap(thumb_path)
|
||||
elif file_path and os.path.exists(file_path):
|
||||
gen_thumb = generate_thumbnail(file_path)
|
||||
if gen_thumb and os.path.exists(gen_thumb):
|
||||
pixmap = QPixmap(gen_thumb)
|
||||
|
||||
if pixmap and not pixmap.isNull():
|
||||
scaled = pixmap.scaled(160, 100, Qt.AspectRatioMode.KeepAspectRatioByExpanding, Qt.TransformationMode.SmoothTransformation)
|
||||
x = max(0, (scaled.width() - 160) // 2)
|
||||
y = max(0, (scaled.height() - 100) // 2)
|
||||
self.thumb_label.setPixmap(scaled.copy(x, y, 160, 100))
|
||||
else:
|
||||
self.thumb_label.setText("No Preview")
|
||||
self.thumb_label.setStyleSheet("background-color: #121216; color: #666; font-size: 11px;")
|
||||
|
||||
layout.addWidget(self.thumb_label)
|
||||
|
||||
# Filename
|
||||
fname = item.get("filename", "File")
|
||||
lbl_name = QLabel(fname)
|
||||
lbl_name.setStyleSheet("font-weight: bold; font-size: 11px; color: #e0e0e0;")
|
||||
lbl_name.setToolTip(item.get("filename", ""))
|
||||
layout.addWidget(lbl_name)
|
||||
|
||||
# Timestamp
|
||||
ts = item.get("timestamp", 0)
|
||||
dt_str = time.strftime("%Y-%m-%d %H:%M", time.localtime(ts)) if ts else ""
|
||||
lbl_time = QLabel(dt_str)
|
||||
lbl_time.setStyleSheet("font-size: 9px; color: #8888a0;")
|
||||
layout.addWidget(lbl_time)
|
||||
|
||||
# Action Buttons
|
||||
btn_layout = QHBoxLayout()
|
||||
btn_layout.setSpacing(4)
|
||||
|
||||
btn_copy = QPushButton("Copy")
|
||||
btn_copy.setToolTip("Copy URL to clipboard")
|
||||
btn_copy.setStyleSheet("font-size: 10px; padding: 4px 6px;")
|
||||
btn_copy.clicked.connect(self.on_copy_link)
|
||||
|
||||
btn_open = QPushButton("Open")
|
||||
btn_open.setToolTip("Open link in browser")
|
||||
btn_open.setStyleSheet("font-size: 10px; padding: 4px 6px;")
|
||||
btn_open.clicked.connect(self.on_open_url)
|
||||
|
||||
btn_del = QPushButton("✕")
|
||||
btn_del.setToolTip("Remove from history")
|
||||
btn_del.setStyleSheet("font-size: 10px; padding: 4px 6px; color: #ff6666;")
|
||||
btn_del.clicked.connect(self.on_remove_item)
|
||||
|
||||
btn_layout.addWidget(btn_copy)
|
||||
btn_layout.addWidget(btn_open)
|
||||
btn_layout.addWidget(btn_del)
|
||||
|
||||
layout.addLayout(btn_layout)
|
||||
|
||||
def on_copy_link(self):
|
||||
url = self.item.get("url", "")
|
||||
if url:
|
||||
QApplication.clipboard().setText(url)
|
||||
|
||||
def on_open_url(self):
|
||||
url = self.item.get("url", "")
|
||||
if url:
|
||||
QDesktopServices.openUrl(QUrl(url))
|
||||
|
||||
def on_remove_item(self):
|
||||
if self.on_delete:
|
||||
self.on_delete(self.item)
|
||||
|
||||
class GalleryWindow(QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("f0ckm Upload Gallery")
|
||||
self.resize(760, 560)
|
||||
app_icon = get_app_icon()
|
||||
if not app_icon.isNull():
|
||||
self.setWindowIcon(app_icon)
|
||||
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
main_layout = QVBoxLayout(self)
|
||||
main_layout.setContentsMargins(15, 15, 15, 15)
|
||||
main_layout.setSpacing(12)
|
||||
|
||||
# Header bar
|
||||
header_layout = QHBoxLayout()
|
||||
|
||||
lbl_title = QLabel("Recent Uploads")
|
||||
lbl_title.setStyleSheet("font-size: 16px; font-weight: bold; color: #ffffff;")
|
||||
header_layout.addWidget(lbl_title)
|
||||
|
||||
header_layout.addStretch()
|
||||
|
||||
self.txt_search = QLineEdit()
|
||||
self.txt_search.setPlaceholderText("Search uploads...")
|
||||
self.txt_search.setFixedWidth(200)
|
||||
self.txt_search.textChanged.connect(self.load_items)
|
||||
header_layout.addWidget(self.txt_search)
|
||||
|
||||
btn_clear = QPushButton("Clear History")
|
||||
btn_clear.clicked.connect(self.on_clear_history)
|
||||
header_layout.addWidget(btn_clear)
|
||||
|
||||
main_layout.addLayout(header_layout)
|
||||
|
||||
# Scroll Area for Gallery Cards
|
||||
self.scroll_area = QScrollArea()
|
||||
self.scroll_area.setWidgetResizable(True)
|
||||
self.scroll_area.setStyleSheet("QScrollArea { border: 1px solid #333340; background: #141418; border-radius: 6px; }")
|
||||
|
||||
self.scroll_content = QWidget()
|
||||
self.grid_layout = QGridLayout(self.scroll_content)
|
||||
self.grid_layout.setContentsMargins(12, 12, 12, 12)
|
||||
self.grid_layout.setSpacing(12)
|
||||
self.grid_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
|
||||
|
||||
self.scroll_area.setWidget(self.scroll_content)
|
||||
main_layout.addWidget(self.scroll_area)
|
||||
|
||||
self.load_items()
|
||||
|
||||
def load_items(self):
|
||||
while self.grid_layout.count():
|
||||
child = self.grid_layout.takeAt(0)
|
||||
if child.widget():
|
||||
child.widget().deleteLater()
|
||||
|
||||
history = load_history()
|
||||
query = self.txt_search.text().strip().lower()
|
||||
if query:
|
||||
history = [h for h in history if query in h.get("filename", "").lower() or query in h.get("url", "").lower()]
|
||||
|
||||
if not history:
|
||||
lbl_empty = QLabel("No uploads found.")
|
||||
lbl_empty.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
lbl_empty.setStyleSheet("color: #8888a0; font-size: 14px; margin: 40px;")
|
||||
self.grid_layout.addWidget(lbl_empty, 0, 0)
|
||||
return
|
||||
|
||||
cols = 4
|
||||
for idx, item in enumerate(history):
|
||||
card = GalleryCard(item, on_delete=self.delete_item)
|
||||
row = idx // cols
|
||||
col = idx % cols
|
||||
self.grid_layout.addWidget(card, row, col)
|
||||
|
||||
def delete_item(self, item):
|
||||
history = load_history()
|
||||
history = [h for h in history if h.get("url") != item.get("url")]
|
||||
save_history(history)
|
||||
self.load_items()
|
||||
|
||||
def on_clear_history(self):
|
||||
if QMessageBox.question(self, "Clear History", "Are you sure you want to clear your upload history?", QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
|
||||
save_history([])
|
||||
self.load_items()
|
||||
|
||||
# ==========================================
|
||||
# Dynamic Tray Digit Icon Painter
|
||||
# ==========================================
|
||||
@@ -827,6 +1046,10 @@ class SystemTrayApp(QObject):
|
||||
settings_action = QAction("Settings...", self.menu)
|
||||
settings_action.triggered.connect(self.on_open_settings)
|
||||
self.menu.addAction(settings_action)
|
||||
|
||||
gallery_action = QAction("Recent Uploads Gallery", self.menu)
|
||||
gallery_action.triggered.connect(self.on_open_gallery)
|
||||
self.menu.addAction(gallery_action)
|
||||
|
||||
self.menu.addSeparator()
|
||||
|
||||
@@ -838,6 +1061,15 @@ class SystemTrayApp(QObject):
|
||||
self.tray.activated.connect(self.on_tray_activated)
|
||||
|
||||
self.settings_dialog = None
|
||||
self.gallery_window = None
|
||||
|
||||
def on_open_gallery(self):
|
||||
if self.gallery_window is None:
|
||||
self.gallery_window = GalleryWindow()
|
||||
self.gallery_window.load_items()
|
||||
self.gallery_window.show()
|
||||
self.gallery_window.raise_()
|
||||
self.gallery_window.activateWindow()
|
||||
|
||||
def show(self):
|
||||
self.tray.show()
|
||||
@@ -975,6 +1207,19 @@ class SystemTrayApp(QObject):
|
||||
if res.get("success") and res.get("url"):
|
||||
item_url = res.get("url")
|
||||
QApplication.clipboard().setText(item_url)
|
||||
|
||||
# Add to history gallery
|
||||
thumb = generate_thumbnail(file_path)
|
||||
add_history_entry({
|
||||
"timestamp": time.time(),
|
||||
"filename": os.path.basename(file_path),
|
||||
"file_path": file_path,
|
||||
"url": item_url,
|
||||
"thumbnail_path": thumb if thumb and os.path.exists(thumb) else ""
|
||||
})
|
||||
if hasattr(self, "gallery_window") and self.gallery_window and self.gallery_window.isVisible():
|
||||
self.gallery_window.load_items()
|
||||
|
||||
self.show_success_notification(file_path, item_url)
|
||||
else:
|
||||
msg = res.get("msg", "Upload failed")
|
||||
|
||||
Reference in New Issue
Block a user