From ad351030d928d012ae557ab9cc140bb950bf70fc Mon Sep 17 00:00:00 2001 From: ingvar1995 Date: Tue, 1 May 2018 21:40:29 +0300 Subject: [PATCH] messenger fixes, refactoring (history) --- toxygen/app.py | 10 +-- toxygen/contacts/contacts_manager.py | 68 ++++++++----------- toxygen/history/history_loader.py | 76 +++++----------------- toxygen/history/history_logs_generators.py | 48 ++++++++++++++ toxygen/messenger/messages.py | 10 +++ toxygen/messenger/messenger.py | 33 ++++++---- toxygen/ui/items_factory.py | 4 +- toxygen/ui/main_screen.py | 33 +++++----- toxygen/ui/widgets_factory.py | 3 +- 9 files changed, 150 insertions(+), 135 deletions(-) create mode 100644 toxygen/history/history_logs_generators.py diff --git a/toxygen/app.py b/toxygen/app.py index 82d1618..53c4dff 100644 --- a/toxygen/app.py +++ b/toxygen/app.py @@ -141,6 +141,8 @@ class App: def _load_app_styles(self): # application color scheme + if self._settings['theme'] == 'dark': + return for theme in self._settings.built_in_themes().keys(): if self._settings['theme'] == theme: with open(curr_directory(__file__) + self._settings.built_in_themes()[theme]) as fl: @@ -294,17 +296,17 @@ class App: self._friend_factory = FriendFactory(self._profile_manager, self._settings, self._tox, db, items_factory) self._contacts_provider = ContactProvider(self._tox, self._friend_factory) widgets_factory = WidgetsFactory(self._settings, profile, self._contacts_manager, self._file_transfer_handler, - self._smiley_loader, self._plugin_loader, self._toxes) + self._smiley_loader, self._plugin_loader, self._toxes, self._version) self._contacts_manager = ContactsManager(self._tox, self._settings, self._ms, self._profile_manager, self._contacts_provider, db) self._messenger = Messenger(self._tox, self._plugin_loader, self._ms, self._contacts_manager, - self._contacts_provider) + self._contacts_provider, items_factory) self._tray = tray.init_tray(profile, self._settings, self._ms) - self._ms.set_dependencies(widgets_factory, self._tray, self._contacts_manager, self._messenger) + self._ms.set_dependencies(widgets_factory, self._tray, self._contacts_manager, self._messenger, profile) self._calls_manager = CallsManager(self._tox.AV, self._settings) self._file_transfer_handler = FileTransfersHandler(self._tox, self._settings, self._contacts_provider) - self._tray.show() + self._tray.show() self._ms.show() # callbacks initialization diff --git a/toxygen/contacts/contacts_manager.py b/toxygen/contacts/contacts_manager.py index 0f7b4bc..e468ecc 100644 --- a/toxygen/contacts/contacts_manager.py +++ b/toxygen/contacts/contacts_manager.py @@ -1,7 +1,6 @@ import util.util as util import util.ui as util_ui from contacts.friend import Friend -import os from PyQt5 import QtCore, QtGui from messenger.messages import * from wrapper.toxcore_enums_and_consts import * @@ -9,10 +8,10 @@ from network.tox_dns import tox_dns from history.history_loader import HistoryLoader -# TODO: move messaging and typing notifications to other class - - class ContactsManager: + """ + Represents contacts list. + """ def __init__(self, tox, settings, screen, profile_manager, contact_provider, db): self._tox = tox @@ -134,12 +133,11 @@ class ContactsManager: # self._screen.call_finished() else: friend = self.get_curr_contact() - + # TODO: to separate method self._screen.account_name.setText(friend.name) self._screen.account_status.setText(friend.status_message) self._screen.account_status.setToolTip(friend.get_full_status()) avatar_path = friend.get_avatar_path() - os.chdir(os.path.dirname(avatar_path)) pixmap = QtGui.QPixmap(avatar_path) self._screen.account_avatar.setPixmap(pixmap.scaled(64, 64, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)) @@ -171,6 +169,7 @@ class ContactsManager: :param sorting: 0 - no sort, 1 - online only, 2 - online first, 4 - by name :param filter_str: show contacts which name contains this substring """ + # TODO: simplify? filter_str = filter_str.lower() number = self.get_active_number() is_friend = self._is_active_a_friend() @@ -196,16 +195,16 @@ class ContactsManager: part1 = sorted(part1, key=lambda x: x.number) part2 = sorted(part2, key=lambda x: x.number) self._contacts = part1 + part2 - self._screen.friends_list.clear() - for contact in self._contacts: - contact.set_widget(self.create_friend_item()) + # self._screen.friends_list.clear() + # for contact in self._contacts: + # contact.set_widget(self.create_friend_item()) for index, friend in enumerate(self._contacts): friend.visibility = (friend.status is not None or not (sorting & 1)) and (filter_str in friend.name.lower()) friend.visibility = friend.visibility or friend.messages or friend.actions - # if friend.visibility: - # self._screen.friends_list.item(index).setSizeHint(QtCore.QSize(250, self._friend_item_height)) - # else: - # self._screen.friends_list.item(index).setSizeHint(QtCore.QSize(250, 0)) + if friend.visibility: + self._screen.friends_list.item(index).setSizeHint(QtCore.QSize(250, self._friend_item_height)) + else: + self._screen.friends_list.item(index).setSizeHint(QtCore.QSize(250, 0)) self._sorting, self._filter_string = sorting, filter_str self._settings['sorting'] = self._sorting self._settings.save() @@ -217,13 +216,6 @@ class ContactsManager: """ self.filtration_and_sorting(self._sorting, self._filter_string) - def _create_friend_item(self): - """ - Method-factory - :return: new widget for friend instance - """ - return self._factory.friend_item() - # ----------------------------------------------------------------------------------------------------------------- # Friend getters # ----------------------------------------------------------------------------------------------------------------- @@ -233,7 +225,7 @@ class ContactsManager: def get_last_message(self): if self._active_contact + 1: - return self.get_current_contact().get_last_message_text() + return self.get_curr_contact().get_last_message_text() else: return '' @@ -241,12 +233,13 @@ class ContactsManager: return self.get_curr_contact().number if self._active_contact + 1 else -1 def get_active_name(self): - return self.get_current_contact().name if self._active_contact + 1 else '' + return self.get_curr_contact().name if self._active_contact + 1 else '' def is_active_online(self): - return self._active_contact + 1 and self.get_current_contact().status is not None + return self._active_contact + 1 and self.get_curr_contact().status is not None def new_name(self, number, name): + # TODO: move to somewhere else? friend = self.get_friend_by_number(number) tmp = friend.name friend.set_name(name) @@ -254,7 +247,7 @@ class ContactsManager: if friend.name == name and tmp != name: message = util_ui.tr('User {} is now known as {}') message = message.format(tmp, name) - friend.append_message(InfoMessage(message, time.time())) + friend.append_message(InfoMessage(0, message, util.get_unix_time())) friend.actions = True if number == self.get_active_number(): self.create_message_item(message, time.time(), '', MESSAGE_TYPE['INFO_MESSAGE']) @@ -293,12 +286,16 @@ class ContactsManager: except: pass self._settings.save() - if num == self.get_active_number() and self.is_active_a_friend(): - self.update() + # if num == self.get_active_number() and self.is_active_a_friend(): + # self.update() def friend_public_key(self, num): return self._contacts[num].tox_id + def export_history(self, num, as_text): + contact = self._contacts[num] + return self._history.export_history(contact, as_text) + def delete_friend(self, num): """ Removes friend from contact list @@ -313,17 +310,12 @@ class ContactsManager: if friend.tox_id in self._settings['notes']: del self._settings['notes'][friend.tox_id] self._settings.save() - self.clear_history(num) - if self._history.friend_exists_in_db(friend.tox_id): - self._history.delete_friend_from_db(friend.tox_id) + self._history.delete_history(friend) self._tox.friend_delete(friend.number) del self._contacts[num] self._screen.friends_list.takeItem(num) if num == self._active_contact: # active friend was deleted - if not len(self._contacts): # last friend was deleted - self.set_active(-1) - else: - self.set_active(0) + self.set_active(0 if len(self._contacts) else -1) data = self._tox.get_savedata() self._profile_manager.save_profile(data) @@ -387,13 +379,9 @@ class ContactsManager: text = util_ui.tr('Friend added without sending friend request') util_ui.message_box(text, title) else: - result = self._tox.friend_add(tox_id, message.encode('utf-8')) + self._tox.friend_add(tox_id, message.encode('utf-8')) tox_id = tox_id[:TOX_PUBLIC_KEY_SIZE * 2] - item = self.create_friend_item() - if not self._history.friend_exists_in_db(tox_id): - self._history.add_friend_to_db(tox_id) - message_getter = self._history.messages_getter(tox_id) - friend = Friend(message_getter, result, tox_id, '', item, tox_id) + friend = self._contact_provider.get_friend_by_public_key(tox_id) self._contacts.append(friend) self.save_profile() return True @@ -420,7 +408,7 @@ class ContactsManager: util.log('Accept friend request failed! ' + str(ex)) def can_send_typing_notification(self): - return self._settings['typing_notifications'] and self._active_contact != -1 + return self._settings['typing_notifications'] and self._active_contact + 1 # ----------------------------------------------------------------------------------------------------------------- # Private methods diff --git a/toxygen/history/history_loader.py b/toxygen/history/history_loader.py index 801125b..a380ddb 100644 --- a/toxygen/history/history_loader.py +++ b/toxygen/history/history_loader.py @@ -1,4 +1,4 @@ -from messenger.messages import * +from history.history_logs_generators import * # TODO: fix history loading and saving @@ -96,65 +96,21 @@ class HistoryLoader: return self._db.messages_getter(friend_public_key) - @staticmethod - def export_history(friend, as_text=True, _range=None): - if _range is None: - friend.load_all_corr() - corr = friend.get_corr() - elif _range[1] + 1: - corr = friend.get_corr()[_range[0]:_range[1] + 1] - else: - corr = friend.get_corr()[_range[0]:] + def delete_history(self, friend): + self.clear_history(friend) + if self._db.friend_exists_in_db(friend.tox_id): + self._db.delete_friend_from_db(friend.tox_id) - generator = TextHistoryGenerator(corr) if as_text else HtmlHistoryGenerator(corr) + @staticmethod + def export_history(contact, as_text=True, _range=None): + if _range is None: + contact.load_all_corr() + corr = contact.get_corr() + elif _range[1] + 1: + corr = contact.get_corr()[_range[0]:_range[1] + 1] + else: + corr = contact.get_corr()[_range[0]:] + + generator = TextHistoryGenerator(corr, contact.name) if as_text else HtmlHistoryGenerator(corr, contact.name) return generator.generate() - - -class HistoryLogsGenerator: - - def __init__(self, history): - self._history = history - - def generate(self): - return str() - - -class HtmlHistoryGenerator(HistoryLogsGenerator): - - def __init__(self, history): - super().__init__(history) - - def generate(self): - arr = [] - for message in self._history: - if type(message) is TextMessage: - data = message.get_data() - x = '[{}] {}: {}
' - arr.append(x.format(convert_time(data[2]) if data[1] != MESSAGE_OWNER['NOT_SENT'] else 'Unsent', - friend.name if data[1] == MESSAGE_OWNER['FRIEND'] else self.name, - data[0])) - s = '
'.join(arr) - s = '{}{}'.format(friend.name, - s) - return s - - -class TextHistoryGenerator(HistoryLogsGenerator): - - def __init__(self, history): - super().__init__(history) - - def generate(self): - arr = [] - for message in self._history: - if type(message) is TextMessage: - data = message.get_data() - x = '[{}] {}: {}\n' - arr.append(x.format(convert_time(data[2]) if data[1] != MESSAGE_OWNER['NOT_SENT'] else 'Unsent', - friend.name if data[1] == MESSAGE_OWNER['FRIEND'] else self.name, - data[0])) - s = '\n'.join(arr) - - return s - diff --git a/toxygen/history/history_logs_generators.py b/toxygen/history/history_logs_generators.py new file mode 100644 index 0000000..3e46562 --- /dev/null +++ b/toxygen/history/history_logs_generators.py @@ -0,0 +1,48 @@ +from messenger.messages import * +import util.util as util + + +class HistoryLogsGenerator: + + def __init__(self, history, contact_name): + self._history = history + self._contact_name = contact_name + + def generate(self): + return str() + + @staticmethod + def _get_message_time(message): + return util.convert_time(message.time) if message.author.type != MESSAGE_AUTHOR['NOT_SENT'] else 'Unsent' + + +class HtmlHistoryGenerator(HistoryLogsGenerator): + + def __init__(self, history, contact_name): + super().__init__(history, contact_name) + + def generate(self): + arr = [] + for message in self._history: + if type(message) is TextMessage: + x = '[{}] {}: {}
' + arr.append(x.format(self._get_message_time(message), message.author.name, message.text)) + s = '
'.join(arr) + html = '{}{}' + + return html.format(self._contact_name, s) + + +class TextHistoryGenerator(HistoryLogsGenerator): + + def __init__(self, history, contact_name): + super().__init__(history, contact_name) + + def generate(self): + arr = [self._contact_name] + for message in self._history: + if type(message) is TextMessage: + x = '[{}] {}: {}\n' + arr.append(x.format(self._get_message_time(message), message.author.name, message.text)) + + return '\n'.join(arr) diff --git a/toxygen/messenger/messages.py b/toxygen/messenger/messages.py index 023a2e7..41c046d 100644 --- a/toxygen/messenger/messages.py +++ b/toxygen/messenger/messages.py @@ -38,6 +38,11 @@ class Message: author = property(get_author) + def get_time(self): + return self._time + + time = property(get_time) + def get_message_id(self): return self._message_id @@ -70,6 +75,11 @@ class TextMessage(Message): super().__init__(id, message_type, owner, time) self._message = message + def get_text(self): + return self._message + + text = property(get_text) + def get_data(self): return self._message, self._owner, self._time, self._type diff --git a/toxygen/messenger/messenger.py b/toxygen/messenger/messenger.py index 77cb431..8cb25e1 100644 --- a/toxygen/messenger/messenger.py +++ b/toxygen/messenger/messenger.py @@ -5,19 +5,21 @@ from messenger.messages import * class Messenger(util.ToxSave): - def __init__(self, tox, plugin_loader, screen, contacts_manager, contacts_provider): + def __init__(self, tox, plugin_loader, screen, contacts_manager, contacts_provider, items_factory): super().__init__(tox) self._plugin_loader = plugin_loader self._screen = screen self._contacts_manager = contacts_manager self._contacts_provider = contacts_provider + self._items_factory = items_factory # ----------------------------------------------------------------------------------------------------------------- # Private methods # ----------------------------------------------------------------------------------------------------------------- - def _create_message_item(self): - pass + def _create_message_item(self, text_message): + # pixmap = self._contacts_manager.get_curr_contact().get_pixmap() + self._items_factory.message_item(text_message) # ----------------------------------------------------------------------------------------------------------------- # Messaging @@ -66,17 +68,20 @@ class Messenger(util.ToxSave): else: message_type = TOX_MESSAGE_TYPE['NORMAL'] friend = self.get_friend_by_number(friend_number) - friend.inc_receipts() - if friend.status is not None: - messages = self._split_message(text.encode('utf-8')) - t = util.get_unix_time() - for message in messages: + messages = self._split_message(text.encode('utf-8')) + t = util.get_unix_time() + for message in messages: + if friend.status is not None: message_id = self._tox.friend_send_message(friend_number, message_type, message) - friend.append_message(TextMessage(message_id, text, MESSAGE_AUTHOR['NOT_SENT'], t, message_type)) - if self._contacts_manager.is_friend_active(friend_number): - self.create_message_item(text, t, MESSAGE_AUTHOR['NOT_SENT'], message_type) - self._screen.messageEdit.clear() - self._screen.messages.scrollToBottom() + friend.inc_receipts() + else: + message_id = 0 + message = TextMessage(message_id, text, MESSAGE_AUTHOR['NOT_SENT'], t, message_type) + friend.append_message(message) + if self._contacts_manager.is_friend_active(friend_number): + self._create_message_item(message) + self._screen.messageEdit.clear() + self._screen.messages.scrollToBottom() # ----------------------------------------------------------------------------------------------------------------- # Typing notifications @@ -121,6 +126,8 @@ class Messenger(util.ToxSave): index += size + 1 messages.append(message[:index]) message = message[index:] + if message: + messages.append(message) return messages diff --git a/toxygen/ui/items_factory.py b/toxygen/ui/items_factory.py index 347424d..10ca02b 100644 --- a/toxygen/ui/items_factory.py +++ b/toxygen/ui/items_factory.py @@ -18,8 +18,8 @@ class ItemsFactory: self._friends_list.setItemWidget(elem, item) return item - def message_item(self, text, time, name, sent, message_type, append, pixmap): - item = MessageItem(text, time, name, sent, message_type, self._messages) + def message_item(self, message, pixmap=None): + item = MessageItem(message, self._messages) if pixmap is not None: item.set_avatar(pixmap) elem = QtWidgets.QListWidgetItem() diff --git a/toxygen/ui/main_screen.py b/toxygen/ui/main_screen.py index c059b1f..05007f9 100644 --- a/toxygen/ui/main_screen.py +++ b/toxygen/ui/main_screen.py @@ -17,13 +17,14 @@ class MainWindow(QtWidgets.QMainWindow): self._modal_window = None self.setAcceptDrops(True) self._saved = False - self.profile = None + self._profile = None self.initUI() - def set_dependencies(self, widget_factory, tray, contacts_manager, messenger): + def set_dependencies(self, widget_factory, tray, contacts_manager, messenger, profile): self._widget_factory = widget_factory self._tray = tray self._contacts_manager = contacts_manager + self._profile = profile self.messageEdit.set_messenger(messenger) def show(self): @@ -401,17 +402,18 @@ class MainWindow(QtWidgets.QMainWindow): #self.profile.update() def keyPressEvent(self, event): - if event.key() == QtCore.Qt.Key_Escape and QtWidgets.QSystemTrayIcon.isSystemTrayAvailable(): + key, modifiers = event.key(), event.modifiers() + if key == QtCore.Qt.Key_Escape and QtWidgets.QSystemTrayIcon.isSystemTrayAvailable(): self.hide() - elif event.key() == QtCore.Qt.Key_C and event.modifiers() & QtCore.Qt.ControlModifier and self.messages.selectedIndexes(): + elif key == QtCore.Qt.Key_C and modifiers & QtCore.Qt.ControlModifier and self.messages.selectedIndexes(): rows = list(map(lambda x: self.messages.row(x), self.messages.selectedItems())) indexes = (rows[0] - self.messages.count(), rows[-1] - self.messages.count()) s = self.profile.export_history(self.profile.active_friend, True, indexes) clipboard = QtWidgets.QApplication.clipboard() clipboard.setText(s) - elif event.key() == QtCore.Qt.Key_Z and event.modifiers() & QtCore.Qt.ControlModifier and self.messages.selectedIndexes(): + elif key == QtCore.Qt.Key_Z and modifiers & QtCore.Qt.ControlModifier and self.messages.selectedIndexes(): self.messages.clearSelection() - elif event.key() == QtCore.Qt.Key_F and event.modifiers() & QtCore.Qt.ControlModifier: + elif key == QtCore.Qt.Key_F and modifiers & QtCore.Qt.ControlModifier: self.show_search_field() else: super().keyPressEvent(event) @@ -421,6 +423,7 @@ class MainWindow(QtWidgets.QMainWindow): # ----------------------------------------------------------------------------------------------------------------- def about_program(self): + # TODO: replace with window text = util_ui.tr('Toxygen is Tox client written on Python.\nVersion: ') text += '' + '\nGitHub: https://github.com/toxygen-project/toxygen/' title = util_ui.tr('About') @@ -435,7 +438,7 @@ class MainWindow(QtWidgets.QMainWindow): self._modal_window.show() def add_contact(self, link=''): - self._modal_window = self._widget_factory.create_add_contact_window(link or '') + self._modal_window = self._widget_factory.create_add_contact_window(link) self._modal_window.show() def create_gc(self): @@ -507,7 +510,7 @@ class MainWindow(QtWidgets.QMainWindow): def send_file(self): self.menu.hide() - if self._contacts_manager.active_friend + 1 and self._contacts_manager.is_active_a_friend(): + if self._contacts_manager.is_active_a_friend(): caption = util_ui.tr('Choose file') name = util_ui.file_dialog(caption) if name[0]: @@ -515,8 +518,8 @@ class MainWindow(QtWidgets.QMainWindow): def send_screenshot(self, hide=False): self.menu.hide() - if self._contacts_manager.active_friend + 1 and self._contacts_manager.is_active_a_friend(): - self.sw = ScreenShotWindow(self) + if self._contacts_manager.is_active_a_friend(): + self.sw = self._widget_factory.create_screenshot_window(self) self.sw.show() if hide: self.hide() @@ -533,7 +536,7 @@ class MainWindow(QtWidgets.QMainWindow): def send_sticker(self): self.menu.hide() - if self._contacts_manager.active_friend + 1 and self._contacts_manager.is_active_a_friend(): + if self._contacts_manager.is_active_a_friend(): self.sticker = self._widget_factory.create_sticker_window(self) self.sticker.setGeometry(QtCore.QRect(self.x() if self._settings['mirror_mode'] else 270 + self.x(), self.y() + self.height() - 200, @@ -643,7 +646,7 @@ class MainWindow(QtWidgets.QMainWindow): self.note.show() def export_history(self, num, as_text=True): - s = self._history_loader.export_history(num, as_text) + s = self._contacts_manager.export_history(num, as_text) extension = 'txt' if as_text else 'html' file_name, _ = util_ui.save_file_dialog(util_ui.tr('Choose file name'), extension) @@ -712,11 +715,11 @@ class MainWindow(QtWidgets.QMainWindow): if (x < event.x() < x + 32) and (y < event.y() < y + 32): self.profile.change_status() else: - super(MainWindow, self).mouseReleaseEvent(event) + super().mouseReleaseEvent(event) def show(self): super().show() - #self._contacts_manager.update() + self._contacts_manager.update() def filtering(self): ind = self.online_contacts.currentIndex() @@ -726,7 +729,7 @@ class MainWindow(QtWidgets.QMainWindow): def show_search_field(self): if hasattr(self, 'search_field') and self.search_field.isVisible(): return - if self._c4.get_curr_friend() is None: + if self._contacts_manager.get_curr_friend() is None: return self.search_field = SearchScreen(self.messages, self.messages.width(), self.messages.parent()) x, y = self.messages.x(), self.messages.y() + self.messages.height() - 40 diff --git a/toxygen/ui/widgets_factory.py b/toxygen/ui/widgets_factory.py index 4051656..1bba4a7 100644 --- a/toxygen/ui/widgets_factory.py +++ b/toxygen/ui/widgets_factory.py @@ -5,7 +5,7 @@ from ui.menu import * class WidgetsFactory: def __init__(self, settings, profile, contacts_manager, file_transfer_handler, smiley_loader, plugin_loader, - toxes): + toxes, version): self._settings = settings self._profile = profile self._contacts_manager = contacts_manager @@ -13,6 +13,7 @@ class WidgetsFactory: self._smiley_loader = smiley_loader self._plugin_loader = plugin_loader self._toxes = toxes + self._version = version def create_screenshot_window(self, *args): return ScreenShotWindow(self._file_transfer_handler, *args)