Implement replying to event in backend

This commit is contained in:
miruka 2020-05-20 06:17:14 -04:00
parent aa8d3cf8d3
commit fb35a6ec14
7 changed files with 68 additions and 13 deletions

View File

@ -53,6 +53,18 @@ else:
CryptDict = Dict[str, Any]
REPLY_FALLBACK = (
"<mx-reply>"
"<blockquote>"
'<a href="https://matrix.to/#/{room_id}/{event_id}">In reply to</a> '
'<a href="https://matrix.to/#/{user_id}">{user_id}</a>'
"<br>"
"{content}"
"</blockquote>"
"</mx-reply>"
"{reply_content}"
)
class UploadReturn(NamedTuple):
"""Details for an uploaded file."""
@ -380,7 +392,9 @@ class MatrixClient(nio.AsyncClient):
return {**self.invited_rooms, **self.rooms}
async def send_text(self, room_id: str, text: str) -> None:
async def send_text(
self, room_id: str, text: str, reply_to_event_id: Optional[str] = None,
) -> None:
"""Send a markdown `m.text` or `m.notice` (with `/me`) message ."""
from_md = partial(HTML.from_markdown, room_id=room_id)
@ -390,6 +404,8 @@ class MatrixClient(nio.AsyncClient):
escape = True
text = text[1:]
content: Dict[str, Any]
if text.startswith("/me ") and not escape:
event_type = nio.RoomMessageEmote
text = text[len("/me "): ]
@ -406,6 +422,30 @@ class MatrixClient(nio.AsyncClient):
content["format"] = "org.matrix.custom.html"
content["formatted_body"] = to_html
if reply_to_event_id:
to: Event = \
self.models[self.user_id, room_id, "events"][reply_to_event_id]
content["format"] = "org.matrix.custom.html"
content["body"] = f"> <{to.sender_id}> {to.origin_body}"
to_html = REPLY_FALLBACK.format(
room_id = room_id,
event_id = reply_to_event_id,
user_id = to.sender_id,
content =
to.origin_formatted_body or html.escape(to.origin_body),
reply_content = to_html,
)
echo_body = HTML.filter(to_html)
content["formatted_body"] = HTML.filter(to_html, outgoing=True)
content["m.relates_to"] = {
"m.in_reply_to": { "event_id": reply_to_event_id },
}
# Can't use the standard Matrix transaction IDs; they're only visible
# to the sender so our other accounts wouldn't be able to replace
# local echoes by real messages.
@ -414,7 +454,13 @@ class MatrixClient(nio.AsyncClient):
mentions = HTML.mentions_in_html(echo_body)
await self._local_echo(
room_id, tx_id, event_type, content=echo_body, mentions=mentions,
room_id,
tx_id,
event_type,
content = echo_body,
mentions = mentions,
origin_body = content["body"],
origin_formatted_body = content.get("formatted_body") or "",
)
await self._send_message(room_id, content, tx_id)
@ -650,7 +696,8 @@ class MatrixClient(nio.AsyncClient):
room_id,
transaction_id,
event_type,
inline_content = path.name,
inline_content = content["body"],
origin_body = content["body"],
media_url = url,
media_title = path.name,
media_width = content["info"].get("w", 0),
@ -1389,6 +1436,10 @@ class MatrixClient(nio.AsyncClient):
target_name = target_name,
target_avatar = target_avatar,
links = Event.parse_links(content),
origin_body = getattr(ev, "body", "") or "",
origin_formatted_body = getattr(ev, "formatted_body", "") or "",
fetch_profile =
(must_fetch_sender or must_fetch_target)
if override_fetch_profile is None else

View File

@ -219,11 +219,13 @@ class Event(ModelItem):
sender_avatar: str = field()
fetch_profile: bool = False
content: str = ""
inline_content: str = ""
reason: str = ""
links: List[str] = field(default_factory=list)
mentions: List[Tuple[str, str]] = field(default_factory=list)
origin_body: str = ""
origin_formatted_body: str = ""
content: str = ""
inline_content: str = ""
reason: str = ""
links: List[str] = field(default_factory=list)
mentions: List[Tuple[str, str]] = field(default_factory=list)
type_specifier: TypeSpecifier = TypeSpecifier.Unset

View File

@ -22,6 +22,7 @@ Item {
property bool ready: Boolean(userInfo && roomInfo)
property bool longLoading: false
property string replyToEventId: ""
property string replyToUserId: ""
property string replyToDisplayName: ""

View File

@ -69,9 +69,11 @@ HColumnPage {
}
ReplyBar {
replyToEventId: chat.replyToEventId
replyToUserId: chat.replyToUserId
replyToDisplayName: chat.replyToDisplayName
onCancel: {
chat.replyToEventId = ""
chat.replyToUserId = ""
chat.replyToDisplayName = ""
}

View File

@ -188,7 +188,7 @@ Rectangle {
if (textArea.text === "") { return }
const args = [chat.roomId, toSend]
const args = [chat.roomId, toSend, chat.replyToEventId]
py.callClientCoro(writingUserId, "send_text", args)
area.clear()

View File

@ -9,7 +9,7 @@ InfoBar {
icon.svgName: "reply-to"
label.textFormat: Text.StyledText
label.text:
replyToUserId ?
replyToEventId ?
utils.coloredNameHtml(replyToDisplayName, replyToUserId) :
""
@ -17,6 +17,7 @@ InfoBar {
signal cancel()
property string replyToEventId: ""
property string replyToUserId: ""
property string replyToDisplayName: ""
@ -25,9 +26,6 @@ InfoBar {
backgroundColor: "transparent"
icon.name: "reply-cancel"
icon.color: theme.colors.negativeBackground
// iconItem.small: true
// topPadding: 0
// bottomPadding: topPadding
onClicked: cancel()
Layout.fillHeight: true

View File

@ -233,6 +233,7 @@ HColumnLayout {
text: qsTr("Reply")
onTriggered: {
chat.replyToEventId = model.id
chat.replyToUserId = model.sender_id
chat.replyToDisplayName = model.sender_name
}