From 296882410ee8d45e31a4461c99a75c00d509fea9 Mon Sep 17 00:00:00 2001 From: lovetox Date: Thu, 18 Aug 2022 07:14:41 +0200 Subject: Initial --- gajim/common/setting_values.py | 15 +++++-- gajim/common/settings.py | 31 +++++++++++--- gajim/gtk/chat_list.py | 94 +++++++++++++++++++++++++++++++++++------- gajim/gtk/chat_list_stack.py | 22 +++++++--- gajim/gtk/chat_page.py | 13 +++--- 5 files changed, 141 insertions(+), 34 deletions(-) diff --git a/gajim/common/setting_values.py b/gajim/common/setting_values.py index f18d10f28..d3f71b40b 100644 --- a/gajim/common/setting_values.py +++ b/gajim/common/setting_values.py @@ -508,15 +508,24 @@ StringWorkspaceSettings = Literal[ AllWorkspaceSettings = Literal[StringWorkspaceSettings, 'open_chats'] -OpenChatSettingT = list[tuple[str, JID, str, bool]] -AllWorkspaceSettingsT = Union[str, OpenChatSettingT] + +class OpenChatSettingDetails(TypedDict): + account: str + jid: JID + type: str + pinned: bool + position: int + + +OpenChatsSettingT = list[OpenChatSettingDetails] +AllWorkspaceSettingsT = Union[str, OpenChatsSettingT] class WorkspaceSettings(TypedDict): name: str color: str avatar_sha: str - open_chats: OpenChatSettingT + open_chats: OpenChatsSettingT WORKSPACE_SETTINGS: WorkspaceSettings = { diff --git a/gajim/common/settings.py b/gajim/common/settings.py index 43bba70bb..f1a05a390 100644 --- a/gajim/common/settings.py +++ b/gajim/common/settings.py @@ -56,7 +56,7 @@ from gajim.common.setting_values import IntGroupChatSettings from gajim.common.setting_values import StringGroupChatSettings from gajim.common.setting_values import AllWorkspaceSettings from gajim.common.setting_values import AllWorkspaceSettingsT -from gajim.common.setting_values import OpenChatSettingT +from gajim.common.setting_values import OpenChatsSettingT from gajim.common.setting_values import StringWorkspaceSettings from gajim.common.setting_values import ACCOUNT_SETTINGS from gajim.common.setting_values import PROXY_SETTINGS @@ -82,6 +82,8 @@ SETTING_TYPE = Union[bool, int, str, object] log = logging.getLogger('gajim.c.settings') +CURRENT_USER_VERSION = 2 + CREATE_SQL = ''' CREATE TABLE settings ( name TEXT UNIQUE, @@ -100,10 +102,11 @@ CREATE_SQL = ''' INSERT INTO settings(name, settings) VALUES ('plugins', '{}'); INSERT INTO settings(name, settings) VALUES ('workspaces', '%s'); - PRAGMA user_version=1; + PRAGMA user_version=%s; ''' % (json.dumps(STATUS_PRESET_EXAMPLES), json.dumps(PROXY_EXAMPLES), - json.dumps(INITAL_WORKSPACE)) + json.dumps(INITAL_WORKSPACE), + CURRENT_USER_VERSION) _SignalCallable = Callable[[Any, str, Optional[str], Optional[JID]], Any] @@ -217,6 +220,7 @@ class Settings: self._commit() self._migrate_database() self._load_app_overrides() + self._commit() @staticmethod def _setup_installation_defaults() -> None: @@ -310,6 +314,8 @@ class Settings: self._con.close() log.exception('Error') sys.exit() + else: + self._commit_settings('workspaces') def _migrate(self) -> None: version = self._get_user_version() @@ -320,6 +326,21 @@ class Settings: self._settings['workspaces'] = INITAL_WORKSPACE self._set_user_version(1) + if version < 2: + # Migrate open chats tuple to dict + for workspace in self._settings['workspaces'].values(): + open_chats = [] + for open_chat in workspace.get('open_chats', []): + account, jid, type_, pinned = open_chat + open_chats.append({'account': account, + 'jid': jid, + 'type': type_, + 'pinned': pinned, + 'position': -1}) + + workspace['open_chats'] = open_chats + self._set_user_version(2) + def _migrate_old_config(self) -> None: config_file = configpaths.get('CONFIG_FILE') if not config_file.exists(): @@ -1175,7 +1196,7 @@ class Settings: def set_workspace_setting(self, workspace_id: str, setting: Literal['open_chats'], - value: list[tuple[str, JID, str, bool]] + value: OpenChatsSettingT ) -> None: ... @@ -1202,7 +1223,7 @@ class Settings: def get_workspace_setting(self, workspace_id: str, setting: Literal['open_chats'] - ) -> OpenChatSettingT: + ) -> OpenChatsSettingT: ... @overload diff --git a/gajim/gtk/chat_list.py b/gajim/gtk/chat_list.py index 9a0424dfb..e53695a95 100644 --- a/gajim/gtk/chat_list.py +++ b/gajim/gtk/chat_list.py @@ -22,6 +22,7 @@ from typing import Union import logging import time import pickle +import operator from gi.repository import Gio from gi.repository import Gdk @@ -47,6 +48,7 @@ from gajim.common.helpers import message_needs_highlight from gajim.common.helpers import AdditionalDataDict from gajim.common.preview_helpers import filename_from_uri from gajim.common.preview_helpers import guess_simple_file_type +from gajim.common.setting_values import OpenChatsSettingT from gajim.common.types import ChatContactT from gajim.common.types import OneOnOneContactT from gajim.common.modules.contacts import BareContact @@ -73,6 +75,7 @@ class ChatList(Gtk.ListBox, EventHelper): self._chats: dict[tuple[str, JID], Any] = {} self._current_filter: str = 'all' self._current_filter_text: str = '' + self._chat_order: dict[tuple[str, JID], int] = {} self.get_style_context().add_class('chatlist') self.set_filter_func(self._filter_func) @@ -198,9 +201,11 @@ class ChatList(Gtk.ListBox, EventHelper): log.debug('Mouseover active, don’t sort rows') return 0 - # Don’t sort pinned rows themselves + # Sort pinned rows according to stored order if row1.is_pinned and row2.is_pinned: - return 0 + if row1.position > row2.position: + return 1 + return -1 # Sort pinned rows to top if row1.is_pinned > row2.is_pinned: @@ -250,14 +255,29 @@ class ChatList(Gtk.ListBox, EventHelper): return row.type return None - def add_chat(self, account: str, jid: JID, type_: str, - pinned: bool = False) -> None: - if self._chats.get((account, jid)) is not None: + def add_chat(self, + account: str, + jid: JID, + type_: str, + pinned: bool, + position: int + ) -> None: + + key = (account, jid) + if self._chats.get(key) is not None: # Chat is already in the List return - row = ChatRow(self._workspace_id, account, jid, type_, pinned) - self._chats[(account, jid)] = row + row = ChatRow(self._workspace_id, + account, + jid, + type_, + pinned, + self._chat_order) + + self._chat_order[key] = position + self._chats[key] = row + self.add(row) def select_chat(self, account: str, jid: JID) -> None: @@ -335,8 +355,12 @@ class ChatList(Gtk.ListBox, EventHelper): row.toggle_pinned() self.invalidate_sort() - def remove_chat(self, account: str, jid: JID, - emit_unread: bool = True) -> None: + def remove_chat(self, + account: str, + jid: JID, + emit_unread: bool = True + ) -> None: + row = self._chats.pop((account, jid)) self.remove(row) row.destroy() @@ -359,10 +383,15 @@ class ChatList(Gtk.ListBox, EventHelper): def contains_chat(self, account: str, jid: JID) -> bool: return self._chats.get((account, jid)) is not None - def get_open_chats(self) -> list[tuple[str, JID, str, bool]]: - open_chats: list[tuple[str, JID, str, bool]] = [] - for key, value in self._chats.items(): - open_chats.append(key + (value.type, value.is_pinned)) + def get_open_chats(self) -> OpenChatsSettingT: + open_chats: OpenChatsSettingT = [] + for key, row in self._chats.items(): + account, jid = key + open_chats.append({'account': account, + 'jid': jid, + 'type': row.type, + 'pinned': row.is_pinned, + 'position': row.position}) return open_chats def update_time(self) -> None: @@ -534,16 +563,47 @@ class ChatList(Gtk.ListBox, EventHelper): for row in rows: row.update_name() + def _change_pinned_order(self, + row: ChatRow, + row_after: Optional[ChatRow]) -> None: + + # Make list ordered by position of tuple[account, JID] + order = [item[0] for item in sorted(self._chat_order.items(), + key=operator.itemgetter(1))] + + key = (row.account, row.jid) + + order.remove(key) + if row_after is None or not row_after.is_pinned: + order.append(key) + else: + pos = order.index((row_after.account, row_after.jid)) + order.insert(pos, key) + + self._chat_order.clear() + for pos, value in enumerate(order): + self._chat_order[value] = pos + + self.invalidate_sort() + class ChatRow(Gtk.ListBoxRow): - def __init__(self, workspace_id: str, account: str, jid: JID, type_: str, - pinned: bool) -> None: + def __init__(self, + workspace_id: str, + account: str, + jid: JID, + type_: str, + pinned: bool, + position: dict[tuple[str, JID], int] + ) -> None: + Gtk.ListBoxRow.__init__(self) self.account = account self.jid = jid self.workspace_id = workspace_id self.type = type_ + self._position = position self.active_label = ActiveHeader() self.conversations_label = ConversationsHeader() @@ -705,6 +765,10 @@ class ChatRow(Gtk.ListBoxRow): def is_pinned(self) -> bool: return self._pinned + @property + def position(self) -> int: + return self._position.get((self.account, self.jid), -1) + def _on_button_press(self, _widget: Gtk.Widget, event: Gdk.EventButton diff --git a/gajim/gtk/chat_list_stack.py b/gajim/gtk/chat_list_stack.py index 117a9f197..9e216349f 100644 --- a/gajim/gtk/chat_list_stack.py +++ b/gajim/gtk/chat_list_stack.py @@ -161,8 +161,10 @@ class ChatListStack(Gtk.Stack, EventHelper): def remove_chat_list(self, workspace_id: str) -> None: chat_list = self._chat_lists[workspace_id] self.remove(chat_list) - for account, jid, _type, _pinned in chat_list.get_open_chats(): - self.remove_chat(workspace_id, account, jid) + for open_chat in chat_list.get_open_chats(): + self.remove_chat(workspace_id, + open_chat['account'], + open_chat['jid']) self._chat_lists.pop(workspace_id) chat_list.destroy() @@ -187,12 +189,19 @@ class ChatListStack(Gtk.Stack, EventHelper): self.set_visible_child_name(workspace_id) - def add_chat(self, workspace_id: str, account: str, jid: JID, type_: str, - pinned: bool = False) -> None: + def add_chat(self, + workspace_id: str, + account: str, + jid: JID, + type_: str, + pinned: bool, + position: int + ) -> None: + chat_list = self._chat_lists.get(workspace_id) if chat_list is None: chat_list = self.add_chat_list(workspace_id) - chat_list.add_chat(account, jid, type_, pinned) + chat_list.add_chat(account, jid, type_, pinned, position) def select_chat(self, account: str, jid: JID) -> None: chat_list = self.find_chat(account, jid) @@ -235,7 +244,8 @@ class ChatListStack(Gtk.Stack, EventHelper): current_chatlist.remove_chat(params.account, params.jid) new_chatlist = self.get_chatlist(workspace_id) - new_chatlist.add_chat(params.account, params.jid, type_) + new_chatlist.add_chat(params.account, params.jid, type_, False, -1) + self.store_open_chats(current_chatlist.workspace_id) self.store_open_chats(workspace_id) diff --git a/gajim/gtk/chat_page.py b/gajim/gtk/chat_page.py index ec9cdee17..63f99583a 100644 --- a/gajim/gtk/chat_page.py +++ b/gajim/gtk/chat_page.py @@ -221,6 +221,7 @@ class ChatPage(Gtk.Box): jid: JID, type_: str, pinned: bool = False, + position: int = -1, select: bool = False) -> None: client = app.get_client(account) @@ -240,7 +241,7 @@ class ChatPage(Gtk.Box): return self._chat_list_stack.add_chat(workspace_id, account, jid, type_, - pinned) + pinned, position) if self._startup_finished: if select: @@ -252,15 +253,17 @@ class ChatPage(Gtk.Box): 'open_chats') active_accounts = app.settings.get_active_accounts() - for account, jid, type_, pinned in open_chats: + for open_chat in open_chats: + account = open_chat['account'] if account not in active_accounts: continue self.add_chat_for_workspace(workspace_id, account, - jid, - type_, - pinned=pinned) + open_chat['jid'], + open_chat['type'], + pinned=open_chat['pinned'], + position=open_chat['position']) def is_chat_active(self, account: str, jid: JID) -> bool: return self._chat_list_stack.is_chat_active(account, jid) -- cgit v1.2.3