adbsshdeck 0.1.1__tar.gz

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 (37) hide show
  1. adbsshdeck-0.1.1/LICENSE +21 -0
  2. adbsshdeck-0.1.1/MANIFEST.in +3 -0
  3. adbsshdeck-0.1.1/PKG-INFO +136 -0
  4. adbsshdeck-0.1.1/README.md +103 -0
  5. adbsshdeck-0.1.1/adbsshdeck.egg-info/PKG-INFO +136 -0
  6. adbsshdeck-0.1.1/adbsshdeck.egg-info/SOURCES.txt +35 -0
  7. adbsshdeck-0.1.1/adbsshdeck.egg-info/dependency_links.txt +1 -0
  8. adbsshdeck-0.1.1/adbsshdeck.egg-info/entry_points.txt +2 -0
  9. adbsshdeck-0.1.1/adbsshdeck.egg-info/requires.txt +9 -0
  10. adbsshdeck-0.1.1/adbsshdeck.egg-info/top_level.txt +1 -0
  11. adbsshdeck-0.1.1/devicedeck/__init__.py +4 -0
  12. adbsshdeck-0.1.1/devicedeck/__main__.py +4 -0
  13. adbsshdeck-0.1.1/devicedeck/app.py +45 -0
  14. adbsshdeck-0.1.1/devicedeck/config.py +130 -0
  15. adbsshdeck-0.1.1/devicedeck/services/__init__.py +1 -0
  16. adbsshdeck-0.1.1/devicedeck/services/adb_devices.py +74 -0
  17. adbsshdeck-0.1.1/devicedeck/services/commands.py +96 -0
  18. adbsshdeck-0.1.1/devicedeck/services/remote_clients.py +84 -0
  19. adbsshdeck-0.1.1/devicedeck/session.py +52 -0
  20. adbsshdeck-0.1.1/devicedeck/ui/__init__.py +1 -0
  21. adbsshdeck-0.1.1/devicedeck/ui/app_icon.py +46 -0
  22. adbsshdeck-0.1.1/devicedeck/ui/combo_utils.py +45 -0
  23. adbsshdeck-0.1.1/devicedeck/ui/first_run_dialog.py +107 -0
  24. adbsshdeck-0.1.1/devicedeck/ui/icon_utils.py +144 -0
  25. adbsshdeck-0.1.1/devicedeck/ui/main_window.py +691 -0
  26. adbsshdeck-0.1.1/devicedeck/ui/preferences_dialog.py +122 -0
  27. adbsshdeck-0.1.1/devicedeck/ui/session_login_dialog.py +795 -0
  28. adbsshdeck-0.1.1/devicedeck/ui/styles.py +1021 -0
  29. adbsshdeck-0.1.1/devicedeck/ui/tabs/__init__.py +1 -0
  30. adbsshdeck-0.1.1/devicedeck/ui/tabs/file_explorer_tab.py +3680 -0
  31. adbsshdeck-0.1.1/devicedeck/ui/tabs/scrcpy_tab.py +770 -0
  32. adbsshdeck-0.1.1/devicedeck/ui/tabs/terminal_tab.py +1192 -0
  33. adbsshdeck-0.1.1/devicedeck/ui/win_scrcpy_hotkey.py +76 -0
  34. adbsshdeck-0.1.1/pyproject.toml +55 -0
  35. adbsshdeck-0.1.1/setup.cfg +4 -0
  36. adbsshdeck-0.1.1/tests/test_config.py +50 -0
  37. adbsshdeck-0.1.1/tests/test_first_serial_token.py +21 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DeviceDeck contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ include README.md
2
+ include LICENSE
3
+ include pyproject.toml
@@ -0,0 +1,136 @@
1
+ Metadata-Version: 2.2
2
+ Name: adbsshdeck
3
+ Version: 0.1.1
4
+ Summary: Desktop workspace for Android: ADB and SSH terminals, serial, file access, and USB screen control (DeviceDeck).
5
+ Author: DeviceDeck contributors
6
+ License: MIT
7
+ Project-URL: Homepage, https://nvnkennedy.github.io/Device_Deck/
8
+ Project-URL: Repository, https://github.com/nvnkennedy/Device_Deck
9
+ Project-URL: Documentation, https://github.com/nvnkennedy/Device_Deck#readme
10
+ Project-URL: PyPI, https://pypi.org/project/adbsshdeck/
11
+ Keywords: android,adb,ssh,serial,scrcpy,pyqt5,sftp,desktop,screen-mirroring
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: X11 Applications :: Qt
14
+ Classifier: Environment :: Win32 (MS Windows)
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Software Development :: Testing
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: PyQt5<6.0,>=5.15.11
27
+ Requires-Dist: pyserial<4.0,>=3.5
28
+ Requires-Dist: paramiko<5.0,>=3.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0; extra == "dev"
31
+ Provides-Extra: build
32
+ Requires-Dist: pyinstaller<7.0,>=6.0; extra == "build"
33
+
34
+ # DeviceDeck (PyQt5)
35
+
36
+ Desktop workspace for Android debugging: ADB file transfer, multi-session **SSH**, **serial**, USB **screen** forwarding, and on-device files — in one app.
37
+
38
+ | | |
39
+ |--|--|
40
+ | **PyPI package** | **`adbsshdeck`** (ADB + SSH + workspace “deck”, including screen control) |
41
+ | **Run after install** | **`adbsshdeck`** (also in `Scripts` on Windows) |
42
+ | **Python import** | `devicedeck` (unchanged) |
43
+ | **Website** | [nvnkennedy.github.io/Device_Deck](https://nvnkennedy.github.io/Device_Deck/) |
44
+ | **PyPI** | [pypi.org/project/adbsshdeck](https://pypi.org/project/adbsshdeck/) |
45
+
46
+ The name **`devicedeck`** on PyPI was already taken; **`adbsshdeck`** is this project’s distribution name.
47
+
48
+ ## Prerequisites
49
+
50
+ - Python 3.9+
51
+ - **ADB** and a **USB display-forwarding** tool on `PATH`, or paths in **File → Preferences**
52
+ - **`ssh` on PATH** if you use SSH terminal sessions
53
+ - **Serial/COM** hardware if you use serial tabs (pyserial is a dependency)
54
+
55
+ ## Install (recommended)
56
+
57
+ From [PyPI](https://pypi.org/project/adbsshdeck/):
58
+
59
+ ```bash
60
+ python -m pip install --upgrade pip
61
+ python -m pip install adbsshdeck
62
+ ```
63
+
64
+ Then:
65
+
66
+ ```bash
67
+ adbsshdeck
68
+ ```
69
+
70
+ Same as: `python -m devicedeck` (import package is still `devicedeck`).
71
+
72
+ This repository is **source-only** on GitHub — users install the **published package** with pip.
73
+
74
+ ## Install from a git clone (development)
75
+
76
+ ```bash
77
+ git clone https://github.com/nvnkennedy/Device_Deck.git
78
+ cd Device_Deck
79
+ pip install -e ".[dev]"
80
+ ```
81
+
82
+ Or:
83
+
84
+ ```bash
85
+ pip install "git+https://github.com/nvnkennedy/Device_Deck.git"
86
+ ```
87
+
88
+ `main.py` is a thin launcher for local development only.
89
+
90
+ ## Publishing to PyPI
91
+
92
+ See **[docs/PYPI_PUBLISH.md](docs/PYPI_PUBLISH.md)** (build wheel/sdist, API token, optional GitHub Actions).
93
+
94
+ ## Website (GitHub Pages)
95
+
96
+ Static site under `site/` — **Install** instructions for end users. Deployed by `.github/workflows/pages.yml` when you push changes under `site/`.
97
+
98
+ ## Windows standalone executable (optional, maintainers only)
99
+
100
+ For machines **without** Python, you can build a **PyInstaller** folder or installer **locally** — outputs are **not** committed to this repo.
101
+
102
+ ```powershell
103
+ pip install -e ".[build]"
104
+ powershell -ExecutionPolicy Bypass -File scripts\build_windows_exe.ps1
105
+ ```
106
+
107
+ See `DeviceDeck.spec`. ADB and display-forwarding tools are **not** bundled.
108
+
109
+ ## Project layout
110
+
111
+ - `pyproject.toml` — metadata; console entry **`adbsshdeck`**
112
+ - `devicedeck/` — application code (import name)
113
+ - `site/` — GitHub Pages (home + install + PyPI links)
114
+ - `scripts/` — `build_windows_exe.ps1`, `export_app_icon.py`
115
+ - `tests/` — pytest
116
+ - `DeviceDeck.spec` — PyInstaller (optional)
117
+
118
+ ## Build wheel / sdist
119
+
120
+ ```bash
121
+ pip install build
122
+ python -m build
123
+ ```
124
+
125
+ Artifacts: `dist/adbsshdeck-*.whl` and `dist/*.tar.gz`.
126
+
127
+ ## Testing
128
+
129
+ ```bash
130
+ python -m pytest tests/ -q
131
+ ```
132
+
133
+ ## Notes
134
+
135
+ - Settings: `~/.devicedeck.json`
136
+ - License: MIT — see [LICENSE](LICENSE)
@@ -0,0 +1,103 @@
1
+ # DeviceDeck (PyQt5)
2
+
3
+ Desktop workspace for Android debugging: ADB file transfer, multi-session **SSH**, **serial**, USB **screen** forwarding, and on-device files — in one app.
4
+
5
+ | | |
6
+ |--|--|
7
+ | **PyPI package** | **`adbsshdeck`** (ADB + SSH + workspace “deck”, including screen control) |
8
+ | **Run after install** | **`adbsshdeck`** (also in `Scripts` on Windows) |
9
+ | **Python import** | `devicedeck` (unchanged) |
10
+ | **Website** | [nvnkennedy.github.io/Device_Deck](https://nvnkennedy.github.io/Device_Deck/) |
11
+ | **PyPI** | [pypi.org/project/adbsshdeck](https://pypi.org/project/adbsshdeck/) |
12
+
13
+ The name **`devicedeck`** on PyPI was already taken; **`adbsshdeck`** is this project’s distribution name.
14
+
15
+ ## Prerequisites
16
+
17
+ - Python 3.9+
18
+ - **ADB** and a **USB display-forwarding** tool on `PATH`, or paths in **File → Preferences**
19
+ - **`ssh` on PATH** if you use SSH terminal sessions
20
+ - **Serial/COM** hardware if you use serial tabs (pyserial is a dependency)
21
+
22
+ ## Install (recommended)
23
+
24
+ From [PyPI](https://pypi.org/project/adbsshdeck/):
25
+
26
+ ```bash
27
+ python -m pip install --upgrade pip
28
+ python -m pip install adbsshdeck
29
+ ```
30
+
31
+ Then:
32
+
33
+ ```bash
34
+ adbsshdeck
35
+ ```
36
+
37
+ Same as: `python -m devicedeck` (import package is still `devicedeck`).
38
+
39
+ This repository is **source-only** on GitHub — users install the **published package** with pip.
40
+
41
+ ## Install from a git clone (development)
42
+
43
+ ```bash
44
+ git clone https://github.com/nvnkennedy/Device_Deck.git
45
+ cd Device_Deck
46
+ pip install -e ".[dev]"
47
+ ```
48
+
49
+ Or:
50
+
51
+ ```bash
52
+ pip install "git+https://github.com/nvnkennedy/Device_Deck.git"
53
+ ```
54
+
55
+ `main.py` is a thin launcher for local development only.
56
+
57
+ ## Publishing to PyPI
58
+
59
+ See **[docs/PYPI_PUBLISH.md](docs/PYPI_PUBLISH.md)** (build wheel/sdist, API token, optional GitHub Actions).
60
+
61
+ ## Website (GitHub Pages)
62
+
63
+ Static site under `site/` — **Install** instructions for end users. Deployed by `.github/workflows/pages.yml` when you push changes under `site/`.
64
+
65
+ ## Windows standalone executable (optional, maintainers only)
66
+
67
+ For machines **without** Python, you can build a **PyInstaller** folder or installer **locally** — outputs are **not** committed to this repo.
68
+
69
+ ```powershell
70
+ pip install -e ".[build]"
71
+ powershell -ExecutionPolicy Bypass -File scripts\build_windows_exe.ps1
72
+ ```
73
+
74
+ See `DeviceDeck.spec`. ADB and display-forwarding tools are **not** bundled.
75
+
76
+ ## Project layout
77
+
78
+ - `pyproject.toml` — metadata; console entry **`adbsshdeck`**
79
+ - `devicedeck/` — application code (import name)
80
+ - `site/` — GitHub Pages (home + install + PyPI links)
81
+ - `scripts/` — `build_windows_exe.ps1`, `export_app_icon.py`
82
+ - `tests/` — pytest
83
+ - `DeviceDeck.spec` — PyInstaller (optional)
84
+
85
+ ## Build wheel / sdist
86
+
87
+ ```bash
88
+ pip install build
89
+ python -m build
90
+ ```
91
+
92
+ Artifacts: `dist/adbsshdeck-*.whl` and `dist/*.tar.gz`.
93
+
94
+ ## Testing
95
+
96
+ ```bash
97
+ python -m pytest tests/ -q
98
+ ```
99
+
100
+ ## Notes
101
+
102
+ - Settings: `~/.devicedeck.json`
103
+ - License: MIT — see [LICENSE](LICENSE)
@@ -0,0 +1,136 @@
1
+ Metadata-Version: 2.2
2
+ Name: adbsshdeck
3
+ Version: 0.1.1
4
+ Summary: Desktop workspace for Android: ADB and SSH terminals, serial, file access, and USB screen control (DeviceDeck).
5
+ Author: DeviceDeck contributors
6
+ License: MIT
7
+ Project-URL: Homepage, https://nvnkennedy.github.io/Device_Deck/
8
+ Project-URL: Repository, https://github.com/nvnkennedy/Device_Deck
9
+ Project-URL: Documentation, https://github.com/nvnkennedy/Device_Deck#readme
10
+ Project-URL: PyPI, https://pypi.org/project/adbsshdeck/
11
+ Keywords: android,adb,ssh,serial,scrcpy,pyqt5,sftp,desktop,screen-mirroring
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: X11 Applications :: Qt
14
+ Classifier: Environment :: Win32 (MS Windows)
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Software Development :: Testing
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: PyQt5<6.0,>=5.15.11
27
+ Requires-Dist: pyserial<4.0,>=3.5
28
+ Requires-Dist: paramiko<5.0,>=3.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0; extra == "dev"
31
+ Provides-Extra: build
32
+ Requires-Dist: pyinstaller<7.0,>=6.0; extra == "build"
33
+
34
+ # DeviceDeck (PyQt5)
35
+
36
+ Desktop workspace for Android debugging: ADB file transfer, multi-session **SSH**, **serial**, USB **screen** forwarding, and on-device files — in one app.
37
+
38
+ | | |
39
+ |--|--|
40
+ | **PyPI package** | **`adbsshdeck`** (ADB + SSH + workspace “deck”, including screen control) |
41
+ | **Run after install** | **`adbsshdeck`** (also in `Scripts` on Windows) |
42
+ | **Python import** | `devicedeck` (unchanged) |
43
+ | **Website** | [nvnkennedy.github.io/Device_Deck](https://nvnkennedy.github.io/Device_Deck/) |
44
+ | **PyPI** | [pypi.org/project/adbsshdeck](https://pypi.org/project/adbsshdeck/) |
45
+
46
+ The name **`devicedeck`** on PyPI was already taken; **`adbsshdeck`** is this project’s distribution name.
47
+
48
+ ## Prerequisites
49
+
50
+ - Python 3.9+
51
+ - **ADB** and a **USB display-forwarding** tool on `PATH`, or paths in **File → Preferences**
52
+ - **`ssh` on PATH** if you use SSH terminal sessions
53
+ - **Serial/COM** hardware if you use serial tabs (pyserial is a dependency)
54
+
55
+ ## Install (recommended)
56
+
57
+ From [PyPI](https://pypi.org/project/adbsshdeck/):
58
+
59
+ ```bash
60
+ python -m pip install --upgrade pip
61
+ python -m pip install adbsshdeck
62
+ ```
63
+
64
+ Then:
65
+
66
+ ```bash
67
+ adbsshdeck
68
+ ```
69
+
70
+ Same as: `python -m devicedeck` (import package is still `devicedeck`).
71
+
72
+ This repository is **source-only** on GitHub — users install the **published package** with pip.
73
+
74
+ ## Install from a git clone (development)
75
+
76
+ ```bash
77
+ git clone https://github.com/nvnkennedy/Device_Deck.git
78
+ cd Device_Deck
79
+ pip install -e ".[dev]"
80
+ ```
81
+
82
+ Or:
83
+
84
+ ```bash
85
+ pip install "git+https://github.com/nvnkennedy/Device_Deck.git"
86
+ ```
87
+
88
+ `main.py` is a thin launcher for local development only.
89
+
90
+ ## Publishing to PyPI
91
+
92
+ See **[docs/PYPI_PUBLISH.md](docs/PYPI_PUBLISH.md)** (build wheel/sdist, API token, optional GitHub Actions).
93
+
94
+ ## Website (GitHub Pages)
95
+
96
+ Static site under `site/` — **Install** instructions for end users. Deployed by `.github/workflows/pages.yml` when you push changes under `site/`.
97
+
98
+ ## Windows standalone executable (optional, maintainers only)
99
+
100
+ For machines **without** Python, you can build a **PyInstaller** folder or installer **locally** — outputs are **not** committed to this repo.
101
+
102
+ ```powershell
103
+ pip install -e ".[build]"
104
+ powershell -ExecutionPolicy Bypass -File scripts\build_windows_exe.ps1
105
+ ```
106
+
107
+ See `DeviceDeck.spec`. ADB and display-forwarding tools are **not** bundled.
108
+
109
+ ## Project layout
110
+
111
+ - `pyproject.toml` — metadata; console entry **`adbsshdeck`**
112
+ - `devicedeck/` — application code (import name)
113
+ - `site/` — GitHub Pages (home + install + PyPI links)
114
+ - `scripts/` — `build_windows_exe.ps1`, `export_app_icon.py`
115
+ - `tests/` — pytest
116
+ - `DeviceDeck.spec` — PyInstaller (optional)
117
+
118
+ ## Build wheel / sdist
119
+
120
+ ```bash
121
+ pip install build
122
+ python -m build
123
+ ```
124
+
125
+ Artifacts: `dist/adbsshdeck-*.whl` and `dist/*.tar.gz`.
126
+
127
+ ## Testing
128
+
129
+ ```bash
130
+ python -m pytest tests/ -q
131
+ ```
132
+
133
+ ## Notes
134
+
135
+ - Settings: `~/.devicedeck.json`
136
+ - License: MIT — see [LICENSE](LICENSE)
@@ -0,0 +1,35 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ adbsshdeck.egg-info/PKG-INFO
6
+ adbsshdeck.egg-info/SOURCES.txt
7
+ adbsshdeck.egg-info/dependency_links.txt
8
+ adbsshdeck.egg-info/entry_points.txt
9
+ adbsshdeck.egg-info/requires.txt
10
+ adbsshdeck.egg-info/top_level.txt
11
+ devicedeck/__init__.py
12
+ devicedeck/__main__.py
13
+ devicedeck/app.py
14
+ devicedeck/config.py
15
+ devicedeck/session.py
16
+ devicedeck/services/__init__.py
17
+ devicedeck/services/adb_devices.py
18
+ devicedeck/services/commands.py
19
+ devicedeck/services/remote_clients.py
20
+ devicedeck/ui/__init__.py
21
+ devicedeck/ui/app_icon.py
22
+ devicedeck/ui/combo_utils.py
23
+ devicedeck/ui/first_run_dialog.py
24
+ devicedeck/ui/icon_utils.py
25
+ devicedeck/ui/main_window.py
26
+ devicedeck/ui/preferences_dialog.py
27
+ devicedeck/ui/session_login_dialog.py
28
+ devicedeck/ui/styles.py
29
+ devicedeck/ui/win_scrcpy_hotkey.py
30
+ devicedeck/ui/tabs/__init__.py
31
+ devicedeck/ui/tabs/file_explorer_tab.py
32
+ devicedeck/ui/tabs/scrcpy_tab.py
33
+ devicedeck/ui/tabs/terminal_tab.py
34
+ tests/test_config.py
35
+ tests/test_first_serial_token.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ adbsshdeck = devicedeck.app:main
@@ -0,0 +1,9 @@
1
+ PyQt5<6.0,>=5.15.11
2
+ pyserial<4.0,>=3.5
3
+ paramiko<5.0,>=3.0
4
+
5
+ [build]
6
+ pyinstaller<7.0,>=6.0
7
+
8
+ [dev]
9
+ pytest>=7.0
@@ -0,0 +1 @@
1
+ devicedeck
@@ -0,0 +1,4 @@
1
+ # Application display name (window title, About, scrcpy default window title, etc.).
2
+ APP_TITLE = "DeviceDeck"
3
+
4
+ __version__ = "0.1.1"
@@ -0,0 +1,4 @@
1
+ from .app import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,45 @@
1
+ import sys
2
+
3
+ from PyQt5.QtCore import Qt
4
+ from PyQt5.QtWidgets import QApplication, QStyleFactory
5
+
6
+ from . import APP_TITLE
7
+ from .config import AppConfig, has_existing_config_file
8
+ from .ui.app_icon import create_app_icon
9
+ from .ui.main_window import MainWindow
10
+
11
+
12
+ def _set_windows_app_user_model_id() -> None:
13
+ """So the taskbar uses our window icon instead of the generic Python icon."""
14
+ if sys.platform != "win32":
15
+ return
16
+ try:
17
+ import ctypes
18
+
19
+ ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("DeviceDeck.DeviceDeck.Application.1")
20
+ except Exception:
21
+ pass
22
+
23
+
24
+ def main():
25
+ _set_windows_app_user_model_id()
26
+ try:
27
+ QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
28
+ except AttributeError:
29
+ pass
30
+ app = QApplication(sys.argv)
31
+ app.setWindowIcon(create_app_icon())
32
+ fusion = QStyleFactory.create("Fusion")
33
+ if fusion is not None:
34
+ app.setStyle(fusion)
35
+ app.setApplicationName(APP_TITLE)
36
+ # Blinking text caret (ms). QApplication provides this in Qt5; ignore if unavailable.
37
+ try:
38
+ QApplication.setCursorFlashTime(530)
39
+ except AttributeError:
40
+ pass
41
+ fresh_config = not has_existing_config_file()
42
+ config = AppConfig.load()
43
+ window = MainWindow(config, first_launch=fresh_config)
44
+ window.show()
45
+ sys.exit(app.exec_())
@@ -0,0 +1,130 @@
1
+ import json
2
+ import os
3
+ import tempfile
4
+ from dataclasses import asdict, dataclass, field, fields
5
+ from pathlib import Path
6
+ from typing import Any, Dict, List
7
+
8
+
9
+ # Primary settings file; legacy `~/.adb_explorer_pro.json` is still read and removed after first save.
10
+ CONFIG_PATH = Path.home() / ".devicedeck.json"
11
+ _LEGACY_CONFIG_PATH = Path.home() / ".adb_explorer_pro.json"
12
+
13
+
14
+ def has_existing_config_file() -> bool:
15
+ return CONFIG_PATH.exists() or _LEGACY_CONFIG_PATH.exists()
16
+
17
+
18
+ def _sanitize_bookmark(bookmark: Dict[str, Any]) -> Dict[str, Any]:
19
+ """Drop sensitive fields before keeping bookmark data in config."""
20
+ cleaned = dict(bookmark)
21
+ for key in ("ssh_password", "sftp_password", "ftp_password"):
22
+ cleaned.pop(key, None)
23
+ return cleaned
24
+
25
+
26
+ @dataclass
27
+ class AppConfig:
28
+ # Empty on first run; resolved at runtime to "adb"/"scrcpy" when unset.
29
+ adb_path: str = ""
30
+ scrcpy_path: str = ""
31
+ dark_theme: bool = False
32
+ # When True, dock scrcpy into the Screen Control tab (Windows). Default False: separate window keeps
33
+ # reliable touch/swipe (embedded HWND reparenting often breaks input).
34
+ embed_scrcpy_mirror: bool = False
35
+ # Legacy mirror of embed checkbox; kept for older configs (embed off => opt_out true).
36
+ embed_scrcpy_mirror_opt_out: bool = True
37
+ default_ssh_host: str = ""
38
+ default_serial_port: str = "COM3"
39
+ default_serial_baud: str = "115200"
40
+ # Optional SSH: sent to the active terminal when using Commands → SSH (after you open an SSH tab).
41
+ ssh_mount_command: str = ""
42
+ # List of {"label": str, "command": str} — customizable in Preferences.
43
+ ssh_quick_commands: List[Dict[str, str]] = field(default_factory=list)
44
+ # Saved sessions (WinSCP/Moba-style): list of dicts with kind, name, host, user, etc.
45
+ session_bookmarks: List[Dict[str, Any]] = field(default_factory=list)
46
+ # Find files dialog: recent folder paths per side (local vs remote search)
47
+ find_folder_history_local: List[str] = field(default_factory=list)
48
+ find_folder_history_remote: List[str] = field(default_factory=list)
49
+
50
+ @classmethod
51
+ def load(cls) -> "AppConfig":
52
+ if CONFIG_PATH.exists():
53
+ read_path = CONFIG_PATH
54
+ elif _LEGACY_CONFIG_PATH.exists():
55
+ read_path = _LEGACY_CONFIG_PATH
56
+ else:
57
+ return cls()
58
+ known = {f.name for f in fields(cls)}
59
+ try:
60
+ raw = json.loads(read_path.read_text(encoding="utf-8"))
61
+ defaults = asdict(cls())
62
+ if isinstance(raw, dict):
63
+ for key, value in raw.items():
64
+ if key in known:
65
+ defaults[key] = value
66
+ if not isinstance(defaults.get("session_bookmarks"), list):
67
+ defaults["session_bookmarks"] = []
68
+ else:
69
+ defaults["session_bookmarks"] = [
70
+ _sanitize_bookmark(x)
71
+ for x in defaults["session_bookmarks"]
72
+ if isinstance(x, dict)
73
+ ]
74
+ qc = defaults.get("ssh_quick_commands")
75
+ if not isinstance(qc, list):
76
+ defaults["ssh_quick_commands"] = []
77
+ else:
78
+ defaults["ssh_quick_commands"] = [
79
+ {"label": str(x.get("label", "")), "command": str(x.get("command", ""))}
80
+ for x in qc
81
+ if isinstance(x, dict) and (x.get("label") or x.get("command"))
82
+ ]
83
+ for key in ("find_folder_history_local", "find_folder_history_remote"):
84
+ lst = defaults.get(key)
85
+ if not isinstance(lst, list):
86
+ defaults[key] = []
87
+ else:
88
+ defaults[key] = [str(x).strip() for x in lst if str(x).strip()][:40]
89
+ return cls(**defaults)
90
+ except Exception as exc:
91
+ print(f"[DeviceDeck] Could not load config '{read_path}': {exc}")
92
+ return cls()
93
+
94
+ def save(self) -> None:
95
+ data = asdict(self)
96
+ data["session_bookmarks"] = [
97
+ _sanitize_bookmark(x)
98
+ for x in data.get("session_bookmarks", [])
99
+ if isinstance(x, dict)
100
+ ]
101
+ qc = data.get("ssh_quick_commands")
102
+ if isinstance(qc, list):
103
+ data["ssh_quick_commands"] = [
104
+ {"label": str(x.get("label", "")), "command": str(x.get("command", ""))}
105
+ for x in qc
106
+ if isinstance(x, dict) and (str(x.get("label", "")).strip() or str(x.get("command", "")).strip())
107
+ ]
108
+ text = json.dumps(data, indent=2, ensure_ascii=False) + "\n"
109
+ path = CONFIG_PATH
110
+ path.parent.mkdir(parents=True, exist_ok=True)
111
+ fd, tmp_path = tempfile.mkstemp(
112
+ suffix=".tmp",
113
+ prefix=f"{path.name}.",
114
+ dir=str(path.parent),
115
+ )
116
+ try:
117
+ with os.fdopen(fd, "w", encoding="utf-8") as f:
118
+ f.write(text)
119
+ os.replace(tmp_path, path)
120
+ except Exception:
121
+ try:
122
+ os.unlink(tmp_path)
123
+ except OSError:
124
+ pass
125
+ raise
126
+ try:
127
+ if _LEGACY_CONFIG_PATH.is_file():
128
+ _LEGACY_CONFIG_PATH.unlink()
129
+ except OSError:
130
+ pass
@@ -0,0 +1 @@
1
+ # Service helpers package