feat(v1): settings camera connection test and preview
Settings tab gains a camera group (host/port/channel/user/masked password), a background connection-test worker that probes one frame off the GUI thread and shows it in a preview, and a save button that writes the structured source to the untracked config.local.json. 60 tests pass; Qt shell compiles and needs a Windows smoke. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -6,11 +6,12 @@ only renders them. Settings edits become a new immutable runtime snapshot at the
|
||||
next start, so screenshots and logs stay traceable to the actual config version.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from dataclasses import replace
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from typing import Dict, Optional
|
||||
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
|
||||
@@ -82,7 +83,13 @@ def _draft_from_config(config: AppConfig) -> SettingsDraft:
|
||||
class ApplicationController:
|
||||
"""Own the window, draft and worker lifecycle without doing event logic."""
|
||||
|
||||
def __init__(self, config: AppConfig, pose_adapter: PoseAdapter) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
config: AppConfig,
|
||||
pose_adapter: PoseAdapter,
|
||||
config_path: Optional[str] = None,
|
||||
camera: Optional[Dict] = None,
|
||||
) -> None:
|
||||
from v1.gui import MainWindow
|
||||
|
||||
self._config = config
|
||||
@@ -90,7 +97,9 @@ class ApplicationController:
|
||||
self._draft = _draft_from_config(config)
|
||||
env_ready = bool(config.source_url)
|
||||
model_summary = "{0} · {1}…".format(config.model_path.name, config.model_sha256[:12])
|
||||
self.window = MainWindow(self._draft, env_ready, model_summary, config.source_id)
|
||||
self.window = MainWindow(
|
||||
self._draft, env_ready, model_summary, config.source_id, config_path, camera
|
||||
)
|
||||
self.window.monitor.start_requested.connect(self.start)
|
||||
self.window.monitor.stop_requested.connect(self.stop)
|
||||
self._worker: Optional[FrameWorker] = None
|
||||
@@ -137,11 +146,24 @@ def main(config_path: Optional[str] = None) -> int:
|
||||
pose_adapter = PoseAdapter(
|
||||
config.model_path, config.model_sha256, config.confidence_threshold
|
||||
)
|
||||
camera = _camera_fields(path)
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
controller = ApplicationController(config, pose_adapter)
|
||||
controller = ApplicationController(config, pose_adapter, str(path), camera)
|
||||
controller.window.show()
|
||||
return app.exec_()
|
||||
|
||||
|
||||
def _camera_fields(path: Path) -> Dict:
|
||||
"""Pre-fill the settings camera form from a structured local source, if any."""
|
||||
|
||||
try:
|
||||
source = json.loads(Path(path).read_text(encoding="utf-8")).get("source", {})
|
||||
except (OSError, ValueError):
|
||||
return {}
|
||||
if "host" not in source:
|
||||
return {}
|
||||
return {k: source.get(k) for k in ("host", "port", "channel", "username", "password")}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
|
||||
Reference in New Issue
Block a user