2
This commit is contained in:
@@ -46,6 +46,7 @@ class DuktoProtocol:
|
|||||||
self.on_send_complete: Optional[Callable[[List[str]], None]] = None
|
self.on_send_complete: Optional[Callable[[List[str]], None]] = None
|
||||||
self.on_transfer_progress: Optional[Callable[[int, int], None]] = None
|
self.on_transfer_progress: Optional[Callable[[int, int], None]] = None
|
||||||
self.on_error: Optional[Callable[[str], None]] = None
|
self.on_error: Optional[Callable[[str], None]] = None
|
||||||
|
self.on_incoming_connection: Optional[Callable[[str, socket.socket], None]] = None
|
||||||
|
|
||||||
def set_ports(self, udp_port: int, tcp_port: int):
|
def set_ports(self, udp_port: int, tcp_port: int):
|
||||||
self.local_udp_port = udp_port
|
self.local_udp_port = udp_port
|
||||||
@@ -192,12 +193,22 @@ class DuktoProtocol:
|
|||||||
conn.close()
|
conn.close()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
threading.Thread(target=self._receive_files,
|
if self.on_incoming_connection:
|
||||||
args=(conn, addr[0]), daemon=True).start()
|
# Pass the connection to the handler to decide
|
||||||
|
self.on_incoming_connection(addr[0], conn)
|
||||||
|
else:
|
||||||
|
# Auto-reject if no handler is set
|
||||||
|
conn.close()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if self.running:
|
if self.running:
|
||||||
print(f"TCP listener error: {e}")
|
print(f"TCP listener error: {e}")
|
||||||
|
|
||||||
|
def start_receiving(self, conn: socket.socket, sender_ip: str):
|
||||||
|
"""Starts the receiving process on an already accepted connection."""
|
||||||
|
threading.Thread(target=self._receive_files,
|
||||||
|
args=(conn, sender_ip), daemon=True).start()
|
||||||
|
|
||||||
def _receive_files(self, conn: socket.socket, sender_ip: str):
|
def _receive_files(self, conn: socket.socket, sender_ip: str):
|
||||||
self.is_receiving = True
|
self.is_receiving = True
|
||||||
|
|
||||||
|
|||||||
290
main.py
290
main.py
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
import sys, os, subprocess
|
import sys, os, subprocess, socket
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from PySide6 import QtCore, QtGui, QtWidgets
|
from PySide6 import QtCore, QtGui, QtWidgets
|
||||||
from pynput import keyboard
|
from pynput import keyboard
|
||||||
@@ -13,140 +13,6 @@ from core.dukto import DuktoProtocol, Peer
|
|||||||
|
|
||||||
ASSET = Path(__file__).parent / "assets" / "2ktan.png"
|
ASSET = Path(__file__).parent / "assets" / "2ktan.png"
|
||||||
|
|
||||||
class DuktoDialog(QtWidgets.QDialog):
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.setWindowTitle("LAN Transfer (Dukto)")
|
|
||||||
self.setMinimumSize(600, 400)
|
|
||||||
|
|
||||||
# Dukto Protocol Backend
|
|
||||||
self.protocol = DuktoProtocol()
|
|
||||||
self.setup_callbacks()
|
|
||||||
|
|
||||||
# UI Elements
|
|
||||||
self.peer_list_widget = QtWidgets.QListWidget()
|
|
||||||
self.send_file_button = QtWidgets.QPushButton("Send File(s)")
|
|
||||||
self.send_text_button = QtWidgets.QPushButton("Send Text")
|
|
||||||
self.refresh_button = QtWidgets.QPushButton("Refresh")
|
|
||||||
self.progress_bar = QtWidgets.QProgressBar()
|
|
||||||
|
|
||||||
# Layout
|
|
||||||
layout = QtWidgets.QVBoxLayout(self)
|
|
||||||
layout.addWidget(QtWidgets.QLabel("Discovered Peers:"))
|
|
||||||
layout.addWidget(self.peer_list_widget)
|
|
||||||
|
|
||||||
button_layout = QtWidgets.QHBoxLayout()
|
|
||||||
button_layout.addWidget(self.refresh_button)
|
|
||||||
button_layout.addStretch()
|
|
||||||
button_layout.addWidget(self.send_text_button)
|
|
||||||
button_layout.addWidget(self.send_file_button)
|
|
||||||
layout.addLayout(button_layout)
|
|
||||||
layout.addWidget(self.progress_bar)
|
|
||||||
|
|
||||||
self.progress_bar.hide()
|
|
||||||
|
|
||||||
# Connect signals
|
|
||||||
self.refresh_button.clicked.connect(self.refresh_peers)
|
|
||||||
self.send_file_button.clicked.connect(self.send_files)
|
|
||||||
self.send_text_button.clicked.connect(self.send_text)
|
|
||||||
|
|
||||||
# Initialize Dukto
|
|
||||||
self.protocol.initialize()
|
|
||||||
self.refresh_peers()
|
|
||||||
|
|
||||||
def setup_callbacks(self):
|
|
||||||
self.protocol.on_peer_added = self.add_peer
|
|
||||||
self.protocol.on_peer_removed = self.remove_peer
|
|
||||||
self.protocol.on_receive_start = lambda ip: self.show_progress()
|
|
||||||
self.protocol.on_transfer_progress = self.update_progress
|
|
||||||
self.protocol.on_receive_text = self.handle_received_text
|
|
||||||
self.protocol.on_receive_complete = self.handle_receive_complete
|
|
||||||
self.protocol.on_send_complete = lambda files: self.progress_bar.hide()
|
|
||||||
self.protocol.on_error = self.handle_error
|
|
||||||
|
|
||||||
@QtCore.Slot(Peer)
|
|
||||||
def add_peer(self, peer: Peer):
|
|
||||||
# Check if peer already exists
|
|
||||||
for i in range(self.peer_list_widget.count()):
|
|
||||||
item = self.peer_list_widget.item(i)
|
|
||||||
if item.data(QtCore.Qt.UserRole).address == peer.address: # type: ignore
|
|
||||||
return
|
|
||||||
|
|
||||||
item = QtWidgets.QListWidgetItem(f"{peer.signature} ({peer.address})")
|
|
||||||
item.setData(QtCore.Qt.UserRole, peer) # type: ignore
|
|
||||||
self.peer_list_widget.addItem(item)
|
|
||||||
|
|
||||||
@QtCore.Slot(Peer)
|
|
||||||
def remove_peer(self, peer: Peer):
|
|
||||||
for i in range(self.peer_list_widget.count()):
|
|
||||||
item = self.peer_list_widget.item(i)
|
|
||||||
if item and item.data(QtCore.Qt.UserRole).address == peer.address: # type: ignore
|
|
||||||
self.peer_list_widget.takeItem(i)
|
|
||||||
break
|
|
||||||
|
|
||||||
def refresh_peers(self):
|
|
||||||
self.peer_list_widget.clear()
|
|
||||||
self.protocol.peers.clear()
|
|
||||||
self.protocol.say_hello()
|
|
||||||
|
|
||||||
def get_selected_peer(self) -> Peer | None:
|
|
||||||
selected_items = self.peer_list_widget.selectedItems()
|
|
||||||
if not selected_items:
|
|
||||||
QtWidgets.QMessageBox.warning(self, "No Peer Selected", "Please select a peer from the list.")
|
|
||||||
return None
|
|
||||||
return selected_items[0].data(QtCore.Qt.UserRole) # type: ignore
|
|
||||||
|
|
||||||
def send_files(self):
|
|
||||||
peer = self.get_selected_peer()
|
|
||||||
if not peer:
|
|
||||||
return
|
|
||||||
|
|
||||||
files, _ = QtWidgets.QFileDialog.getOpenFileNames(self, "Select Files to Send")
|
|
||||||
if files:
|
|
||||||
self.show_progress()
|
|
||||||
self.protocol.send_file(peer.address, files, peer.port)
|
|
||||||
|
|
||||||
def send_text(self):
|
|
||||||
peer = self.get_selected_peer()
|
|
||||||
if not peer:
|
|
||||||
return
|
|
||||||
|
|
||||||
text, ok = QtWidgets.QInputDialog.getMultiLineText(self, "Send Text", "Enter text to send:")
|
|
||||||
if ok and text:
|
|
||||||
self.show_progress()
|
|
||||||
self.protocol.send_text(peer.address, text, peer.port)
|
|
||||||
|
|
||||||
def show_progress(self):
|
|
||||||
self.progress_bar.setValue(0)
|
|
||||||
self.progress_bar.show()
|
|
||||||
|
|
||||||
@QtCore.Slot(int, int)
|
|
||||||
def update_progress(self, total_size, transferred):
|
|
||||||
if total_size > 0:
|
|
||||||
percentage = int((transferred / total_size) * 100)
|
|
||||||
self.progress_bar.setValue(percentage)
|
|
||||||
|
|
||||||
@QtCore.Slot(str, int)
|
|
||||||
def handle_received_text(self, text, size):
|
|
||||||
self.progress_bar.hide()
|
|
||||||
QtWidgets.QMessageBox.information(self, "Text Received", text)
|
|
||||||
|
|
||||||
@QtCore.Slot(list, int)
|
|
||||||
def handle_receive_complete(self, files, size):
|
|
||||||
self.progress_bar.hide()
|
|
||||||
msg = f"Received {len(files)} file(s) successfully.\nThey are located in the application's directory."
|
|
||||||
QtWidgets.QMessageBox.information(self, "Transfer Complete", msg)
|
|
||||||
|
|
||||||
@QtCore.Slot(str)
|
|
||||||
def handle_error(self, error_message):
|
|
||||||
self.progress_bar.hide()
|
|
||||||
QtWidgets.QMessageBox.critical(self, "Transfer Error", error_message)
|
|
||||||
|
|
||||||
def closeEvent(self, event):
|
|
||||||
self.protocol.shutdown()
|
|
||||||
super().closeEvent(event)
|
|
||||||
|
|
||||||
|
|
||||||
class AppLauncherDialog(QtWidgets.QDialog):
|
class AppLauncherDialog(QtWidgets.QDialog):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
@@ -453,6 +319,14 @@ class WebSearchResults(QtWidgets.QDialog):
|
|||||||
|
|
||||||
class MainWindow(QtWidgets.QMainWindow):
|
class MainWindow(QtWidgets.QMainWindow):
|
||||||
show_menu_signal = QtCore.Signal()
|
show_menu_signal = QtCore.Signal()
|
||||||
|
# Dukto signals for thread-safety
|
||||||
|
peer_added_signal = QtCore.Signal(object)
|
||||||
|
peer_removed_signal = QtCore.Signal(object)
|
||||||
|
incoming_connection_signal = QtCore.Signal(str, object)
|
||||||
|
dukto_error_signal = QtCore.Signal(str)
|
||||||
|
transfer_progress_signal = QtCore.Signal(int, int)
|
||||||
|
transfer_complete_signal = QtCore.Signal(str)
|
||||||
|
text_received_signal = QtCore.Signal(str, str)
|
||||||
|
|
||||||
def __init__(self, restart=False, no_quit=False, super_menu=True):
|
def __init__(self, restart=False, no_quit=False, super_menu=True):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -479,6 +353,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
self.setMask(mask)
|
self.setMask(mask)
|
||||||
|
|
||||||
self.super_menu = super_menu
|
self.super_menu = super_menu
|
||||||
|
self.progress_dialog = None
|
||||||
|
|
||||||
self.tray = QtWidgets.QSystemTrayIcon(self)
|
self.tray = QtWidgets.QSystemTrayIcon(self)
|
||||||
self.tray.setIcon(QtGui.QIcon(str(ASSET)))
|
self.tray.setIcon(QtGui.QIcon(str(ASSET)))
|
||||||
@@ -488,7 +363,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
right_menu.addAction("Launch App", self.start_app_launcher)
|
right_menu.addAction("Launch App", self.start_app_launcher)
|
||||||
right_menu.addAction("Search Files", self.start_file_search)
|
right_menu.addAction("Search Files", self.start_file_search)
|
||||||
right_menu.addAction("Search Web", self.start_web_search)
|
right_menu.addAction("Search Web", self.start_web_search)
|
||||||
right_menu.addAction("LAN Transfer (Dukto)", self.start_dukto)
|
self.dukto_peers_menu_right = right_menu.addMenu("Dukto")
|
||||||
|
self.dukto_peers_menu_right.setEnabled(False)
|
||||||
right_menu.addSeparator()
|
right_menu.addSeparator()
|
||||||
right_menu.addAction("Check for updates", self.update_git)
|
right_menu.addAction("Check for updates", self.update_git)
|
||||||
if restart:
|
if restart:
|
||||||
@@ -496,7 +372,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
right_menu.addAction("Hide/Show", self.toggle_visible)
|
right_menu.addAction("Hide/Show", self.toggle_visible)
|
||||||
right_menu.addSeparator()
|
right_menu.addSeparator()
|
||||||
if not no_quit:
|
if not no_quit:
|
||||||
right_menu.addAction("Quit", QtWidgets.QApplication.quit)
|
right_menu.addAction("Quit", self.quit_application)
|
||||||
self.tray.setContextMenu(right_menu)
|
self.tray.setContextMenu(right_menu)
|
||||||
self.tray.activated.connect(self.handle_tray_activated)
|
self.tray.activated.connect(self.handle_tray_activated)
|
||||||
self.tray.show()
|
self.tray.show()
|
||||||
@@ -506,7 +382,11 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
self.left_menu.addAction("Launch App", self.start_app_launcher)
|
self.left_menu.addAction("Launch App", self.start_app_launcher)
|
||||||
self.left_menu.addAction("Search Files", self.start_file_search)
|
self.left_menu.addAction("Search Files", self.start_file_search)
|
||||||
self.left_menu.addAction("Search Web", self.start_web_search)
|
self.left_menu.addAction("Search Web", self.start_web_search)
|
||||||
self.left_menu.addAction("LAN Transfer (Dukto)", self.start_dukto)
|
self.dukto_peers_menu_left = self.left_menu.addMenu("Dukto")
|
||||||
|
self.dukto_peers_menu_left.setEnabled(False)
|
||||||
|
|
||||||
|
# Dukto peer menu storage
|
||||||
|
self.dukto_peer_menus = {}
|
||||||
|
|
||||||
# always on top timer
|
# always on top timer
|
||||||
self.stay_on_top_timer = QtCore.QTimer(self)
|
self.stay_on_top_timer = QtCore.QTimer(self)
|
||||||
@@ -517,6 +397,43 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
self.show_menu_signal.connect(self.show_menu)
|
self.show_menu_signal.connect(self.show_menu)
|
||||||
self.start_hotkey_listener()
|
self.start_hotkey_listener()
|
||||||
|
|
||||||
|
# Init Dukto Protocol
|
||||||
|
self.init_dukto()
|
||||||
|
|
||||||
|
def init_dukto(self):
|
||||||
|
self.dukto = DuktoProtocol()
|
||||||
|
|
||||||
|
# Connect signals to slots
|
||||||
|
self.peer_added_signal.connect(self.add_dukto_peer_slot)
|
||||||
|
self.peer_removed_signal.connect(self.remove_dukto_peer_slot)
|
||||||
|
self.incoming_connection_signal.connect(self.handle_incoming_transfer_slot)
|
||||||
|
self.dukto_error_signal.connect(self.handle_dukto_error_slot)
|
||||||
|
self.transfer_progress_signal.connect(self.update_transfer_progress_slot)
|
||||||
|
self.transfer_complete_signal.connect(self.finish_transfer_slot)
|
||||||
|
self.text_received_signal.connect(self.show_received_text_slot)
|
||||||
|
|
||||||
|
# Assign callbacks that emit signals
|
||||||
|
self.dukto.on_peer_added = lambda peer: self.peer_added_signal.emit(peer)
|
||||||
|
self.dukto.on_peer_removed = lambda peer: self.peer_removed_signal.emit(peer)
|
||||||
|
self.dukto.on_incoming_connection = lambda ip, conn: self.incoming_connection_signal.emit(ip, conn)
|
||||||
|
self.dukto.on_error = lambda msg: self.dukto_error_signal.emit(msg)
|
||||||
|
|
||||||
|
def on_receive_start(sender_ip):
|
||||||
|
peer_name = self.dukto.peers.get(sender_ip, Peer(sender_ip, sender_ip)).signature
|
||||||
|
# Use QTimer to ensure this runs on the main thread
|
||||||
|
QtCore.QTimer.singleShot(0, lambda: self.start_transfer_progress_slot(f"Receiving from {peer_name}..."))
|
||||||
|
self.dukto.on_receive_start = on_receive_start
|
||||||
|
|
||||||
|
self.dukto.on_transfer_progress = lambda total, current: self.transfer_progress_signal.emit(current, total)
|
||||||
|
self.dukto.on_receive_complete = lambda files, size: self.transfer_complete_signal.emit("Files received successfully!")
|
||||||
|
self.dukto.on_send_complete = lambda files: self.transfer_complete_signal.emit("Files sent successfully!")
|
||||||
|
self.dukto.on_receive_text = lambda text, size: self.text_received_signal.emit(
|
||||||
|
self.dukto.peers.get("unknown", Peer("unknown", "An unknown user")).signature, text
|
||||||
|
)
|
||||||
|
|
||||||
|
self.dukto.initialize()
|
||||||
|
self.dukto.say_hello()
|
||||||
|
|
||||||
def show_menu(self):
|
def show_menu(self):
|
||||||
self.left_menu.popup(QtGui.QCursor.pos())
|
self.left_menu.popup(QtGui.QCursor.pos())
|
||||||
|
|
||||||
@@ -560,11 +477,6 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
self.app_launcher_dialog.move(QtGui.QCursor.pos())
|
self.app_launcher_dialog.move(QtGui.QCursor.pos())
|
||||||
self.app_launcher_dialog.show()
|
self.app_launcher_dialog.show()
|
||||||
|
|
||||||
def start_dukto(self):
|
|
||||||
self.dukto_dialog = DuktoDialog(self)
|
|
||||||
self.dukto_dialog.move(QtGui.QCursor.pos())
|
|
||||||
self.dukto_dialog.show()
|
|
||||||
|
|
||||||
def start_file_search(self):
|
def start_file_search(self):
|
||||||
dialog = QtWidgets.QInputDialog(self)
|
dialog = QtWidgets.QInputDialog(self)
|
||||||
dialog.setWindowTitle("File Search")
|
dialog.setWindowTitle("File Search")
|
||||||
@@ -660,14 +572,99 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
QtWidgets.QMessageBox.critical(self, "Update Failed", message)
|
QtWidgets.QMessageBox.critical(self, "Update Failed", message)
|
||||||
|
|
||||||
def restart_application(self):
|
def restart_application(self):
|
||||||
|
self.dukto.shutdown()
|
||||||
presence.end()
|
presence.end()
|
||||||
|
|
||||||
args = [sys.executable] + sys.argv
|
args = [sys.executable] + sys.argv
|
||||||
|
|
||||||
subprocess.Popen(args)
|
subprocess.Popen(args)
|
||||||
|
|
||||||
QtWidgets.QApplication.quit()
|
QtWidgets.QApplication.quit()
|
||||||
|
|
||||||
|
def quit_application(self):
|
||||||
|
self.dukto.shutdown()
|
||||||
|
QtWidgets.QApplication.quit()
|
||||||
|
|
||||||
|
# --- Dukto Slots ---
|
||||||
|
def add_dukto_peer_slot(self, peer: Peer):
|
||||||
|
if not self.dukto_peers_menu_left.isEnabled():
|
||||||
|
self.dukto_peers_menu_left.setEnabled(True)
|
||||||
|
self.dukto_peers_menu_right.setEnabled(True)
|
||||||
|
|
||||||
|
peer_menu_left = QtWidgets.QMenu(peer.signature, self.dukto_peers_menu_left)
|
||||||
|
peer_menu_right = QtWidgets.QMenu(peer.signature, self.dukto_peers_menu_right)
|
||||||
|
|
||||||
|
for menu in [peer_menu_left, peer_menu_right]:
|
||||||
|
send_files_action = menu.addAction("Send Files...")
|
||||||
|
send_files_action.triggered.connect(lambda: self.send_files_to_peer(peer))
|
||||||
|
send_text_action = menu.addAction("Send Text...")
|
||||||
|
send_text_action.triggered.connect(lambda: self.send_text_to_peer(peer))
|
||||||
|
|
||||||
|
self.dukto_peers_menu_left.addMenu(peer_menu_left)
|
||||||
|
self.dukto_peers_menu_right.addMenu(peer_menu_right)
|
||||||
|
self.dukto_peer_menus[peer.address] = (peer_menu_left, peer_menu_right)
|
||||||
|
|
||||||
|
def remove_dukto_peer_slot(self, peer: Peer):
|
||||||
|
if peer.address in self.dukto_peer_menus:
|
||||||
|
menus = self.dukto_peer_menus.pop(peer.address)
|
||||||
|
self.dukto_peers_menu_left.removeAction(menus[0].menuAction())
|
||||||
|
self.dukto_peers_menu_right.removeAction(menus[1].menuAction())
|
||||||
|
|
||||||
|
if not self.dukto_peer_menus:
|
||||||
|
self.dukto_peers_menu_left.setEnabled(False)
|
||||||
|
self.dukto_peers_menu_right.setEnabled(False)
|
||||||
|
|
||||||
|
def handle_incoming_transfer_slot(self, sender_ip: str, conn: socket.socket):
|
||||||
|
peer = self.dukto.peers.get(sender_ip)
|
||||||
|
peer_name = peer.signature if peer else sender_ip
|
||||||
|
|
||||||
|
reply = QtWidgets.QMessageBox.question(self, "Incoming Transfer",
|
||||||
|
f"Accept incoming files from {peer_name}?",
|
||||||
|
QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No,
|
||||||
|
QtWidgets.QMessageBox.StandardButton.Yes)
|
||||||
|
|
||||||
|
if reply == QtWidgets.QMessageBox.StandardButton.Yes:
|
||||||
|
self.dukto.start_receiving(conn, sender_ip)
|
||||||
|
else:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def send_files_to_peer(self, peer: Peer):
|
||||||
|
file_dialog = QtWidgets.QFileDialog(self)
|
||||||
|
file_dialog.setFileMode(QtWidgets.QFileDialog.FileMode.ExistingFiles)
|
||||||
|
if file_dialog.exec():
|
||||||
|
files = file_dialog.selectedFiles()
|
||||||
|
if files:
|
||||||
|
self.start_transfer_progress_slot(f"Sending to {peer.signature}...")
|
||||||
|
self.dukto.send_file(peer.address, files, peer.port)
|
||||||
|
|
||||||
|
def send_text_to_peer(self, peer: Peer):
|
||||||
|
text, ok = QtWidgets.QInputDialog.getMultiLineText(self, "Send Text", f"Enter text to send to {peer.signature}:")
|
||||||
|
if ok and text:
|
||||||
|
self.dukto.send_text(peer.address, text, peer.port)
|
||||||
|
|
||||||
|
def handle_dukto_error_slot(self, message: str):
|
||||||
|
QtWidgets.QMessageBox.critical(self, "Dukto Error", message)
|
||||||
|
if self.progress_dialog:
|
||||||
|
self.progress_dialog.close()
|
||||||
|
self.progress_dialog = None
|
||||||
|
|
||||||
|
def start_transfer_progress_slot(self, title: str):
|
||||||
|
self.progress_dialog = QtWidgets.QProgressDialog(title, "Cancel", 0, 100, self)
|
||||||
|
self.progress_dialog.setWindowModality(QtCore.Qt.WindowModality.WindowModal)
|
||||||
|
self.progress_dialog.setValue(0)
|
||||||
|
self.progress_dialog.show()
|
||||||
|
|
||||||
|
def update_transfer_progress_slot(self, current: int, total: int):
|
||||||
|
if self.progress_dialog:
|
||||||
|
self.progress_dialog.setMaximum(total)
|
||||||
|
self.progress_dialog.setValue(current)
|
||||||
|
|
||||||
|
def finish_transfer_slot(self, message: str):
|
||||||
|
if self.progress_dialog:
|
||||||
|
self.progress_dialog.close()
|
||||||
|
self.progress_dialog = None
|
||||||
|
QtWidgets.QMessageBox.information(self, "Transfer Complete", message)
|
||||||
|
|
||||||
|
def show_received_text_slot(self, sender_name: str, text: str):
|
||||||
|
QtWidgets.QMessageBox.information(self, f"Text from {sender_name}", text)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
app = QtWidgets.QApplication(sys.argv)
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
@@ -689,6 +686,7 @@ def main():
|
|||||||
pet.show()
|
pet.show()
|
||||||
|
|
||||||
app.aboutToQuit.connect(presence.end)
|
app.aboutToQuit.connect(presence.end)
|
||||||
|
app.aboutToQuit.connect(pet.dukto.shutdown)
|
||||||
sys.exit(app.exec())
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user