aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrygve Aaberge <trygveaa@gmail.com>2023-10-19 22:09:30 +0200
committerTrygve Aaberge <trygveaa@gmail.com>2024-02-18 11:32:54 +0100
commit20fcca5f2ccbd7b524908d11d14a9ce8f33c2dd6 (patch)
tree3e1cdff1ebcc3342fce8f916ba577d4a058b3eb6
parent6eac18fb0080132e42285b0976205d2bb6d36848 (diff)
downloadwee-slack-20fcca5f2ccbd7b524908d11d14a9ce8f33c2dd6.tar.gz
Show user status in DM buffer title
-rw-r--r--slack/slack_conversation.py16
-rw-r--r--slack/slack_emoji.py29
-rw-r--r--slack/slack_message.py30
-rw-r--r--slack/slack_user.py18
-rw-r--r--slack/slack_workspace.py7
-rw-r--r--typings/slack_api/slack_users_info.pyi2
-rw-r--r--typings/slack_rtm/slack_rtm_message.pyi9
7 files changed, 78 insertions, 33 deletions
diff --git a/slack/slack_conversation.py b/slack/slack_conversation.py
index 257796a..351d24d 100644
--- a/slack/slack_conversation.py
+++ b/slack/slack_conversation.py
@@ -188,6 +188,11 @@ class SlackConversation(SlackBuffer):
def muted(self) -> bool:
return self.id in self.workspace.muted_channels
+ @property
+ def im_user_id(self) -> Optional[str]:
+ if self.type == "im":
+ return self._info.get("user")
+
async def sort_key(self) -> str:
type_sort_key = {
"channel": 0,
@@ -248,9 +253,14 @@ class SlackConversation(SlackBuffer):
return True
return False
- def buffer_title(self) -> str:
+ async def buffer_title(self) -> str:
# TODO: unfurl and apply styles
- return unhtmlescape(self._info.get("topic", {}).get("value", ""))
+ topic = unhtmlescape(self._info.get("topic", {}).get("value", ""))
+ if self.im_user_id:
+ user = await self.workspace.users[self.im_user_id]
+ status = f"{user.status_emoji} {user.status_text}".strip()
+ return " | ".join(part for part in [status, topic] if part)
+ return topic
async def set_topic(self, title: str):
if "topic" not in self._info:
@@ -269,7 +279,7 @@ class SlackConversation(SlackBuffer):
return name, {
"short_name": short_name,
- "title": self.buffer_title(),
+ "title": await self.buffer_title(),
"input_multiline": "1",
"nicklist": "0" if self.type == "im" else "1",
"nicklist_display_groups": "0",
diff --git a/slack/slack_emoji.py b/slack/slack_emoji.py
index d6247c3..e3d898b 100644
--- a/slack/slack_emoji.py
+++ b/slack/slack_emoji.py
@@ -2,15 +2,16 @@ from __future__ import annotations
import json
import os
-from typing import TYPE_CHECKING, Dict
+from typing import TYPE_CHECKING, Dict, Optional
import weechat
from slack.error import store_and_format_exception
from slack.log import print_error
+from slack.shared import shared
if TYPE_CHECKING:
- from typing_extensions import NotRequired, TypedDict
+ from typing_extensions import NotRequired, TypedDict, assert_never
class EmojiSkinVariation(TypedDict):
name: str
@@ -58,3 +59,27 @@ def load_standard_emojis() -> Dict[str, Emoji]:
except Exception as e:
print_error(f"couldn't read weemoji.json: {store_and_format_exception(e)}")
return {}
+
+
+def get_emoji(emoji_name: str, skin_tone: Optional[int] = None) -> str:
+ emoji_name_with_colons = f":{emoji_name}:"
+ if shared.config.look.render_emoji_as.value == "name":
+ return emoji_name_with_colons
+
+ emoji_item = shared.standard_emojis.get(emoji_name)
+ if emoji_item is None:
+ return emoji_name_with_colons
+
+ skin_tone_item = (
+ emoji_item.get("skinVariations", {}).get(str(skin_tone)) if skin_tone else None
+ )
+ emoji_unicode = (
+ skin_tone_item["unicode"] if skin_tone_item else emoji_item["unicode"]
+ )
+
+ if shared.config.look.render_emoji_as.value == "emoji":
+ return emoji_unicode
+ elif shared.config.look.render_emoji_as.value == "both":
+ return f"{emoji_unicode}({emoji_name_with_colons})"
+ else:
+ assert_never(shared.config.look.render_emoji_as.value)
diff --git a/slack/slack_message.py b/slack/slack_message.py
index 438166f..2ac30e4 100644
--- a/slack/slack_message.py
+++ b/slack/slack_message.py
@@ -18,6 +18,7 @@ from slack.error import (
from slack.log import print_error
from slack.python_compatibility import removeprefix, removesuffix
from slack.shared import shared
+from slack.slack_emoji import get_emoji
from slack.slack_user import SlackBot, SlackUser, format_bot_nick, nick_color
from slack.task import gather
from slack.util import htmlescape, intersperse, unhtmlescape, with_color
@@ -796,31 +797,6 @@ class SlackMessage:
else:
yield item
- def _get_emoji(self, emoji_name: str, skin_tone: Optional[int] = None) -> str:
- emoji_name_with_colons = f":{emoji_name}:"
- if shared.config.look.render_emoji_as.value == "name":
- return emoji_name_with_colons
-
- emoji_item = shared.standard_emojis.get(emoji_name)
- if emoji_item is None:
- return emoji_name_with_colons
-
- skin_tone_item = (
- emoji_item.get("skinVariations", {}).get(str(skin_tone))
- if skin_tone
- else None
- )
- emoji_unicode = (
- skin_tone_item["unicode"] if skin_tone_item else emoji_item["unicode"]
- )
-
- if shared.config.look.render_emoji_as.value == "emoji":
- return emoji_unicode
- elif shared.config.look.render_emoji_as.value == "both":
- return f"{emoji_unicode}({emoji_name_with_colons})"
- else:
- assert_never(shared.config.look.render_emoji_as.value)
-
async def _create_reaction_string(self, reaction: SlackMessageReaction) -> str:
if self.conversation.display_reaction_nicks():
users = await gather(
@@ -832,7 +808,7 @@ class SlackMessage:
users_str = ""
reaction_string = (
- f"{self._get_emoji(reaction['name'])}{len(reaction['users'])}{users_str}"
+ f"{get_emoji(reaction['name'])}{len(reaction['users'])}{users_str}"
)
if self.workspace.my_user.id in reaction["users"]:
@@ -1063,7 +1039,7 @@ class SlackMessage:
else:
return element["url"]
elif element["type"] == "emoji":
- return self._get_emoji(element["name"], element.get("skin_tone"))
+ return get_emoji(element["name"], element.get("skin_tone"))
elif element["type"] == "channel":
return PendingMessageItem(self, "conversation", element["channel_id"])
elif element["type"] == "user":
diff --git a/slack/slack_user.py b/slack/slack_user.py
index 4e2ceae..f081f1c 100644
--- a/slack/slack_user.py
+++ b/slack/slack_user.py
@@ -6,6 +6,7 @@ import weechat
from slack.error import SlackError
from slack.shared import shared
+from slack.slack_emoji import get_emoji
from slack.util import with_color
if TYPE_CHECKING:
@@ -71,6 +72,17 @@ class SlackUser:
def is_external(self) -> bool:
return self._info["profile"]["team"] != self.workspace.id
+ @property
+ def status_text(self) -> str:
+ return self._info["profile"].get("status_text", "") or ""
+
+ @property
+ def status_emoji(self) -> str:
+ status_emoji = self._info["profile"].get("status_emoji")
+ if not status_emoji:
+ return ""
+ return get_emoji(status_emoji.strip(":"))
+
def nick(self, colorize: bool = False, only_nick: bool = False) -> str:
nick = self._name_without_spaces()
@@ -93,6 +105,12 @@ class SlackUser:
return nick_color(self._name_without_spaces())
+ def update_info_json(self, info_json: SlackUserInfo):
+ self._info.update(info_json) # pyright: ignore [reportGeneralTypeIssues]
+ self._rendered_prefix = None
+ self._rendered_message = None
+ self._parsed_message = None
+
class SlackBot:
def __init__(self, workspace: SlackWorkspace, info: SlackBotInfo):
diff --git a/slack/slack_workspace.py b/slack/slack_workspace.py
index bde1b4d..f2cb33a 100644
--- a/slack/slack_workspace.py
+++ b/slack/slack_workspace.py
@@ -350,6 +350,13 @@ class SlackWorkspace:
if channel:
await channel.update_buffer_props()
return
+ elif data["type"] == "user_status_changed":
+ user = await self.users[data["user"]["id"]]
+ user.update_info_json(data["user"])
+ for conversation in self.open_conversations.values():
+ if conversation.im_user_id == user.id:
+ await conversation.update_buffer_props()
+ return
elif data["type"] == "reaction_added" or data["type"] == "reaction_removed":
channel_id = data["item"]["channel"]
elif (
diff --git a/typings/slack_api/slack_users_info.pyi b/typings/slack_api/slack_users_info.pyi
index a6a67d9..cd493ed 100644
--- a/typings/slack_api/slack_users_info.pyi
+++ b/typings/slack_api/slack_users_info.pyi
@@ -101,7 +101,7 @@ class SlackUserInfoPerson(SlackUserInfoCommon):
profile: SlackProfilePerson
is_bot: Literal[False]
is_stranger: NotRequired[bool]
- has_2fa: bool
+ has_2fa: NotRequired[bool]
@final
class SlackUserInfoBot(SlackUserInfoCommon):
diff --git a/typings/slack_rtm/slack_rtm_message.pyi b/typings/slack_rtm/slack_rtm_message.pyi
index efb9e6b..fccb6da 100644
--- a/typings/slack_rtm/slack_rtm_message.pyi
+++ b/typings/slack_rtm/slack_rtm_message.pyi
@@ -17,6 +17,7 @@ from slack_api.slack_conversations_history import (
SlackMessageWithFiles,
)
from slack_api.slack_conversations_replies import SlackMessageThreadCommon
+from slack_api.slack_users_info import SlackUserInfoPerson
from typing_extensions import Literal, NotRequired, TypedDict, final
class SlackRtmHello(TypedDict):
@@ -252,6 +253,13 @@ class SlackPrefChange(TypedDict):
name: str
value: str
+@final
+class SlackUserStatusChanged(TypedDict):
+ type: Literal["user_status_changed"]
+ user: SlackUserInfoPerson
+ cache_ts: str
+ event_ts: str
+
SlackMessageRtm = (
SlackMessageStandardRtm
| SlackMessageMeRtm
@@ -288,4 +296,5 @@ SlackRtmMessage = (
| SlackShRoomUpdate
| SlackUserTyping
| SlackPrefChange
+ | SlackUserStatusChanged
)