messages - minimal working version

This commit is contained in:
ingvar1995 2018-05-04 00:17:48 +03:00
parent ad351030d9
commit c8443b56dd
19 changed files with 174 additions and 148 deletions

View file

@ -289,22 +289,23 @@ class App:
def _create_dependencies(self):
self._smiley_loader = SmileyLoader(self._settings)
self._ms = MainWindow(self._settings, self._tray)
self._calls_manager = CallsManager(self._tox.AV, self._settings)
db = Database(self._path.replace('.tox', '.db'), self._toxes)
profile = Profile(self._profile_manager, self._tox, self._ms, self._file_transfer_handler)
self._plugin_loader = PluginLoader(self._tox, self._toxes, profile, self._settings) # plugins support
profile = Profile(self._profile_manager, self._tox, self._ms)
self._plugin_loader = PluginLoader(self._tox, self._toxes, profile, self._settings)
items_factory = ItemsFactory(self._settings, self._plugin_loader, self._smiley_loader, self._ms)
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._version)
self._contacts_manager = ContactsManager(self._tox, self._settings, self._ms, self._profile_manager,
self._contacts_provider, db)
self._file_transfer_handler = FileTransfersHandler(self._tox, self._settings, self._contacts_provider)
widgets_factory = WidgetsFactory(self._settings, profile, self._contacts_manager, self._file_transfer_handler,
self._smiley_loader, self._plugin_loader, self._toxes, self._version)
self._messenger = Messenger(self._tox, self._plugin_loader, self._ms, self._contacts_manager,
self._contacts_provider, items_factory)
self._contacts_provider, items_factory, profile)
self._tray = tray.init_tray(profile, self._settings, self._ms)
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._ms.show()

View file

@ -1,6 +1,6 @@
import random
import urllib.request
from util.util import log, curr_directory, join_path
from util.util import *
from PyQt5 import QtNetwork, QtCore
import json

View file

@ -4,7 +4,6 @@ from contacts.friend import Friend
from PyQt5 import QtCore, QtGui
from messenger.messages import *
from wrapper.toxcore_enums_and_consts import *
from network.tox_dns import tox_dns
from history.history_loader import HistoryLoader

View file

@ -1,7 +1,5 @@
from contacts.friend import *
from user_data.settings import *
from wrapper.toxcore_enums_and_consts import *
from util.util import log
from history.database import *
from file_transfers.file_transfers import *
import time
@ -14,7 +12,7 @@ class Profile(basecontact.BaseContact):
"""
Profile of current toxygen user. Contains friends list, tox instance
"""
def __init__(self, profile_manager, tox, screen, file_transfer_handler):
def __init__(self, profile_manager, tox, screen):
"""
:param tox: tox instance
:param screen: ref to main screen
@ -25,7 +23,6 @@ class Profile(basecontact.BaseContact):
tox.self_get_status_message(),
screen.user_info,
tox.self_get_address())
self._file_transfer_handler = file_transfer_handler
self._screen = screen
self._messages = screen.messages
self._tox = tox
@ -83,30 +80,6 @@ class Profile(basecontact.BaseContact):
# Friend connection status callbacks
# -----------------------------------------------------------------------------------------------------------------
def send_files(self, friend_number):
friend = self.get_friend_by_number(friend_number)
friend.remove_invalid_unsent_files()
files = friend.get_unsent_files()
try:
for fl in files:
data = fl.get_data()
if data[1] is not None:
self.send_inline(data[1], data[0], friend_number, True)
else:
self.send_file(data[0], friend_number, True)
friend.clear_unsent_files()
for key in list(self._paused_file_transfers.keys()):
data = self._paused_file_transfers[key]
if not os.path.exists(data[0]):
del self._paused_file_transfers[key]
elif data[1] == friend_number and not data[2]:
self.send_file(data[0], friend_number, True, key)
del self._paused_file_transfers[key]
if friend_number == self.get_active_number() and self.is_active_a_friend():
self.update()
except Exception as ex:
print('Exception in file sending: ' + str(ex))
def friend_exit(self, friend_number):
"""
Friend with specified number quit
@ -133,20 +106,6 @@ class Profile(basecontact.BaseContact):
while i < self._messages.count() and not self._messages.itemWidget(self._messages.item(i)).mark_as_sent():
i += 1
def send_messages(self, friend_number):
"""
Send 'offline' messages to friend
"""
friend = self.get_friend_by_number(friend_number)
friend.load_corr()
messages = friend.get_unsent_messages()
try:
for message in messages:
self.split_and_send(friend_number, message.get_data()[-1], message.get_data()[0].encode('utf-8'))
friend.inc_receipts()
except Exception as ex:
log('Sending pending messages failed with ' + str(ex))
def delete_message(self, message_id):
friend = self.get_curr_friend()
friend.delete_message(time)

View file

@ -172,7 +172,7 @@ class SendAvatar(SendTransfer):
else:
with open(path, 'rb') as fl:
avatar_hash = Tox.hash(fl.read())
super(SendAvatar, self).__init__(path, tox, friend_number, TOX_FILE_KIND['AVATAR'], avatar_hash)
super().__init__(path, tox, friend_number, TOX_FILE_KIND['AVATAR'], avatar_hash)
class SendFromBuffer(FileTransfer):

View file

@ -2,6 +2,8 @@ from file_transfers.file_transfers import *
from messenger.messages import *
from history.database import MESSAGE_AUTHOR
import os
from ui.list_items import *
from PyQt5 import QtWidgets
import util.util as util
@ -130,7 +132,7 @@ class FileTransfersHandler:
tr = self._file_transfers[(friend_number, file_number)]
tr.pause(by_friend)
t = TOX_FILE_TRANSFER_STATE['PAUSED_BY_FRIEND'] if by_friend else TOX_FILE_TRANSFER_STATE['PAUSED_BY_USER']
self.get_friend_by_number(friend_number).update_transfer_data(file_number, t)
self._get_friend_by_number(friend_number).update_transfer_data(file_number, t)
def resume_transfer(self, friend_number, file_number, by_friend=False):
"""
@ -175,7 +177,7 @@ class FileTransfersHandler:
self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['RESUME'])
if item is not None:
rt.set_state_changed_handler(item.update_transfer_state)
self.get_friend_by_number(friend_number).update_transfer_data(file_number,
self._get_friend_by_number(friend_number).update_transfer_data(file_number,
TOX_FILE_TRANSFER_STATE['RUNNING'])
def send_screenshot(self, data):
@ -192,7 +194,7 @@ class FileTransfersHandler:
def send_inline(self, data, file_name, friend_number=None, is_resend=False):
friend_number = friend_number or self.get_active_number()
friend = self.get_friend_by_number(friend_number)
friend = self._get_friend_by_number(friend_number)
if friend.status is None and not is_resend:
m = UnsentFile(file_name, data, time.time())
friend.append_message(m)
@ -224,7 +226,7 @@ class FileTransfersHandler:
:param file_id: file id of transfer
"""
friend_number = self.get_active_number() if number is None else number
friend = self.get_friend_by_number(friend_number)
friend = self._get_friend_by_number(friend_number)
if friend.status is None and not is_resend:
m = UnsentFile(path, None, time.time())
friend.append_message(m)
@ -265,13 +267,13 @@ class FileTransfersHandler:
transfer = self._file_transfers[(friend_number, file_number)]
t = type(transfer)
if t is ReceiveAvatar:
self.get_friend_by_number(friend_number).load_avatar()
self._get_friend_by_number(friend_number).load_avatar()
if friend_number == self.get_active_number() and self.is_active_a_friend():
self.set_active(None)
elif t is ReceiveToBuffer or (t is SendFromBuffer and self._settings.get_instance()['allow_inline']): # inline image
elif t is ReceiveToBuffer or (t is SendFromBuffer and self._settings['allow_inline']): # inline image
print('inline')
inline = InlineImage(transfer.get_data())
i = self.get_friend_by_number(friend_number).update_transfer_data(file_number,
i = self._get_friend_by_number(friend_number).update_transfer_data(file_number,
TOX_FILE_TRANSFER_STATE['FINISHED'],
inline)
if friend_number == self.get_active_number() and self.is_active_a_friend():
@ -284,11 +286,35 @@ class FileTransfersHandler:
self._messages.setItemWidget(elem, item)
self._messages.scrollToBottom()
elif t is not SendAvatar:
self.get_friend_by_number(friend_number).update_transfer_data(file_number,
self._get_friend_by_number(friend_number).update_transfer_data(file_number,
TOX_FILE_TRANSFER_STATE['FINISHED'])
del self._file_transfers[(friend_number, file_number)]
del transfer
def send_files(self, friend_number):
friend = self._get_friend_by_number(friend_number)
friend.remove_invalid_unsent_files()
files = friend.get_unsent_files()
try:
for fl in files:
data = fl.get_data()
if data[1] is not None:
self.send_inline(data[1], data[0], friend_number, True)
else:
self.send_file(data[0], friend_number, True)
friend.clear_unsent_files()
for key in list(self._paused_file_transfers.keys()):
data = self._paused_file_transfers[key]
if not os.path.exists(data[0]):
del self._paused_file_transfers[key]
elif data[1] == friend_number and not data[2]:
self.send_file(data[0], friend_number, True, key)
del self._paused_file_transfers[key]
if friend_number == self.get_active_number() and self.is_active_a_friend():
self.update()
except Exception as ex:
print('Exception in file sending: ' + str(ex))
# -----------------------------------------------------------------------------------------------------------------
# Avatars support
# -----------------------------------------------------------------------------------------------------------------
@ -313,7 +339,7 @@ class FileTransfersHandler:
self._file_transfers[(friend_number, file_number)] = ra
ra.set_transfer_finished_handler(self.transfer_finished)
else:
self.get_friend_by_number(friend_number).load_avatar()
self._get_friend_by_number(friend_number).load_avatar()
if self.get_active_number() == friend_number and self.is_active_a_friend():
self.set_active(None)

View file

@ -163,6 +163,9 @@ class Database:
db.close()
def messages_getter(self, tox_id):
if not self.friend_exists_in_db(tox_id):
self.add_friend_to_db(tox_id)
return Database.MessageGetter(self._path, tox_id)
# -----------------------------------------------------------------------------------------------------------------

View file

@ -1,6 +1,6 @@
import app
from user_data.settings import *
from util.util import remove, get_libs_directory
import util.util as util
import argparse
@ -10,8 +10,8 @@ __version__ = '0.5.0'
def clean():
"""Removes all windows libs from libs folder"""
directory = get_libs_directory()
remove(directory)
directory = util.get_libs_directory()
util.remove(directory)
def reset():

View file

@ -48,6 +48,11 @@ class Message:
message_id = property(get_message_id)
def get_type(self):
return self._type
type = property(get_type)
def get_widget(self):
if self._widget is None:
self._widget = self._create_widget()

View file

@ -5,13 +5,14 @@ from messenger.messages import *
class Messenger(util.ToxSave):
def __init__(self, tox, plugin_loader, screen, contacts_manager, contacts_provider, items_factory):
def __init__(self, tox, plugin_loader, screen, contacts_manager, contacts_provider, items_factory, profile):
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
self._profile = profile
# -----------------------------------------------------------------------------------------------------------------
# Private methods
@ -33,17 +34,16 @@ class Messenger(util.ToxSave):
:param message: text of message
"""
t = util.get_unix_time()
friend = self._get_friend_by_number(friend_number)
text_message = TextMessage(0, message, MessageAuthor(friend.name, MESSAGE_AUTHOR['FRIEND']), t, message_type)
if self._contacts_manager.is_friend_active(friend_number): # add message to list
self.create_message_item(message, t, MESSAGE_AUTHOR['FRIEND'], message_type)
self._create_message_item(text_message)
self._screen.messages.scrollToBottom()
self._contacts_manager.get_curr_contact().append_message(
TextMessage(message, MESSAGE_AUTHOR['FRIEND'], t, message_type))
self._contacts_manager.get_curr_contact().append_message(text_message)
else:
friend = self.get_friend_by_number(friend_number)
friend.inc_messages()
friend.append_message(
TextMessage(message, MESSAGE_AUTHOR['FRIEND'], t, message_type))
friend.append_message(text_message)
if not friend.visibility:
self._contacts_manager.update_filtration()
@ -67,7 +67,7 @@ class Messenger(util.ToxSave):
text = text[4:]
else:
message_type = TOX_MESSAGE_TYPE['NORMAL']
friend = self.get_friend_by_number(friend_number)
friend = self._get_friend_by_number(friend_number)
messages = self._split_message(text.encode('utf-8'))
t = util.get_unix_time()
for message in messages:
@ -76,13 +76,30 @@ class Messenger(util.ToxSave):
friend.inc_receipts()
else:
message_id = 0
message = TextMessage(message_id, text, MESSAGE_AUTHOR['NOT_SENT'], t, message_type)
message_author = MessageAuthor(self._profile.name, MESSAGE_AUTHOR['NOT_SENT'])
message = TextMessage(message_id, text, message_author, 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()
def send_messages(self, friend_number):
"""
Send 'offline' messages to friend
"""
friend = self._get_friend_by_number(friend_number)
friend.load_corr()
messages = friend.get_unsent_messages()
try:
for message in messages:
tox_messages = self._split_message(message.text)
for tox_message in tox_messages:
self._tox.friend_send_message(friend_number, message.message_type, tox_message)
friend.inc_receipts()
except Exception as ex:
util.log('Sending pending messages failed with ' + str(ex))
# -----------------------------------------------------------------------------------------------------------------
# Typing notifications
# -----------------------------------------------------------------------------------------------------------------
@ -131,5 +148,5 @@ class Messenger(util.ToxSave):
return messages
def get_friend_by_number(self, friend_number):
def _get_friend_by_number(self, friend_number):
return self._contacts_provider.get_friend_by_number(friend_number)

View file

@ -55,20 +55,20 @@ def friend_status(contacts_manager, file_transfer_handler, profile, settings):
return wrapped
def friend_connection_status(profile, settings, plugin_loader):
def friend_connection_status(contacts_manager, profile, settings, plugin_loader, file_transfer_handler):
def wrapped(tox, friend_number, new_status, user_data):
"""
Check friend's connection status (offline, udp, tcp)
"""
print("Friend #{} connection status: {}".format(friend_number, new_status))
friend = profile.get_friend_by_number(friend_number)
friend = contacts_manager.get_friend_by_number(friend_number)
if new_status == TOX_CONNECTION['NONE']:
invoke_in_main_thread(profile.friend_exit, friend_number)
invoke_in_main_thread(profile.update_filtration)
invoke_in_main_thread(contacts_manager.update_filtration)
if settings['sound_notifications'] and profile.status != TOX_USER_STATUS['BUSY']:
sound_notification(SOUND_NOTIFICATION['FRIEND_CONNECTION_STATUS'])
elif friend.status is None:
invoke_in_main_thread(profile.send_avatar, friend_number)
invoke_in_main_thread(file_transfer_handler.send_avatar, friend_number)
invoke_in_main_thread(plugin_loader.friend_online, friend_number)
return wrapped
@ -133,9 +133,9 @@ def friend_request(contacts_manager):
return wrapped
def friend_typing(contacts_manager):
def friend_typing(messenger):
def wrapped(tox, friend_number, typing, user_data):
invoke_in_main_thread(contacts_manager.friend_typing, friend_number, typing)
invoke_in_main_thread(messenger.friend_typing, friend_number, typing)
return wrapped
@ -392,11 +392,12 @@ def init_callbacks(tox, profile, settings, plugin_loader, contacts_manager,
# friend callbacks
tox.callback_friend_status(friend_status(contacts_manager, file_transfer_handler, profile, settings), 0)
tox.callback_friend_message(friend_message(messenger, contacts_manager, profile, settings, main_window, tray), 0)
tox.callback_friend_connection_status(friend_connection_status(profile, settings, plugin_loader), 0)
tox.callback_friend_connection_status(friend_connection_status(contacts_manager, profile, settings, plugin_loader,
file_transfer_handler), 0)
tox.callback_friend_name(friend_name(contacts_manager), 0)
tox.callback_friend_status_message(friend_status_message(contacts_manager, messenger), 0)
tox.callback_friend_request(friend_request(contacts_manager), 0)
tox.callback_friend_typing(friend_typing(contacts_manager), 0)
tox.callback_friend_typing(friend_typing(messenger), 0)
tox.callback_friend_read_receipt(friend_read_receipt(contacts_manager), 0)
# file transfer

View file

@ -1,11 +1,26 @@
import json
import urllib.request
from util.util import log
from user_data import settings
import util.util as util
from PyQt5 import QtNetwork, QtCore
def tox_dns(email):
class ToxDns:
def __init__(self, settings):
self._settings = settings
@staticmethod
def _send_request(url, data):
req = urllib.request.Request(url)
req.add_header('Content-Type', 'application/json')
response = urllib.request.urlopen(req, bytes(json.dumps(data), 'utf-8'))
res = json.loads(str(response.read(), 'utf-8'))
if not res['c']:
return res['tox_id']
else:
raise LookupError()
def lookup(self, email):
"""
TOX DNS 4
:param email: data like 'groupbot@toxme.io'
@ -14,19 +29,21 @@ def tox_dns(email):
site = email.split('@')[1]
data = {"action": 3, "name": "{}".format(email)}
urls = ('https://{}/api'.format(site), 'http://{}/api'.format(site))
s = settings.Settings.get_instance()
if not s['proxy_type']: # no proxy
if not self._settings['proxy_type']: # no proxy
for url in urls:
try:
return send_request(url, data)
return self._send_request(url, data)
except Exception as ex:
log('TOX DNS ERROR: ' + str(ex))
util.log('TOX DNS ERROR: ' + str(ex))
else: # proxy
netman = QtNetwork.QNetworkAccessManager()
proxy = QtNetwork.QNetworkProxy()
proxy.setType(QtNetwork.QNetworkProxy.Socks5Proxy if s['proxy_type'] == 2 else QtNetwork.QNetworkProxy.HttpProxy)
proxy.setHostName(s['proxy_host'])
proxy.setPort(s['proxy_port'])
if self._settings['proxy_type'] == 2:
proxy.setType(QtNetwork.QNetworkProxy.Socks5Proxy)
else:
proxy.setType(QtNetwork.QNetworkProxy.HttpProxy)
proxy.setHostName(self._settings['proxy_host'])
proxy.setPort(self._settings['proxy_port'])
netman.setProxy(proxy)
for url in urls:
try:
@ -43,17 +60,6 @@ def tox_dns(email):
if not result['c']:
return result['tox_id']
except Exception as ex:
log('TOX DNS ERROR: ' + str(ex))
util.log('TOX DNS ERROR: ' + str(ex))
return None # error
def send_request(url, data):
req = urllib.request.Request(url)
req.add_header('Content-Type', 'application/json')
response = urllib.request.urlopen(req, bytes(json.dumps(data), 'utf-8'))
res = json.loads(str(response.read(), 'utf-8'))
if not res['c']:
return res['tox_id']
else:
raise LookupError()

View file

@ -5,7 +5,7 @@ import util
import pyaudio
import wave
from user_data import settings
from util.util import curr_directory
from util.util import *
class IncomingCallWidget(widgets.CenteredWidget):

View file

@ -1,6 +1,8 @@
from ui.list_items import *
from ui.messages_widgets import *
# rename methods
class ItemsFactory:
@ -9,6 +11,11 @@ class ItemsFactory:
self._smiley_loader = smiley_loader
self._messages = main_screen.messages
self._friends_list = main_screen.friends_list
self._message_edit = main_screen.messageEdit
def _create_message_browser(self, text, width, message_type, parent=None):
return MessageBrowser(self._settings, self._message_edit, self._smiley_loader, self._plugin_loader,
text, width, message_type, parent)
def friend_item(self):
item = ContactItem(self._settings)
@ -18,8 +25,8 @@ class ItemsFactory:
self._friends_list.setItemWidget(elem, item)
return item
def message_item(self, message, pixmap=None):
item = MessageItem(message, self._messages)
def message_item(self, message, append=True, pixmap=None):
item = MessageItem(self._settings, self._create_message_browser, message, self._messages)
if pixmap is not None:
item.set_avatar(pixmap)
elem = QtWidgets.QListWidgetItem()

View file

@ -2,7 +2,7 @@ from wrapper.toxcore_enums_and_consts import *
from PyQt5 import QtCore, QtGui, QtWidgets
from contacts import profile
from file_transfers.file_transfers import TOX_FILE_TRANSFER_STATE, PAUSED_FILE_TRANSFERS, DO_NOT_SHOW_ACCEPT_BUTTON, ACTIVE_FILE_TRANSFERS, SHOW_PROGRESS_BAR
from util.util import curr_directory, convert_time, curr_time
from util.util import *
from ui.widgets import DataLabel, create_menu
import html as h
import smileys

View file

@ -1,7 +1,7 @@
from PyQt5 import QtCore, QtGui, QtWidgets
from user_data.settings import *
from contacts.profile import Profile
from util.util import curr_directory, copy, get_stickers_directory, join_path
from util.util import *
from ui.widgets import CenteredWidget, DataLabel, LineEdit, RubberBandWindow
import pyaudio
from user_data import toxes

View file

@ -6,9 +6,10 @@ import util.util as util
import ui.menu as menu
import html as h
import re
from messenger.messages import MESSAGE_AUTHOR
class MessageEdit(QtWidgets.QTextBrowser):
class MessageBrowser(QtWidgets.QTextBrowser):
def __init__(self, settings, message_edit, smileys_loader, plugin_loader, text, width, message_type, parent=None):
super().__init__(parent)
@ -122,7 +123,7 @@ class MessageItem(QtWidgets.QWidget):
"""
Message in messages list
"""
def __init__(self, settings, text_message, parent=None):
def __init__(self, settings, message_browser_factory_method, text_message, parent=None):
QtWidgets.QWidget.__init__(self, parent)
self.name = widgets.DataLabel(self)
self.name.setGeometry(QtCore.QRect(2, 2, 95, 23))
@ -132,25 +133,26 @@ class MessageItem(QtWidgets.QWidget):
font.setPointSize(11)
font.setBold(True)
self.name.setFont(font)
self.name.setText(text_message.user)
self.name.setText(text_message.author.name)
self.time = QtWidgets.QLabel(self)
self.time.setGeometry(QtCore.QRect(parent.width() - 60, 0, 50, 25))
font.setPointSize(10)
font.setBold(False)
self.time.setFont(font)
self._time = time
if not sent:
self._time = text_message.time
if text_message.author.type == MESSAGE_AUTHOR['NOT_SENT']:
movie = QtGui.QMovie(util.join_path(util.get_images_directory(), 'spinner.gif'))
self.time.setMovie(movie)
movie.start()
self.t = True
else:
self.time.setText(util.convert_time(time))
self.time.setText(util.convert_time(text_message.time))
self.t = False
self.message = MessageEdit(text, parent.width() - 160, message_type, self)
if message_type != TOX_MESSAGE_TYPE['NORMAL']:
self.message = message_browser_factory_method(text_message.text, parent.width() - 160,
text_message.type, self)
if text_message.type != TOX_MESSAGE_TYPE['NORMAL']:
self.name.setStyleSheet("QLabel { color: #5CB3FF; }")
self.message.setAlignment(QtCore.Qt.AlignCenter)
self.time.setStyleSheet("QLabel { color: #5CB3FF; }")

View file

@ -1,6 +1,6 @@
from PyQt5 import QtWidgets, QtGui, QtCore
from util.ui import tr
from util.util import get_images_directory
from util.util import *
import os.path

View file

@ -1,6 +1,6 @@
import json
import os
from util.util import log, get_base_directory, get_platform, join_path
from util.util import *
import pyaudio
import smileys.smileys as smileys