9578053 Jan 22 2022 distfiles.gentoo.org/distfiles/gajim-1.3.3-2.tar.gz
This commit is contained in:
parent
a5b3822651
commit
4c1b226bff
1045 changed files with 753037 additions and 18 deletions
355
gajim/gtk/profile.py
Normal file
355
gajim/gtk/profile.py
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
import logging
|
||||
|
||||
from gi.repository import Gio
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
|
||||
from nbxmpp.errors import StanzaError
|
||||
from nbxmpp.namespaces import Namespace
|
||||
from nbxmpp.modules.vcard4 import VCard
|
||||
from nbxmpp.modules.user_avatar import Avatar
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common.const import AvatarSize
|
||||
from gajim.common.i18n import _
|
||||
from gajim.common.i18n import Q_
|
||||
|
||||
from gajim.gui.avatar import clip_circle
|
||||
from gajim.gui.avatar_selector import AvatarSelector
|
||||
from gajim.gui.dialogs import ErrorDialog
|
||||
from gajim.gui.filechoosers import AvatarChooserDialog
|
||||
from gajim.gui.util import get_builder
|
||||
from gajim.gui.vcard_grid import VCardGrid
|
||||
from gajim.gui.util import scroll_to_end
|
||||
|
||||
log = logging.getLogger('gajim.gui.profile')
|
||||
|
||||
MENU_DICT = {
|
||||
'fn': Q_('?profile:Full Name'),
|
||||
'bday': _('Birthday'),
|
||||
'gender': Q_('?profile:Gender'),
|
||||
'adr': Q_('?profile:Address'),
|
||||
'email': _('Email'),
|
||||
'impp': Q_('?profile:IM Address'),
|
||||
'tel': _('Phone No.'),
|
||||
'org': Q_('?profile:Organisation'),
|
||||
'title': Q_('?profile:Title'),
|
||||
'role': Q_('?profile:Role'),
|
||||
'url': _('URL'),
|
||||
'key': Q_('?profile:Public Encryption Key'),
|
||||
'note': Q_('?profile:Note'),
|
||||
}
|
||||
|
||||
|
||||
class ProfileWindow(Gtk.ApplicationWindow):
|
||||
def __init__(self, account, *args):
|
||||
Gtk.ApplicationWindow.__init__(self)
|
||||
self.set_application(app.app)
|
||||
self.set_position(Gtk.WindowPosition.CENTER)
|
||||
self.set_show_menubar(False)
|
||||
self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
|
||||
self.set_resizable(True)
|
||||
self.set_default_size(700, 600)
|
||||
self.set_name('ProfileWindow')
|
||||
self.set_title(_('Profile'))
|
||||
|
||||
self.account = account
|
||||
self._jid = app.get_jid_from_account(account)
|
||||
|
||||
self._ui = get_builder('profile.ui')
|
||||
|
||||
menu = Gio.Menu()
|
||||
for action, label in MENU_DICT.items():
|
||||
menu.append(label, 'win.add-' + action.lower())
|
||||
|
||||
self._ui.add_entry_button.set_menu_model(menu)
|
||||
self._add_actions()
|
||||
|
||||
self._avatar_selector = None
|
||||
self._current_avatar = None
|
||||
self._current_vcard = None
|
||||
self._avatar_nick_public = None
|
||||
|
||||
# False - no change to avatar
|
||||
# None - we want to delete the avatar
|
||||
# Avatar - upload new avatar
|
||||
self._new_avatar = False
|
||||
|
||||
self._ui.nickname_entry.set_text(app.nicks[account])
|
||||
|
||||
self._vcard_grid = VCardGrid(self.account)
|
||||
self._ui.profile_box.add(self._vcard_grid)
|
||||
|
||||
self.add(self._ui.profile_stack)
|
||||
self.show_all()
|
||||
|
||||
self._load_avatar()
|
||||
|
||||
client = app.get_client(account)
|
||||
client.get_module('VCard4').request_vcard(
|
||||
callback=self._on_vcard_received)
|
||||
|
||||
client.get_module('PubSub').get_access_model(
|
||||
Namespace.VCARD4_PUBSUB,
|
||||
callback=self._on_access_model_received,
|
||||
user_data=Namespace.VCARD4_PUBSUB)
|
||||
|
||||
client.get_module('PubSub').get_access_model(
|
||||
Namespace.AVATAR_METADATA,
|
||||
callback=self._on_access_model_received,
|
||||
user_data=Namespace.AVATAR_METADATA)
|
||||
|
||||
client.get_module('PubSub').get_access_model(
|
||||
Namespace.AVATAR_DATA,
|
||||
callback=self._on_access_model_received,
|
||||
user_data=Namespace.AVATAR_DATA)
|
||||
|
||||
client.get_module('PubSub').get_access_model(
|
||||
Namespace.NICK,
|
||||
callback=self._on_access_model_received,
|
||||
user_data=Namespace.NICK)
|
||||
|
||||
self._ui.connect_signals(self)
|
||||
self.connect('key-press-event', self._on_key_press_event)
|
||||
|
||||
def _on_access_model_received(self, task):
|
||||
namespace = task.get_user_data()
|
||||
|
||||
try:
|
||||
result = task.finish()
|
||||
except StanzaError as error:
|
||||
log.warning('Unable to get access model for %s: %s',
|
||||
namespace, error)
|
||||
return
|
||||
|
||||
access_model = result == 'open'
|
||||
|
||||
if namespace == Namespace.VCARD4_PUBSUB:
|
||||
self._set_vcard_access_switch(access_model)
|
||||
else:
|
||||
if self._avatar_nick_public is None:
|
||||
self._avatar_nick_public = access_model
|
||||
else:
|
||||
self._avatar_nick_public = (self._avatar_nick_public or
|
||||
access_model)
|
||||
self._set_avatar_nick_access_switch(self._avatar_nick_public)
|
||||
|
||||
def _on_vcard_received(self, task):
|
||||
try:
|
||||
self._current_vcard = task.finish()
|
||||
except StanzaError as error:
|
||||
log.info('Error loading VCard: %s', error)
|
||||
self._current_vcard = VCard()
|
||||
|
||||
if self._current_vcard is None:
|
||||
self._current_vcard = VCard()
|
||||
|
||||
self._load_avatar()
|
||||
self._vcard_grid.set_vcard(self._current_vcard.copy())
|
||||
self._ui.profile_stack.set_visible_child_name('profile')
|
||||
self._ui.spinner.stop()
|
||||
|
||||
def _load_avatar(self):
|
||||
scale = self.get_scale_factor()
|
||||
self._current_avatar = app.contacts.get_avatar(
|
||||
self.account,
|
||||
self._jid,
|
||||
AvatarSize.VCARD,
|
||||
scale)
|
||||
|
||||
self._ui.avatar_image.set_from_surface(self._current_avatar)
|
||||
self._ui.avatar_image.show()
|
||||
|
||||
def _on_key_press_event(self, _widget, event):
|
||||
if event.keyval == Gdk.KEY_Escape:
|
||||
self.destroy()
|
||||
|
||||
def _add_actions(self):
|
||||
for action in MENU_DICT:
|
||||
action_name = 'add-' + action.lower()
|
||||
act = Gio.SimpleAction.new(action_name, None)
|
||||
act.connect('activate', self._on_action)
|
||||
self.add_action(act)
|
||||
|
||||
def _on_action(self, action, _param):
|
||||
name = action.get_name()
|
||||
key = name.split('-')[1]
|
||||
self._vcard_grid.add_new_property(key)
|
||||
GLib.idle_add(scroll_to_end, self._ui.scrolled)
|
||||
|
||||
def _on_edit_clicked(self, *args):
|
||||
self._vcard_grid.set_editable(True)
|
||||
self._ui.edit_button.hide()
|
||||
self._ui.add_entry_button.set_no_show_all(False)
|
||||
self._ui.add_entry_button.show_all()
|
||||
self._ui.cancel_button.show()
|
||||
self._ui.save_button.show()
|
||||
self._ui.remove_avatar_button.show()
|
||||
self._ui.edit_avatar_button.show()
|
||||
self._ui.nickname_entry.set_sensitive(True)
|
||||
self._ui.privacy_button.show()
|
||||
|
||||
def _on_cancel_clicked(self, _widget):
|
||||
self._vcard_grid.set_editable(False)
|
||||
self._ui.edit_button.show()
|
||||
self._ui.add_entry_button.hide()
|
||||
self._ui.cancel_button.hide()
|
||||
self._ui.save_button.hide()
|
||||
self._ui.remove_avatar_button.hide()
|
||||
self._ui.edit_avatar_button.hide()
|
||||
self._ui.privacy_button.hide()
|
||||
self._ui.nickname_entry.set_sensitive(False)
|
||||
self._ui.avatar_image.set_from_surface(self._current_avatar)
|
||||
self._ui.nickname_entry.set_text(app.nicks[self.account])
|
||||
self._vcard_grid.set_vcard(self._current_vcard.copy())
|
||||
self._new_avatar = False
|
||||
|
||||
def _on_save_clicked(self, _widget):
|
||||
self._ui.spinner.start()
|
||||
self._ui.profile_stack.set_visible_child_name('spinner')
|
||||
self._ui.add_entry_button.hide()
|
||||
self._ui.cancel_button.hide()
|
||||
self._ui.save_button.hide()
|
||||
self._ui.edit_button.show()
|
||||
self._ui.remove_avatar_button.hide()
|
||||
self._ui.edit_avatar_button.hide()
|
||||
self._ui.privacy_button.hide()
|
||||
self._ui.nickname_entry.set_sensitive(False)
|
||||
|
||||
self._vcard_grid.validate()
|
||||
self._vcard_grid.sort()
|
||||
|
||||
vcard = self._vcard_grid.get_vcard()
|
||||
self._current_vcard = vcard.copy()
|
||||
|
||||
con = app.connections[self.account]
|
||||
con.get_module('VCard4').set_vcard(
|
||||
self._current_vcard,
|
||||
public=self._ui.vcard_access.get_active(),
|
||||
callback=self._on_save_finished)
|
||||
|
||||
public = self._ui.avatar_nick_access.get_active()
|
||||
|
||||
if self._new_avatar is False:
|
||||
if self._avatar_nick_public != public:
|
||||
con.get_module('UserAvatar').set_access_model(public)
|
||||
|
||||
else:
|
||||
# Only update avatar if it changed
|
||||
con.get_module('UserAvatar').set_avatar(
|
||||
self._new_avatar,
|
||||
public=public,
|
||||
callback=self._on_set_avatar)
|
||||
|
||||
nick = GLib.markup_escape_text(self._ui.nickname_entry.get_text())
|
||||
con.get_module('UserNickname').set_nickname(nick, public=public)
|
||||
|
||||
if not nick:
|
||||
nick = app.settings.get_account_setting(
|
||||
self.account, 'name')
|
||||
app.nicks[self.account] = nick
|
||||
|
||||
def _on_set_avatar(self, task):
|
||||
try:
|
||||
task.finish()
|
||||
except StanzaError as error:
|
||||
if self._new_avatar is None:
|
||||
# Trying to remove the avatar but the node does not exist
|
||||
if error.condition == 'item-not-found':
|
||||
return
|
||||
|
||||
title = _('Error while uploading avatar')
|
||||
text = error.get_text()
|
||||
|
||||
if (error.condition == 'not-acceptable' and
|
||||
error.app_condition == 'payload-too-big'):
|
||||
text = _('Avatar file size too big')
|
||||
|
||||
ErrorDialog(title, text)
|
||||
|
||||
self._ui.avatar_image.set_from_surface(self._current_avatar)
|
||||
self._new_avatar = False
|
||||
return
|
||||
|
||||
def _on_remove_avatar(self, _button):
|
||||
contact = app.contacts.create_contact(self._jid, self.account)
|
||||
scale = self.get_scale_factor()
|
||||
surface = app.interface.avatar_storage.get_surface(
|
||||
contact, AvatarSize.VCARD, scale, default=True)
|
||||
|
||||
self._ui.avatar_image.set_from_surface(surface)
|
||||
self._ui.remove_avatar_button.hide()
|
||||
self._new_avatar = None
|
||||
|
||||
def _on_edit_avatar(self, button):
|
||||
def _on_file_selected(path):
|
||||
if self._avatar_selector is None:
|
||||
self._avatar_selector = AvatarSelector()
|
||||
self._ui.avatar_selector_box.add(self._avatar_selector)
|
||||
|
||||
self._avatar_selector.prepare_crop_area(path)
|
||||
self._ui.avatar_update_button.set_sensitive(
|
||||
self._avatar_selector.get_prepared())
|
||||
self._ui.profile_stack.set_visible_child_name('avatar_selector')
|
||||
|
||||
AvatarChooserDialog(_on_file_selected,
|
||||
transient_for=button.get_toplevel())
|
||||
|
||||
def _on_cancel_update_avatar(self, _button):
|
||||
self._ui.profile_stack.set_visible_child_name('profile')
|
||||
|
||||
def _on_update_avatar(self, _button):
|
||||
success, data, width, height = self._avatar_selector.get_avatar_bytes()
|
||||
if not success:
|
||||
self._ui.profile_stack.set_visible_child_name('profile')
|
||||
ErrorDialog(_('Error while processing image'),
|
||||
_('Failed to generate avatar.'))
|
||||
return
|
||||
|
||||
sha = app.interface.avatar_storage.save_avatar(data)
|
||||
if sha is None:
|
||||
self._ui.profile_stack.set_visible_child_name('profile')
|
||||
ErrorDialog(_('Error while processing image'),
|
||||
_('Failed to generate avatar.'))
|
||||
return
|
||||
|
||||
self._new_avatar = Avatar()
|
||||
self._new_avatar.add_image_source(data, 'image/png', height, width)
|
||||
|
||||
scale = self.get_scale_factor()
|
||||
surface = app.interface.avatar_storage.surface_from_filename(
|
||||
sha, AvatarSize.VCARD, scale)
|
||||
|
||||
self._ui.avatar_image.set_from_surface(clip_circle(surface))
|
||||
self._ui.remove_avatar_button.show()
|
||||
self._ui.profile_stack.set_visible_child_name('profile')
|
||||
|
||||
def _set_vcard_access_switch(self, state):
|
||||
self._ui.vcard_access.set_active(state)
|
||||
self._ui.vcard_access_label.set_text(
|
||||
_('Everyone') if state else _('Contacts'))
|
||||
|
||||
def _set_avatar_nick_access_switch(self, state):
|
||||
self._ui.avatar_nick_access.set_active(state)
|
||||
self._ui.avatar_nick_access_label.set_text(
|
||||
_('Everyone') if state else _('Contacts'))
|
||||
|
||||
def _access_switch_toggled(self, *args):
|
||||
state = self._ui.vcard_access.get_active()
|
||||
self._set_vcard_access_switch(state)
|
||||
|
||||
state = self._ui.avatar_nick_access.get_active()
|
||||
self._set_avatar_nick_access_switch(state)
|
||||
|
||||
def _on_save_finished(self, task):
|
||||
try:
|
||||
task.finish()
|
||||
except StanzaError as err:
|
||||
log.error('Could not publish VCard: %s', err)
|
||||
# TODO Handle error
|
||||
return
|
||||
|
||||
self._vcard_grid.set_editable(False)
|
||||
self._ui.profile_stack.set_visible_child_name('profile')
|
||||
self._ui.spinner.stop()
|
||||
Loading…
Add table
Add a link
Reference in a new issue