group notifications and bug fixes
This commit is contained in:
parent
db519e2608
commit
65167de1fe
8 changed files with 99 additions and 43 deletions
|
@ -384,14 +384,34 @@ def group_invite(tox, friend_number, gc_type, data, length, user_data):
|
|||
bytes(data[:length]))
|
||||
|
||||
|
||||
def group_message(tox, group_number, peer_number, message, length, user_data):
|
||||
invoke_in_main_thread(Profile.get_instance().new_gc_message, group_number,
|
||||
peer_number, TOX_MESSAGE_TYPE['NORMAL'], str(message, 'utf-8'))
|
||||
def show_gc_notification(window, tray, message, group_number):
|
||||
profile = Profile.get_instance()
|
||||
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):
|
||||
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'], str(message, 'utf-8'))
|
||||
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):
|
||||
|
@ -440,7 +460,7 @@ def init_callbacks(tox, window, tray):
|
|||
tox.callback_friend_lossy_packet(lossy_packet, 0)
|
||||
|
||||
tox.callback_group_invite(group_invite)
|
||||
tox.callback_group_message(group_message)
|
||||
tox.callback_group_action(group_action)
|
||||
tox.callback_group_message(group_message(window, tray))
|
||||
tox.callback_group_action(group_action(window, tray))
|
||||
tox.callback_group_title(group_title)
|
||||
tox.callback_group_namelist_change(group_namelist_change)
|
||||
|
|
|
@ -66,3 +66,10 @@ class Friend(contact.Contact):
|
|||
if self._receipts:
|
||||
self._receipts -= 1
|
||||
self.mark_as_sent()
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Full status
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_full_status(self):
|
||||
return self._status_message
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import contact
|
||||
import util
|
||||
from PyQt5 import QtGui, QtCore
|
||||
import toxcore_enums_and_consts as cnst
|
||||
import toxcore_enums_and_consts as constants
|
||||
|
||||
|
||||
class GroupChat(contact.Contact):
|
||||
|
@ -9,7 +9,7 @@ class GroupChat(contact.Contact):
|
|||
def __init__(self, name, status_message, widget, tox, group_number):
|
||||
super().__init__(None, group_number, name, status_message, widget, None)
|
||||
self._tox = tox
|
||||
self._status = cnst.TOX_USER_STATUS['NONE']
|
||||
self.set_status(constants.TOX_USER_STATUS['NONE'])
|
||||
|
||||
def set_name(self, name):
|
||||
self._tox.group_set_title(self._number, name)
|
||||
|
@ -31,3 +31,12 @@ class GroupChat(contact.Contact):
|
|||
|
||||
def remove_invalid_unsent_files(self):
|
||||
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)
|
||||
|
|
|
@ -5,7 +5,6 @@ from widgets import MultilineEdit, ComboBox
|
|||
import plugin_support
|
||||
from mainscreen_widgets import *
|
||||
import settings
|
||||
import platform
|
||||
import toxes
|
||||
|
||||
|
||||
|
@ -519,7 +518,7 @@ class MainWindow(QtWidgets.QMainWindow, Singleton):
|
|||
|
||||
def send_file(self):
|
||||
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')
|
||||
name = QtWidgets.QFileDialog.getOpenFileName(self, choose, options=QtWidgets.QFileDialog.DontUseNativeDialog)
|
||||
if name[0]:
|
||||
|
@ -527,7 +526,7 @@ class MainWindow(QtWidgets.QMainWindow, Singleton):
|
|||
|
||||
def send_screenshot(self, hide=False):
|
||||
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.show()
|
||||
if hide:
|
||||
|
@ -545,7 +544,7 @@ class MainWindow(QtWidgets.QMainWindow, Singleton):
|
|||
|
||||
def send_sticker(self):
|
||||
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.setGeometry(QtCore.QRect(self.x() if Settings.get_instance()['mirror_mode'] else 270 + self.x(),
|
||||
self.y() + self.height() - 200,
|
||||
|
@ -593,6 +592,7 @@ class MainWindow(QtWidgets.QMainWindow, Singleton):
|
|||
is_friend = type(friend) is Friend
|
||||
if is_friend:
|
||||
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'))
|
||||
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'))
|
||||
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()
|
||||
if plugins_loader is not None:
|
||||
submenu = plugins_loader.get_menu(self.listMenu, num)
|
||||
if len(submenu):
|
||||
plug = self.listMenu.addMenu(QtWidgets.QApplication.translate("MainWindow", 'Plugins'))
|
||||
plug.addActions(submenu)
|
||||
set_alias_item.triggered.connect(lambda: self.set_alias(num))
|
||||
copy_key_item.triggered.connect(lambda: self.copy_friend_key(num))
|
||||
remove_item.triggered.connect(lambda: self.remove_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.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
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -508,15 +508,17 @@ class NotificationsSettings(CenteredWidget):
|
|||
|
||||
def initUI(self):
|
||||
self.setObjectName("notificationsForm")
|
||||
self.resize(350, 180)
|
||||
self.setMinimumSize(QtCore.QSize(350, 180))
|
||||
self.setMaximumSize(QtCore.QSize(350, 180))
|
||||
self.resize(350, 210)
|
||||
self.setMinimumSize(QtCore.QSize(350, 210))
|
||||
self.setMaximumSize(QtCore.QSize(350, 210))
|
||||
self.enableNotifications = QtWidgets.QCheckBox(self)
|
||||
self.enableNotifications.setGeometry(QtCore.QRect(10, 20, 340, 18))
|
||||
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.setGeometry(QtCore.QRect(10, 70, 340, 18))
|
||||
self.groupNotifications = QtWidgets.QCheckBox(self)
|
||||
self.groupNotifications.setGeometry(QtCore.QRect(10, 120, 340, 18))
|
||||
font = QtGui.QFont()
|
||||
s = Settings.get_instance()
|
||||
font.setFamily(s['font'])
|
||||
|
@ -524,8 +526,10 @@ class NotificationsSettings(CenteredWidget):
|
|||
self.callsSound.setFont(font)
|
||||
self.soundNotifications.setFont(font)
|
||||
self.enableNotifications.setFont(font)
|
||||
self.groupNotifications.setFont(font)
|
||||
self.enableNotifications.setChecked(s['notifications'])
|
||||
self.soundNotifications.setChecked(s['sound_notifications'])
|
||||
self.groupNotifications.setChecked(s['group_notifications'])
|
||||
self.callsSound.setChecked(s['calls_sound'])
|
||||
self.retranslateUi()
|
||||
QtCore.QMetaObject.connectSlotsByName(self)
|
||||
|
@ -533,6 +537,7 @@ class NotificationsSettings(CenteredWidget):
|
|||
def retranslateUi(self):
|
||||
self.setWindowTitle(QtWidgets.QApplication.translate("notificationsForm", "Notification settings"))
|
||||
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.soundNotifications.setText(QtWidgets.QApplication.translate("notificationsForm", "Enable sound notifications"))
|
||||
|
||||
|
@ -540,6 +545,7 @@ class NotificationsSettings(CenteredWidget):
|
|||
settings = Settings.get_instance()
|
||||
settings['notifications'] = self.enableNotifications.isChecked()
|
||||
settings['sound_notifications'] = self.soundNotifications.isChecked()
|
||||
settings['group_notifications'] = self.groupNotifications.isChecked()
|
||||
settings['calls_sound'] = self.callsSound.isChecked()
|
||||
settings.save()
|
||||
|
||||
|
|
|
@ -205,6 +205,7 @@ class Profile(basecontact.BaseContact, Singleton):
|
|||
if value == -1: # all friends were deleted
|
||||
self._screen.account_name.setText('')
|
||||
self._screen.account_status.setText('')
|
||||
self._screen.account_status.setToolTip('')
|
||||
self._active_friend = -1
|
||||
self._screen.account_avatar.setHidden(True)
|
||||
self._messages.clear()
|
||||
|
@ -274,6 +275,7 @@ class Profile(basecontact.BaseContact, Singleton):
|
|||
|
||||
self._screen.account_name.setText(friend.name)
|
||||
self._screen.account_status.setText(friend.status_message)
|
||||
self._screen.account_status.setToolTip(friend.get_full_status())
|
||||
if friend.tox_id is None:
|
||||
avatar_path = curr_directory() + '/images/group.png'
|
||||
else:
|
||||
|
@ -354,7 +356,7 @@ class Profile(basecontact.BaseContact, Singleton):
|
|||
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():
|
||||
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))
|
||||
|
@ -396,7 +398,7 @@ class Profile(basecontact.BaseContact, Singleton):
|
|||
"""
|
||||
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)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
@ -452,7 +454,7 @@ class Profile(basecontact.BaseContact, Singleton):
|
|||
:param message_type: message type - plain text or action message (/me)
|
||||
: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()
|
||||
self.create_message_item(message, t, MESSAGE_OWNER['FRIEND'], message_type)
|
||||
self._messages.scrollToBottom()
|
||||
|
@ -712,7 +714,7 @@ class Profile(basecontact.BaseContact, Singleton):
|
|||
except:
|
||||
pass
|
||||
settings.save()
|
||||
if num == self.get_active_number():
|
||||
if num == self.get_active_number() and self.is_active_a_friend():
|
||||
self.update()
|
||||
|
||||
def friend_public_key(self, num):
|
||||
|
@ -956,7 +958,7 @@ class Profile(basecontact.BaseContact, Singleton):
|
|||
friend_number,
|
||||
file_number)
|
||||
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)
|
||||
if accepted:
|
||||
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:
|
||||
if not already_cancelled:
|
||||
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
|
||||
if tmp >= 0:
|
||||
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)
|
||||
if t is ReceiveAvatar:
|
||||
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)
|
||||
elif t is ReceiveToBuffer or (t is SendFromBuffer and Settings.get_instance()['allow_inline']): # inline image
|
||||
print('inline')
|
||||
|
@ -1149,7 +1151,7 @@ class Profile(basecontact.BaseContact, Singleton):
|
|||
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():
|
||||
if friend_number == self.get_active_number() and self.is_active_a_friend():
|
||||
count = self._messages.count()
|
||||
if count + i + 1 >= 0:
|
||||
elem = QtWidgets.QListWidgetItem()
|
||||
|
@ -1191,7 +1193,7 @@ class Profile(basecontact.BaseContact, Singleton):
|
|||
ra.set_transfer_finished_handler(self.transfer_finished)
|
||||
else:
|
||||
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)
|
||||
|
||||
def reset_avatar(self):
|
||||
|
@ -1216,6 +1218,8 @@ class Profile(basecontact.BaseContact, Singleton):
|
|||
def call_click(self, audio=True, video=False):
|
||||
"""User clicked audio button in main window"""
|
||||
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 not Settings.get_instance().audio['enabled']:
|
||||
return
|
||||
|
@ -1389,6 +1393,15 @@ class Profile(basecontact.BaseContact, Singleton):
|
|||
self._tox.group_set_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):
|
||||
"""
|
||||
|
|
|
@ -144,7 +144,8 @@ class Settings(dict, Singleton):
|
|||
'show_welcome_screen': True,
|
||||
'close_to_tray': False,
|
||||
'font': 'Times New Roman',
|
||||
'update': 1
|
||||
'update': 1,
|
||||
'group_notifications': True
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -1565,24 +1565,14 @@ class Tox:
|
|||
result = Tox.libtoxcore.tox_group_number_peers(self._tox_pointer, c_int(groupnumber), None)
|
||||
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):
|
||||
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
|
||||
|
||||
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)),
|
||||
None, None, None)
|
||||
None, None)
|
||||
return result
|
||||
|
||||
def callback_group_invite(self, callback, user_data=None):
|
||||
|
|
Loading…
Reference in a new issue