|
1 | 1 | import os |
2 | 2 | import sys |
3 | | -from pathlib import Path |
| 3 | +import fitz # PyMuPDF |
| 4 | +import velopack |
4 | 5 |
|
| 6 | +from pathlib import Path |
5 | 7 | from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, |
6 | 8 | QHBoxLayout, QLabel, QPushButton, QLineEdit, |
7 | 9 | QFileDialog, QMessageBox, QGroupBox, QRadioButton, |
8 | | - QButtonGroup) |
| 10 | + QButtonGroup, QMenu) |
9 | 11 | from PyQt6.QtCore import Qt |
10 | | -from PyQt6.QtGui import QFont |
11 | | -import fitz # PyMuPDF |
| 12 | +from PyQt6.QtGui import QFont, QAction |
12 | 13 |
|
13 | 14 |
|
14 | 15 | class Mode: |
@@ -248,6 +249,37 @@ def convert_to_images(input_path, page_numbers, output_path): |
248 | 249 | return message |
249 | 250 |
|
250 | 251 |
|
| 252 | +def update_app(): |
| 253 | + """Check for updates and apply them if available.""" |
| 254 | + try: |
| 255 | + # Check for updates from GitHub releases |
| 256 | + # GitHub Actions will upload release files to the latest release |
| 257 | + manager = velopack.UpdateManager("https://github.com/kelltom/pdf-page-selector/releases/latest/download/") |
| 258 | + update_info = manager.check_for_updates() |
| 259 | + |
| 260 | + if not update_info: |
| 261 | + QMessageBox.information(None, "No Updates", "You're running the latest version!") |
| 262 | + return # no updates available |
| 263 | + |
| 264 | + # Ask user if they want to update |
| 265 | + reply = QMessageBox.question( |
| 266 | + None, "Update Available", |
| 267 | + f"A new version is available. Would you like to download and install it?\n\nThis will restart the application.", |
| 268 | + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No |
| 269 | + ) |
| 270 | + |
| 271 | + if reply == QMessageBox.StandardButton.Yes: |
| 272 | + # Download the updates |
| 273 | + manager.download_updates(update_info) |
| 274 | + |
| 275 | + # Apply the update and restart the app |
| 276 | + manager.apply_updates_and_restart(update_info) |
| 277 | + except Exception as e: |
| 278 | + # Only show error if it's not the "NotInstalled" development mode error |
| 279 | + if "NotInstalled" not in str(e): |
| 280 | + QMessageBox.warning(None, "Update Error", f"Could not check for updates:\n{str(e)}") |
| 281 | + |
| 282 | + |
251 | 283 | class PDFPageSelectorApp(QMainWindow): |
252 | 284 | def __init__(self): |
253 | 285 | super().__init__() |
@@ -302,6 +334,9 @@ def init_ui(self): |
302 | 334 | self.resize(400, 580) |
303 | 335 | self.setStyleSheet(load_stylesheet()) |
304 | 336 |
|
| 337 | + # Create menu bar |
| 338 | + self._create_menu_bar() |
| 339 | + |
305 | 340 | central_widget = QWidget() |
306 | 341 | self.setCentralWidget(central_widget) |
307 | 342 | layout = QVBoxLayout(central_widget) |
@@ -344,6 +379,18 @@ def init_ui(self): |
344 | 379 |
|
345 | 380 | layout.addStretch() |
346 | 381 |
|
| 382 | + def _create_menu_bar(self): |
| 383 | + """Create the application menu bar.""" |
| 384 | + menubar = self.menuBar() |
| 385 | + |
| 386 | + # Help menu |
| 387 | + help_menu = menubar.addMenu("Help") |
| 388 | + |
| 389 | + # Check for Updates action |
| 390 | + update_action = QAction("Check for Updates", self) |
| 391 | + update_action.triggered.connect(update_app) |
| 392 | + help_menu.addAction(update_action) |
| 393 | + |
347 | 394 | def _create_input_section(self): |
348 | 395 | group = QGroupBox("Input PDF") |
349 | 396 | layout = QVBoxLayout() |
@@ -564,6 +611,9 @@ def _ensure_output_path(self): |
564 | 611 |
|
565 | 612 |
|
566 | 613 | if __name__ == "__main__": |
| 614 | + # Velopack needs to run first - it may quit/restart the process |
| 615 | + velopack.App().run() |
| 616 | + |
567 | 617 | app = QApplication(sys.argv) |
568 | 618 | window = PDFPageSelectorApp() |
569 | 619 | window.show() |
|
0 commit comments