comparison cagou/plugins/plugin_wid_contact_list.py @ 219:9faccd140119

plugin contact list: refactoring: - contacts are now displayed in a grid - they can be filtered thanks to FilterBehaviour - use the new update system of QuickContactList - a new "add a contact" button is visible, but not implemented yet.
author Goffi <goffi@goffi.org>
date Sun, 24 Jun 2018 22:26:15 +0200
parents 0ddd2b20cc6b
children e1a385a791cc
comparison
equal deleted inserted replaced
218:30be583dbabc 219:9faccd140119
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. 18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 19
20 20
21 from sat.core import log as logging 21 from sat.core import log as logging
22 log = logging.getLogger(__name__) 22 log = logging.getLogger(__name__)
23 from cagou.core.constants import Const as C
23 from sat.core.i18n import _ 24 from sat.core.i18n import _
24 from sat_frontends.quick_frontend.quick_contact_list import QuickContactList 25 from sat_frontends.quick_frontend.quick_contact_list import QuickContactList
25 from sat_frontends.tools import jid 26 from sat_frontends.tools import jid
26 from kivy.uix.boxlayout import BoxLayout 27 from kivy.uix.boxlayout import BoxLayout
27 from kivy.uix.listview import ListView 28 from kivy.uix.behaviors import ButtonBehavior
28 from kivy.adapters.listadapter import ListAdapter 29 from cagou.core.utils import FilterBehavior
29 from kivy.metrics import dp 30 from kivy.metrics import dp
30 from kivy import properties 31 from kivy import properties
31 from cagou.core import cagou_widget 32 from cagou.core import cagou_widget
32 from cagou.core import image 33 from cagou.core import image
33 from cagou import G 34 from cagou import G
35 import bisect
34 36
35 37
36 PLUGIN_INFO = { 38 PLUGIN_INFO = {
37 "name": _(u"contacts"), 39 "name": _(u"contacts"),
38 "main": "ContactList", 40 "main": "ContactList",
43 45
44 class Avatar(image.Image): 46 class Avatar(image.Image):
45 pass 47 pass
46 48
47 49
48 class ContactItem(BoxLayout): 50 class ContactItem(ButtonBehavior, BoxLayout):
51 base_width = dp(150)
49 data = properties.DictProperty() 52 data = properties.DictProperty()
50 jid = properties.StringProperty('') 53 jid = properties.StringProperty('')
51 54
52 def __init__(self, **kwargs): 55 def __init__(self, **kwargs):
53 super(ContactItem, self).__init__(**kwargs) 56 super(ContactItem, self).__init__(**kwargs)
54 57
55 def on_touch_down(self, touch): 58 def on_release(self):
56 if self.collide_point(*touch.pos): 59 # XXX: for now clicking on an item launch the corresponding Chat widget
57 # XXX: for now clicking on an item launch the corresponding Chat widget 60 # behaviour should change in the future
58 # behaviour should change in the future 61 try:
59 try: 62 # FIXME: Q&D way to get chat plugin, should be replaced by a clean method
60 # FIXME: Q&D way to get chat plugin, should be replaced by a clean method 63 # in host
61 # in host 64 plg_infos = [p for p in G.host.getPluggedWidgets()
62 plg_infos = [p for p in G.host.getPluggedWidgets() if 'chat' in p['import_name']][0] 65 if 'chat' in p['import_name']][0]
63 except IndexError: 66 except IndexError:
64 log.warning(u"No plugin widget found to display chat") 67 log.warning(u"No plugin widget found to display chat")
65 else: 68 else:
66 factory = plg_infos['factory'] 69 factory = plg_infos['factory']
67 G.host.switchWidget(self, factory(plg_infos, jid.JID(self.jid), profiles=iter(G.host.profiles))) 70 G.host.switchWidget(self, factory(plg_infos,
71 jid.JID(self.jid),
72 profiles=iter(G.host.profiles)))
68 73
69 74
70 class ContactListView(ListView): 75 class ContactList(QuickContactList, cagou_widget.CagouWidget, FilterBehavior):
71 pass 76 float_layout = properties.ObjectProperty()
72 77 layout = properties.ObjectProperty()
73
74 class ContactList(QuickContactList, cagou_widget.CagouWidget):
75 78
76 def __init__(self, host, target, profiles): 79 def __init__(self, host, target, profiles):
77 QuickContactList.__init__(self, G.host, profiles) 80 QuickContactList.__init__(self, G.host, profiles)
78 cagou_widget.CagouWidget.__init__(self) 81 cagou_widget.CagouWidget.__init__(self)
79 self.adapter = ListAdapter(data={}, 82 FilterBehavior.__init__(self)
80 cls=ContactItem, 83 self._wid_map = {} # (profile, bare_jid) to widget map
81 args_converter=self.contactDataConverter,
82 selection_mode='multiple',
83 allow_empty_selection=True,
84 )
85 self.add_widget(ContactListView(adapter=self.adapter))
86 self.postInit() 84 self.postInit()
87 self.update() 85 if len(self.profiles) != 1:
86 raise NotImplementedError('multi profiles is not implemented yet')
87 self.update(profile=next(iter(self.profiles)))
88 88
89 def onHeaderInputComplete(self, wid, text): 89 def onHeaderInputComplete(self, wid, text):
90 # FIXME: this is implementation dependent, need to be done properly 90 self.do_filter(self.layout.children,
91 items = self.children[0].children[0].children[0].children 91 text,
92 lambda c: c.jid,
93 width_cb=lambda c: c.base_width,
94 height_cb=lambda c: c.minimum_height,
95 )
92 96
93 for item in items: 97 def _addContactItem(self, bare_jid, profile):
94 if text not in item.ids.jid_label.text: 98 """Create a new ContactItem instance, and add it
95 item.height = 0
96 item.opacity = 0
97 else:
98 item.height = dp(50)
99 item.opacity = 1
100 99
101 def contactDataConverter(self, idx, bare_jid): 100 item will be added in a sorted position
102 return {"jid": bare_jid, "data": self._items_cache[bare_jid]} 101 @param bare_jid(jid.JID): entity bare JID
102 @param profile(unicode): profile where the contact is
103 """
104 data = G.host.contact_lists[profile].getItem(bare_jid)
105 wid = ContactItem(data=data, jid=bare_jid)
106 child_jids = [c.jid for c in reversed(self.layout.children)]
107 idx = bisect.bisect_right(child_jids, bare_jid)
108 self.layout.add_widget(wid, -idx)
109 self._wid_map[(profile, bare_jid)] = wid
103 110
104 def update(self, entities=None, type_=None, profile=None): 111 def update(self, entities=None, type_=None, profile=None):
105 log.debug("update: %s %s %s" % (entities, type_, profile)) 112 log.debug("update: %s %s %s" % (entities, type_, profile))
106 # FIXME: for now we update on each event 113 if type_ == None or type_ == C.UPDATE_STRUCTURE:
107 # if entities is None and type_ is None: 114 log.debug("full contact list update")
108 self._items_cache = self.items_sorted 115 self.layout.clear_widgets()
109 self.adapter.data = self.items_sorted.keys() 116 for bare_jid, data in self.items_sorted.iteritems():
110 117 wid = ContactItem(data=data, jid=bare_jid)
118 self.layout.add_widget(wid)
119 self._wid_map[(profile, bare_jid)] = wid
120 elif type_ == C.UPDATE_MODIFY:
121 for entity in entities:
122 entity_bare = entity.bare
123 wid = self._wid_map[(profile, entity_bare)]
124 wid.data = G.host.contact_lists[profile].getItem(entity_bare)
125 elif type_ == C.UPDATE_ADD:
126 for entity in entities:
127 self._addContactItem(entity.bare, profile)
128 elif type_ == C.UPDATE_DELETE:
129 for entity in entities:
130 try:
131 self.layout.remove_widget(self._wid_map.pop((profile, entity.bare)))
132 except KeyError:
133 log.debug("entity not found: {entity}".format(entity=entity.bare))
134 else:
135 log.debug("update type not handled: {update_type}".format(update_type=type_))