iOS remote client: native UIKit surface, WS logging, client-side layout persistence
- Add remote-client-ios: full native UIKit app with Objects/View/UILayout/Functions pattern - Widget hierarchy: BaseWidget → Fader, Toggle, Transport, Title, Feedback, LogWidget - LoggingVC: child VC embedded in LogWidget for live WS message inspection - Codable model: ModelPresetLoadToRemoteDevice with snake_case decoder strategy - Layout persistence: UserDefaults keyed by preset_uuid, fully client-side - WS logging: dedicated WS In/Out floating panels on desktop app - Remove HTTP server and JS client (replaced by native iOS app) - Add Xcode noise to .gitignore (xcuserstate, xcuserdata) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,25 +0,0 @@
|
||||
import os
|
||||
import threading
|
||||
from http.server import SimpleHTTPRequestHandler, HTTPServer
|
||||
|
||||
_CLIENT_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "client")
|
||||
|
||||
|
||||
class _Handler(SimpleHTTPRequestHandler):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, directory=_CLIENT_DIR, **kwargs)
|
||||
|
||||
def log_message(self, fmt, *args):
|
||||
pass
|
||||
|
||||
|
||||
def start_http_server(port=8080):
|
||||
server = HTTPServer(("0.0.0.0", port), _Handler)
|
||||
thread = threading.Thread(target=server.serve_forever, daemon=True)
|
||||
thread.start()
|
||||
return server
|
||||
|
||||
|
||||
def stop_http_server(server):
|
||||
if server:
|
||||
threading.Thread(target=server.shutdown, daemon=True).start()
|
||||
+4
-1
@@ -9,6 +9,7 @@ class WSServer(QObject):
|
||||
layout_saved = pyqtSignal(str, object)
|
||||
client_connected = pyqtSignal()
|
||||
log_signal = pyqtSignal(str)
|
||||
raw_in_signal = pyqtSignal(str)
|
||||
|
||||
def __init__(self, port=8765, parent=None):
|
||||
super().__init__(parent)
|
||||
@@ -37,6 +38,7 @@ class WSServer(QObject):
|
||||
self.log_signal.emit(f"client disconnected {peer} ({len(self._clients)} remaining)")
|
||||
|
||||
def _on_message(self, message):
|
||||
self.raw_in_signal.emit(message)
|
||||
try:
|
||||
data = json.loads(message)
|
||||
ev = data.get("event")
|
||||
@@ -64,7 +66,8 @@ class WSServer(QObject):
|
||||
def broadcast_preset(self, snapshot: dict, layout: dict):
|
||||
name = snapshot.get("preset_name", "")
|
||||
self.log_signal.emit(f"broadcast preset '{name}' → {len(self._clients)} client(s)")
|
||||
self.broadcast({"event": "preset", "data": snapshot, "layout": layout})
|
||||
# layout omitted — owned and persisted client-side, keyed by preset_uuid
|
||||
self.broadcast({"event": "preset", "data": snapshot})
|
||||
|
||||
def broadcast_widget_update(self, uid: str, value: int):
|
||||
self.broadcast({"event": "widget_update", "uid": uid, "value": value})
|
||||
|
||||
Reference in New Issue
Block a user