Merge pull request #35 from paul-nameless/chats-scrolling

Chats scrolling
This commit is contained in:
Nameless 2020-05-16 11:27:17 +08:00 committed by GitHub
commit 35ee2b58f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 127 additions and 15 deletions

View file

@ -1,4 +1,5 @@
import logging
from typing import Dict, Any, Optional
import os
import threading
from datetime import datetime
@ -47,7 +48,14 @@ class Controller:
self.tg = tg
self.handlers = {
"updateNewMessage": self.update_new_msg,
"updateMessageContent": self.update_msg_content,
"updateChatIsPinned": self.update_chat_is_pinned,
"updateChatIsMarkedAsUnread": self.update_chat_marked_as_unread,
"updateChatReadInbox": self.update_chat_read_inbox,
"updateChatTitle": self.update_chat_title,
"updateChatLastMessage": self.update_chat_last_msg,
"updateChatDraftMessage": self.update_chat_draft_msg,
"updateChatOrder": self.update_chat_order,
"updateMessageSendSucceeded": self.update_msg_send_succeeded,
"updateFile": self.update_file,
}
@ -278,6 +286,16 @@ class Controller:
)
self.view.msgs.draw(current_msg_idx, msgs, MSGS_LEFT_SCROLL_THRESHOLD)
@handle_exception
def update_msg_content(self, update):
content = MsgProxy(update["new_content"])
chat_id = update["chat_id"]
message_id = update["message_id"]
self.model.msgs.update_msg_content(chat_id, message_id, content)
current_chat_id = self.model.chats.id_by_index(self.model.current_chat)
if current_chat_id == chat_id:
self.refresh_msgs()
@handle_exception
def update_new_msg(self, update):
msg = MsgProxy(update["message"])
@ -289,6 +307,9 @@ class Controller:
if msg.file_id and msg.size <= config.max_download_size:
self.download(msg.file_id, chat_id, msg["id"])
self._notify_for_message(chat_id, msg)
def _notify_for_message(self, chat_id: int, msg: Dict[str, Any]):
# do not notify, if muted
# TODO: optimize
chat = None
@ -318,12 +339,85 @@ class Controller:
notify(text, title=name)
@handle_exception
def update_chat_last_msg(self, update):
def update_chat_order(self, update: Dict[str, Any]):
log.info("Proccessing updateChatOrder")
current_chat_id = self.model.chats.id_by_index(self.model.current_chat)
chat_id = update["chat_id"]
order = update["order"]
self.model.chats.update_chat(chat_id, order=order)
self._refresh_current_chat(current_chat_id)
@handle_exception
def update_chat_title(self, update: Dict[str, Any]):
log.info("Proccessing updateChatTitle")
chat_id = update["chat_id"]
title = update["title"]
current_chat_id = self.model.chats.id_by_index(self.model.current_chat)
self.model.chats.update_chat(chat_id, title=title)
self._refresh_current_chat(current_chat_id)
@handle_exception
def update_chat_marked_as_unread(self, update: Dict[str, Any]):
log.info("Proccessing updateChatIsMarkedAsUnread")
chat_id = update["chat_id"]
is_marked_as_unread = update["is_marked_as_unread"]
current_chat_id = self.model.chats.id_by_index(self.model.current_chat)
self.model.chats.update_chat(
chat_id, is_marked_as_unread=is_marked_as_unread
)
self._refresh_current_chat(current_chat_id)
@handle_exception
def update_chat_is_pinned(self, update: Dict[str, Any]):
log.info("Proccessing updateChatIsPinned")
chat_id = update["chat_id"]
is_pinned = update["is_pinned"]
order = update["order"]
current_chat_id = self.model.chats.id_by_index(self.model.current_chat)
self.model.chats.update_chat(chat_id, is_pinned=is_pinned, order=order)
self._refresh_current_chat(current_chat_id)
@handle_exception
def update_chat_read_inbox(self, update: Dict[str, Any]):
log.info("Proccessing updateChatReadInbox")
chat_id = update["chat_id"]
last_read_inbox_message_id = update["last_read_inbox_message_id"]
unread_count = update["unread_count"]
current_chat_id = self.model.chats.id_by_index(self.model.current_chat)
self.model.chats.update_chat(
chat_id,
last_read_inbox_message_id=last_read_inbox_message_id,
unread_count=unread_count,
)
self._refresh_current_chat(current_chat_id)
@handle_exception
def update_chat_draft_msg(self, update: Dict[str, Any]):
log.info("Proccessing updateChatDraftMessage")
chat_id = update["chat_id"]
# FIXME: ignoring draft message itself for now because UI can't show it
# draft_message = update["draft_message"]
order = update["order"]
current_chat_id = self.model.chats.id_by_index(self.model.current_chat)
self.model.chats.update_chat(chat_id, order=order)
self._refresh_current_chat(current_chat_id)
@handle_exception
def update_chat_last_msg(self, update: Dict[str, Any]):
log.info("Proccessing updateChatLastMessage")
chat_id = update["chat_id"]
message = update["last_message"]
order = update["order"]
current_chat_id = self.model.chats.id_by_index(self.model.current_chat)
self.model.chats.update_last_message(chat_id, message)
self.model.chats.update_chat(
chat_id, last_message=message, order=order
)
self._refresh_current_chat(current_chat_id)
def _refresh_current_chat(self, current_chat_id: Optional[int]):
if current_chat_id is None:
return
# TODO: we can create <index> for chats, it's faster than sqlite anyway
# though need to make sure that creatinng index is atomic operation
# requires locks for read, until index and chats will be the same

View file

@ -174,18 +174,19 @@ class ChatModel:
return {}
return result.update
def update_last_message(self, chat_id, message):
def update_chat(self, chat_id: int, **updates: Dict[str, Any]) -> bool:
for i, c in enumerate(self.chats):
if c["id"] != chat_id:
continue
self.chats[i]["last_message"] = message
self.chats[i].update(updates)
self.chats = sorted(
self.chats,
key=lambda it: it["last_message"]["date"],
# recommended chat order, for more info see
# https://core.telegram.org/tdlib/getting-started#getting-the-lists-of-chats
key=lambda it: (it["order"], it["id"]),
reverse=True,
)
log.info("Updated last message")
log.info(f"Updated chat with keys {list(updates)}")
return True
else:
log.error(f"Can't find chat {chat_id} in existing chats")
@ -232,6 +233,16 @@ class MsgModel:
msg_set.remove(msg_id)
return True
def update_msg_content(
self, chat_id: int, msg_id: int, message_content: Dict[str, Any]
) -> bool:
log.info(f"updating {msg_id=} {message_content=}")
for msg in self.msgs[chat_id]:
if msg["id"] != msg_id:
continue
msg["content"] = message_content
return True
def add_message(self, chat_id: int, message: Dict[str, Any]) -> bool:
msg_id = message["id"]
msg_set = self.msg_ids[chat_id]

View file

@ -145,12 +145,13 @@ class ChatView:
self.win.vline(0, self.w - 1, curses.ACS_VLINE, self.h)
for i, chat in enumerate(chats):
is_selected = i == current
date, title, unread_count, last_msg = (
get_date(chat),
chat["title"],
chat["unread_count"],
get_last_msg(chat),
unread_count = (
chat["unread_count"] or 1 if chat["is_marked_as_unread"] else 0
)
date = get_date(chat)
title = chat["title"]
is_pinned = chat["is_pinned"]
last_msg = get_last_msg(chat)
offset = 0
for attr, elem in zip(
self._msg_attribures(is_selected), [f"{date} ", title]
@ -173,7 +174,9 @@ class ChatView:
self.win.addstr(i, offset, last_msg, self._msg_color(is_selected))
if left_label := self._get_chat_label(unread_count, chat):
if left_label := self._get_chat_label(
unread_count, is_pinned, chat
):
self.win.addstr(
i,
self.w - len(left_label) - 1,
@ -184,10 +187,14 @@ class ChatView:
self._refresh()
@staticmethod
def _get_chat_label(unread_count: int, chat: Dict[str, Any]) -> str:
def _get_chat_label(
unread_count: int, is_pinned: bool, chat: Dict[str, Any]
) -> str:
label = ""
if is_pinned:
label += "pinned "
if unread_count:
label = f"{unread_count} "
label += f"{unread_count} "
if chat["notification_settings"]["mute_for"]:
label = f"muted {label}"