787 lines
32 KiB
Python
787 lines
32 KiB
Python
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton,
|
|
QLineEdit, QTextEdit, QGroupBox, QTabWidget, QListWidget,
|
|
QListWidgetItem, QMessageBox, QSplitter, QComboBox,
|
|
QTableWidget, QTableWidgetItem, QHeaderView, QSizePolicy)
|
|
from PyQt5.QtCore import Qt, pyqtSlot, QDateTime, QSize
|
|
import time
|
|
|
|
class PhoneSmsTab(QWidget):
|
|
def __init__(self, lte_manager, database, sound_manager):
|
|
super().__init__()
|
|
self.lte_manager = lte_manager
|
|
self.database = database
|
|
self.sound_manager = sound_manager
|
|
|
|
# Connect signals
|
|
self.lte_manager.call_received.connect(self.on_call_received)
|
|
self.lte_manager.call_ended.connect(self.on_call_ended)
|
|
self.lte_manager.sms_received.connect(self.on_sms_received)
|
|
self.lte_manager.dtmf_received.connect(self.on_dtmf_received)
|
|
self.lte_manager.status_changed.connect(self.on_status_changed)
|
|
|
|
self.init_ui()
|
|
|
|
def init_ui(self):
|
|
# Main layout
|
|
main_layout = QVBoxLayout(self)
|
|
|
|
# Create inner tab widget for phone and SMS
|
|
inner_tab_widget = QTabWidget()
|
|
main_layout.addWidget(inner_tab_widget)
|
|
|
|
# Phone tab
|
|
phone_widget = QWidget()
|
|
phone_layout = QVBoxLayout(phone_widget)
|
|
|
|
# Create a splitter for phone controls and call history
|
|
phone_splitter = QSplitter(Qt.Vertical)
|
|
phone_layout.addWidget(phone_splitter)
|
|
|
|
# Top widget for phone controls
|
|
phone_top_widget = QWidget()
|
|
phone_top_layout = QVBoxLayout(phone_top_widget)
|
|
|
|
# Phone controls
|
|
phone_group = QGroupBox("电话控制")
|
|
phone_controls_layout = QVBoxLayout()
|
|
|
|
# 通话状态显示
|
|
self.call_status_display = QLabel("通话状态: 无通话")
|
|
self.call_status_display.setStyleSheet("font-size: 14px; font-weight: bold; padding: 5px; background-color: #f0f0f0; border-radius: 3px;")
|
|
self.call_status_display.setAlignment(Qt.AlignCenter)
|
|
phone_controls_layout.addWidget(self.call_status_display)
|
|
|
|
# Number input
|
|
number_layout = QHBoxLayout()
|
|
number_layout.addWidget(QLabel("电话号码:"))
|
|
self.phone_number_input = QLineEdit()
|
|
self.phone_number_input.setPlaceholderText("输入电话号码")
|
|
number_layout.addWidget(self.phone_number_input)
|
|
phone_controls_layout.addLayout(number_layout)
|
|
|
|
# Call buttons
|
|
call_buttons_layout = QHBoxLayout()
|
|
self.call_button = QPushButton("拨号")
|
|
self.call_button.setStyleSheet("QPushButton { background-color: #4CAF50; color: white; padding: 6px; } QPushButton:disabled { background-color: #cccccc; }")
|
|
self.call_button.clicked.connect(self.on_call_button_clicked)
|
|
call_buttons_layout.addWidget(self.call_button)
|
|
|
|
self.answer_button = QPushButton("接听")
|
|
self.answer_button.setStyleSheet("QPushButton { background-color: #2196F3; color: white; padding: 6px; } QPushButton:disabled { background-color: #cccccc; }")
|
|
self.answer_button.clicked.connect(self.on_answer_button_clicked)
|
|
self.answer_button.setEnabled(False)
|
|
call_buttons_layout.addWidget(self.answer_button)
|
|
|
|
self.hangup_button = QPushButton("挂断")
|
|
self.hangup_button.setStyleSheet("QPushButton { background-color: #f44336; color: white; padding: 6px; } QPushButton:disabled { background-color: #cccccc; }")
|
|
self.hangup_button.clicked.connect(self.on_hangup_button_clicked)
|
|
self.hangup_button.setEnabled(False)
|
|
call_buttons_layout.addWidget(self.hangup_button)
|
|
|
|
phone_controls_layout.addLayout(call_buttons_layout)
|
|
phone_group.setLayout(phone_controls_layout)
|
|
phone_top_layout.addWidget(phone_group)
|
|
|
|
# DTMF tones received
|
|
dtmf_group = QGroupBox("DTMF拨号音")
|
|
dtmf_layout = QVBoxLayout()
|
|
self.dtmf_display = QLineEdit()
|
|
self.dtmf_display.setReadOnly(True)
|
|
dtmf_layout.addWidget(self.dtmf_display)
|
|
|
|
# 添加DTMF拨号键盘
|
|
dtmf_keyboard_layout = QVBoxLayout()
|
|
|
|
# 添加拨号键盘行
|
|
dtmf_rows = [
|
|
['1', '2', '3'],
|
|
['4', '5', '6'],
|
|
['7', '8', '9'],
|
|
['*', '0', '#']
|
|
]
|
|
|
|
for row in dtmf_rows:
|
|
row_layout = QHBoxLayout()
|
|
for key in row:
|
|
btn = QPushButton(key)
|
|
btn.setStyleSheet("QPushButton { font-size: 14px; padding: 10px; }")
|
|
btn.clicked.connect(lambda checked, k=key: self.send_dtmf(k))
|
|
row_layout.addWidget(btn)
|
|
dtmf_keyboard_layout.addLayout(row_layout)
|
|
|
|
dtmf_layout.addLayout(dtmf_keyboard_layout)
|
|
dtmf_group.setLayout(dtmf_layout)
|
|
phone_top_layout.addWidget(dtmf_group)
|
|
|
|
# Add phone top widget to splitter
|
|
phone_splitter.addWidget(phone_top_widget)
|
|
|
|
# Bottom widget for call history
|
|
phone_bottom_widget = QWidget()
|
|
phone_bottom_layout = QVBoxLayout(phone_bottom_widget)
|
|
|
|
# Call log
|
|
call_log_group = QGroupBox("Call History")
|
|
call_log_layout = QVBoxLayout()
|
|
|
|
# Call log controls
|
|
call_log_controls = QHBoxLayout()
|
|
self.refresh_call_log_button = QPushButton("Refresh")
|
|
self.refresh_call_log_button.clicked.connect(self.refresh_call_log)
|
|
call_log_controls.addWidget(self.refresh_call_log_button)
|
|
|
|
self.clear_call_log_button = QPushButton("Clear Selected")
|
|
self.clear_call_log_button.clicked.connect(self.clear_selected_call)
|
|
call_log_controls.addWidget(self.clear_call_log_button)
|
|
|
|
call_log_layout.addLayout(call_log_controls)
|
|
|
|
# Call log table
|
|
self.call_log_table = QTableWidget()
|
|
self.call_log_table.setColumnCount(4)
|
|
self.call_log_table.setHorizontalHeaderLabels(["Time", "Number", "Type", "Duration"])
|
|
self.call_log_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
|
self.call_log_table.setMinimumHeight(200) # Set minimum height
|
|
call_log_layout.addWidget(self.call_log_table)
|
|
|
|
call_log_group.setLayout(call_log_layout)
|
|
phone_bottom_layout.addWidget(call_log_group)
|
|
|
|
# Add phone bottom widget to splitter
|
|
phone_splitter.addWidget(phone_bottom_widget)
|
|
|
|
# Set initial sizes for splitter
|
|
phone_splitter.setSizes([200, 400])
|
|
|
|
# SMS tab
|
|
sms_widget = QWidget()
|
|
sms_layout = QVBoxLayout(sms_widget)
|
|
|
|
# Create a splitter for SMS tab
|
|
sms_splitter = QSplitter(Qt.Vertical)
|
|
sms_layout.addWidget(sms_splitter)
|
|
|
|
# Top widget for SMS sending
|
|
sms_top_widget = QWidget()
|
|
sms_top_layout = QVBoxLayout(sms_top_widget)
|
|
|
|
# SMS controls
|
|
sms_group = QGroupBox("Send SMS")
|
|
sms_controls_layout = QVBoxLayout()
|
|
|
|
# Number input
|
|
sms_number_layout = QHBoxLayout()
|
|
sms_number_layout.addWidget(QLabel("To:"))
|
|
self.sms_number_input = QLineEdit()
|
|
self.sms_number_input.setPlaceholderText("Enter recipient number")
|
|
sms_number_layout.addWidget(self.sms_number_input)
|
|
sms_controls_layout.addLayout(sms_number_layout)
|
|
|
|
# Message input
|
|
sms_controls_layout.addWidget(QLabel("Message:"))
|
|
self.sms_message_input = QTextEdit()
|
|
self.sms_message_input.setPlaceholderText("Type your message here")
|
|
self.sms_message_input.setMinimumHeight(100)
|
|
sms_controls_layout.addWidget(self.sms_message_input)
|
|
|
|
# Send button
|
|
self.send_sms_button = QPushButton("Send SMS")
|
|
self.send_sms_button.clicked.connect(self.on_send_sms_button_clicked)
|
|
sms_controls_layout.addWidget(self.send_sms_button)
|
|
|
|
sms_group.setLayout(sms_controls_layout)
|
|
sms_top_layout.addWidget(sms_group)
|
|
|
|
# Add SMS top widget to splitter
|
|
sms_splitter.addWidget(sms_top_widget)
|
|
|
|
# Middle widget for SMS inbox
|
|
sms_middle_widget = QWidget()
|
|
sms_middle_layout = QVBoxLayout(sms_middle_widget)
|
|
|
|
# SMS inbox
|
|
sms_inbox_group = QGroupBox("SMS Messages")
|
|
sms_inbox_layout = QVBoxLayout()
|
|
|
|
# SMS list and controls
|
|
sms_list_controls = QHBoxLayout()
|
|
self.sms_type_combo = QComboBox()
|
|
self.sms_type_combo.addItems(["All", "Unread", "Read", "Sent", "Unsent"])
|
|
sms_list_controls.addWidget(QLabel("Show:"))
|
|
sms_list_controls.addWidget(self.sms_type_combo)
|
|
|
|
self.refresh_sms_button = QPushButton("Refresh")
|
|
self.refresh_sms_button.clicked.connect(self.refresh_sms_list)
|
|
sms_list_controls.addWidget(self.refresh_sms_button)
|
|
|
|
self.delete_sms_button = QPushButton("Delete Selected")
|
|
self.delete_sms_button.clicked.connect(self.delete_selected_sms)
|
|
sms_list_controls.addWidget(self.delete_sms_button)
|
|
|
|
sms_inbox_layout.addLayout(sms_list_controls)
|
|
|
|
# Create a horizontal splitter for SMS list and content
|
|
sms_content_splitter = QSplitter(Qt.Horizontal)
|
|
|
|
# SMS list
|
|
self.sms_list = QListWidget()
|
|
self.sms_list.itemClicked.connect(self.on_sms_item_clicked)
|
|
self.sms_list.setMinimumHeight(150) # Set minimum height
|
|
sms_content_splitter.addWidget(self.sms_list)
|
|
|
|
# SMS content
|
|
sms_content_widget = QWidget()
|
|
sms_content_layout = QVBoxLayout(sms_content_widget)
|
|
sms_content_layout.addWidget(QLabel("Message Content:"))
|
|
self.sms_content = QTextEdit()
|
|
self.sms_content.setReadOnly(True)
|
|
sms_content_layout.addWidget(self.sms_content)
|
|
sms_content_splitter.addWidget(sms_content_widget)
|
|
|
|
# Set initial sizes for content splitter
|
|
sms_content_splitter.setSizes([300, 300])
|
|
|
|
sms_inbox_layout.addWidget(sms_content_splitter)
|
|
sms_inbox_group.setLayout(sms_inbox_layout)
|
|
sms_middle_layout.addWidget(sms_inbox_group)
|
|
|
|
# Add SMS middle widget to splitter
|
|
sms_splitter.addWidget(sms_middle_widget)
|
|
|
|
# Bottom widget for SMS history
|
|
sms_bottom_widget = QWidget()
|
|
sms_bottom_layout = QVBoxLayout(sms_bottom_widget)
|
|
|
|
# SMS history
|
|
sms_history_group = QGroupBox("SMS History")
|
|
sms_history_layout = QVBoxLayout()
|
|
|
|
# SMS history controls
|
|
sms_history_controls = QHBoxLayout()
|
|
self.refresh_sms_history_button = QPushButton("Refresh History")
|
|
self.refresh_sms_history_button.clicked.connect(self.refresh_sms_history)
|
|
sms_history_controls.addWidget(self.refresh_sms_history_button)
|
|
|
|
self.clear_sms_history_button = QPushButton("Clear Selected")
|
|
self.clear_sms_history_button.clicked.connect(self.clear_selected_sms_history)
|
|
sms_history_controls.addWidget(self.clear_sms_history_button)
|
|
|
|
sms_history_layout.addLayout(sms_history_controls)
|
|
|
|
# SMS history table
|
|
self.sms_history_table = QTableWidget()
|
|
self.sms_history_table.setColumnCount(4)
|
|
self.sms_history_table.setHorizontalHeaderLabels(["Time", "Number", "Type", "Message"])
|
|
self.sms_history_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
|
self.sms_history_table.itemClicked.connect(self.on_sms_history_item_clicked)
|
|
self.sms_history_table.setMinimumHeight(150) # Set minimum height
|
|
sms_history_layout.addWidget(self.sms_history_table)
|
|
|
|
sms_history_group.setLayout(sms_history_layout)
|
|
sms_bottom_layout.addWidget(sms_history_group)
|
|
|
|
# Add SMS bottom widget to splitter
|
|
sms_splitter.addWidget(sms_bottom_widget)
|
|
|
|
# Set initial sizes for SMS splitter
|
|
sms_splitter.setSizes([200, 300, 300])
|
|
|
|
# Add tabs to inner tab widget
|
|
inner_tab_widget.addTab(phone_widget, "Phone")
|
|
inner_tab_widget.addTab(sms_widget, "SMS")
|
|
|
|
# Status display
|
|
self.status_display = QTextEdit()
|
|
self.status_display.setReadOnly(True)
|
|
self.status_display.setMaximumHeight(100)
|
|
main_layout.addWidget(QLabel("Status:"))
|
|
main_layout.addWidget(self.status_display)
|
|
|
|
# Load initial data
|
|
self.refresh_call_log()
|
|
self.refresh_sms_history()
|
|
|
|
def update_call_ui_state(self, in_call=False):
|
|
"""根据当前通话状态更新UI"""
|
|
try:
|
|
# 获取最新通话状态
|
|
if self.lte_manager.is_connected():
|
|
call_state = self.lte_manager.get_call_state_text()
|
|
self.call_status_display.setText(f"通话状态: {call_state}")
|
|
|
|
# 获取当前通话
|
|
calls = self.lte_manager.get_call_status()
|
|
|
|
if calls:
|
|
# 有通话存在
|
|
call = calls[0]
|
|
stat = call.get('stat', -1)
|
|
direction = call.get('dir', 0)
|
|
|
|
# 根据通话状态更新按钮状态
|
|
if stat == 4 and direction == 1: # 来电中(MT)
|
|
# 来电振铃中
|
|
self.call_button.setEnabled(False)
|
|
self.answer_button.setEnabled(True)
|
|
self.hangup_button.setEnabled(True)
|
|
|
|
# 设置不同的样式以提示用户
|
|
self.call_status_display.setStyleSheet("font-size: 14px; font-weight: bold; padding: 5px; background-color: #FFF9C4; color: #E65100; border-radius: 3px;")
|
|
elif stat in [0, 1, 2, 3]: # 活动、保持、拨号中、振铃中
|
|
# 通话活动中
|
|
self.call_button.setEnabled(False)
|
|
self.answer_button.setEnabled(False)
|
|
self.hangup_button.setEnabled(True)
|
|
|
|
if stat == 0: # 活动通话
|
|
self.call_status_display.setStyleSheet("font-size: 14px; font-weight: bold; padding: 5px; background-color: #C8E6C9; color: #2E7D32; border-radius: 3px;")
|
|
elif stat == 1: # 保持通话
|
|
self.call_status_display.setStyleSheet("font-size: 14px; font-weight: bold; padding: 5px; background-color: #BBDEFB; color: #1565C0; border-radius: 3px;")
|
|
else: # 拨号中、振铃中
|
|
self.call_status_display.setStyleSheet("font-size: 14px; font-weight: bold; padding: 5px; background-color: #E1BEE7; color: #6A1B9A; border-radius: 3px;")
|
|
else:
|
|
# 未知状态
|
|
self.call_button.setEnabled(True)
|
|
self.answer_button.setEnabled(False)
|
|
self.hangup_button.setEnabled(False)
|
|
self.call_status_display.setStyleSheet("font-size: 14px; font-weight: bold; padding: 5px; background-color: #f0f0f0; border-radius: 3px;")
|
|
else:
|
|
# 无通话
|
|
self.call_button.setEnabled(True)
|
|
self.answer_button.setEnabled(False)
|
|
self.hangup_button.setEnabled(False)
|
|
self.call_status_display.setStyleSheet("font-size: 14px; font-weight: bold; padding: 5px; background-color: #f0f0f0; border-radius: 3px;")
|
|
else:
|
|
# 未连接
|
|
self.call_status_display.setText("通话状态: 未连接")
|
|
self.call_button.setEnabled(False)
|
|
self.answer_button.setEnabled(False)
|
|
self.hangup_button.setEnabled(False)
|
|
self.call_status_display.setStyleSheet("font-size: 14px; font-weight: bold; padding: 5px; background-color: #FFCCBC; color: #BF360C; border-radius: 3px;")
|
|
|
|
except Exception as e:
|
|
print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} - 更新通话UI状态出错: {str(e)}")
|
|
# 出错时重置为安全状态
|
|
self.call_button.setEnabled(True)
|
|
self.answer_button.setEnabled(False)
|
|
self.hangup_button.setEnabled(False)
|
|
|
|
def send_dtmf(self, tone):
|
|
"""发送DTMF拨号音"""
|
|
if not self.lte_manager.is_connected() or not self.lte_manager.is_call_connected():
|
|
# 只有在通话活动时才能发送DTMF音
|
|
print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} - 无法发送DTMF: 当前无活动通话")
|
|
self.sound_manager.play_error()
|
|
QMessageBox.warning(self, "DTMF错误", "只有在通话接通时才能发送拨号音")
|
|
return
|
|
|
|
try:
|
|
# 发送AT+VTS命令发送DTMF音
|
|
response = self.lte_manager.send_at_command(f"AT+VTS={tone}")
|
|
if "OK" in response:
|
|
# 发送成功,更新DTMF显示
|
|
current_text = self.dtmf_display.text()
|
|
self.dtmf_display.setText(current_text + tone)
|
|
self.sound_manager.play_dtmf() # 播放提示音
|
|
else:
|
|
print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} - 发送DTMF音失败: {response}")
|
|
self.sound_manager.play_error()
|
|
except Exception as e:
|
|
print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} - 发送DTMF音出错: {str(e)}")
|
|
self.sound_manager.play_error()
|
|
|
|
def on_call_button_clicked(self):
|
|
"""处理拨号按钮点击"""
|
|
number = self.phone_number_input.text().strip()
|
|
if not number:
|
|
return
|
|
|
|
# 添加到拨号记录,无论成功与否
|
|
self.call_log_history.append(f"拨打电话: {number}")
|
|
self.update_call_log_display()
|
|
|
|
# 尝试拨打电话
|
|
if self.lte_manager.make_call(number):
|
|
self.update_call_ui_state(True) # 拨号中,更新UI状态
|
|
|
|
# 触发主窗口进行通话状态检查
|
|
if hasattr(self.parent(), 'should_check_call_status'):
|
|
self.parent().should_check_call_status = True
|
|
self.parent().call_check_count = 0
|
|
if not self.parent().call_status_timer.isActive():
|
|
self.parent().call_status_timer.start(1000)
|
|
|
|
# 记录到数据库
|
|
self.database.add_call(number, "outgoing")
|
|
else:
|
|
# 拨号失败,提示用户
|
|
self.call_status_display.setText("拨号失败")
|
|
self.call_log_history.append(f"拨号失败: {number}")
|
|
self.update_call_log_display()
|
|
|
|
def on_answer_button_clicked(self):
|
|
"""处理接听按钮点击"""
|
|
# 先停止所有铃声,确保不会有铃声继续播放
|
|
try:
|
|
self.parent().sound_manager.stop_ringtone()
|
|
self.parent().sound_manager.stop_incoming_call()
|
|
except:
|
|
pass
|
|
|
|
# 尝试接听电话
|
|
if self.lte_manager.answer_call():
|
|
self.call_log_history.append("已接听来电")
|
|
self.update_call_log_display()
|
|
self.update_call_ui_state(True) # 通话中,更新UI状态
|
|
|
|
# 触发主窗口进行通话状态检查
|
|
if hasattr(self.parent(), 'should_check_call_status'):
|
|
self.parent().should_check_call_status = True
|
|
self.parent().call_check_count = 0
|
|
if not self.parent().call_status_timer.isActive():
|
|
self.parent().call_status_timer.start(1000)
|
|
|
|
# 检查通话状态,确认通话是否实际连接
|
|
time.sleep(0.5) # 给模块一点时间更新状态
|
|
calls = self.lte_manager.get_call_status()
|
|
call_connected = False
|
|
|
|
for call in calls:
|
|
if call.get('stat') in [0, 1]: # 活动或保持状态
|
|
call_connected = True
|
|
self.call_status_display.setText(f"通话中: {call.get('number', '未知')}")
|
|
break
|
|
|
|
if not call_connected:
|
|
self.call_status_display.setText("接听失败或通话已结束")
|
|
else:
|
|
self.call_log_history.append("接听失败")
|
|
self.update_call_log_display()
|
|
self.call_status_display.setText("接听失败")
|
|
|
|
def on_hangup_button_clicked(self):
|
|
"""处理挂断按钮点击"""
|
|
if self.lte_manager.end_call():
|
|
self.call_log_history.append("通话结束")
|
|
self.update_call_log_display()
|
|
self.update_call_ui_state(False) # 通话结束,更新UI状态
|
|
|
|
# 触发主窗口进行通话状态检查
|
|
if hasattr(self.parent(), 'should_check_call_status'):
|
|
self.parent().should_check_call_status = True
|
|
self.parent().call_check_count = 0
|
|
if not self.parent().call_status_timer.isActive():
|
|
self.parent().call_status_timer.start(1000)
|
|
else:
|
|
self.call_log_history.append("挂断失败")
|
|
self.update_call_log_display()
|
|
|
|
def on_send_sms_button_clicked(self):
|
|
"""Handle send SMS button click"""
|
|
number = self.sms_number_input.text().strip()
|
|
message = self.sms_message_input.toPlainText().strip()
|
|
|
|
if not number:
|
|
QMessageBox.warning(self, "Input Error", "Please enter a recipient number")
|
|
return
|
|
|
|
if not message:
|
|
QMessageBox.warning(self, "Input Error", "Please enter a message")
|
|
return
|
|
|
|
if self.lte_manager.send_sms(number, message):
|
|
self.sms_message_input.clear()
|
|
self.add_status_message(f"SMS sent to {number}")
|
|
|
|
# Play success sound
|
|
self.sound_manager.play_success()
|
|
|
|
# Add to database
|
|
self.database.add_sms(number, message, "outgoing", "sent")
|
|
|
|
# Refresh SMS list and history
|
|
self.refresh_sms_list()
|
|
self.refresh_sms_history()
|
|
else:
|
|
QMessageBox.warning(self, "SMS Error", "Failed to send SMS")
|
|
|
|
# Play error sound
|
|
self.sound_manager.play_error()
|
|
|
|
# Add to database as failed
|
|
self.database.add_sms(number, message, "outgoing", "failed")
|
|
|
|
def on_call_received(self, number):
|
|
"""Handle incoming call"""
|
|
self.answer_button.setEnabled(True)
|
|
self.call_button.setEnabled(False)
|
|
self.hangup_button.setEnabled(True)
|
|
self.add_to_call_log(f"Incoming call from {number}")
|
|
|
|
# Play ringtone
|
|
self.sound_manager.play_ringtone()
|
|
|
|
# Note: Call recording in database is now handled in the main window
|
|
# to ensure it's recorded exactly once when the notification appears
|
|
|
|
def on_call_ended(self, duration):
|
|
"""处理通话结束事件"""
|
|
self.sound_manager.play_call_end()
|
|
self.call_button.setEnabled(True)
|
|
self.answer_button.setEnabled(False)
|
|
self.hangup_button.setEnabled(False)
|
|
self.add_to_call_log(f"通话结束,持续时间: {duration}")
|
|
|
|
# 停止所有铃声
|
|
self._stop_all_ringtones()
|
|
|
|
# 清除DTMF显示
|
|
self.dtmf_display.clear()
|
|
|
|
# 更新通话状态
|
|
self.call_status_display.setText("通话状态: 无通话")
|
|
self.call_status_display.setStyleSheet("font-size: 14px; font-weight: bold; padding: 5px; background-color: #f0f0f0; border-radius: 3px;")
|
|
|
|
# 刷新通话记录
|
|
self.refresh_call_log()
|
|
|
|
def _stop_all_ringtones(self):
|
|
"""停止所有铃声,确保彻底停止"""
|
|
try:
|
|
print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} - 停止所有铃声")
|
|
self.sound_manager.stop_ringtone()
|
|
self.sound_manager.stop_incoming_call()
|
|
|
|
# 额外尝试停止系统声音
|
|
try:
|
|
import winsound
|
|
winsound.PlaySound(None, winsound.SND_PURGE)
|
|
except:
|
|
pass
|
|
except Exception as e:
|
|
print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} - 停止铃声出错: {str(e)}")
|
|
|
|
def on_sms_received(self, sender, timestamp, message):
|
|
"""Handle SMS received"""
|
|
self.add_status_message(f"SMS received from {sender}")
|
|
|
|
# Play message received sound - play three beeps
|
|
self.sound_manager.play_message_received()
|
|
self.sound_manager.play_message_received()
|
|
self.sound_manager.play_message_received()
|
|
|
|
# Add to database
|
|
self.database.add_sms(sender, message, "incoming", "received")
|
|
|
|
# Refresh SMS list and history
|
|
self.refresh_sms_list()
|
|
self.refresh_sms_history()
|
|
|
|
# Update the SMS content display directly
|
|
self.sms_content.setText(f"From: {sender}\nTime: {timestamp}\n\n{message}")
|
|
|
|
# Show a message box to alert the user
|
|
QMessageBox.information(self, "New SMS", f"New message from {sender}\n\n{message[:100]}" + ("..." if len(message) > 100 else ""))
|
|
|
|
def on_dtmf_received(self, tone):
|
|
"""Handle DTMF tone received"""
|
|
current_text = self.dtmf_display.text()
|
|
self.dtmf_display.setText(current_text + tone)
|
|
|
|
def on_status_changed(self, status):
|
|
"""Handle status change"""
|
|
self.add_status_message(status)
|
|
|
|
def add_to_call_log(self, message):
|
|
"""Add message to status display"""
|
|
timestamp = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
|
|
self.status_display.append(f"{timestamp} - {message}")
|
|
self.status_display.ensureCursorVisible()
|
|
|
|
def add_status_message(self, message):
|
|
"""Add message to status display"""
|
|
timestamp = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
|
|
self.status_display.append(f"{timestamp} - {message}")
|
|
self.status_display.ensureCursorVisible()
|
|
|
|
def refresh_sms_list(self):
|
|
"""Refresh SMS list from module"""
|
|
if not self.lte_manager.is_connected():
|
|
return
|
|
|
|
self.sms_list.clear()
|
|
self.sms_content.clear()
|
|
|
|
# Get SMS type filter
|
|
sms_type = self.sms_type_combo.currentText()
|
|
if sms_type == "All":
|
|
status = "ALL"
|
|
elif sms_type == "Unread":
|
|
status = "REC UNREAD"
|
|
elif sms_type == "Read":
|
|
status = "REC READ"
|
|
elif sms_type == "Sent":
|
|
status = "STO SENT"
|
|
elif sms_type == "Unsent":
|
|
status = "STO UNSENT"
|
|
|
|
# Get SMS list
|
|
messages = self.lte_manager.get_sms_list(status)
|
|
|
|
# Add messages to list
|
|
for msg in messages:
|
|
item = QListWidgetItem(f"{msg['index']} - From: {msg['sender']} - {msg['timestamp']}")
|
|
item.setData(Qt.UserRole, msg)
|
|
self.sms_list.addItem(item)
|
|
|
|
# If no messages from module, show a message
|
|
if self.sms_list.count() == 0:
|
|
self.add_status_message("No messages found on the module. Check SMS history tab for stored messages.")
|
|
|
|
# Try to get messages from database to show in the content area
|
|
db_messages = self.database.get_sms_history(limit=1)
|
|
if db_messages:
|
|
# Format: id, phone_number, message, sms_type, timestamp, status
|
|
_, _, message, _, _, _ = db_messages[0]
|
|
self.sms_content.setText("Last message from database:\n\n" + message)
|
|
|
|
def on_sms_item_clicked(self, item):
|
|
"""Handle SMS item click"""
|
|
msg = item.data(Qt.UserRole)
|
|
if msg:
|
|
self.sms_content.setText(msg['content'])
|
|
|
|
def delete_selected_sms(self):
|
|
"""Delete selected SMS from module"""
|
|
selected_items = self.sms_list.selectedItems()
|
|
if not selected_items:
|
|
QMessageBox.warning(self, "Selection Error", "Please select an SMS to delete")
|
|
return
|
|
|
|
for item in selected_items:
|
|
msg = item.data(Qt.UserRole)
|
|
if msg:
|
|
if self.lte_manager.delete_sms(msg['index']):
|
|
self.add_status_message(f"Deleted SMS at index {msg['index']}")
|
|
else:
|
|
self.add_status_message(f"Failed to delete SMS at index {msg['index']}")
|
|
|
|
self.refresh_sms_list()
|
|
|
|
def refresh_call_log(self):
|
|
"""Refresh call log from database"""
|
|
# Get call history from database
|
|
calls = self.database.get_call_history()
|
|
|
|
# Clear table
|
|
self.call_log_table.setRowCount(0)
|
|
|
|
# Add calls to table
|
|
for call in calls:
|
|
row = self.call_log_table.rowCount()
|
|
self.call_log_table.insertRow(row)
|
|
|
|
# Format: id, phone_number, call_type, duration, timestamp, notes
|
|
call_id, phone_number, call_type, duration, timestamp, notes = call
|
|
|
|
# Format duration
|
|
if duration:
|
|
duration_str = f"{duration}s"
|
|
else:
|
|
duration_str = ""
|
|
|
|
# Add items to row
|
|
self.call_log_table.setItem(row, 0, QTableWidgetItem(timestamp))
|
|
self.call_log_table.setItem(row, 1, QTableWidgetItem(phone_number))
|
|
self.call_log_table.setItem(row, 2, QTableWidgetItem(call_type))
|
|
self.call_log_table.setItem(row, 3, QTableWidgetItem(duration_str))
|
|
|
|
# Store call ID in first column
|
|
self.call_log_table.item(row, 0).setData(Qt.UserRole, call_id)
|
|
|
|
def clear_selected_call(self):
|
|
"""Clear selected call from database"""
|
|
selected_items = self.call_log_table.selectedItems()
|
|
if not selected_items:
|
|
QMessageBox.warning(self, "Selection Error", "Please select a call to delete")
|
|
return
|
|
|
|
# Get unique rows
|
|
rows = set()
|
|
for item in selected_items:
|
|
rows.add(item.row())
|
|
|
|
# Delete each selected call
|
|
for row in rows:
|
|
call_id = self.call_log_table.item(row, 0).data(Qt.UserRole)
|
|
if self.database.delete_call(call_id):
|
|
self.add_status_message(f"Deleted call record {call_id}")
|
|
else:
|
|
self.add_status_message(f"Failed to delete call record {call_id}")
|
|
|
|
# Refresh call log
|
|
self.refresh_call_log()
|
|
|
|
def refresh_sms_history(self):
|
|
"""Refresh SMS history from database"""
|
|
# Get SMS history from database
|
|
messages = self.database.get_sms_history()
|
|
|
|
# Clear table
|
|
self.sms_history_table.setRowCount(0)
|
|
|
|
# Add messages to table
|
|
for msg in messages:
|
|
row = self.sms_history_table.rowCount()
|
|
self.sms_history_table.insertRow(row)
|
|
|
|
# Format: id, phone_number, message, sms_type, timestamp, status
|
|
sms_id, phone_number, message, sms_type, timestamp, status = msg
|
|
|
|
# Add items to row
|
|
self.sms_history_table.setItem(row, 0, QTableWidgetItem(timestamp))
|
|
self.sms_history_table.setItem(row, 1, QTableWidgetItem(phone_number))
|
|
self.sms_history_table.setItem(row, 2, QTableWidgetItem(f"{sms_type} ({status})"))
|
|
|
|
# Truncate message if too long
|
|
if len(message) > 50:
|
|
display_message = message[:47] + "..."
|
|
else:
|
|
display_message = message
|
|
|
|
self.sms_history_table.setItem(row, 3, QTableWidgetItem(display_message))
|
|
|
|
# Store full message and SMS ID
|
|
self.sms_history_table.item(row, 3).setData(Qt.UserRole, message)
|
|
self.sms_history_table.item(row, 0).setData(Qt.UserRole, sms_id)
|
|
|
|
def on_sms_history_item_clicked(self, item):
|
|
"""Handle SMS history item click"""
|
|
# If clicked on message column, show full message
|
|
if item.column() == 3:
|
|
full_message = item.data(Qt.UserRole)
|
|
if full_message:
|
|
self.sms_content.setText(full_message)
|
|
|
|
def clear_selected_sms_history(self):
|
|
"""Clear selected SMS from history database"""
|
|
selected_items = self.sms_history_table.selectedItems()
|
|
if not selected_items:
|
|
QMessageBox.warning(self, "Selection Error", "Please select an SMS to delete")
|
|
return
|
|
|
|
# Get unique rows
|
|
rows = set()
|
|
for item in selected_items:
|
|
rows.add(item.row())
|
|
|
|
# Delete each selected SMS
|
|
for row in rows:
|
|
sms_id = self.sms_history_table.item(row, 0).data(Qt.UserRole)
|
|
if self.database.delete_sms(sms_id):
|
|
self.add_status_message(f"Deleted SMS record {sms_id}")
|
|
else:
|
|
self.add_status_message(f"Failed to delete SMS record {sms_id}")
|
|
|
|
# Refresh SMS history
|
|
self.refresh_sms_history() |