shellwhisper-cli 1.0.4__tar.gz → 1.0.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {shellwhisper_cli-1.0.4 → shellwhisper_cli-1.0.5}/PKG-INFO +1 -1
- {shellwhisper_cli-1.0.4 → shellwhisper_cli-1.0.5}/pyproject.toml +6 -3
- {shellwhisper_cli-1.0.4 → shellwhisper_cli-1.0.5}/shellwhisper_cli.egg-info/PKG-INFO +1 -1
- shellwhisper_cli-1.0.5/shellwhisper_cli.egg-info/SOURCES.txt +21 -0
- shellwhisper_cli-1.0.5/src/components/sidebar.py +90 -0
- shellwhisper_cli-1.0.5/src/screens/chat_screen.py +661 -0
- shellwhisper_cli-1.0.5/src/screens/forgot_password.py +79 -0
- shellwhisper_cli-1.0.5/src/screens/join_screen.py +23 -0
- shellwhisper_cli-1.0.5/src/screens/login.py +104 -0
- shellwhisper_cli-1.0.5/src/screens/private_whisper_screen.py +26 -0
- shellwhisper_cli-1.0.5/src/screens/room_action_screen.py +35 -0
- shellwhisper_cli-1.0.5/src/screens/security_screen.py +45 -0
- shellwhisper_cli-1.0.5/src/styles/main.tcss +278 -0
- shellwhisper_cli-1.0.5/src/utils/api_client.py +133 -0
- shellwhisper_cli-1.0.4/shellwhisper_cli.egg-info/SOURCES.txt +0 -11
- {shellwhisper_cli-1.0.4 → shellwhisper_cli-1.0.5}/LICENSE +0 -0
- {shellwhisper_cli-1.0.4 → shellwhisper_cli-1.0.5}/README.md +0 -0
- {shellwhisper_cli-1.0.4 → shellwhisper_cli-1.0.5}/setup.cfg +0 -0
- {shellwhisper_cli-1.0.4 → shellwhisper_cli-1.0.5}/shellwhisper_cli.egg-info/dependency_links.txt +0 -0
- {shellwhisper_cli-1.0.4 → shellwhisper_cli-1.0.5}/shellwhisper_cli.egg-info/entry_points.txt +0 -0
- {shellwhisper_cli-1.0.4 → shellwhisper_cli-1.0.5}/shellwhisper_cli.egg-info/requires.txt +0 -0
- {shellwhisper_cli-1.0.4 → shellwhisper_cli-1.0.5}/shellwhisper_cli.egg-info/top_level.txt +0 -0
- {shellwhisper_cli-1.0.4 → shellwhisper_cli-1.0.5}/src/app.py +0 -0
- {shellwhisper_cli-1.0.4 → shellwhisper_cli-1.0.5}/src/events.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "shellwhisper-cli"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.5" # Bumped to clear the PyPI filename collision
|
|
8
8
|
description = "A sleek terminal-based real-time chat client for ShellWhisper"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -24,8 +24,11 @@ dependencies = [
|
|
|
24
24
|
[project.scripts]
|
|
25
25
|
shellwhisper = "src.app:main"
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
packages
|
|
27
|
+
# 🛠️ THE ULTIMATE PACKAGE FINDER
|
|
28
|
+
[tool.setuptools.packages.find]
|
|
29
|
+
where = ["."] # Forces scanning from the root client folder
|
|
30
|
+
include = ["src*"] # Catches 'src' and every nested subfolder (src.screens, src.utils, etc.)
|
|
31
|
+
namespaces = true # Forces inclusion of subfolders even if they lack __init__.py
|
|
29
32
|
|
|
30
33
|
[tool.setuptools.package-data]
|
|
31
34
|
"*" = ["*.tcss", "*.css"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
shellwhisper_cli.egg-info/PKG-INFO
|
|
5
|
+
shellwhisper_cli.egg-info/SOURCES.txt
|
|
6
|
+
shellwhisper_cli.egg-info/dependency_links.txt
|
|
7
|
+
shellwhisper_cli.egg-info/entry_points.txt
|
|
8
|
+
shellwhisper_cli.egg-info/requires.txt
|
|
9
|
+
shellwhisper_cli.egg-info/top_level.txt
|
|
10
|
+
src/app.py
|
|
11
|
+
src/events.py
|
|
12
|
+
src/components/sidebar.py
|
|
13
|
+
src/screens/chat_screen.py
|
|
14
|
+
src/screens/forgot_password.py
|
|
15
|
+
src/screens/join_screen.py
|
|
16
|
+
src/screens/login.py
|
|
17
|
+
src/screens/private_whisper_screen.py
|
|
18
|
+
src/screens/room_action_screen.py
|
|
19
|
+
src/screens/security_screen.py
|
|
20
|
+
src/styles/main.tcss
|
|
21
|
+
src/utils/api_client.py
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from textual.widgets import Static, Label, Button, LoadingIndicator
|
|
2
|
+
from textual.containers import Vertical
|
|
3
|
+
from textual.app import ComposeResult
|
|
4
|
+
|
|
5
|
+
class Sidebar(Static):
|
|
6
|
+
def compose(self) -> ComposeResult:
|
|
7
|
+
yield Label("ShellWhisper", id="sidebar-title")
|
|
8
|
+
yield Static(classes='spacer')
|
|
9
|
+
|
|
10
|
+
yield Button("🌐 ROOM ACTIONS", id="btn_room_mgmt")
|
|
11
|
+
yield Button("✉️ PRIVATE WHISPER", id="btn_private")
|
|
12
|
+
|
|
13
|
+
yield Static(classes='spacer')
|
|
14
|
+
yield Label("MY ROOMS", id="section-label")
|
|
15
|
+
|
|
16
|
+
with Vertical(id="rooms-list"):
|
|
17
|
+
yield LoadingIndicator()
|
|
18
|
+
|
|
19
|
+
yield Static(classes='spacer')
|
|
20
|
+
yield Button("Logout", variant="error", id="logout_btn")
|
|
21
|
+
|
|
22
|
+
# async def update_rooms(self, rooms: list):
|
|
23
|
+
# rooms_list = self.query_one("#rooms-list")
|
|
24
|
+
# await rooms_list.query("*").remove()
|
|
25
|
+
|
|
26
|
+
# if not rooms:
|
|
27
|
+
# await rooms_list.mount(Label("No rooms yet...", classes="empty-msg"))
|
|
28
|
+
# else:
|
|
29
|
+
# current_user = self.app.current_user
|
|
30
|
+
|
|
31
|
+
# for room in rooms:
|
|
32
|
+
# display_name = room['roomName']
|
|
33
|
+
|
|
34
|
+
# if room.get("type") == "PRIVATE":
|
|
35
|
+
# clean_name = display_name.replace("private_", "")
|
|
36
|
+
|
|
37
|
+
# parts = clean_name.split("_")
|
|
38
|
+
|
|
39
|
+
# if len(parts) == 2:
|
|
40
|
+
# display_name = parts[1] if parts[0] == current_user else parts[0]
|
|
41
|
+
|
|
42
|
+
# btn_label = f"💬 {display_name}"
|
|
43
|
+
# else:
|
|
44
|
+
# btn_label = f"#{display_name}"
|
|
45
|
+
|
|
46
|
+
# btn = Button(
|
|
47
|
+
# # label=f"#{room['roomName']}",
|
|
48
|
+
# label=btn_label,
|
|
49
|
+
# id=f"room_{room['id']}",
|
|
50
|
+
# classes="room-link"
|
|
51
|
+
# )
|
|
52
|
+
# await rooms_list.mount(btn)
|
|
53
|
+
|
|
54
|
+
async def update_rooms(self, rooms: list):
|
|
55
|
+
rooms_list = self.query_one("#rooms-list")
|
|
56
|
+
await rooms_list.query("*").remove()
|
|
57
|
+
|
|
58
|
+
if not rooms:
|
|
59
|
+
await rooms_list.mount(Label("No rooms yet...", classes="empty-msg"))
|
|
60
|
+
else:
|
|
61
|
+
current_user = self.app.current_user
|
|
62
|
+
|
|
63
|
+
for room in rooms:
|
|
64
|
+
room_name = room['roomName']
|
|
65
|
+
room_type = room.get("type", "GROUP")
|
|
66
|
+
|
|
67
|
+
if room_type == "PRIVATE":
|
|
68
|
+
raw = room_name
|
|
69
|
+
|
|
70
|
+
if raw.startswith("private_"):
|
|
71
|
+
raw = raw[len("private_"):]
|
|
72
|
+
|
|
73
|
+
other = raw
|
|
74
|
+
|
|
75
|
+
if raw.startswith(current_user + "_"):
|
|
76
|
+
other = raw[len(current_user) + 1:]
|
|
77
|
+
elif raw.endswith("_" + current_user):
|
|
78
|
+
other = raw[: -(len(current_user) + 1)]
|
|
79
|
+
|
|
80
|
+
btn_label = f"💬 {other}"
|
|
81
|
+
else:
|
|
82
|
+
btn_label = room_name
|
|
83
|
+
|
|
84
|
+
btn = Button(
|
|
85
|
+
label=btn_label,
|
|
86
|
+
id=f"room_{room['id']}",
|
|
87
|
+
classes="room-link"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
await rooms_list.mount(btn)
|