group notifications and bug fixes

This commit is contained in:
ingvar1995 2017-07-18 21:36:14 +03:00
parent db519e2608
commit 65167de1fe
8 changed files with 99 additions and 43 deletions

View File

@ -384,14 +384,34 @@ def group_invite(tox, friend_number, gc_type, data, length, user_data):
bytes(data[:length])) bytes(data[:length]))
def group_message(tox, group_number, peer_number, message, length, user_data): def show_gc_notification(window, tray, message, group_number):
invoke_in_main_thread(Profile.get_instance().new_gc_message, group_number, profile = Profile.get_instance()
peer_number, TOX_MESSAGE_TYPE['NORMAL'], str(message, 'utf-8')) settings = Settings.get_instance()
chat = profile.get_group_by_number(group_number)
if not window.isActiveWindow() and (profile.name in message or settings['group_notifications']):
if settings['notifications'] and profile.status != TOX_USER_STATUS['BUSY'] and not settings.locked:
invoke_in_main_thread(tray_notification, chat.name, message, tray, window)
if settings['sound_notifications'] and profile.status != TOX_USER_STATUS['BUSY']:
sound_notification(SOUND_NOTIFICATION['MESSAGE'])
invoke_in_main_thread(tray.setIcon, QtGui.QIcon(curr_directory() + '/images/icon_new_messages.png'))
def group_action(tox, group_number, peer_number, message, length, user_data): def group_message(window, tray):
invoke_in_main_thread(Profile.get_instance().new_gc_message, group_number, def wrapped(tox, group_number, peer_number, message, length, user_data):
peer_number, TOX_MESSAGE_TYPE['ACTION'], str(message, 'utf-8')) message = str(message[:length], 'utf-8')
invoke_in_main_thread(Profile.get_instance().new_gc_message, group_number,
peer_number, TOX_MESSAGE_TYPE['NORMAL'], message)
show_gc_notification(window, tray, message, group_number)
return wrapped
def group_action(window, tray):
def wrapped(tox, group_number, peer_number, message, length, user_data):
message = str(message[:length], 'utf-8')
invoke_in_main_thread(Profile.get_instance().new_gc_message, group_number,
peer_number, TOX_MESSAGE_TYPE['ACTION'], message)
show_gc_notification(window, tray, message, group_number)
return wrapped
def group_title(tox, group_number, peer_number, title, length, user_data): def group_title(tox, group_number, peer_number, title, length, user_data):
@ -440,7 +460,7 @@ def init_callbacks(tox, window, tray):
tox.callback_friend_lossy_packet(lossy_packet, 0) tox.callback_friend_lossy_packet(lossy_packet, 0)
tox.callback_group_invite(group_invite) tox.callback_group_invite(group_invite)
tox.callback_group_message(group_message) tox.callback_group_message(group_message(window, tray))
tox.callback_group_action(group_action) tox.callback_group_action(group_action(window, tray))
tox.callback_group_title(group_title) tox.callback_group_title(group_title)
tox.callback_group_namelist_change(group_namelist_change) tox.callback_group_namelist_change(group_namelist_change)

View File

@ -66,3 +66,10 @@ class Friend(contact.Contact):
if self._receipts: if self._receipts:
self._receipts -= 1 self._receipts -= 1
self.mark_as_sent() self.mark_as_sent()
# -----------------------------------------------------------------------------------------------------------------
# Full status
# -----------------------------------------------------------------------------------------------------------------
def get_full_status(self):
return self._status_message

View File

@ -1,7 +1,7 @@
import contact import contact
import util import util
from PyQt5 import QtGui, QtCore from PyQt5 import QtGui, QtCore
import toxcore_enums_and_consts as cnst import toxcore_enums_and_consts as constants
class GroupChat(contact.Contact): class GroupChat(contact.Contact):
@ -9,7 +9,7 @@ class GroupChat(contact.Contact):
def __init__(self, name, status_message, widget, tox, group_number): def __init__(self, name, status_message, widget, tox, group_number):
super().__init__(None, group_number, name, status_message, widget, None) super().__init__(None, group_number, name, status_message, widget, None)
self._tox = tox self._tox = tox
self._status = cnst.TOX_USER_STATUS['NONE'] self.set_status(constants.TOX_USER_STATUS['NONE'])
def set_name(self, name): def set_name(self, name):
self._tox.group_set_title(self._number, name) self._tox.group_set_title(self._number, name)
@ -31,3 +31,12 @@ class GroupChat(contact.Contact):
def remove_invalid_unsent_files(self): def remove_invalid_unsent_files(self):
pass pass
def get_full_status(self):
peers_count = self._tox.group_number_peers(self._number)
names = []
for i in range(peers_count):
name = self._tox.group_peername(self._number, i)
names.append(name)
names = sorted(names, key=lambda n: n.lower())
return '\n'.join(names)

View File

@ -5,7 +5,6 @@ from widgets import MultilineEdit, ComboBox
import plugin_support import plugin_support
from mainscreen_widgets import * from mainscreen_widgets import *
import settings import settings
import platform
import toxes import toxes
@ -519,7 +518,7 @@ class MainWindow(QtWidgets.QMainWindow, Singleton):
def send_file(self): def send_file(self):
self.menu.hide() self.menu.hide()
if self.profile.active_friend + 1: if self.profile.active_friend + 1and self.profile.is_active_a_friend():
choose = QtWidgets.QApplication.translate("MainWindow", 'Choose file') choose = QtWidgets.QApplication.translate("MainWindow", 'Choose file')
name = QtWidgets.QFileDialog.getOpenFileName(self, choose, options=QtWidgets.QFileDialog.DontUseNativeDialog) name = QtWidgets.QFileDialog.getOpenFileName(self, choose, options=QtWidgets.QFileDialog.DontUseNativeDialog)
if name[0]: if name[0]:
@ -527,7 +526,7 @@ class MainWindow(QtWidgets.QMainWindow, Singleton):
def send_screenshot(self, hide=False): def send_screenshot(self, hide=False):
self.menu.hide() self.menu.hide()
if self.profile.active_friend + 1: if self.profile.active_friend + 1 and self.profile.is_active_a_friend():
self.sw = ScreenShotWindow(self) self.sw = ScreenShotWindow(self)
self.sw.show() self.sw.show()
if hide: if hide:
@ -545,7 +544,7 @@ class MainWindow(QtWidgets.QMainWindow, Singleton):
def send_sticker(self): def send_sticker(self):
self.menu.hide() self.menu.hide()
if self.profile.active_friend + 1: if self.profile.active_friend + 1 and self.profile.is_active_a_friend():
self.sticker = StickerWindow(self) self.sticker = StickerWindow(self)
self.sticker.setGeometry(QtCore.QRect(self.x() if Settings.get_instance()['mirror_mode'] else 270 + self.x(), self.sticker.setGeometry(QtCore.QRect(self.x() if Settings.get_instance()['mirror_mode'] else 270 + self.x(),
self.y() + self.height() - 200, self.y() + self.height() - 200,
@ -593,6 +592,7 @@ class MainWindow(QtWidgets.QMainWindow, Singleton):
is_friend = type(friend) is Friend is_friend = type(friend) is Friend
if is_friend: if is_friend:
set_alias_item = self.listMenu.addAction(QtWidgets.QApplication.translate("MainWindow", 'Set alias')) set_alias_item = self.listMenu.addAction(QtWidgets.QApplication.translate("MainWindow", 'Set alias'))
set_alias_item.triggered.connect(lambda: self.set_alias(num))
history_menu = self.listMenu.addMenu(QtWidgets.QApplication.translate("MainWindow", 'Chat history')) history_menu = self.listMenu.addMenu(QtWidgets.QApplication.translate("MainWindow", 'Chat history'))
clear_history_item = history_menu.addAction(QtWidgets.QApplication.translate("MainWindow", 'Clear history')) clear_history_item = history_menu.addAction(QtWidgets.QApplication.translate("MainWindow", 'Clear history'))
@ -610,13 +610,20 @@ class MainWindow(QtWidgets.QMainWindow, Singleton):
block_item = self.listMenu.addAction(QtWidgets.QApplication.translate("MainWindow", 'Block friend')) block_item = self.listMenu.addAction(QtWidgets.QApplication.translate("MainWindow", 'Block friend'))
notes_item = self.listMenu.addAction(QtWidgets.QApplication.translate("MainWindow", 'Notes')) notes_item = self.listMenu.addAction(QtWidgets.QApplication.translate("MainWindow", 'Notes'))
chats = self.profile.get_group_chats()
if len(chats) and self.profile.is_active_online():
invite_menu = self.listMenu.addMenu(QtWidgets.QApplication.translate("MainWindow", 'Invite to group chat'))
for i in range(len(chats)):
name, number = chats[i]
item = invite_menu.addAction(name)
item.triggered.connect(lambda: self.invite_friend_to_gc(num, number))
plugins_loader = plugin_support.PluginLoader.get_instance() plugins_loader = plugin_support.PluginLoader.get_instance()
if plugins_loader is not None: if plugins_loader is not None:
submenu = plugins_loader.get_menu(self.listMenu, num) submenu = plugins_loader.get_menu(self.listMenu, num)
if len(submenu): if len(submenu):
plug = self.listMenu.addMenu(QtWidgets.QApplication.translate("MainWindow", 'Plugins')) plug = self.listMenu.addMenu(QtWidgets.QApplication.translate("MainWindow", 'Plugins'))
plug.addActions(submenu) plug.addActions(submenu)
set_alias_item.triggered.connect(lambda: self.set_alias(num))
copy_key_item.triggered.connect(lambda: self.copy_friend_key(num)) copy_key_item.triggered.connect(lambda: self.copy_friend_key(num))
remove_item.triggered.connect(lambda: self.remove_friend(num)) remove_item.triggered.connect(lambda: self.remove_friend(num))
block_item.triggered.connect(lambda: self.block_friend(num)) block_item.triggered.connect(lambda: self.block_friend(num))
@ -705,6 +712,9 @@ class MainWindow(QtWidgets.QMainWindow, Singleton):
settings['auto_accept_from_friends'].remove(tox_id) settings['auto_accept_from_friends'].remove(tox_id)
settings.save() settings.save()
def invite_friend_to_gc(self, friend_number, group_number):
self.profile.invite_friend(friend_number, group_number)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Functions which called when user click somewhere else # Functions which called when user click somewhere else
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------

View File

@ -508,15 +508,17 @@ class NotificationsSettings(CenteredWidget):
def initUI(self): def initUI(self):
self.setObjectName("notificationsForm") self.setObjectName("notificationsForm")
self.resize(350, 180) self.resize(350, 210)
self.setMinimumSize(QtCore.QSize(350, 180)) self.setMinimumSize(QtCore.QSize(350, 210))
self.setMaximumSize(QtCore.QSize(350, 180)) self.setMaximumSize(QtCore.QSize(350, 210))
self.enableNotifications = QtWidgets.QCheckBox(self) self.enableNotifications = QtWidgets.QCheckBox(self)
self.enableNotifications.setGeometry(QtCore.QRect(10, 20, 340, 18)) self.enableNotifications.setGeometry(QtCore.QRect(10, 20, 340, 18))
self.callsSound = QtWidgets.QCheckBox(self) self.callsSound = QtWidgets.QCheckBox(self)
self.callsSound.setGeometry(QtCore.QRect(10, 120, 340, 18)) self.callsSound.setGeometry(QtCore.QRect(10, 170, 340, 18))
self.soundNotifications = QtWidgets.QCheckBox(self) self.soundNotifications = QtWidgets.QCheckBox(self)
self.soundNotifications.setGeometry(QtCore.QRect(10, 70, 340, 18)) self.soundNotifications.setGeometry(QtCore.QRect(10, 70, 340, 18))
self.groupNotifications = QtWidgets.QCheckBox(self)
self.groupNotifications.setGeometry(QtCore.QRect(10, 120, 340, 18))
font = QtGui.QFont() font = QtGui.QFont()
s = Settings.get_instance() s = Settings.get_instance()
font.setFamily(s['font']) font.setFamily(s['font'])
@ -524,8 +526,10 @@ class NotificationsSettings(CenteredWidget):
self.callsSound.setFont(font) self.callsSound.setFont(font)
self.soundNotifications.setFont(font) self.soundNotifications.setFont(font)
self.enableNotifications.setFont(font) self.enableNotifications.setFont(font)
self.groupNotifications.setFont(font)
self.enableNotifications.setChecked(s['notifications']) self.enableNotifications.setChecked(s['notifications'])
self.soundNotifications.setChecked(s['sound_notifications']) self.soundNotifications.setChecked(s['sound_notifications'])
self.groupNotifications.setChecked(s['group_notifications'])
self.callsSound.setChecked(s['calls_sound']) self.callsSound.setChecked(s['calls_sound'])
self.retranslateUi() self.retranslateUi()
QtCore.QMetaObject.connectSlotsByName(self) QtCore.QMetaObject.connectSlotsByName(self)
@ -533,6 +537,7 @@ class NotificationsSettings(CenteredWidget):
def retranslateUi(self): def retranslateUi(self):
self.setWindowTitle(QtWidgets.QApplication.translate("notificationsForm", "Notification settings")) self.setWindowTitle(QtWidgets.QApplication.translate("notificationsForm", "Notification settings"))
self.enableNotifications.setText(QtWidgets.QApplication.translate("notificationsForm", "Enable notifications")) self.enableNotifications.setText(QtWidgets.QApplication.translate("notificationsForm", "Enable notifications"))
self.groupNotifications.setText(QtWidgets.QApplication.translate("notificationsForm", "Notify about all messages in groups"))
self.callsSound.setText(QtWidgets.QApplication.translate("notificationsForm", "Enable call\'s sound")) self.callsSound.setText(QtWidgets.QApplication.translate("notificationsForm", "Enable call\'s sound"))
self.soundNotifications.setText(QtWidgets.QApplication.translate("notificationsForm", "Enable sound notifications")) self.soundNotifications.setText(QtWidgets.QApplication.translate("notificationsForm", "Enable sound notifications"))
@ -540,6 +545,7 @@ class NotificationsSettings(CenteredWidget):
settings = Settings.get_instance() settings = Settings.get_instance()
settings['notifications'] = self.enableNotifications.isChecked() settings['notifications'] = self.enableNotifications.isChecked()
settings['sound_notifications'] = self.soundNotifications.isChecked() settings['sound_notifications'] = self.soundNotifications.isChecked()
settings['group_notifications'] = self.groupNotifications.isChecked()
settings['calls_sound'] = self.callsSound.isChecked() settings['calls_sound'] = self.callsSound.isChecked()
settings.save() settings.save()

View File

@ -205,6 +205,7 @@ class Profile(basecontact.BaseContact, Singleton):
if value == -1: # all friends were deleted if value == -1: # all friends were deleted
self._screen.account_name.setText('') self._screen.account_name.setText('')
self._screen.account_status.setText('') self._screen.account_status.setText('')
self._screen.account_status.setToolTip('')
self._active_friend = -1 self._active_friend = -1
self._screen.account_avatar.setHidden(True) self._screen.account_avatar.setHidden(True)
self._messages.clear() self._messages.clear()
@ -274,6 +275,7 @@ class Profile(basecontact.BaseContact, Singleton):
self._screen.account_name.setText(friend.name) self._screen.account_name.setText(friend.name)
self._screen.account_status.setText(friend.status_message) self._screen.account_status.setText(friend.status_message)
self._screen.account_status.setToolTip(friend.get_full_status())
if friend.tox_id is None: if friend.tox_id is None:
avatar_path = curr_directory() + '/images/group.png' avatar_path = curr_directory() + '/images/group.png'
else: else:
@ -354,7 +356,7 @@ class Profile(basecontact.BaseContact, Singleton):
elif data[1] == friend_number and not data[2]: elif data[1] == friend_number and not data[2]:
self.send_file(data[0], friend_number, True, key) self.send_file(data[0], friend_number, True, key)
del self._paused_file_transfers[key] del self._paused_file_transfers[key]
if friend_number == self.get_active_number(): if friend_number == self.get_active_number() and self.is_active_a_friend():
self.update() self.update()
except Exception as ex: except Exception as ex:
print('Exception in file sending: ' + str(ex)) print('Exception in file sending: ' + str(ex))
@ -396,7 +398,7 @@ class Profile(basecontact.BaseContact, Singleton):
""" """
Display incoming typing notification Display incoming typing notification
""" """
if friend_number == self.get_active_number(): if friend_number == self.get_active_number() and self.is_active_a_friend():
self._screen.typing.setVisible(typing) self._screen.typing.setVisible(typing)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
@ -452,7 +454,7 @@ class Profile(basecontact.BaseContact, Singleton):
:param message_type: message type - plain text or action message (/me) :param message_type: message type - plain text or action message (/me)
:param message: text of message :param message: text of message
""" """
if friend_num == self.get_active_number(): # add message to list if friend_num == self.get_active_number()and self.is_active_a_friend(): # add message to list
t = time.time() t = time.time()
self.create_message_item(message, t, MESSAGE_OWNER['FRIEND'], message_type) self.create_message_item(message, t, MESSAGE_OWNER['FRIEND'], message_type)
self._messages.scrollToBottom() self._messages.scrollToBottom()
@ -712,7 +714,7 @@ class Profile(basecontact.BaseContact, Singleton):
except: except:
pass pass
settings.save() settings.save()
if num == self.get_active_number(): if num == self.get_active_number() and self.is_active_a_friend():
self.update() self.update()
def friend_public_key(self, num): def friend_public_key(self, num):
@ -956,7 +958,7 @@ class Profile(basecontact.BaseContact, Singleton):
friend_number, friend_number,
file_number) file_number)
accepted = False accepted = False
if friend_number == self.get_active_number(): if friend_number == self.get_active_number() and self.is_active_a_friend():
item = self.create_file_transfer_item(tm) item = self.create_file_transfer_item(tm)
if accepted: if accepted:
self._file_transfers[(friend_number, file_number)].set_state_changed_handler(item.update_transfer_state) self._file_transfers[(friend_number, file_number)].set_state_changed_handler(item.update_transfer_state)
@ -987,7 +989,7 @@ class Profile(basecontact.BaseContact, Singleton):
else: else:
if not already_cancelled: if not already_cancelled:
self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['CANCEL']) self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['CANCEL'])
if friend_number == self.get_active_number(): if friend_number == self.get_active_number() and self.is_active_a_friend():
tmp = self._messages.count() + i tmp = self._messages.count() + i
if tmp >= 0: if tmp >= 0:
self._messages.itemWidget(self._messages.item(tmp)).update(TOX_FILE_TRANSFER_STATE['CANCELLED'], self._messages.itemWidget(self._messages.item(tmp)).update(TOX_FILE_TRANSFER_STATE['CANCELLED'],
@ -1141,7 +1143,7 @@ class Profile(basecontact.BaseContact, Singleton):
t = type(transfer) t = type(transfer)
if t is ReceiveAvatar: 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(): if friend_number == self.get_active_number() and self.is_active_a_friend():
self.set_active(None) self.set_active(None)
elif t is ReceiveToBuffer or (t is SendFromBuffer and Settings.get_instance()['allow_inline']): # inline image elif t is ReceiveToBuffer or (t is SendFromBuffer and Settings.get_instance()['allow_inline']): # inline image
print('inline') print('inline')
@ -1149,7 +1151,7 @@ class Profile(basecontact.BaseContact, Singleton):
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'], TOX_FILE_TRANSFER_STATE['FINISHED'],
inline) inline)
if friend_number == self.get_active_number(): if friend_number == self.get_active_number() and self.is_active_a_friend():
count = self._messages.count() count = self._messages.count()
if count + i + 1 >= 0: if count + i + 1 >= 0:
elem = QtWidgets.QListWidgetItem() elem = QtWidgets.QListWidgetItem()
@ -1191,7 +1193,7 @@ class Profile(basecontact.BaseContact, Singleton):
ra.set_transfer_finished_handler(self.transfer_finished) ra.set_transfer_finished_handler(self.transfer_finished)
else: 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: if self.get_active_number() == friend_number and self.is_active_a_friend():
self.set_active(None) self.set_active(None)
def reset_avatar(self): def reset_avatar(self):
@ -1216,6 +1218,8 @@ class Profile(basecontact.BaseContact, Singleton):
def call_click(self, audio=True, video=False): def call_click(self, audio=True, video=False):
"""User clicked audio button in main window""" """User clicked audio button in main window"""
num = self.get_active_number() num = self.get_active_number()
if not self.is_active_a_friend():
return
if num not in self._call and self.is_active_online(): # start call if num not in self._call and self.is_active_online(): # start call
if not Settings.get_instance().audio['enabled']: if not Settings.get_instance().audio['enabled']:
return return
@ -1389,6 +1393,15 @@ class Profile(basecontact.BaseContact, Singleton):
self._tox.group_set_title(gc.number, text) self._tox.group_set_title(gc.number, text)
self.new_gc_title(gc.number, text) self.new_gc_title(gc.number, text)
def get_group_chats(self):
chats = filter(lambda x: type(x) is GroupChat, self._contacts)
chats = map(lambda c: (c.name, c.number), chats)
return list(chats)
def invite_friend(self, friend_num, group_number):
friend = self._contacts[friend_num]
self._tox.invite_friend(friend.number, group_number)
def tox_factory(data=None, settings=None): def tox_factory(data=None, settings=None):
""" """

View File

@ -144,7 +144,8 @@ class Settings(dict, Singleton):
'show_welcome_screen': True, 'show_welcome_screen': True,
'close_to_tray': False, 'close_to_tray': False,
'font': 'Times New Roman', 'font': 'Times New Roman',
'update': 1 'update': 1,
'group_notifications': True
} }
@staticmethod @staticmethod

View File

@ -1565,24 +1565,14 @@ class Tox:
result = Tox.libtoxcore.tox_group_number_peers(self._tox_pointer, c_int(groupnumber), None) result = Tox.libtoxcore.tox_group_number_peers(self._tox_pointer, c_int(groupnumber), None)
return result return result
def group_get_names(self, groupnumber):
peers_count = self.group_number_peers(groupnumber)
arr = (c_char_p * peers_count)()
for i in range(peers_count):
arr[i] = create_string_buffer(TOX_MAX_NAME_LENGTH)
result = Tox.libtoxcore.tox_group_get_names(self._tox_pointer, c_int(groupnumber),
arr, None, c_uint16(peers_count), None)
arr = map(lambda x: str(x, 'utf-8'), arr)
return list(arr)
def add_av_groupchat(self): def add_av_groupchat(self):
result = self.AV.libtoxav.tox_add_av_groupchat(self._tox_pointer, None, None, None) result = self.AV.libtoxav.toxav_add_av_groupchat(self._tox_pointer, None, None)
return result return result
def join_av_groupchat(self, friendnumber, data): def join_av_groupchat(self, friendnumber, data):
result = self.AV.libtoxav.tox_join_av_groupchat(self._tox_pointer, c_int(friendnumber), result = self.AV.libtoxav.toxav_join_av_groupchat(self._tox_pointer, c_int32(friendnumber),
c_char_p(data), c_uint16(len(data)), c_char_p(data), c_uint16(len(data)),
None, None, None) None, None)
return result return result
def callback_group_invite(self, callback, user_data=None): def callback_group_invite(self, callback, user_data=None):