feat: split ui in multiple files for maintainability
All checks were successful
/ mirror (push) Successful in 4s

This commit is contained in:
Florian Griffon 2025-05-24 01:04:29 +03:00
parent 225b40b34f
commit bf6ac57f51
4 changed files with 117 additions and 114 deletions

View File

@ -1,122 +1,14 @@
import sys
import random
import socket
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QPushButton, QLabel, QFrame, QSizePolicy, QStyle
)
from PyQt5.QtCore import Qt, QTimer, QSize, QPointF, pyqtSignal, QThread
from PyQt5.QtGui import QPainter, QColor, QPen, QLinearGradient, QBrush, QIcon, QFont
# --- Phone Client Thread ---
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()
# --- 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
from PyQt5.QtCore import Qt, QTimer, QSize
from PyQt5.QtGui import QFont
from phone_client import PhoneClient
from waveform_widget import WaveformWidget
from phone_state import PhoneState
class PhoneUI(QMainWindow):
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.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(
f"Phone {i+1}", lambda checked, phone_id=i: self.phone_action(phone_id)
)

View 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()

View File

@ -0,0 +1,5 @@
class PhoneState:
IDLE = 0
CALLING = 1
IN_CALL = 2
RINGING = 3

View 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()