Redesign message viewer as Telegram-style chat with bubbles, replies, infinite scroll, and orientation
- Chat bubbles with 1px border-radius, angular tail arrows - Own messages right (blue), others left (dark) via sender_id vs user_id - Reply preview with left border accent, clickable scroll to original - Infinite scroll up via IntersectionObserver on scroll-sentinel - Date separators (Today/Yesterday/date) between messages - Full-height messages panel with sidebar (channels) + header - Backend: reply_to_message data in load_messages(), user_id exposed in auth snapshot - Auto-scroll to bottom on channel load (triple scrollTop fallback) - history.scrollRestoration = manual to prevent mid-page jumps
This commit is contained in:
@@ -205,6 +205,37 @@ def load_messages(
|
||||
"reactions": row["reactions"],
|
||||
}
|
||||
)
|
||||
|
||||
reply_ids = list({m["reply_to"] for m in messages if m["reply_to"]})
|
||||
if reply_ids:
|
||||
placeholders = ",".join("?" for _ in reply_ids)
|
||||
try:
|
||||
conn2 = sqlite3.connect(str(db_path))
|
||||
conn2.row_factory = sqlite3.Row
|
||||
try:
|
||||
rows2 = conn2.execute(
|
||||
f"SELECT message_id, message, first_name, last_name, username "
|
||||
f"FROM messages WHERE message_id IN ({placeholders})",
|
||||
reply_ids,
|
||||
).fetchall()
|
||||
reply_map: Dict[int, Dict[str, str]] = {}
|
||||
for r in rows2:
|
||||
r_sender = " ".join(
|
||||
part for part in [r["first_name"], r["last_name"]] if part
|
||||
).strip() or (r["username"] or "")
|
||||
reply_map[r["message_id"]] = {
|
||||
"text": (r["message"] or "")[:300],
|
||||
"sender_name": r_sender,
|
||||
}
|
||||
for m in messages:
|
||||
rt = m.get("reply_to")
|
||||
if rt and rt in reply_map:
|
||||
m["reply_to_message"] = reply_map[rt]
|
||||
finally:
|
||||
conn2.close()
|
||||
except sqlite3.Error:
|
||||
pass
|
||||
|
||||
return messages
|
||||
|
||||
|
||||
@@ -328,6 +359,7 @@ class TelegramAuthManager:
|
||||
self.thread = threading.Thread(target=self._run_loop, daemon=True)
|
||||
self.thread.start()
|
||||
self.client: Optional[TelegramClient] = None
|
||||
self.user_id: Optional[int] = None
|
||||
self.qr_login = None
|
||||
self.qr_wait_task = None
|
||||
self.phone = None
|
||||
@@ -359,6 +391,7 @@ class TelegramAuthManager:
|
||||
auth = auth_status()
|
||||
with self.lock:
|
||||
snapshot = dict(self.state)
|
||||
snapshot["user_id"] = self.user_id
|
||||
snapshot["saved_credentials"] = {
|
||||
"api_id": load_state().get("api_id"),
|
||||
"api_hash_present": bool(load_state().get("api_hash")),
|
||||
@@ -376,6 +409,12 @@ class TelegramAuthManager:
|
||||
self.client = TelegramClient(str(SESSION_DIR / "session"), api_id, api_hash)
|
||||
if not self.client.is_connected():
|
||||
await self.client.connect()
|
||||
if self.user_id is None and await self.client.is_user_authorized():
|
||||
try:
|
||||
me = await self.client.get_me()
|
||||
self.user_id = me.id
|
||||
except Exception:
|
||||
pass
|
||||
return self.client
|
||||
|
||||
async def _is_authorized(self) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user