voidremote 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. voidremote/__init__.py +31 -0
  2. voidremote/adb/__init__.py +28 -0
  3. voidremote/adb/client.py +385 -0
  4. voidremote/adb/device_parser.py +286 -0
  5. voidremote/cli/__init__.py +5 -0
  6. voidremote/cli/main.py +987 -0
  7. voidremote/config/__init__.py +37 -0
  8. voidremote/config/settings.py +203 -0
  9. voidremote/controllers/__init__.py +5 -0
  10. voidremote/controllers/app_controller.py +222 -0
  11. voidremote/core/__init__.py +1 -0
  12. voidremote/core/automation.py +184 -0
  13. voidremote/models/__init__.py +31 -0
  14. voidremote/models/device.py +263 -0
  15. voidremote/network/__init__.py +1 -0
  16. voidremote/network/discovery.py +116 -0
  17. voidremote/services/__init__.py +13 -0
  18. voidremote/services/device_service.py +340 -0
  19. voidremote/services/input_service.py +181 -0
  20. voidremote/services/monitor_service.py +198 -0
  21. voidremote/ui/__init__.py +1 -0
  22. voidremote/ui/app.py +70 -0
  23. voidremote/ui/dialogs/__init__.py +6 -0
  24. voidremote/ui/dialogs/connect_dialog.py +149 -0
  25. voidremote/ui/dialogs/pair_dialog.py +189 -0
  26. voidremote/ui/main_window.py +371 -0
  27. voidremote/ui/theme.py +529 -0
  28. voidremote/ui/views/__init__.py +15 -0
  29. voidremote/ui/views/dashboard_view.py +233 -0
  30. voidremote/ui/views/files_view.py +305 -0
  31. voidremote/ui/views/monitor_view.py +236 -0
  32. voidremote/ui/views/settings_view.py +257 -0
  33. voidremote/ui/views/shell_view.py +234 -0
  34. voidremote/ui/widgets/__init__.py +14 -0
  35. voidremote/ui/widgets/device_card.py +259 -0
  36. voidremote/ui/widgets/log_view.py +159 -0
  37. voidremote/ui/widgets/metric_gauge.py +90 -0
  38. voidremote/utils/__init__.py +28 -0
  39. voidremote/utils/logging.py +120 -0
  40. voidremote/utils/security.py +216 -0
  41. voidremote-1.0.0.dist-info/METADATA +578 -0
  42. voidremote-1.0.0.dist-info/RECORD +46 -0
  43. voidremote-1.0.0.dist-info/WHEEL +5 -0
  44. voidremote-1.0.0.dist-info/entry_points.txt +5 -0
  45. voidremote-1.0.0.dist-info/licenses/LICENSE +21 -0
  46. voidremote-1.0.0.dist-info/top_level.txt +1 -0
voidremote/ui/theme.py ADDED
@@ -0,0 +1,529 @@
1
+ """
2
+ VoidRemote dark theme and style definitions.
3
+
4
+ Provides QSS stylesheets, color palettes, and font definitions
5
+ for the PySide6 GUI.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from PySide6.QtGui import QColor, QPalette
11
+ from PySide6.QtWidgets import QApplication
12
+
13
+
14
+ # ------------------------------------------------------------------
15
+ # Color Palette
16
+ # ------------------------------------------------------------------
17
+
18
+ class Colors:
19
+ """VoidRemote design system colors."""
20
+
21
+ # Backgrounds
22
+ BG_BASE = "#0d1117"
23
+ BG_SURFACE = "#161b22"
24
+ BG_ELEVATED = "#1c2128"
25
+ BG_OVERLAY = "#22272e"
26
+
27
+ # Sidebar
28
+ SIDEBAR_BG = "#0d1117"
29
+ SIDEBAR_ACTIVE = "#1c2128"
30
+ SIDEBAR_HOVER = "#161b22"
31
+
32
+ # Accent
33
+ ACCENT = "#4f8ef7"
34
+ ACCENT_HOVER = "#6ba3f8"
35
+ ACCENT_PRESSED = "#3a7af5"
36
+ ACCENT_DIM = "rgba(79, 142, 247, 0.15)"
37
+
38
+ # Status
39
+ SUCCESS = "#3fb950"
40
+ WARNING = "#d29922"
41
+ ERROR = "#f85149"
42
+ INFO = "#58a6ff"
43
+
44
+ # Text
45
+ TEXT_PRIMARY = "#e6edf3"
46
+ TEXT_SECONDARY = "#8b949e"
47
+ TEXT_MUTED = "#484f58"
48
+ TEXT_ON_ACCENT = "#ffffff"
49
+
50
+ # Borders
51
+ BORDER = "#30363d"
52
+ BORDER_FOCUS = "#4f8ef7"
53
+ BORDER_SUBTLE = "#21262d"
54
+
55
+ # Buttons
56
+ BTN_BG = "#21262d"
57
+ BTN_HOVER = "#30363d"
58
+ BTN_PRESSED = "#1c2128"
59
+
60
+ # Device card
61
+ CARD_BG = "#161b22"
62
+ CARD_BORDER = "#30363d"
63
+
64
+ # Battery
65
+ BATTERY_FULL = "#3fb950"
66
+ BATTERY_MID = "#d29922"
67
+ BATTERY_LOW = "#f85149"
68
+
69
+
70
+ DARK_STYLESHEET = """
71
+ /* ============================================================
72
+ VoidRemote Dark Theme — Qt Style Sheet
73
+ ============================================================ */
74
+
75
+ * {{
76
+ font-family: "Inter", "Segoe UI", "SF Pro Display", "Helvetica Neue", Arial, sans-serif;
77
+ font-size: 13px;
78
+ color: {TEXT_PRIMARY};
79
+ outline: none;
80
+ }}
81
+
82
+ QMainWindow, QDialog, QWidget#MainWidget {{
83
+ background-color: {BG_BASE};
84
+ border: none;
85
+ }}
86
+
87
+ /* ---- Scroll Bars ---- */
88
+ QScrollBar:vertical {{
89
+ background: {BG_SURFACE};
90
+ width: 8px;
91
+ border-radius: 4px;
92
+ margin: 0;
93
+ }}
94
+ QScrollBar::handle:vertical {{
95
+ background: {BORDER};
96
+ border-radius: 4px;
97
+ min-height: 32px;
98
+ }}
99
+ QScrollBar::handle:vertical:hover {{
100
+ background: {TEXT_MUTED};
101
+ }}
102
+ QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {{
103
+ height: 0;
104
+ }}
105
+ QScrollBar:horizontal {{
106
+ background: {BG_SURFACE};
107
+ height: 8px;
108
+ border-radius: 4px;
109
+ }}
110
+ QScrollBar::handle:horizontal {{
111
+ background: {BORDER};
112
+ border-radius: 4px;
113
+ min-width: 32px;
114
+ }}
115
+
116
+ /* ---- Tool Bar ---- */
117
+ QToolBar {{
118
+ background-color: {BG_SURFACE};
119
+ border-bottom: 1px solid {BORDER};
120
+ spacing: 4px;
121
+ padding: 4px 8px;
122
+ }}
123
+ QToolButton {{
124
+ background: transparent;
125
+ border: 1px solid transparent;
126
+ border-radius: 6px;
127
+ padding: 6px 10px;
128
+ color: {TEXT_SECONDARY};
129
+ }}
130
+ QToolButton:hover {{
131
+ background: {BTN_HOVER};
132
+ color: {TEXT_PRIMARY};
133
+ border-color: {BORDER};
134
+ }}
135
+ QToolButton:pressed {{
136
+ background: {BTN_PRESSED};
137
+ }}
138
+
139
+ /* ---- Status Bar ---- */
140
+ QStatusBar {{
141
+ background-color: {BG_SURFACE};
142
+ border-top: 1px solid {BORDER};
143
+ color: {TEXT_SECONDARY};
144
+ font-size: 12px;
145
+ padding: 2px 8px;
146
+ }}
147
+
148
+ /* ---- Tab Widget ---- */
149
+ QTabWidget::pane {{
150
+ background: {BG_ELEVATED};
151
+ border: 1px solid {BORDER};
152
+ border-radius: 8px;
153
+ }}
154
+ QTabBar::tab {{
155
+ background: transparent;
156
+ color: {TEXT_SECONDARY};
157
+ padding: 8px 18px;
158
+ margin-right: 2px;
159
+ border-bottom: 2px solid transparent;
160
+ }}
161
+ QTabBar::tab:selected {{
162
+ color: {ACCENT};
163
+ border-bottom: 2px solid {ACCENT};
164
+ }}
165
+ QTabBar::tab:hover:!selected {{
166
+ color: {TEXT_PRIMARY};
167
+ }}
168
+
169
+ /* ---- Push Button ---- */
170
+ QPushButton {{
171
+ background: {BTN_BG};
172
+ border: 1px solid {BORDER};
173
+ border-radius: 6px;
174
+ padding: 7px 16px;
175
+ color: {TEXT_PRIMARY};
176
+ font-weight: 500;
177
+ }}
178
+ QPushButton:hover {{
179
+ background: {BTN_HOVER};
180
+ border-color: {TEXT_MUTED};
181
+ }}
182
+ QPushButton:pressed {{
183
+ background: {BTN_PRESSED};
184
+ }}
185
+ QPushButton:disabled {{
186
+ color: {TEXT_MUTED};
187
+ background: {BG_ELEVATED};
188
+ border-color: {BORDER_SUBTLE};
189
+ }}
190
+ QPushButton#accent {{
191
+ background: {ACCENT};
192
+ border-color: {ACCENT};
193
+ color: {TEXT_ON_ACCENT};
194
+ }}
195
+ QPushButton#accent:hover {{
196
+ background: {ACCENT_HOVER};
197
+ border-color: {ACCENT_HOVER};
198
+ }}
199
+ QPushButton#accent:pressed {{
200
+ background: {ACCENT_PRESSED};
201
+ }}
202
+ QPushButton#danger {{
203
+ background: transparent;
204
+ border-color: {ERROR};
205
+ color: {ERROR};
206
+ }}
207
+ QPushButton#danger:hover {{
208
+ background: rgba(248, 81, 73, 0.15);
209
+ }}
210
+
211
+ /* ---- Line Edit ---- */
212
+ QLineEdit {{
213
+ background: {BG_ELEVATED};
214
+ border: 1px solid {BORDER};
215
+ border-radius: 6px;
216
+ padding: 8px 12px;
217
+ color: {TEXT_PRIMARY};
218
+ selection-background-color: {ACCENT_DIM};
219
+ }}
220
+ QLineEdit:focus {{
221
+ border-color: {BORDER_FOCUS};
222
+ background: {BG_OVERLAY};
223
+ }}
224
+ QLineEdit:disabled {{
225
+ color: {TEXT_MUTED};
226
+ background: {BG_SURFACE};
227
+ }}
228
+
229
+ /* ---- Combo Box ---- */
230
+ QComboBox {{
231
+ background: {BG_ELEVATED};
232
+ border: 1px solid {BORDER};
233
+ border-radius: 6px;
234
+ padding: 7px 12px;
235
+ color: {TEXT_PRIMARY};
236
+ }}
237
+ QComboBox:hover {{
238
+ border-color: {TEXT_MUTED};
239
+ }}
240
+ QComboBox::drop-down {{
241
+ border: none;
242
+ width: 24px;
243
+ }}
244
+ QComboBox QAbstractItemView {{
245
+ background: {BG_OVERLAY};
246
+ border: 1px solid {BORDER};
247
+ selection-background-color: {ACCENT_DIM};
248
+ outline: none;
249
+ }}
250
+
251
+ /* ---- Spin Box ---- */
252
+ QSpinBox, QDoubleSpinBox {{
253
+ background: {BG_ELEVATED};
254
+ border: 1px solid {BORDER};
255
+ border-radius: 6px;
256
+ padding: 7px 12px;
257
+ color: {TEXT_PRIMARY};
258
+ }}
259
+ QSpinBox:focus, QDoubleSpinBox:focus {{
260
+ border-color: {BORDER_FOCUS};
261
+ }}
262
+
263
+ /* ---- Check Box ---- */
264
+ QCheckBox {{
265
+ spacing: 8px;
266
+ color: {TEXT_PRIMARY};
267
+ }}
268
+ QCheckBox::indicator {{
269
+ width: 16px;
270
+ height: 16px;
271
+ border: 1px solid {BORDER};
272
+ border-radius: 4px;
273
+ background: {BG_ELEVATED};
274
+ }}
275
+ QCheckBox::indicator:checked {{
276
+ background: {ACCENT};
277
+ border-color: {ACCENT};
278
+ }}
279
+
280
+ /* ---- Radio Button ---- */
281
+ QRadioButton {{
282
+ spacing: 8px;
283
+ color: {TEXT_PRIMARY};
284
+ }}
285
+ QRadioButton::indicator {{
286
+ width: 16px;
287
+ height: 16px;
288
+ border: 1px solid {BORDER};
289
+ border-radius: 8px;
290
+ background: {BG_ELEVATED};
291
+ }}
292
+ QRadioButton::indicator:checked {{
293
+ background: {ACCENT};
294
+ border-color: {ACCENT};
295
+ }}
296
+
297
+ /* ---- Progress Bar ---- */
298
+ QProgressBar {{
299
+ background: {BG_ELEVATED};
300
+ border: 1px solid {BORDER};
301
+ border-radius: 4px;
302
+ text-align: center;
303
+ color: {TEXT_PRIMARY};
304
+ font-size: 11px;
305
+ height: 8px;
306
+ }}
307
+ QProgressBar::chunk {{
308
+ background: {ACCENT};
309
+ border-radius: 3px;
310
+ }}
311
+
312
+ /* ---- Slider ---- */
313
+ QSlider::groove:horizontal {{
314
+ background: {BG_ELEVATED};
315
+ height: 4px;
316
+ border-radius: 2px;
317
+ }}
318
+ QSlider::handle:horizontal {{
319
+ background: {ACCENT};
320
+ width: 14px;
321
+ height: 14px;
322
+ border-radius: 7px;
323
+ margin: -5px 0;
324
+ }}
325
+ QSlider::sub-page:horizontal {{
326
+ background: {ACCENT};
327
+ border-radius: 2px;
328
+ }}
329
+
330
+ /* ---- List / Tree / Table Widgets ---- */
331
+ QListWidget, QTreeWidget, QTableWidget {{
332
+ background: {BG_SURFACE};
333
+ border: 1px solid {BORDER};
334
+ border-radius: 8px;
335
+ alternate-background-color: {BG_ELEVATED};
336
+ gridline-color: {BORDER_SUBTLE};
337
+ outline: none;
338
+ }}
339
+ QListWidget::item, QTreeWidget::item, QTableWidget::item {{
340
+ padding: 6px 8px;
341
+ border: none;
342
+ }}
343
+ QListWidget::item:selected, QTreeWidget::item:selected, QTableWidget::item:selected {{
344
+ background: {ACCENT_DIM};
345
+ color: {TEXT_PRIMARY};
346
+ border-radius: 4px;
347
+ }}
348
+ QListWidget::item:hover, QTreeWidget::item:hover, QTableWidget::item:hover {{
349
+ background: {BG_ELEVATED};
350
+ }}
351
+ QHeaderView::section {{
352
+ background: {BG_OVERLAY};
353
+ border: none;
354
+ border-right: 1px solid {BORDER};
355
+ border-bottom: 1px solid {BORDER};
356
+ padding: 6px 12px;
357
+ color: {TEXT_SECONDARY};
358
+ font-weight: 600;
359
+ font-size: 11px;
360
+ text-transform: uppercase;
361
+ letter-spacing: 0.5px;
362
+ }}
363
+
364
+ /* ---- Group Box ---- */
365
+ QGroupBox {{
366
+ border: 1px solid {BORDER};
367
+ border-radius: 8px;
368
+ margin-top: 14px;
369
+ padding: 12px;
370
+ font-weight: 600;
371
+ color: {TEXT_SECONDARY};
372
+ font-size: 12px;
373
+ }}
374
+ QGroupBox::title {{
375
+ subcontrol-origin: margin;
376
+ left: 12px;
377
+ padding: 0 6px;
378
+ color: {TEXT_SECONDARY};
379
+ }}
380
+
381
+ /* ---- Splitter ---- */
382
+ QSplitter::handle {{
383
+ background: {BORDER};
384
+ }}
385
+ QSplitter::handle:horizontal {{
386
+ width: 1px;
387
+ }}
388
+ QSplitter::handle:vertical {{
389
+ height: 1px;
390
+ }}
391
+
392
+ /* ---- Menu ---- */
393
+ QMenuBar {{
394
+ background: {BG_SURFACE};
395
+ border-bottom: 1px solid {BORDER};
396
+ color: {TEXT_SECONDARY};
397
+ padding: 2px;
398
+ }}
399
+ QMenuBar::item {{
400
+ padding: 6px 10px;
401
+ border-radius: 4px;
402
+ }}
403
+ QMenuBar::item:selected {{
404
+ background: {BTN_HOVER};
405
+ color: {TEXT_PRIMARY};
406
+ }}
407
+ QMenu {{
408
+ background: {BG_OVERLAY};
409
+ border: 1px solid {BORDER};
410
+ border-radius: 8px;
411
+ padding: 4px;
412
+ }}
413
+ QMenu::item {{
414
+ padding: 7px 18px;
415
+ border-radius: 4px;
416
+ }}
417
+ QMenu::item:selected {{
418
+ background: {ACCENT_DIM};
419
+ color: {TEXT_PRIMARY};
420
+ }}
421
+ QMenu::separator {{
422
+ background: {BORDER};
423
+ height: 1px;
424
+ margin: 4px 8px;
425
+ }}
426
+
427
+ /* ---- Tooltip ---- */
428
+ QToolTip {{
429
+ background: {BG_OVERLAY};
430
+ border: 1px solid {BORDER};
431
+ border-radius: 6px;
432
+ color: {TEXT_PRIMARY};
433
+ padding: 6px 10px;
434
+ font-size: 12px;
435
+ }}
436
+
437
+ /* ---- Text Edit / Plain Text Edit ---- */
438
+ QTextEdit, QPlainTextEdit {{
439
+ background: {BG_ELEVATED};
440
+ border: 1px solid {BORDER};
441
+ border-radius: 8px;
442
+ padding: 10px;
443
+ color: {TEXT_PRIMARY};
444
+ selection-background-color: {ACCENT_DIM};
445
+ font-family: "JetBrains Mono", "Cascadia Code", "Fira Code", "Consolas", monospace;
446
+ font-size: 13px;
447
+ }}
448
+ QTextEdit:focus, QPlainTextEdit:focus {{
449
+ border-color: {BORDER_FOCUS};
450
+ }}
451
+
452
+ /* ---- Sidebar List ---- */
453
+ QListWidget#Sidebar {{
454
+ background: {SIDEBAR_BG};
455
+ border: none;
456
+ border-right: 1px solid {BORDER};
457
+ border-radius: 0;
458
+ padding: 8px 0;
459
+ }}
460
+ QListWidget#Sidebar::item {{
461
+ padding: 10px 16px;
462
+ border-radius: 0;
463
+ margin: 1px 8px;
464
+ border-radius: 6px;
465
+ color: {TEXT_SECONDARY};
466
+ }}
467
+ QListWidget#Sidebar::item:selected {{
468
+ background: {SIDEBAR_ACTIVE};
469
+ color: {TEXT_PRIMARY};
470
+ }}
471
+ QListWidget#Sidebar::item:hover:!selected {{
472
+ background: {SIDEBAR_HOVER};
473
+ color: {TEXT_PRIMARY};
474
+ }}
475
+
476
+ /* ---- Device Cards ---- */
477
+ QFrame#DeviceCard {{
478
+ background: {CARD_BG};
479
+ border: 1px solid {CARD_BORDER};
480
+ border-radius: 10px;
481
+ padding: 16px;
482
+ }}
483
+ QFrame#DeviceCard:hover {{
484
+ border-color: {ACCENT};
485
+ }}
486
+
487
+ /* ---- Log View ---- */
488
+ QTextEdit#LogView {{
489
+ background: {BG_BASE};
490
+ font-family: "JetBrains Mono", "Consolas", monospace;
491
+ font-size: 12px;
492
+ color: {TEXT_SECONDARY};
493
+ border: none;
494
+ padding: 12px;
495
+ }}
496
+ """.format(
497
+ **{k: v for k, v in Colors.__dict__.items()
498
+ if not k.startswith("_") and isinstance(v, (str, int, float))}
499
+ )
500
+
501
+ def apply_dark_theme(app: QApplication) -> None:
502
+ """Apply the VoidRemote dark theme to a QApplication."""
503
+ app.setStyleSheet(DARK_STYLESHEET)
504
+
505
+ # Also set QPalette for native widgets
506
+ palette = QPalette()
507
+ bg = QColor(Colors.BG_BASE)
508
+ surface = QColor(Colors.BG_SURFACE)
509
+ text = QColor(Colors.TEXT_PRIMARY)
510
+ text_dim = QColor(Colors.TEXT_SECONDARY)
511
+ accent = QColor(Colors.ACCENT)
512
+ border = QColor(Colors.BORDER)
513
+
514
+ palette.setColor(QPalette.ColorRole.Window, bg)
515
+ palette.setColor(QPalette.ColorRole.WindowText, text)
516
+ palette.setColor(QPalette.ColorRole.Base, surface)
517
+ palette.setColor(QPalette.ColorRole.AlternateBase, QColor(Colors.BG_ELEVATED))
518
+ palette.setColor(QPalette.ColorRole.Text, text)
519
+ palette.setColor(QPalette.ColorRole.Button, QColor(Colors.BTN_BG))
520
+ palette.setColor(QPalette.ColorRole.ButtonText, text)
521
+ palette.setColor(QPalette.ColorRole.Highlight, accent)
522
+ palette.setColor(QPalette.ColorRole.HighlightedText, QColor(Colors.TEXT_ON_ACCENT))
523
+ palette.setColor(QPalette.ColorRole.ToolTipBase, QColor(Colors.BG_OVERLAY))
524
+ palette.setColor(QPalette.ColorRole.ToolTipText, text)
525
+ palette.setColor(QPalette.ColorRole.PlaceholderText, text_dim)
526
+ palette.setColor(QPalette.ColorRole.Link, accent)
527
+ palette.setColor(QPalette.ColorRole.LinkVisited, QColor(Colors.ACCENT_PRESSED))
528
+
529
+ app.setPalette(palette)
@@ -0,0 +1,15 @@
1
+ """VoidRemote UI views."""
2
+
3
+ from voidremote.ui.views.dashboard_view import DashboardView
4
+ from voidremote.ui.views.files_view import FilesView
5
+ from voidremote.ui.views.monitor_view import MonitorView
6
+ from voidremote.ui.views.settings_view import SettingsView
7
+ from voidremote.ui.views.shell_view import ShellView
8
+
9
+ __all__ = [
10
+ "DashboardView",
11
+ "FilesView",
12
+ "MonitorView",
13
+ "SettingsView",
14
+ "ShellView",
15
+ ]