Mercurial > libervia-desktop-kivy
annotate cagou/plugins/plugin_wid_contact_list.py @ 412:7c6149c249c1
chat: attachment sending:
- files to send are not sent directly anymore, but added to attachment, and linked to the
message when it is sent, this is more user friendly and avoid the accidental sending of
wrong file
- user can remove the attachment before sending the message, using the "close" symbol
- new "Chat.addAtachment" method
- upload progress is shown on the AttachmentItem thanks to the "progress" property
- AttachmentItem stays in the attachments layout until uploaded or an error happens.
Messages can still be sent while the item is being uploaded.
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 23 Feb 2020 15:39:03 +0100 |
parents | f7476818f9fb |
children | 167c3e198f73 |
rev | line source |
---|---|
379 | 1 #!/usr/bin/env python3 |
2 | |
9 | 3 |
4 # Cagou: desktop/mobile frontend for Salut à Toi XMPP client | |
378 | 5 # Copyright (C) 2016-2020 Jérôme Poisson (goffi@goffi.org) |
9 | 6 |
7 # This program is free software: you can redistribute it and/or modify | |
8 # it under the terms of the GNU Affero General Public License as published by | |
9 # the Free Software Foundation, either version 3 of the License, or | |
10 # (at your option) any later version. | |
11 | |
12 # This program is distributed in the hope that it will be useful, | |
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 # GNU Affero General Public License for more details. | |
16 | |
17 # You should have received a copy of the GNU Affero General Public License | |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | |
20 | |
365
9c6fe392d623
core (widgets_handler): use a StencilView + BoxLayout instead of ScrollView as wrapper:
Goffi <goffi@goffi.org>
parents:
322
diff
changeset
|
21 from functools import partial |
9c6fe392d623
core (widgets_handler): use a StencilView + BoxLayout instead of ScrollView as wrapper:
Goffi <goffi@goffi.org>
parents:
322
diff
changeset
|
22 import bisect |
9c6fe392d623
core (widgets_handler): use a StencilView + BoxLayout instead of ScrollView as wrapper:
Goffi <goffi@goffi.org>
parents:
322
diff
changeset
|
23 import re |
9 | 24 from sat.core import log as logging |
14 | 25 from sat.core.i18n import _ |
9 | 26 from sat_frontends.quick_frontend.quick_contact_list import QuickContactList |
22 | 27 from sat_frontends.tools import jid |
9 | 28 from kivy import properties |
16
ba14b596b90e
host can now be get as a global value:
Goffi <goffi@goffi.org>
parents:
15
diff
changeset
|
29 from cagou import G |
365
9c6fe392d623
core (widgets_handler): use a StencilView + BoxLayout instead of ScrollView as wrapper:
Goffi <goffi@goffi.org>
parents:
322
diff
changeset
|
30 from ..core import cagou_widget |
9c6fe392d623
core (widgets_handler): use a StencilView + BoxLayout instead of ScrollView as wrapper:
Goffi <goffi@goffi.org>
parents:
322
diff
changeset
|
31 from ..core.constants import Const as C |
9c6fe392d623
core (widgets_handler): use a StencilView + BoxLayout instead of ScrollView as wrapper:
Goffi <goffi@goffi.org>
parents:
322
diff
changeset
|
32 from ..core.common import ContactItem |
404
f7476818f9fb
core (common): JidSelector + behaviors various improvments:
Goffi <goffi@goffi.org>
parents:
387
diff
changeset
|
33 from ..core.behaviors import FilterBehavior, TouchMenuBehavior, TouchMenuItemBehavior |
f7476818f9fb
core (common): JidSelector + behaviors various improvments:
Goffi <goffi@goffi.org>
parents:
387
diff
changeset
|
34 from ..core.menu import SideMenu |
365
9c6fe392d623
core (widgets_handler): use a StencilView + BoxLayout instead of ScrollView as wrapper:
Goffi <goffi@goffi.org>
parents:
322
diff
changeset
|
35 |
9c6fe392d623
core (widgets_handler): use a StencilView + BoxLayout instead of ScrollView as wrapper:
Goffi <goffi@goffi.org>
parents:
322
diff
changeset
|
36 |
9c6fe392d623
core (widgets_handler): use a StencilView + BoxLayout instead of ScrollView as wrapper:
Goffi <goffi@goffi.org>
parents:
322
diff
changeset
|
37 log = logging.getLogger(__name__) |
9 | 38 |
39 | |
14 | 40 PLUGIN_INFO = { |
312 | 41 "name": _("contacts"), |
14 | 42 "main": "ContactList", |
312 | 43 "description": _("list of contacts"), |
44 "icon_medium": "{media}/icons/muchoslava/png/contact_list_no_border_blue_44.png" | |
14 | 45 } |
46 | |
47 | |
221
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
48 class AddContactMenu(SideMenu): |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
49 profile = properties.StringProperty() |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
50 size_hint_close = (1, 0) |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
51 size_hint_open = (1, 0.5) |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
52 |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
53 def __init__(self, **kwargs): |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
54 super(AddContactMenu, self).__init__(**kwargs) |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
55 if self.profile is None: |
312 | 56 log.warning(_("profile not set in AddContactMenu")) |
221
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
57 self.profile = next(iter(G.host.profiles)) |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
58 |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
59 def addContact(self, contact_jid): |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
60 """Actually add the contact |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
61 |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
62 @param contact_jid(unicode): jid of the contact to add |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
63 """ |
223
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
64 self.hide() |
221
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
65 contact_jid = contact_jid.strip() |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
66 # FIXME: trivial jid verification |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
67 if not contact_jid or not re.match(r"[^@ ]+@[^@ ]+", contact_jid): |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
68 return |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
69 contact_jid = jid.JID(contact_jid).bare |
312 | 70 G.host.bridge.addContact(str(contact_jid), |
221
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
71 self.profile, |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
72 callback=lambda: G.host.addNote( |
312 | 73 _("contact request"), |
74 _("a contact request has been sent to {contact_jid}").format( | |
221
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
75 contact_jid=contact_jid)), |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
76 errback=partial(G.host.errback, |
312 | 77 title=_("can't add contact"), |
78 message=_("error while trying to add contact: {msg}"))) | |
223
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
79 |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
80 |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
81 class DelContactMenu(SideMenu): |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
82 size_hint_close = (1, 0) |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
83 size_hint_open = (1, 0.5) |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
84 |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
85 def __init__(self, contact_item, **kwargs): |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
86 self.contact_item = contact_item |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
87 super(DelContactMenu, self).__init__(**kwargs) |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
88 |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
89 def do_delete_contact(self): |
221
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
90 self.hide() |
312 | 91 G.host.bridge.delContact(str(self.contact_item.jid.bare), |
223
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
92 self.contact_item.profile, |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
93 callback=lambda: G.host.addNote( |
312 | 94 _("contact removed"), |
95 _("{contact_jid} has been removed from your contacts list").format( | |
223
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
96 contact_jid=self.contact_item.jid.bare)), |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
97 errback=partial(G.host.errback, |
312 | 98 title=_("can't remove contact"), |
99 message=_("error while trying to remove contact: {msg}"))) | |
223
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
100 |
221
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
101 |
404
f7476818f9fb
core (common): JidSelector + behaviors various improvments:
Goffi <goffi@goffi.org>
parents:
387
diff
changeset
|
102 class CLContactItem(TouchMenuItemBehavior, ContactItem): |
9 | 103 |
223
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
104 def do_item_action(self, touch): |
221
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
105 assert self.profile |
219 | 106 # XXX: for now clicking on an item launch the corresponding Chat widget |
107 # behaviour should change in the future | |
312 | 108 G.host.doAction('chat', jid.JID(self.jid), [self.profile]) |
22 | 109 |
223
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
110 def getMenuChoices(self): |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
111 choices = [] |
312 | 112 choices.append(dict(text=_('delete'), |
223
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
113 index=len(choices)+1, |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
114 callback=self.main_wid.removeContact)) |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
115 return choices |
22 | 116 |
223
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
117 |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
118 class ContactList(QuickContactList, cagou_widget.CagouWidget, FilterBehavior, |
404
f7476818f9fb
core (common): JidSelector + behaviors various improvments:
Goffi <goffi@goffi.org>
parents:
387
diff
changeset
|
119 TouchMenuBehavior): |
219 | 120 float_layout = properties.ObjectProperty() |
121 layout = properties.ObjectProperty() | |
387
d61bbbac4160
cagou widget: don't add header_input systematically anymore:
Goffi <goffi@goffi.org>
parents:
379
diff
changeset
|
122 use_header_input = True |
9 | 123 |
124 def __init__(self, host, target, profiles): | |
16
ba14b596b90e
host can now be get as a global value:
Goffi <goffi@goffi.org>
parents:
15
diff
changeset
|
125 QuickContactList.__init__(self, G.host, profiles) |
ba14b596b90e
host can now be get as a global value:
Goffi <goffi@goffi.org>
parents:
15
diff
changeset
|
126 cagou_widget.CagouWidget.__init__(self) |
219 | 127 FilterBehavior.__init__(self) |
128 self._wid_map = {} # (profile, bare_jid) to widget map | |
17
5c9feaa060a5
contact list: added call to the new postInit method
Goffi <goffi@goffi.org>
parents:
16
diff
changeset
|
129 self.postInit() |
219 | 130 if len(self.profiles) != 1: |
131 raise NotImplementedError('multi profiles is not implemented yet') | |
132 self.update(profile=next(iter(self.profiles))) | |
9 | 133 |
221
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
134 def addContactMenu(self): |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
135 """Show the "add a contact" menu""" |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
136 # FIXME: for now we add contact to the first profile we find |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
137 profile = next(iter(self.profiles)) |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
138 AddContactMenu(profile=profile).show() |
e1a385a791cc
plugin contact list: implemented contact addition
Goffi <goffi@goffi.org>
parents:
219
diff
changeset
|
139 |
223
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
140 def removeContact(self, menu_label): |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
141 item = self.menu_item |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
142 self.clear_menu() |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
143 DelContactMenu(contact_item=item).show() |
9e5f9f0cee48
plugin contact list: use new TouchMenuBehaviour to implement contact deletion
Goffi <goffi@goffi.org>
parents:
221
diff
changeset
|
144 |
110
34dfe0e32064
contact list: text entered in header input do filtering in shown contacts
Goffi <goffi@goffi.org>
parents:
90
diff
changeset
|
145 def onHeaderInputComplete(self, wid, text): |
404
f7476818f9fb
core (common): JidSelector + behaviors various improvments:
Goffi <goffi@goffi.org>
parents:
387
diff
changeset
|
146 self.do_filter(self.layout, |
219 | 147 text, |
148 lambda c: c.jid, | |
149 width_cb=lambda c: c.base_width, | |
150 height_cb=lambda c: c.minimum_height, | |
151 ) | |
152 | |
153 def _addContactItem(self, bare_jid, profile): | |
322
e2b51663d8b8
core, android: new share widget + added Cagou to "share" menu:
Goffi <goffi@goffi.org>
parents:
312
diff
changeset
|
154 """Create a new CLContactItem instance, and add it |
110
34dfe0e32064
contact list: text entered in header input do filtering in shown contacts
Goffi <goffi@goffi.org>
parents:
90
diff
changeset
|
155 |
219 | 156 item will be added in a sorted position |
157 @param bare_jid(jid.JID): entity bare JID | |
158 @param profile(unicode): profile where the contact is | |
159 """ | |
160 data = G.host.contact_lists[profile].getItem(bare_jid) | |
322
e2b51663d8b8
core, android: new share widget + added Cagou to "share" menu:
Goffi <goffi@goffi.org>
parents:
312
diff
changeset
|
161 wid = CLContactItem(profile=profile, data=data, jid=bare_jid, main_wid=self) |
219 | 162 child_jids = [c.jid for c in reversed(self.layout.children)] |
163 idx = bisect.bisect_right(child_jids, bare_jid) | |
164 self.layout.add_widget(wid, -idx) | |
165 self._wid_map[(profile, bare_jid)] = wid | |
9 | 166 |
167 def update(self, entities=None, type_=None, profile=None): | |
50
c45d6e9ec731
contact list: fixed contact list display
Goffi <goffi@goffi.org>
parents:
39
diff
changeset
|
168 log.debug("update: %s %s %s" % (entities, type_, profile)) |
219 | 169 if type_ == None or type_ == C.UPDATE_STRUCTURE: |
170 log.debug("full contact list update") | |
171 self.layout.clear_widgets() | |
312 | 172 for bare_jid, data in self.items_sorted.items(): |
322
e2b51663d8b8
core, android: new share widget + added Cagou to "share" menu:
Goffi <goffi@goffi.org>
parents:
312
diff
changeset
|
173 wid = CLContactItem(profile=profile, data=data, jid=bare_jid, main_wid=self) |
219 | 174 self.layout.add_widget(wid) |
175 self._wid_map[(profile, bare_jid)] = wid | |
176 elif type_ == C.UPDATE_MODIFY: | |
177 for entity in entities: | |
178 entity_bare = entity.bare | |
179 wid = self._wid_map[(profile, entity_bare)] | |
180 wid.data = G.host.contact_lists[profile].getItem(entity_bare) | |
181 elif type_ == C.UPDATE_ADD: | |
182 for entity in entities: | |
183 self._addContactItem(entity.bare, profile) | |
184 elif type_ == C.UPDATE_DELETE: | |
185 for entity in entities: | |
186 try: | |
187 self.layout.remove_widget(self._wid_map.pop((profile, entity.bare))) | |
188 except KeyError: | |
189 log.debug("entity not found: {entity}".format(entity=entity.bare)) | |
190 else: | |
191 log.debug("update type not handled: {update_type}".format(update_type=type_)) |