Revert "Update client.py"

This reverts commit cfd13cfad8.
Dear WHE Team. Your commits are sucks + it looks like AI slop.
This commit is contained in:
unknown 2026-05-20 10:58:32 +03:00
parent d99563dc73
commit 5190492f1a

401
TUI.py
View file

@ -13,16 +13,26 @@ def auto_install_deps():
__import__(import_name) __import__(import_name)
except ImportError: except ImportError:
missing_packages.append(pip_name) missing_packages.append(pip_name)
if not missing_packages: if not missing_packages:
return return
print("[Auto-Installer] Installing client dependencies:", ", ".join(missing_packages))
cmd = [sys.executable, "-m", "pip", "install"] + missing_packages cmd = [sys.executable, "-m", "pip", "install"] + missing_packages
result = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE) result = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
if result.returncode != 0: if result.returncode != 0:
stderr_output = result.stderr.decode('utf-8', errors='ignore') stderr_output = result.stderr.decode('utf-8', errors='ignore')
if "externally-managed-environment" in stderr_output.lower(): if "externally-managed-environment" in stderr_output.lower():
print("\n" + "!"*50)
print("[Warning] OS blocks global package installation via pip.")
print("!"*50 + "\n")
choice = input("Use --break-system-packages flag? (y/n): ").strip().lower()
if choice == 'y':
force_cmd = cmd + ["--break-system-packages"] force_cmd = cmd + ["--break-system-packages"]
force_result = subprocess.run(force_cmd) force_result = subprocess.run(force_cmd)
if force_result.returncode == 0: if force_result.returncode == 0:
print("[Success] Restart the script!")
sys.exit(0) sys.exit(0)
sys.exit(1) sys.exit(1)
@ -54,7 +64,19 @@ try:
except: except:
auto_install_deps() auto_install_deps()
<<<<<<< HEAD:TUI.py
import socket_manager import socket_manager
=======
from prompt_toolkit.application import Application
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.containers import HSplit, VSplit, Window
from prompt_toolkit.layout.controls import FormattedTextControl
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.widgets import TextArea, Frame
from prompt_toolkit.styles import Style
from prompt_toolkit.application.current import get_app
from prompt_toolkit.filters import has_focus
>>>>>>> parent of cfd13cf (Update client.py):client.py
CONFIG_FILE = "settings.json" CONFIG_FILE = "settings.json"
WIKI_URL = "https://git.idkmail.ru/lohrrrr/TyChat-Client/wiki" WIKI_URL = "https://git.idkmail.ru/lohrrrr/TyChat-Client/wiki"
@ -71,6 +93,7 @@ ASCII_ART = r"""
|___/ |___/
""" """
<<<<<<< HEAD:TUI.py
class CommandCompleter(Completer): class CommandCompleter(Completer):
def __init__(self): def __init__(self):
self.completions = { self.completions = {
@ -148,6 +171,9 @@ class PluginManager:
proto["failed"] = True proto["failed"] = True
proto["enabled"] = False proto["enabled"] = False
return None return None
=======
sio = socketio.Client()
>>>>>>> parent of cfd13cf (Update client.py):client.py
class TyClient: class TyClient:
def __init__(self): def __init__(self):
@ -156,21 +182,13 @@ class TyClient:
self.uin = "" self.uin = ""
self.password = "" self.password = ""
self.contacts = {} self.contacts = {}
self.groups = {}
self.history = {} self.history = {}
self.preserved = {} self.preserved = {}
self.blocklist = []
self.active_chat = None self.active_chat = None
self.app = None self.app = None
self.loop_running = True self.loop_running = True
self.selected_contact_idx = 0 self.selected_contact_idx = 0
self.is_busy = False
self.dialing_uin = None
self.pending_requests = []
self.pending_windows = []
self.show_welcome_popup = False
self.current_tab = "chat" self.current_tab = "chat"
self.settings_cursor = 0 self.settings_cursor = 0
self.settings_section = "protocols" self.settings_section = "protocols"
@ -190,9 +208,9 @@ class TyClient:
self.uin = cfg.get("uin", "") self.uin = cfg.get("uin", "")
self.password = cfg.get("password", "") self.password = cfg.get("password", "")
self.contacts = cfg.get("contacts", {}) self.contacts = cfg.get("contacts", {})
self.groups = cfg.get("groups", {})
self.history = cfg.get("history", {}) self.history = cfg.get("history", {})
self.preserved = cfg.get("preserved", {}) self.preserved = cfg.get("preserved", {})
<<<<<<< HEAD:TUI.py
self.blocklist = cfg.get("blocklist", []) self.blocklist = cfg.get("blocklist", [])
self.primary_protocol = cfg.get("primary_protocol", "") self.primary_protocol = cfg.get("primary_protocol", "")
@ -212,6 +230,8 @@ class TyClient:
self.primary_protocol = list(self.plugin_manager.protocols.keys())[0] self.primary_protocol = list(self.plugin_manager.protocols.keys())[0]
if not self.primary_transport and self.plugin_manager.transports: if not self.primary_transport and self.plugin_manager.transports:
self.primary_transport = list(self.plugin_manager.transports.keys())[0] self.primary_transport = list(self.plugin_manager.transports.keys())[0]
=======
>>>>>>> parent of cfd13cf (Update client.py):client.py
return True return True
except: except:
return False return False
@ -226,18 +246,22 @@ class TyClient:
"uin": self.uin, "uin": self.uin,
"password": self.password, "password": self.password,
"contacts": self.contacts, "contacts": self.contacts,
"groups": self.groups,
"history": self.history, "history": self.history,
<<<<<<< HEAD:TUI.py
"preserved": self.preserved, "preserved": self.preserved,
"blocklist": self.blocklist, "blocklist": self.blocklist,
"primary_protocol": self.primary_protocol, "primary_protocol": self.primary_protocol,
"primary_transport": self.primary_transport, "primary_transport": self.primary_transport,
"enabled_protocols": enabled_protos, "enabled_protocols": enabled_protos,
"enabled_transports": enabled_trans "enabled_transports": enabled_trans
=======
"preserved": self.preserved
>>>>>>> parent of cfd13cf (Update client.py):client.py
} }
with open(CONFIG_FILE, "w", encoding="utf-8") as f: with open(CONFIG_FILE, "w", encoding="utf-8") as f:
json.dump(cfg, f, indent=4, ensure_ascii=False) json.dump(cfg, f, indent=4, ensure_ascii=False)
<<<<<<< HEAD:TUI.py
def play_dial_tones(self, target_uin): def play_dial_tones(self, target_uin):
self.dialing_uin = target_uin self.dialing_uin = target_uin
while self.dialing_uin == target_uin and self.loop_running: while self.dialing_uin == target_uin and self.loop_running:
@ -249,6 +273,20 @@ class TyClient:
if self.dialing_uin != target_uin or not self.loop_running: if self.dialing_uin != target_uin or not self.loop_running:
break break
time.sleep(0.1) time.sleep(0.1)
=======
def text_to_audio(self, text):
audio_signals = []
t_start = np.linspace(0, 0.3, int(SAMPLE_RATE * 0.3), False)
audio_signals.append(np.sin(1000 * t_start * 2 * np.pi))
for char in text:
freq = BASE_FREQ + ord(char) * FREQ_STEP
t = np.linspace(0, TONE_DURATION, int(SAMPLE_RATE * TONE_DURATION), False)
audio_signals.append(np.sin(freq * t * 2 * np.pi))
full_audio = np.concatenate(audio_signals).astype(np.float32)
if np.max(np.abs(full_audio)) > 0:
full_audio = full_audio / np.max(np.abs(full_audio))
return full_audio.tobytes()
>>>>>>> parent of cfd13cf (Update client.py):client.py
def play_and_decode(self, audio_bytes, sender_uin): def play_and_decode(self, audio_bytes, sender_uin):
audio_data = np.frombuffer(audio_bytes, dtype=np.float32) audio_data = np.frombuffer(audio_bytes, dtype=np.float32)
@ -265,24 +303,37 @@ class TyClient:
self.history[sender_uin].append(msg_buffer) self.history[sender_uin].append(msg_buffer)
self.refresh_ui() self.refresh_ui()
full_text_received = ""
while current_sample < len(audio_data) and self.loop_running: while current_sample < len(audio_data) and self.loop_running:
chunk = audio_data[current_sample : current_sample + samples_per_tone] chunk = audio_data[current_sample : current_sample + samples_per_tone]
if len(chunk) < samples_per_tone: if len(chunk) < samples_per_tone:
break break
<<<<<<< HEAD:TUI.py
window_data = np.hanning(len(chunk)) window_data = np.hanning(len(chunk))
fft_data = np.abs(np.fft.rfft(chunk * window_data)) fft_data = np.abs(np.fft.rfft(chunk * window_data))
frequencies = np.fft.rfftfreq(len(chunk), d=1/44100) frequencies = np.fft.rfftfreq(len(chunk), d=1/44100)
=======
window = np.hanning(len(chunk))
fft_data = np.abs(np.fft.rfft(chunk * window))
frequencies = np.fft.rfftfreq(len(chunk), d=1/SAMPLE_RATE)
>>>>>>> parent of cfd13cf (Update client.py):client.py
detected_freq = frequencies[np.argmax(fft_data)] detected_freq = frequencies[np.argmax(fft_data)]
ascii_code = int(round((detected_freq - 600) / 25)) ascii_code = int(round((detected_freq - 600) / 25))
if 0 <= ascii_code < 65535: if 0 <= ascii_code < 65535:
try: try:
char = chr(ascii_code) char = chr(ascii_code)
self.history[sender_uin][-1] += char self.history[sender_uin][-1] += char
full_text_received += char
self.refresh_ui() self.refresh_ui()
except: except:
pass pass
time.sleep(0.1) time.sleep(0.1)
current_sample += samples_per_tone current_sample += samples_per_tone
if "ALARM! URGENT CALL!" in full_text_received:
client.contacts[sender_uin]["attention"] = True
self.refresh_ui()
sd.wait() sd.wait()
self.save_config() self.save_config()
@ -293,6 +344,7 @@ class TyClient:
self.refresh_ui() self.refresh_ui()
self.save_config() self.save_config()
<<<<<<< HEAD:TUI.py
def send_sys_packet(self, to_uin, cmd): def send_sys_packet(self, to_uin, cmd):
text_payload = f"SYS:{cmd}" text_payload = f"SYS:{cmd}"
proto_order = [] proto_order = []
@ -327,12 +379,51 @@ class TyClient:
socket_manager.sio.emit("relay_packet", {"to_uin": to_uin, "payload": base64.b64encode(wrapped).decode('utf-8')}) socket_manager.sio.emit("relay_packet", {"to_uin": to_uin, "payload": base64.b64encode(wrapped).decode('utf-8')})
return return
=======
>>>>>>> parent of cfd13cf (Update client.py):client.py
def refresh_ui(self): def refresh_ui(self):
if self.app: if self.app:
self.app.invalidate() self.app.invalidate()
client = TyClient() client = TyClient()
<<<<<<< HEAD:TUI.py
=======
@sio.event
def incoming_packet(data):
from_uin = data["from_uin"]
payload_base64 = data["payload"]
try:
audio_bytes = base64.b64decode(payload_base64.encode('utf-8'))
if from_uin not in client.contacts:
client.contacts[from_uin] = {"status": "offline", "unread": 0, "attention": False}
if client.active_chat != from_uin:
client.contacts[from_uin]["unread"] += 1
threading.Thread(target=client.play_and_decode, args=(audio_bytes, from_uin), daemon=True).start()
except:
pass
@sio.event
def online_statuses_response(data):
for uin, status in data.items():
if uin in client.contacts:
client.contacts[uin]["status"] = status
client.refresh_ui()
@sio.event
def error(data):
msg = data.get("message")
target = data.get("target_uin")
if msg == "offline" and target:
if target in client.contacts:
client.contacts[target]["status"] = "offline"
client.add_to_history(target, f"[SYSTEM]: They went offline. Everything that you will send now will be sent if they will back online while your client opened.")
if target in client.preserved:
if len(client.preserved[target]) > 0:
last_p = client.preserved[target][-1]
client.add_to_history(target, f"[You]: {last_p} (Preserved)")
>>>>>>> parent of cfd13cf (Update client.py):client.py
def status_checker_thread(): def status_checker_thread():
while client.loop_running: while client.loop_running:
if socket_manager.sio.connected and client.contacts: if socket_manager.sio.connected and client.contacts:
@ -371,10 +462,15 @@ def make_layout():
tokens = [] tokens = []
for idx, (uin, info) in enumerate(client.contacts.items()): for idx, (uin, info) in enumerate(client.contacts.items()):
status_str = "" status_str = ""
if info.get("attention"): status_str = " [!]" if info.get("attention"):
elif info.get("unread", 0) > 0: status_str = f" ({info['unread']})" status_str = " [!]"
elif info.get("status") == "online": status_str = " *" elif info.get("unread", 0) > 0:
status_str = f" ({info['unread']})"
elif info.get("status") == "online":
status_str = " *"
content = f" {uin}{status_str}" content = f" {uin}{status_str}"
<<<<<<< HEAD:TUI.py
if client.active_chat == uin and client.current_tab == "chat": style = "class:contact-active" if client.active_chat == uin and client.current_tab == "chat": style = "class:contact-active"
elif idx == client.selected_contact_idx and get_app().layout.has_focus(sidebar_window) and client.current_tab == "chat": style = "class:contact-focused" elif idx == client.selected_contact_idx and get_app().layout.has_focus(sidebar_window) and client.current_tab == "chat": style = "class:contact-focused"
else: style = "class:contact" else: style = "class:contact"
@ -385,6 +481,19 @@ def make_layout():
if client.active_chat == g_id and client.current_tab == "chat": style = "class:contact-active" if client.active_chat == g_id and client.current_tab == "chat": style = "class:contact-active"
else: style = "class:contact" else: style = "class:contact"
tokens.extend([(style, f"{content}\n")]) tokens.extend([(style, f"{content}\n")])
=======
if client.active_chat == uin:
style = "class:contact-active"
elif idx == client.selected_contact_idx and get_app().layout.has_focus(sidebar_window):
style = "class:contact-focused"
else:
style = "class:contact"
tokens.extend([
(style, f"{content}\n"),
])
>>>>>>> parent of cfd13cf (Update client.py):client.py
return tokens return tokens
def get_main_text(): def get_main_text():
@ -397,15 +506,14 @@ def make_layout():
("class:desc", "Messenger on custom protocol named\n"), ("class:desc", "Messenger on custom protocol named\n"),
("class:desc", "AcoustiOverSocket inspired by rtty\n"), ("class:desc", "AcoustiOverSocket inspired by rtty\n"),
("", "\n"), ("", "\n"),
<<<<<<< HEAD:TUI.py
("class:help-tip", "Type / to trigger interactive command menu | F2: Settings Panel\n"), ("class:help-tip", "Type / to trigger interactive command menu | F2: Settings Panel\n"),
=======
("class:help-tip", "Type /help to open project Wiki\n"),
>>>>>>> parent of cfd13cf (Update client.py):client.py
("", "\n" * 2), ("", "\n" * 2),
("class:help-tip", f"{DEV_SIGNATURE}\n") ("class:help-tip", f"{DEV_SIGNATURE}\n")
]) ])
if client.dialing_uin:
tokens.extend([
("", "\n" * 2),
("class:system", f"Dialing UIN {client.dialing_uin}... Waiting for accept.\n")
])
return tokens return tokens
tokens = [] tokens = []
@ -419,6 +527,7 @@ def make_layout():
tokens.append(("", line + "\n")) tokens.append(("", line + "\n"))
return tokens return tokens
<<<<<<< HEAD:TUI.py
def get_settings_text(): def get_settings_text():
tokens = [("class:popup-title", " === SETTINGS & PLUGINS PANEL ===\n\n")] tokens = [("class:popup-title", " === SETTINGS & PLUGINS PANEL ===\n\n")]
@ -463,17 +572,19 @@ def make_layout():
newlines = text.count('\n') newlines = text.count('\n')
return Point(0, max(0, newlines - 1)) return Point(0, max(0, newlines - 1))
=======
>>>>>>> parent of cfd13cf (Update client.py):client.py
sidebar_control = FormattedTextControl(get_sidebar_text, focusable=True) sidebar_control = FormattedTextControl(get_sidebar_text, focusable=True)
sidebar_window = Frame(Window(content=sidebar_control, width=25), title="chats", style="class:border") sidebar_window = Frame(Window(content=sidebar_control, width=25), title="chats", style="class:border")
main_control = FormattedTextControl(get_main_text, get_cursor_position=get_cursor_pos)
main_control = FormattedTextControl(get_main_text)
def get_main_title(): def get_main_title():
base_title = f"TyChat | You: {client.username} ({client.uin})" if client.active_chat:
if client.is_busy: base_title += " [DND/BUSY]" return f"TyChat | You: {client.username} ({client.uin}) | Chat with UIN: {client.active_chat}"
if client.active_chat: return f"{base_title} | Chat: {client.active_chat}" return f"TyChat | You: {client.username} ({client.uin})"
return base_title
main_window = Frame(Window(content=main_control, wrap_lines=True), title=get_main_title, style="class:border") main_window = Frame(Window(content=main_control), title=get_main_title, style="class:border")
settings_control = FormattedTextControl(get_settings_text, focusable=True) settings_control = FormattedTextControl(get_settings_text, focusable=True)
settings_window = Frame(Window(content=settings_control, wrap_lines=True), title="Settings Router", style="class:border") settings_window = Frame(Window(content=settings_control, wrap_lines=True), title="Settings Router", style="class:border")
@ -482,15 +593,15 @@ def make_layout():
height=3, height=3,
prompt="> ", prompt="> ",
multiline=False, multiline=False,
wrap_lines=True, wrap_lines=True
completer=CommandCompleter(),
complete_while_typing=True
) )
input_window = Frame(input_field, title="Input")
input_window = Frame(input_field, title="Type message and press Enter (/exit to quit)")
def accept_handler(buff): def accept_handler(buff):
text = input_field.text.strip() text = input_field.text.strip()
if not text: return if not text:
return
if text.lower() == "/exit": if text.lower() == "/exit":
client.loop_running = False client.loop_running = False
@ -499,66 +610,29 @@ def make_layout():
return return
if text.lower() == "/help": if text.lower() == "/help":
try: webbrowser.open(WIKI_URL) try:
except: pass webbrowser.open(WIKI_URL)
input_field.text = ""
return
if text.lower() == "/busy":
client.is_busy = not client.is_busy
if client.active_chat: if client.active_chat:
status_msg = "enabled" if client.is_busy else "disabled" client.add_to_history(client.active_chat, "[SYSTEM]: Wiki link opened in browser.")
client.add_to_history(client.active_chat, f"[SYSTEM]: DND Mode {status_msg}.") except:
if client.active_chat:
client.add_to_history(client.active_chat, f"[SYSTEM]: Failed to open browser. Wiki: {WIKI_URL}")
input_field.text = "" input_field.text = ""
client.refresh_ui() client.refresh_ui()
return return
if text.lower().startswith("/add "): if text.lower().startswith("/add "):
new_uin = text.split(" ", 1)[1].strip() new_uin = text.split(" ", 1)[1].strip()
if not new_uin: return if new_uin and new_uin not in client.contacts:
if new_uin in client.contacts: client.contacts[new_uin] = {"status": "offline", "unread": 0, "attention": False}
client.active_chat = new_uin client.history[new_uin] = []
input_field.text = ""
client.refresh_ui()
return
client.active_chat = None
threading.Thread(target=client.play_dial_tones, args=(new_uin,), daemon=True).start()
client.send_sys_packet(new_uin, "REQ_ADD")
input_field.text = ""
client.refresh_ui()
return
if text.lower().startswith("/room create "):
match = re.match(r'^/room create "([^"]+)"$', text, re.IGNORECASE)
if match:
r_name = match.group(1)
r_id = f"ROOM:{client.uin}:{r_name}"
client.groups[r_id] = {"title": r_name, "owner": client.uin, "members": [client.uin]}
client.history[r_id] = [f"[SYSTEM]: Room \"{r_name}\" created successfully. Local GUID: {r_id}"]
client.active_chat = r_id
client.save_config() client.save_config()
client.refresh_ui()
input_field.text = "" input_field.text = ""
return
if text.lower().startswith("/room join "):
match = re.match(r'^/room join ([0-9]+):"([^"]+)"$', text, re.IGNORECASE)
if match:
r_owner = match.group(1)
r_name = match.group(2)
r_id = f"ROOM:{r_owner}:{r_name}"
if r_owner not in client.contacts and r_owner != client.uin:
client.contacts[r_owner] = {"status": "offline", "unread": 0, "attention": False}
client.groups[r_id] = {"title": r_name, "owner": r_owner, "members": list(set([client.uin, r_owner]))}
client.history[r_id] = [f"[SYSTEM]: Joined room \"{r_name}\". Local GUID: {r_id}"]
client.active_chat = r_id
client.save_config()
client.refresh_ui() client.refresh_ui()
client.send_sys_packet(r_owner, f"REQ_JOIN_ROOM:{r_name}")
input_field.text = ""
return return
if client.active_chat: if client.active_chat:
<<<<<<< HEAD:TUI.py
if client.active_chat.startswith("ROOM:"): if client.active_chat.startswith("ROOM:"):
group = client.groups[client.active_chat] group = client.groups[client.active_chat]
owner_uin = group["owner"] owner_uin = group["owner"]
@ -602,10 +676,14 @@ def make_layout():
input_field.text = "" input_field.text = ""
return return
if len(text) > 300: if len(text) > 300:
=======
if len(text) > 100:
>>>>>>> parent of cfd13cf (Update client.py):client.py
client.add_to_history(client.active_chat, f"[SYSTEM]: Message too long!") client.add_to_history(client.active_chat, f"[SYSTEM]: Message too long!")
input_field.text = "" input_field.text = ""
return return
<<<<<<< HEAD:TUI.py
proto_to_use = client.peer_session_protocols.get(client.active_chat, client.primary_protocol) proto_to_use = client.peer_session_protocols.get(client.active_chat, client.primary_protocol)
encoded = client.plugin_manager.safe_encode(proto_to_use, text) encoded = client.plugin_manager.safe_encode(proto_to_use, text)
@ -648,18 +726,52 @@ def make_layout():
ConditionalContainer(content=settings_window, filter=is_settings_panel), ConditionalContainer(content=settings_window, filter=is_settings_panel),
input_window input_window
]) ])
=======
match = re.match(r'^s/([^/]+)/([^/]*)/?$', text)
if match:
search_str, replace_str = match.groups()
lines = client.history.get(client.active_chat, [])
edited = False
for i in range(len(lines) - 1, -1, -1):
if lines[i].startswith(f"[{client.username}]:") or lines[i].startswith("[You]:"):
if search_str in lines[i]:
lines[i] = lines[i].replace(search_str, replace_str)
edited = True
break
if edited:
client.refresh_ui()
client.save_config()
input_field.text = ""
return
def get_popup_text(): if text.startswith("/alert"):
if not client.pending_requests: return [] text = "ALARM! URGENT CALL!"
req_uin = client.pending_requests[0] client.contacts[client.active_chat]["attention"] = True
return [
("class:popup-title", f" Incoming Handshake Request \n"),
("class:popup-title", f" UIN: {req_uin} \n\n"),
("", " Do you want to add them to contacts?\n\n"),
("class:popup-keys", " [Y]es [N]o N[e]ver ")
]
popup_window = Frame(Window(FormattedTextControl(get_popup_text), align=WindowAlign.CENTER, width=42, height=6), style="class:popup-border")
audio_b = client.text_to_audio(text)
p_b64 = base64.b64encode(audio_b).decode('utf-8')
if client.contacts[client.active_chat]["status"] == "online":
sio.emit("relay_packet", {"to_uin": client.active_chat, "payload": p_b64})
client.add_to_history(client.active_chat, f"[You]: {text}")
else:
if client.active_chat not in client.preserved:
client.preserved[client.active_chat] = []
client.preserved[client.active_chat].append(text)
client.add_to_history(client.active_chat, f"[You]: {text} (Preserved)")
client.save_config()
input_field.text = ""
input_field.accept_handler = accept_handler
>>>>>>> parent of cfd13cf (Update client.py):client.py
right_side = HSplit([
main_window,
input_window
])
<<<<<<< HEAD:TUI.py
def get_signal_popup_text(): def get_signal_popup_text():
if not client.pending_windows: return [] if not client.pending_windows: return []
win_info = client.pending_windows[0] win_info = client.pending_windows[0]
@ -768,34 +880,51 @@ def make_layout():
client.refresh_ui() client.refresh_ui()
@kb.add('tab', filter=~has_pending_request & ~has_pending_window & ~has_welcome_popup & is_chat_panel) @kb.add('tab', filter=~has_pending_request & ~has_pending_window & ~has_welcome_popup & is_chat_panel)
def _(event): =======
if event.app.layout.has_focus(input_field): event.app.layout.focus(sidebar_window) root_container = VSplit([
else: event.app.layout.focus(input_field) sidebar_window,
right_side
])
kb = KeyBindings()
@kb.add('tab')
>>>>>>> parent of cfd13cf (Update client.py):client.py
def _(event):
if event.app.layout.has_focus(input_field):
event.app.layout.focus(sidebar_window)
else:
event.app.layout.focus(input_field)
<<<<<<< HEAD:TUI.py
@kb.add('up', filter=has_focus(sidebar_window) & ~has_pending_request & ~has_pending_window & ~has_welcome_popup & is_chat_panel) @kb.add('up', filter=has_focus(sidebar_window) & ~has_pending_request & ~has_pending_window & ~has_welcome_popup & is_chat_panel)
=======
@kb.add('up', filter=has_focus(sidebar_window))
>>>>>>> parent of cfd13cf (Update client.py):client.py
def _(event): def _(event):
all_chats = list(client.contacts.keys()) + list(client.groups.keys()) if client.contacts:
if all_chats: client.selected_contact_idx = (client.selected_contact_idx - 1) % len(client.contacts)
client.selected_contact_idx = (client.selected_contact_idx - 1) % len(all_chats) target_uin = list(client.contacts.keys())[client.selected_contact_idx]
target = all_chats[client.selected_contact_idx] client.active_chat = target_uin
client.active_chat = target client.contacts[target_uin]["unread"] = 0
if target in client.contacts: client.contacts[target_uin]["attention"] = False
client.contacts[target]["unread"] = 0
client.contacts[target]["attention"] = False
client.refresh_ui() client.refresh_ui()
<<<<<<< HEAD:TUI.py
@kb.add('down', filter=has_focus(sidebar_window) & ~has_pending_request & ~has_pending_window & ~has_welcome_popup & is_chat_panel) @kb.add('down', filter=has_focus(sidebar_window) & ~has_pending_request & ~has_pending_window & ~has_welcome_popup & is_chat_panel)
=======
@kb.add('down', filter=has_focus(sidebar_window))
>>>>>>> parent of cfd13cf (Update client.py):client.py
def _(event): def _(event):
all_chats = list(client.contacts.keys()) + list(client.groups.keys()) if client.contacts:
if all_chats: client.selected_contact_idx = (client.selected_contact_idx + 1) % len(client.contacts)
client.selected_contact_idx = (client.selected_contact_idx + 1) % len(all_chats) target_uin = list(client.contacts.keys())[client.selected_contact_idx]
target = all_chats[client.selected_contact_idx] client.active_chat = target_uin
client.active_chat = target client.contacts[target_uin]["unread"] = 0
if target in client.contacts: client.contacts[target_uin]["attention"] = False
client.contacts[target]["unread"] = 0
client.contacts[target]["attention"] = False
client.refresh_ui() client.refresh_ui()
<<<<<<< HEAD:TUI.py
@kb.add('y', filter=has_welcome_popup) @kb.add('y', filter=has_welcome_popup)
@kb.add('Y', filter=has_welcome_popup) @kb.add('Y', filter=has_welcome_popup)
def _(event): def _(event):
@ -854,6 +983,8 @@ def make_layout():
client.send_sys_packet(req_uin, "RES_DEC") client.send_sys_packet(req_uin, "RES_DEC")
client.refresh_ui() client.refresh_ui()
=======
>>>>>>> parent of cfd13cf (Update client.py):client.py
@kb.add('c-c') @kb.add('c-c')
def _(event): def _(event):
client.loop_running = False client.loop_running = False
@ -873,13 +1004,6 @@ ui_style = Style.from_dict({
'system': '#ff0000 bold', 'system': '#ff0000 bold',
'border': '#00ff00', 'border': '#00ff00',
'frame.border': '#00ff00', 'frame.border': '#00ff00',
'popup-title': '#ffffff bold',
'popup-keys': '#00ff00 bold',
'popup-border': '#ff0000 bold',
'query-title': '#00ffff bold',
'alert-title': '#ff0000 bold',
'completion-menu.completion': 'bg:#00ffff #000000',
'completion-menu.completion.current': 'bg:#00aa00 #ffffff bold'
}) })
def main(): def main():
@ -888,38 +1012,54 @@ def main():
try: try:
kernel32 = ctypes.windll.kernel32 kernel32 = ctypes.windll.kernel32
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7) kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
<<<<<<< HEAD:TUI.py
except: pass except: pass
is_new_registration = False is_new_registration = False
socket_manager.init_network(client) socket_manager.init_network(client)
=======
except:
pass
>>>>>>> parent of cfd13cf (Update client.py):client.py
if not client.load_config(): if not client.load_config():
print("!" * 60) print("!" * 60)
print("WARNING: All data is local.") print("WARNING:")
print("You will receive new messages only when you are online.")
print("All history is stored locally in settings.json.")
print("Anyone who knows your UIN can message you.")
print("This software uses loud sounds, adjust your client volume beforehand!")
print("!" * 60 + "\n") print("!" * 60 + "\n")
client.server_url = input("Enter server URL: ").strip() client.server_url = input("Enter server URL (e.g., http://localhost:5000): ").strip()
if not client.server_url.startswith("http://") and not client.server_url.startswith("https://"): if not client.server_url.startswith("http://") and not client.server_url.startswith("https://"):
client.server_url = "http://" + client.server_url client.server_url = "http://" + client.server_url
<<<<<<< HEAD:TUI.py
try: socket_manager.sio.connect(client.server_url, transports=['websocket']) try: socket_manager.sio.connect(client.server_url, transports=['websocket'])
except Exception as e: return except Exception as e: return
=======
try:
sio.connect(client.server_url, transports=['websocket'])
except Exception as e:
print(f"Failed to connect to server: {e}")
return
>>>>>>> parent of cfd13cf (Update client.py):client.py
print("\n1. Register\n2. Login") print("\n1. Register\n2. Login")
mode = input("> ") mode = input("> ")
username_or_uin = input("UIN/Username: ").strip() username_or_uin = input("Enter Username (for reg) or UIN (for login): ").strip()
password = input("Password: ").strip() password = input("Enter password: ").strip()
event_wait = threading.Event() event_wait = threading.Event()
@socket_manager.sio.event @socket_manager.sio.event
def register_response(data): def register_response(data):
nonlocal is_new_registration
if data["status"] == "success": if data["status"] == "success":
client.uin = data['uin'] client.uin = data['uin']
client.username = username_or_uin client.username = username_or_uin
client.password = password client.password = password
is_new_registration = True print(f"\nSuccess! Your UIN: {client.uin}")
event_wait.set() event_wait.set()
@socket_manager.sio.event @socket_manager.sio.event
@ -928,25 +1068,47 @@ def main():
client.uin = username_or_uin client.uin = username_or_uin
client.username = data["username"] client.username = data["username"]
client.password = password client.password = password
print(f"\nHello, {client.username}! Logged in successfully.")
event_wait.set() event_wait.set()
<<<<<<< HEAD:TUI.py
if mode == "1": socket_manager.sio.emit("register", {"username": username_or_uin, "password": password}) if mode == "1": socket_manager.sio.emit("register", {"username": username_or_uin, "password": password})
else: socket_manager.sio.emit("login", {"uin": username_or_uin, "password": password}) else: socket_manager.sio.emit("login", {"uin": username_or_uin, "password": password})
event_wait.wait() event_wait.wait()
=======
if mode == "1":
sio.emit("register", {"username": username_or_uin, "password": password})
event_wait.wait()
else:
sio.emit("login", {"uin": username_or_uin, "password": password})
event_wait.wait()
if not client.uin:
print("Auth error.")
return
>>>>>>> parent of cfd13cf (Update client.py):client.py
if not client.uin: return
client.save_config() client.save_config()
print("\nYou can change configurations inside settings.json.")
input("Press Enter to open TUI...") input("Press Enter to open TUI...")
else: else:
try: try:
<<<<<<< HEAD:TUI.py
socket_manager.sio.connect(client.server_url, transports=['websocket']) socket_manager.sio.connect(client.server_url, transports=['websocket'])
socket_manager.sio.emit("login", {"uin": client.uin, "password": client.password}) socket_manager.sio.emit("login", {"uin": client.uin, "password": client.password})
except: pass except: pass
if is_new_registration: if is_new_registration:
client.show_welcome_popup = True client.show_welcome_popup = True
=======
sio.connect(client.server_url, transports=['websocket'])
sio.emit("login", {"uin": client.uin, "password": client.password})
except:
pass
>>>>>>> parent of cfd13cf (Update client.py):client.py
threading.Thread(target=status_checker_thread, daemon=True).start() threading.Thread(target=status_checker_thread, daemon=True).start()
layout, bindings = make_layout() layout, bindings = make_layout()
client.app = Application( client.app = Application(
@ -956,6 +1118,7 @@ def main():
full_screen=True, full_screen=True,
enable_page_navigation_bindings=True enable_page_navigation_bindings=True
) )
client.app.run() client.app.run()
if __name__ == "__main__": if __name__ == "__main__":