muc: remove non-deterministic nick colors

This commit is contained in:
mathieui 2021-02-17 21:43:43 +01:00
parent 5a9e143c53
commit ee8a3c1121
9 changed files with 42 additions and 118 deletions

View file

@ -404,9 +404,6 @@ use_bookmarks_method =
# possible values: desc, asc # possible values: desc, asc
#user_list_sort = desc #user_list_sort = desc
# If the chatroom nicks should receive a fixed color based on their text or not
#deterministic_nick_colors = true
# If _nick, nick_, _nick_, nick__ etc. should have the same color as nick # If _nick, nick_, _nick_, nick__ etc. should have the same color as nick
#nick_color_aliases = true #nick_color_aliases = true

View file

@ -343,8 +343,7 @@ MultiUserChat tab commands
are considered identical if they only differ by the presence of one are considered identical if they only differ by the presence of one
ore more **_** character at the beginning or the end. For example ore more **_** character at the beginning or the end. For example
_Foo and Foo___ are considered aliases of the nick Foo) will then _Foo and Foo___ are considered aliases of the nick Foo) will then
always have the specified color, in all MultiUserChat tabs. This is always have the specified color, in all MultiUserChat tabs.
true whatever the value of **deterministic_nick_colors** is.
Use the completion to get a list of all the available color values. Use the completion to get a list of all the available color values.
Use the special color **unset** to remove the attributed color on Use the special color **unset** to remove the attributed color on
@ -428,12 +427,10 @@ MultiUserChat tab commands
Change your nickname in the current room. Change your nickname in the current room.
/recolor /recolor
**Usage:** ``/recolor [random]`` **Usage:** ``/recolor``
Re-assign a color to all the participants in the current Re-assign a color to all the participants in the current room,
room, based on the last time they talked. Use this if the participants if the theme has changed.
currently talking have too many identical colors. If a random argument is
given, the participants will be shuffled before they are assigned a color.
/cycle /cycle
**Usage:** ``/cycle [message]`` **Usage:** ``/cycle [message]``

View file

@ -512,23 +512,14 @@ or the way messages are displayed.
bottom in the list, if set to ``asc``, they will be displayed from bottom in the list, if set to ``asc``, they will be displayed from
bottom to top. bottom to top.
deterministic_nick_colors
**Default value:** ``true``
Use a deterministic algorithm to choose the user colors in chatrooms if
set to ``true``. Otherwise the colors will be picked randomly.
The value of this option affects the behavior of :term:`/recolor`.
nick_color_aliases nick_color_aliases
**Default value:** ``true`` **Default value:** ``true``
Automatically search for color of nick aliases. For example, if nick is Automatically search for color of nick aliases. For example, if nick is
set to red, _nick, nick\_, _nick_, nick\__ etc. will have the same color. set to red, _nick, nick\_, _nick_, nick\__ etc. will have the same color.
Aliases colors are checked first, so that it is still possible to have Aliases colors are checked first, so that it is still possible to have
different colors for nick\_ and nick. different colors for nick\_ and nick.
vertical_tab_list_size vertical_tab_list_size

View file

@ -49,7 +49,6 @@ DEFAULT_CONFIG = {
'custom_port': '', 'custom_port': '',
'default_nick': '', 'default_nick': '',
'default_muc_service': '', 'default_muc_service': '',
'deterministic_nick_colors': True,
'device_id': '', 'device_id': '',
'nick_color_aliases': True, 'nick_color_aliases': True,
'display_activity_notifications': False, 'display_activity_notifications': False,

View file

@ -329,7 +329,6 @@ class Core:
('connection_check_interval', self.xmpp.set_keepalive_values), ('connection_check_interval', self.xmpp.set_keepalive_values),
('connection_timeout_delay', self.xmpp.set_keepalive_values), ('connection_timeout_delay', self.xmpp.set_keepalive_values),
('create_gaps', self.on_gaps_config_change), ('create_gaps', self.on_gaps_config_change),
('deterministic_nick_colors', self.on_nick_determinism_changed),
('enable_carbons', self.on_carbons_switch), ('enable_carbons', self.on_carbons_switch),
('enable_vertical_tab_list', ('enable_vertical_tab_list',
self.on_vertical_tab_list_config_change), self.on_vertical_tab_list_config_change),
@ -441,14 +440,6 @@ class Core:
""" """
self.xmpp.password = value self.xmpp.password = value
def on_nick_determinism_changed(self, option, value):
"""If we change the value to true, we call /recolor on all the MucTabs, to
make the current nick colors reflect their deterministic value.
"""
if value.lower() == "true":
for tab in self.get_tabs(tabs.MucTab):
tab.command_recolor('')
def on_carbons_switch(self, option, value): def on_carbons_switch(self, option, value):
"""Whenever the user enables or disables carbons using /set, we should """Whenever the user enables or disables carbons using /set, we should
inform the server immediately, this way we do not require a restart inform the server immediately, this way we do not require a restart

View file

@ -48,7 +48,6 @@ def make_line(
time: datetime, time: datetime,
jid: JID, jid: JID,
identifier: str = '', identifier: str = '',
deterministic: bool = True,
) -> Message: ) -> Message:
"""Adds a textual entry in the TextBuffer""" """Adds a textual entry in the TextBuffer"""
@ -59,22 +58,17 @@ def make_line(
if isinstance(tab, tabs.MucTab): if isinstance(tab, tabs.MucTab):
nick = jid.resource nick = jid.resource
user = tab.get_user_by_name(nick) user = tab.get_user_by_name(nick)
if deterministic: if user:
if user: color = user.color
color = user.color
else:
theme = get_theme()
if theme.ccg_palette:
fg_color = colors.ccg_text_to_color(theme.ccg_palette, nick)
color = fg_color, -1
else:
mod = len(theme.LIST_COLOR_NICKNAMES)
nick_pos = int(md5(nick.encode('utf-8')).hexdigest(), 16) % mod
color = theme.LIST_COLOR_NICKNAMES[nick_pos]
else: else:
color = random.choice(list(xhtml.colors)) theme = get_theme()
color = xhtml.colors.get(color) if theme.ccg_palette:
color = (color, -1) fg_color = colors.ccg_text_to_color(theme.ccg_palette, nick)
color = fg_color, -1
else:
mod = len(theme.LIST_COLOR_NICKNAMES)
nick_pos = int(md5(nick.encode('utf-8')).hexdigest(), 16) % mod
color = theme.LIST_COLOR_NICKNAMES[nick_pos]
else: else:
if jid.bare == tab.core.xmpp.boundjid.bare: if jid.bare == tab.core.xmpp.boundjid.bare:
nick = tab.core.own_nick nick = tab.core.own_nick
@ -144,21 +138,16 @@ async def retrieve_messages(tab: tabs.ChatTab,
results: AsyncIterable[SMessage], results: AsyncIterable[SMessage],
amount: int = 100) -> List[BaseMessage]: amount: int = 100) -> List[BaseMessage]:
"""Run the MAM query and put messages in order""" """Run the MAM query and put messages in order"""
text_buffer = tab._text_buffer
msg_count = 0 msg_count = 0
msgs = [] msgs = []
to_add = [] to_add = []
deterministic = config.get_by_tabname(
'deterministic_nick_colors',
tab.jid.bare
)
try: try:
async for rsm in results: async for rsm in results:
for msg in rsm['mam']['results']: for msg in rsm['mam']['results']:
if msg['mam_result']['forwarded']['stanza'] \ if msg['mam_result']['forwarded']['stanza'] \
.xml.find('{%s}%s' % ('jabber:client', 'body')) is not None: .xml.find('{%s}%s' % ('jabber:client', 'body')) is not None:
args = _parse_message(msg) args = _parse_message(msg)
msgs.append(make_line(tab, deterministic=deterministic, **args)) msgs.append(make_line(tab, **args))
for msg in reversed(msgs): for msg in reversed(msgs):
to_add.append(msg) to_add.append(msg)
msg_count += 1 msg_count += 1

View file

@ -380,37 +380,15 @@ class MucTab(ChatTab):
) )
@refresh_wrapper.always @refresh_wrapper.always
def recolor(self, random_colors: bool = False) -> None: def recolor(self) -> None:
"""Recolor the current MUC users""" """Recolor the current MUC users"""
deterministic = config.get_by_tabname('deterministic_nick_colors', for user in self.users:
self.jid.bare)
if deterministic:
for user in self.users:
if user is self.own_user:
continue
color = self.search_for_color(user.nick)
if color != '':
continue
user.set_deterministic_color()
return
# Sort the user list by last talked, to avoid color conflicts
# on active participants
sorted_users = sorted(self.users, key=COMPARE_USERS_LAST_TALKED, reverse=True)
full_sorted_users = sorted_users[:]
# search our own user, to remove it from the list
# Also remove users whose color is fixed
for user in full_sorted_users:
color = self.search_for_color(user.nick)
if user is self.own_user: if user is self.own_user:
sorted_users.remove(user) continue
elif color != '': color = self.search_for_color(user.nick)
sorted_users.remove(user) if color != '':
user.change_color(color, deterministic) continue
colors = list(get_theme().LIST_COLOR_NICKNAMES) user.set_deterministic_color()
if random_colors:
random.shuffle(colors)
for i, user in enumerate(sorted_users):
user.color = colors[i % len(colors)]
self.text_win.rebuild_everything(self._text_buffer) self.text_win.rebuild_everything(self._text_buffer)
@refresh_wrapper.conditional @refresh_wrapper.conditional
@ -527,16 +505,13 @@ class MucTab(ChatTab):
""" """
Batch-process all the initial presences Batch-process all the initial presences
""" """
deterministic = config.get_by_tabname('deterministic_nick_colors',
self.jid.bare)
for stanza in self.presence_buffer: for stanza in self.presence_buffer:
try: try:
self.handle_presence_unjoined(stanza, deterministic) self.handle_presence_unjoined(stanza)
except PresenceError: except PresenceError:
self.core.room_error(stanza, stanza['from'].bare) self.core.room_error(stanza, stanza['from'].bare)
self.presence_buffer = [] self.presence_buffer = []
self.handle_presence_unjoined(last_presence, deterministic, own) self.handle_presence_unjoined(last_presence, own)
self.users.sort() self.users.sort()
# Enable the self ping event, to regularly check if we # Enable the self ping event, to regularly check if we
# are still in the room. # are still in the room.
@ -547,7 +522,7 @@ class MucTab(ChatTab):
self.core.tabs.current_tab.refresh_input() self.core.tabs.current_tab.refresh_input()
self.core.doupdate() self.core.doupdate()
def handle_presence_unjoined(self, presence: Presence, deterministic: bool, own: bool = False) -> None: def handle_presence_unjoined(self, presence: Presence, own: bool = False) -> None:
""" """
Presence received while we are not in the room (before code=110) Presence received while we are not in the room (before code=110)
""" """
@ -560,7 +535,7 @@ class MucTab(ChatTab):
return return
user_color = self.search_for_color(from_nick) user_color = self.search_for_color(from_nick)
new_user = User(from_nick, affiliation, show, status, role, jid, new_user = User(from_nick, affiliation, show, status, role, jid,
deterministic, user_color) user_color)
self.users.append(new_user) self.users.append(new_user)
self.core.events.trigger('muc_join', presence, self) self.core.events.trigger('muc_join', presence, self)
if own: if own:
@ -710,10 +685,8 @@ class MucTab(ChatTab):
""" """
When a new user joins the groupchat When a new user joins the groupchat
""" """
deterministic = config.get_by_tabname('deterministic_nick_colors',
self.jid.bare)
user = User(from_nick, affiliation, show, status, role, jid, user = User(from_nick, affiliation, show, status, role, jid,
deterministic, color) color)
bisect.insort_left(self.users, user) bisect.insort_left(self.users, user)
hide_exit_join = config.get_by_tabname('hide_exit_join', hide_exit_join = config.get_by_tabname('hide_exit_join',
self.general_jid) self.general_jid)
@ -763,11 +736,8 @@ class MucTab(ChatTab):
user.change_nick(new_nick) user.change_nick(new_nick)
else: else:
user.change_nick(new_nick) user.change_nick(new_nick)
deterministic = config.get_by_tabname('deterministic_nick_colors',
self.jid.bare)
color = config.get_by_tabname(new_nick, 'muc_colors') or None color = config.get_by_tabname(new_nick, 'muc_colors') or None
if color or deterministic: user.change_color(color)
user.change_color(color, deterministic)
self.users.remove(user) self.users.remove(user)
bisect.insort_left(self.users, user) bisect.insort_left(self.users, user)
@ -2169,12 +2139,11 @@ class MucTab(ChatTab):
'func': 'func':
self.command_recolor, self.command_recolor,
'usage': 'usage':
'[random]', '',
'desc': ('Re-assign a color to all participants of the' 'desc': (
' current room, based on the last time they talked.' 'Re-assign a color to all participants of the room '
' Use this if the participants currently talking ' 'if the theme has changed.'
'have too many identical colors. Use /recolor random' ),
' for a non-deterministic result.'),
'shortdesc': 'shortdesc':
'Change the nicks colors.', 'Change the nicks colors.',
'completion': 'completion':

View file

@ -38,7 +38,6 @@ class User:
status: str, status: str,
role: str, role: str,
jid: JID, jid: JID,
deterministic=True,
color='') -> None: color='') -> None:
# The oldest possible time # The oldest possible time
self.last_talked: datetime = datetime(1, 1, 1) self.last_talked: datetime = datetime(1, 1, 1)
@ -48,12 +47,9 @@ class User:
self.chatstate: Optional[str] = None self.chatstate: Optional[str] = None
self.color: Tuple[int, int] = (1, 1) self.color: Tuple[int, int] = (1, 1)
if color != '': if color != '':
self.change_color(color, deterministic) self.change_color(color)
else: else:
if deterministic: self.set_deterministic_color()
self.set_deterministic_color()
else:
self.color = choice(get_theme().LIST_COLOR_NICKNAMES)
def set_deterministic_color(self) -> None: def set_deterministic_color(self) -> None:
theme = get_theme() theme = get_theme()
@ -82,14 +78,10 @@ class User:
def change_nick(self, nick: str): def change_nick(self, nick: str):
self.nick = nick self.nick = nick
def change_color(self, color_name: Optional[str], deterministic=False): def change_color(self, color_name: Optional[str]):
color = xhtml.colors.get(color_name or '') color = xhtml.colors.get(color_name or '')
if color is None: if color is None:
if deterministic: self.set_deterministic_color()
self.set_deterministic_color()
else:
log.error('Unknown color "%s"', color_name)
self.color = choice(get_theme().LIST_COLOR_NICKNAMES)
else: else:
self.color = (color, -1) self.color = (color, -1)

View file

@ -17,7 +17,6 @@ def user1():
'My Status!', 'My Status!',
'moderator', 'moderator',
JID('foo@muc/nick1'), JID('foo@muc/nick1'),
False,
'red', 'red',
) )
@ -41,5 +40,5 @@ def test_change_nick(user1):
def test_change_color(user1): def test_change_color(user1):
user1.change_color('blue', deterministic=False) user1.change_color('blue')
assert user1.color == (21, -1) assert user1.color == (21, -1)