tenseleyflow/wulftp / 7f3ab12

Browse files

refactor stable

Authored by espadonne
SHA
7f3ab124ae32e06753fcae36babf8126623c44de
Parents
864133f
Tree
6034f3e

3 changed files

StatusFile+-
M src/wulftp/ui/__init__.py 6 2
M src/wulftp/ui/dialogs.py 171 7
M src/wulftp/ui/main_window.py 8 17
src/wulftp/ui/__init__.pymodified
@@ -12,9 +12,11 @@ from .components import (
1212
 from .dialogs import (
1313
     FastConfirmDialog,
1414
     FastMessageDialog,
15
+    FastInputDialog,
1516
     InlineConfirmBar,
1617
     fast_confirm,
17
-    fast_message
18
+    fast_message,
19
+    fast_input
1820
 )
1921
 from .main_window import WulFTPClient
2022
 
@@ -28,8 +30,10 @@ __all__ = [
2830
     "FileContextMenu",
2931
     "FastConfirmDialog",
3032
     "FastMessageDialog",
33
+    "FastInputDialog", 
3134
     "InlineConfirmBar",
3235
     "fast_confirm",
3336
     "fast_message",
37
+    "fast_input",
3438
     "WulFTPClient"
3539
 ]
src/wulftp/ui/dialogs.pymodified
@@ -3,7 +3,7 @@
33
 from PyQt6.QtCore import Qt, pyqtSignal, QTimer, QPropertyAnimation, QRect
44
 from PyQt6.QtWidgets import (
55
     QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton,
6
-    QWidget, QFrame, QGraphicsOpacityEffect, QSizePolicy
6
+    QWidget, QFrame, QGraphicsOpacityEffect, QSizePolicy, QLineEdit
77
 )
88
 from PyQt6.QtGui import QKeyEvent
99
 import qtawesome as qta
@@ -18,8 +18,7 @@ class FastConfirmDialog(QDialog):
1818
         self.setModal(True)
1919
         self.setWindowFlags(
2020
             Qt.WindowType.Dialog | 
21
-            Qt.WindowType.FramelessWindowHint |
22
-            Qt.WindowType.WindowStaysOnTopHint
21
+            Qt.WindowType.FramelessWindowHint
2322
         )
2423
         
2524
         # Make it slightly transparent for modern look
@@ -264,8 +263,7 @@ class FastMessageDialog(QDialog):
264263
         self.setModal(True)
265264
         self.setWindowFlags(
266265
             Qt.WindowType.Dialog | 
267
-            Qt.WindowType.FramelessWindowHint |
268
-            Qt.WindowType.WindowStaysOnTopHint
266
+            Qt.WindowType.FramelessWindowHint
269267
         )
270268
         
271269
         self.setWindowOpacity(0.95)
@@ -356,10 +354,158 @@ class FastMessageDialog(QDialog):
356354
         self.accept()
357355
 
358356
 
357
+class FastInputDialog(QDialog):
358
+    """Fast input dialog for text entry."""
359
+    
360
+    def __init__(self, title: str, label: str, placeholder: str = "", parent=None):
361
+        super().__init__(parent)
362
+        self.setWindowTitle(title)
363
+        self.setModal(True)
364
+        self.setWindowFlags(
365
+            Qt.WindowType.Dialog | 
366
+            Qt.WindowType.FramelessWindowHint
367
+        )
368
+        
369
+        self.setWindowOpacity(0.95)
370
+        self.input_text = ""
371
+        
372
+        self._setup_ui(title, label, placeholder)
373
+        
374
+        # Size and position
375
+        self.setFixedSize(400, 180)
376
+        if parent:
377
+            parent_rect = parent.geometry()
378
+            x = parent_rect.x() + (parent_rect.width() - self.width()) // 2
379
+            y = parent_rect.y() + (parent_rect.height() - self.height()) // 2
380
+            self.move(x, y)
381
+    
382
+    def _setup_ui(self, title: str, label: str, placeholder: str):
383
+        """Set up the dialog UI."""
384
+        layout = QVBoxLayout(self)
385
+        layout.setContentsMargins(0, 0, 0, 0)
386
+        
387
+        # Frame
388
+        frame = QFrame()
389
+        frame.setObjectName("inputFrame")
390
+        frame.setStyleSheet("""
391
+            #inputFrame {
392
+                background-color: #2b2b2b;
393
+                border: 2px solid #555;
394
+                border-radius: 8px;
395
+            }
396
+        """)
397
+        
398
+        frame_layout = QVBoxLayout(frame)
399
+        frame_layout.setContentsMargins(20, 20, 20, 20)
400
+        frame_layout.setSpacing(15)
401
+        
402
+        # Title
403
+        title_label = QLabel(title)
404
+        title_label.setStyleSheet("font-size: 16px; font-weight: bold; color: #fff;")
405
+        frame_layout.addWidget(title_label)
406
+        
407
+        # Label
408
+        label_widget = QLabel(label)
409
+        label_widget.setStyleSheet("color: #ddd;")
410
+        frame_layout.addWidget(label_widget)
411
+        
412
+        # Input field
413
+        self.input_field = QLineEdit()
414
+        self.input_field.setPlaceholderText(placeholder)
415
+        self.input_field.setStyleSheet("""
416
+            QLineEdit {
417
+                background-color: #3a3a3a;
418
+                color: #fff;
419
+                border: 1px solid #555;
420
+                border-radius: 4px;
421
+                padding: 8px;
422
+                font-size: 14px;
423
+            }
424
+            QLineEdit:focus {
425
+                border-color: #0d7377;
426
+            }
427
+        """)
428
+        self.input_field.returnPressed.connect(self.accept)
429
+        frame_layout.addWidget(self.input_field)
430
+        
431
+        frame_layout.addStretch()
432
+        
433
+        # Buttons
434
+        button_layout = QHBoxLayout()
435
+        button_layout.addStretch()
436
+        
437
+        # OK button
438
+        self.ok_btn = QPushButton("OK")
439
+        self.ok_btn.setDefault(True)
440
+        self.ok_btn.setStyleSheet("""
441
+            QPushButton {
442
+                background-color: #0d7377;
443
+                color: white;
444
+                border: none;
445
+                padding: 8px 20px;
446
+                border-radius: 4px;
447
+                font-weight: bold;
448
+                min-width: 80px;
449
+            }
450
+            QPushButton:hover {
451
+                background-color: #14b8bd;
452
+            }
453
+            QPushButton:pressed {
454
+                background-color: #0a5d61;
455
+            }
456
+        """)
457
+        self.ok_btn.clicked.connect(self.accept)
458
+        button_layout.addWidget(self.ok_btn)
459
+        
460
+        # Cancel button
461
+        self.cancel_btn = QPushButton("Cancel")
462
+        self.cancel_btn.setStyleSheet("""
463
+            QPushButton {
464
+                background-color: #555;
465
+                color: white;
466
+                border: none;
467
+                padding: 8px 20px;
468
+                border-radius: 4px;
469
+                font-weight: bold;
470
+                min-width: 80px;
471
+            }
472
+            QPushButton:hover {
473
+                background-color: #666;
474
+            }
475
+            QPushButton:pressed {
476
+                background-color: #444;
477
+            }
478
+        """)
479
+        self.cancel_btn.clicked.connect(self.reject)
480
+        button_layout.addWidget(self.cancel_btn)
481
+        
482
+        frame_layout.addLayout(button_layout)
483
+        layout.addWidget(frame)
484
+        
485
+        # Focus on input field
486
+        self.input_field.setFocus()
487
+        
488
+    def accept(self):
489
+        """Accept the dialog and store the input."""
490
+        self.input_text = self.input_field.text()
491
+        super().accept()
492
+        
493
+    def get_text(self) -> str:
494
+        """Get the entered text."""
495
+        return self.input_text
496
+
497
+
359498
 def fast_confirm(parent, title: str, message: str) -> bool:
360499
     """Show fast confirmation dialog and return result."""
361500
     dialog = FastConfirmDialog(title, message, parent)
362
-    return dialog.exec() == QDialog.DialogCode.Accepted
501
+    result = dialog.exec() == QDialog.DialogCode.Accepted
502
+    
503
+    # Restore parent focus after dialog
504
+    if parent and hasattr(parent, 'window'):
505
+        parent.window().raise_()
506
+        parent.window().activateWindow()
507
+    
508
+    return result
363509
 
364510
 
365511
 def fast_message(parent, title: str, message: str, message_type: str = "info"):
@@ -374,3 +520,21 @@ def fast_message(parent, title: str, message: str, message_type: str = "info"):
374520
     icon_name, icon_color = icon_configs.get(message_type, icon_configs["info"])
375521
     dialog = FastMessageDialog(title, message, icon_name, icon_color, parent)
376522
     dialog.exec()
523
+    
524
+    # Restore parent focus after dialog
525
+    if parent and hasattr(parent, 'window'):
526
+        parent.window().raise_()
527
+        parent.window().activateWindow()
528
+
529
+
530
+def fast_input(parent, title: str, label: str, placeholder: str = "") -> tuple[str, bool]:
531
+    """Show fast input dialog and return (text, ok)."""
532
+    dialog = FastInputDialog(title, label, placeholder, parent)
533
+    ok = dialog.exec() == QDialog.DialogCode.Accepted
534
+    
535
+    # Restore parent focus after dialog
536
+    if parent and hasattr(parent, 'window'):
537
+        parent.window().raise_()
538
+        parent.window().activateWindow()
539
+    
540
+    return dialog.get_text(), ok
src/wulftp/ui/main_window.pymodified
@@ -23,7 +23,6 @@ from PyQt6.QtWidgets import (
2323
     QStatusBar,
2424
     QVBoxLayout,
2525
     QWidget,
26
-    QInputDialog,
2726
 )
2827
 
2928
 from ..core import (
@@ -39,7 +38,7 @@ from ..ui.components import (
3938
     RemoteFilePane,
4039
     FileContextMenu
4140
 )
42
-from ..ui.dialogs import fast_confirm, fast_message
41
+from ..ui.dialogs import fast_confirm, fast_message, fast_input
4342
 
4443
 
4544
 class WulFTPClient(QMainWindow):
@@ -87,7 +86,10 @@ class WulFTPClient(QMainWindow):
8786
 
8887
     def _restore_focus(self):
8988
         """Restore window focus - used after dialogs and operations."""
90
-        QTimer.singleShot(100, lambda: (self.raise_(), self.activateWindow()))
89
+        # Only restore focus if we don't currently have it
90
+        if not self.isActiveWindow():
91
+            self.raise_()
92
+            self.activateWindow()
9193
 
9294
     def _create_status_bar(self):
9395
         """Create the status bar."""
@@ -233,15 +235,6 @@ class WulFTPClient(QMainWindow):
233235
                 AppConfig.STATUS_MESSAGE_TIMEOUT
234236
             )
235237
 
236
-            # Defer focus restoration to ensure it happens after all UI updates
237
-            # Using a slightly longer delay to ensure all connection-related 
238
-            # UI updates have completed
239
-            QTimer.singleShot(200, lambda: (
240
-                self.raise_(), 
241
-                self.activateWindow(),
242
-                self.remote_pane.tree_view.setFocus()  # Also set focus to remote pane
243
-            ))
244
-
245238
         except Exception as e:
246239
             fast_message(self, "Connection Error", str(e), "error")
247240
             self._update_connection_state(False)
@@ -300,9 +293,6 @@ class WulFTPClient(QMainWindow):
300293
         # Show menu at cursor position
301294
         menu.exec(view.mapToGlobal(pos))
302295
 
303
-        # Restore focus after context menu
304
-        QTimer.singleShot(100, lambda: self.activateWindow())
305
-
306296
     def upload_selected(self):
307297
         """Upload selected local files and directories."""
308298
         if not self.sftp or not self.transfer_manager:
@@ -562,10 +552,11 @@ class WulFTPClient(QMainWindow):
562552
         else:
563553
             current_path = self.remote_pane.model.rootPath()
564554
         
565
-        name, ok = QInputDialog.getText(
555
+        name, ok = fast_input(
566556
             self, 
567557
             "Create Directory", 
568
-            "Directory name:"
558
+            "Directory name:",
559
+            "new_folder"
569560
         )
570561
         
571562
         if ok and name: