feat: split ui in multiple files for maintainability
All checks were successful
/ mirror (push) Successful in 4s
All checks were successful
/ mirror (push) Successful in 4s
This commit is contained in:
parent
225b40b34f
commit
bf6ac57f51
@ -1,122 +1,14 @@
|
|||||||
import sys
|
import sys
|
||||||
import random
|
import random
|
||||||
import socket
|
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||||||
QPushButton, QLabel, QFrame, QSizePolicy, QStyle
|
QPushButton, QLabel, QFrame, QSizePolicy, QStyle
|
||||||
)
|
)
|
||||||
from PyQt5.QtCore import Qt, QTimer, QSize, QPointF, pyqtSignal, QThread
|
from PyQt5.QtCore import Qt, QTimer, QSize
|
||||||
from PyQt5.QtGui import QPainter, QColor, QPen, QLinearGradient, QBrush, QIcon, QFont
|
from PyQt5.QtGui import QFont
|
||||||
|
from phone_client import PhoneClient
|
||||||
# --- Phone Client Thread ---
|
from waveform_widget import WaveformWidget
|
||||||
class PhoneClient(QThread):
|
from phone_state import PhoneState
|
||||||
data_received = pyqtSignal(bytes, int) # Include client_id
|
|
||||||
state_changed = pyqtSignal(str, str, int) # Include client_id
|
|
||||||
|
|
||||||
def __init__(self, host, port, client_id):
|
|
||||||
super().__init__()
|
|
||||||
self.host = host
|
|
||||||
self.port = port
|
|
||||||
self.client_id = client_id
|
|
||||||
self.sock = None
|
|
||||||
self.running = True
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
try:
|
|
||||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
|
||||||
self.sock.settimeout(15)
|
|
||||||
self.sock.connect((self.host, self.port))
|
|
||||||
print(f"Client {self.client_id} connected to {self.host}:{self.port}")
|
|
||||||
while self.running:
|
|
||||||
try:
|
|
||||||
data = self.sock.recv(1024)
|
|
||||||
if not data:
|
|
||||||
print(f"Client {self.client_id} disconnected")
|
|
||||||
self.state_changed.emit("CALL_END", "", self.client_id)
|
|
||||||
break
|
|
||||||
decoded_data = data.decode('utf-8', errors='ignore').strip()
|
|
||||||
print(f"Client {self.client_id} received raw: {decoded_data}")
|
|
||||||
if decoded_data in ["RINGING", "CALL_END", "CALL_DROPPED", "IN_CALL"]:
|
|
||||||
self.state_changed.emit(decoded_data, "", self.client_id)
|
|
||||||
else:
|
|
||||||
self.data_received.emit(data, self.client_id)
|
|
||||||
print(f"Client {self.client_id} received audio: {decoded_data}")
|
|
||||||
except socket.timeout:
|
|
||||||
print(f"Client {self.client_id} timed out waiting for data")
|
|
||||||
continue
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Client {self.client_id} error: {e}")
|
|
||||||
self.state_changed.emit("CALL_END", "", self.client_id)
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Client {self.client_id} connection failed: {e}")
|
|
||||||
finally:
|
|
||||||
if self.sock:
|
|
||||||
self.sock.close()
|
|
||||||
|
|
||||||
def send(self, message):
|
|
||||||
if self.sock and self.running:
|
|
||||||
try:
|
|
||||||
self.sock.send(message.encode())
|
|
||||||
print(f"Client {self.client_id} sent: {message}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Client {self.client_id} send error: {e}")
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
self.running = False
|
|
||||||
if self.sock:
|
|
||||||
self.sock.close()
|
|
||||||
|
|
||||||
# --- Custom Waveform Widget ---
|
|
||||||
class WaveformWidget(QWidget):
|
|
||||||
def __init__(self, parent=None, dynamic=False):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.dynamic = dynamic
|
|
||||||
self.setMinimumSize(200, 80)
|
|
||||||
self.setMaximumHeight(100)
|
|
||||||
self.waveform_data = [random.randint(10, 90) for _ in range(50)]
|
|
||||||
if self.dynamic:
|
|
||||||
self.timer = QTimer(self)
|
|
||||||
self.timer.timeout.connect(self.update_waveform)
|
|
||||||
self.timer.start(100)
|
|
||||||
|
|
||||||
def update_waveform(self):
|
|
||||||
self.waveform_data = self.waveform_data[1:] + [random.randint(10, 90)]
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def set_data(self, data):
|
|
||||||
amplitude = sum(byte for byte in data) % 90 + 10
|
|
||||||
self.waveform_data = self.waveform_data[1:] + [amplitude]
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def paintEvent(self, event):
|
|
||||||
painter = QPainter(self)
|
|
||||||
painter.setRenderHint(QPainter.Antialiasing)
|
|
||||||
painter.fillRect(self.rect(), QColor("#2D2D2D"))
|
|
||||||
gradient = QLinearGradient(0, 0, 0, self.height())
|
|
||||||
gradient.setColorAt(0.0, QColor("#0078D4"))
|
|
||||||
gradient.setColorAt(1.0, QColor("#50E6A4"))
|
|
||||||
pen = QPen(QBrush(gradient), 2)
|
|
||||||
painter.setPen(pen)
|
|
||||||
bar_width = self.width() / len(self.waveform_data)
|
|
||||||
max_h = self.height() - 10
|
|
||||||
for i, val in enumerate(self.waveform_data):
|
|
||||||
bar_height = (val / 100.0) * max_h
|
|
||||||
x = i * bar_width
|
|
||||||
y = (self.height() - bar_height) / 2
|
|
||||||
painter.drawLine(QPointF(x + bar_width / 2, y), QPointF(x + bar_width / 2, y + bar_height))
|
|
||||||
|
|
||||||
def resizeEvent(self, event):
|
|
||||||
super().resizeEvent(event)
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
# --- Phone State ---
|
|
||||||
class PhoneState:
|
|
||||||
IDLE = 0
|
|
||||||
CALLING = 1
|
|
||||||
IN_CALL = 2
|
|
||||||
RINGING = 3
|
|
||||||
|
|
||||||
class PhoneUI(QMainWindow):
|
class PhoneUI(QMainWindow):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -182,7 +74,6 @@ class PhoneUI(QMainWindow):
|
|||||||
client.state_changed.connect(lambda state, num, cid=i: self.set_phone_state(cid, self.map_state(state), num))
|
client.state_changed.connect(lambda state, num, cid=i: self.set_phone_state(cid, self.map_state(state), num))
|
||||||
client.start()
|
client.start()
|
||||||
|
|
||||||
# Corrected lambda to handle 'checked' and capture phone_id
|
|
||||||
phone_widget_container, phone_display, phone_button, phone_waveform, phone_status_label = self._create_phone_ui(
|
phone_widget_container, phone_display, phone_button, phone_waveform, phone_status_label = self._create_phone_ui(
|
||||||
f"Phone {i+1}", lambda checked, phone_id=i: self.phone_action(phone_id)
|
f"Phone {i+1}", lambda checked, phone_id=i: self.phone_action(phone_id)
|
||||||
)
|
)
|
61
protocol_prototype/DryBox/UI/phone_client.py
Normal file
61
protocol_prototype/DryBox/UI/phone_client.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import socket
|
||||||
|
from PyQt5.QtCore import QThread, pyqtSignal
|
||||||
|
|
||||||
|
class PhoneClient(QThread):
|
||||||
|
data_received = pyqtSignal(bytes, int) # Include client_id
|
||||||
|
state_changed = pyqtSignal(str, str, int) # Include client_id
|
||||||
|
|
||||||
|
def __init__(self, host, port, client_id):
|
||||||
|
super().__init__()
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
self.client_id = client_id
|
||||||
|
self.sock = None
|
||||||
|
self.running = True
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
try:
|
||||||
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||||
|
self.sock.settimeout(15)
|
||||||
|
self.sock.connect((self.host, self.port))
|
||||||
|
print(f"Client {self.client_id} connected to {self.host}:{self.port}")
|
||||||
|
while self.running:
|
||||||
|
try:
|
||||||
|
data = self.sock.recv(1024)
|
||||||
|
if not data:
|
||||||
|
print(f"Client {self.client_id} disconnected")
|
||||||
|
self.state_changed.emit("CALL_END", "", self.client_id)
|
||||||
|
break
|
||||||
|
decoded_data = data.decode('utf-8', errors='ignore').strip()
|
||||||
|
print(f"Client {self.client_id} received raw: {decoded_data}")
|
||||||
|
if decoded_data in ["RINGING", "CALL_END", "CALL_DROPPED", "IN_CALL"]:
|
||||||
|
self.state_changed.emit(decoded_data, "", self.client_id)
|
||||||
|
else:
|
||||||
|
self.data_received.emit(data, self.client_id)
|
||||||
|
print(f"Client {self.client_id} received audio: {decoded_data}")
|
||||||
|
except socket.timeout:
|
||||||
|
print(f"Client {self.client_id} timed out waiting for data")
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Client {self.client_id} error: {e}")
|
||||||
|
self.state_changed.emit("CALL_END", "", self.client_id)
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Client {self.client_id} connection failed: {e}")
|
||||||
|
finally:
|
||||||
|
if self.sock:
|
||||||
|
self.sock.close()
|
||||||
|
|
||||||
|
def send(self, message):
|
||||||
|
if self.sock and self.running:
|
||||||
|
try:
|
||||||
|
self.sock.send(message.encode())
|
||||||
|
print(f"Client {self.client_id} sent: {message}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Client {self.client_id} send error: {e}")
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.running = False
|
||||||
|
if self.sock:
|
||||||
|
self.sock.close()
|
5
protocol_prototype/DryBox/UI/phone_state.py
Normal file
5
protocol_prototype/DryBox/UI/phone_state.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
class PhoneState:
|
||||||
|
IDLE = 0
|
||||||
|
CALLING = 1
|
||||||
|
IN_CALL = 2
|
||||||
|
RINGING = 3
|
46
protocol_prototype/DryBox/UI/waveform_widget.py
Normal file
46
protocol_prototype/DryBox/UI/waveform_widget.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import random
|
||||||
|
from PyQt5.QtWidgets import QWidget
|
||||||
|
from PyQt5.QtCore import QTimer, QSize, QPointF
|
||||||
|
from PyQt5.QtGui import QPainter, QColor, QPen, QLinearGradient, QBrush
|
||||||
|
|
||||||
|
class WaveformWidget(QWidget):
|
||||||
|
def __init__(self, parent=None, dynamic=False):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.dynamic = dynamic
|
||||||
|
self.setMinimumSize(200, 80)
|
||||||
|
self.setMaximumHeight(100)
|
||||||
|
self.waveform_data = [random.randint(10, 90) for _ in range(50)]
|
||||||
|
if self.dynamic:
|
||||||
|
self.timer = QTimer(self)
|
||||||
|
self.timer.timeout.connect(self.update_waveform)
|
||||||
|
self.timer.start(100)
|
||||||
|
|
||||||
|
def update_waveform(self):
|
||||||
|
self.waveform_data = self.waveform_data[1:] + [random.randint(10, 90)]
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def set_data(self, data):
|
||||||
|
amplitude = sum(byte for byte in data) % 90 + 10
|
||||||
|
self.waveform_data = self.waveform_data[1:] + [amplitude]
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def paintEvent(self, event):
|
||||||
|
painter = QPainter(self)
|
||||||
|
painter.setRenderHint(QPainter.Antialiasing)
|
||||||
|
painter.fillRect(self.rect(), QColor("#2D2D2D"))
|
||||||
|
gradient = QLinearGradient(0, 0, 0, self.height())
|
||||||
|
gradient.setColorAt(0.0, QColor("#0078D4"))
|
||||||
|
gradient.setColorAt(1.0, QColor("#50E6A4"))
|
||||||
|
pen = QPen(QBrush(gradient), 2)
|
||||||
|
painter.setPen(pen)
|
||||||
|
bar_width = self.width() / len(self.waveform_data)
|
||||||
|
max_h = self.height() - 10
|
||||||
|
for i, val in enumerate(self.waveform_data):
|
||||||
|
bar_height = (val / 100.0) * max_h
|
||||||
|
x = i * bar_width
|
||||||
|
y = (self.height() - bar_height) / 2
|
||||||
|
painter.drawLine(QPointF(x + bar_width / 2, y), QPointF(x + bar_width / 2, y + bar_height))
|
||||||
|
|
||||||
|
def resizeEvent(self, event):
|
||||||
|
super().resizeEvent(event)
|
||||||
|
self.update()
|
Loading…
Reference in New Issue
Block a user