comparison cagou/plugins/plugin_wid_contact_list.py @ 221:e1a385a791cc

plugin contact list: implemented contact addition
author Goffi <goffi@goffi.org>
date Tue, 26 Jun 2018 07:36:11 +0200
parents 9faccd140119
children 9e5f9f0cee48
comparison
equal deleted inserted replaced
220:24f8ab7c08be 221:e1a385a791cc
25 from sat_frontends.quick_frontend.quick_contact_list import QuickContactList 25 from sat_frontends.quick_frontend.quick_contact_list import QuickContactList
26 from sat_frontends.tools import jid 26 from sat_frontends.tools import jid
27 from kivy.uix.boxlayout import BoxLayout 27 from kivy.uix.boxlayout import BoxLayout
28 from kivy.uix.behaviors import ButtonBehavior 28 from kivy.uix.behaviors import ButtonBehavior
29 from cagou.core.utils import FilterBehavior 29 from cagou.core.utils import FilterBehavior
30 from cagou.core.menu import SideMenu
30 from kivy.metrics import dp 31 from kivy.metrics import dp
31 from kivy import properties 32 from kivy import properties
32 from cagou.core import cagou_widget 33 from cagou.core import cagou_widget
33 from cagou.core import image 34 from cagou.core import image
34 from cagou import G 35 from cagou import G
36 from functools import partial
35 import bisect 37 import bisect
38 import re
36 39
37 40
38 PLUGIN_INFO = { 41 PLUGIN_INFO = {
39 "name": _(u"contacts"), 42 "name": _(u"contacts"),
40 "main": "ContactList", 43 "main": "ContactList",
41 "description": _(u"list of contacts"), 44 "description": _(u"list of contacts"),
42 "icon_medium": u"{media}/icons/muchoslava/png/contact_list_no_border_blue_44.png" 45 "icon_medium": u"{media}/icons/muchoslava/png/contact_list_no_border_blue_44.png"
43 } 46 }
44 47
45 48
49 class AddContactMenu(SideMenu):
50 profile = properties.StringProperty()
51 instructions = properties.StringProperty(_(u"Please enter new contact JID"))
52 size_hint_close = (1, 0)
53 size_hint_open = (1, 0.5)
54
55 def __init__(self, **kwargs):
56 super(AddContactMenu, self).__init__(**kwargs)
57 if self.profile is None:
58 log.warning(_(u"profile not set in AddContactMenu"))
59 self.profile = next(iter(G.host.profiles))
60
61 def addContact(self, contact_jid):
62 """Actually add the contact
63
64 @param contact_jid(unicode): jid of the contact to add
65 """
66 contact_jid = contact_jid.strip()
67 # FIXME: trivial jid verification
68 if not contact_jid or not re.match(r"[^@ ]+@[^@ ]+", contact_jid):
69 return
70 contact_jid = jid.JID(contact_jid).bare
71 G.host.bridge.addContact(contact_jid,
72 self.profile,
73 callback=lambda: G.host.addNote(
74 _(u"contact request"),
75 _(u"a contact request has been sent to {contact_jid}").format(
76 contact_jid=contact_jid)),
77 errback=partial(G.host.errback,
78 title=_(u"can't add contact"),
79 message=_(u"error while trying to add contact: {msg}")))
80 self.hide()
81
82
46 class Avatar(image.Image): 83 class Avatar(image.Image):
47 pass 84 pass
48 85
49 86
50 class ContactItem(ButtonBehavior, BoxLayout): 87 class ContactItem(ButtonBehavior, BoxLayout):
51 base_width = dp(150) 88 base_width = dp(150)
89 profile = properties.StringProperty()
52 data = properties.DictProperty() 90 data = properties.DictProperty()
53 jid = properties.StringProperty('') 91 jid = properties.StringProperty('')
54 92
55 def __init__(self, **kwargs): 93 def __init__(self, **kwargs):
56 super(ContactItem, self).__init__(**kwargs) 94 super(ContactItem, self).__init__(**kwargs)
57 95
58 def on_release(self): 96 def on_release(self):
97 assert self.profile
59 # XXX: for now clicking on an item launch the corresponding Chat widget 98 # XXX: for now clicking on an item launch the corresponding Chat widget
60 # behaviour should change in the future 99 # behaviour should change in the future
61 try: 100 try:
62 # FIXME: Q&D way to get chat plugin, should be replaced by a clean method 101 # FIXME: Q&D way to get chat plugin, should be replaced by a clean method
63 # in host 102 # in host
67 log.warning(u"No plugin widget found to display chat") 106 log.warning(u"No plugin widget found to display chat")
68 else: 107 else:
69 factory = plg_infos['factory'] 108 factory = plg_infos['factory']
70 G.host.switchWidget(self, factory(plg_infos, 109 G.host.switchWidget(self, factory(plg_infos,
71 jid.JID(self.jid), 110 jid.JID(self.jid),
72 profiles=iter(G.host.profiles))) 111 profiles=[self.profile]))
73 112
74 113
75 class ContactList(QuickContactList, cagou_widget.CagouWidget, FilterBehavior): 114 class ContactList(QuickContactList, cagou_widget.CagouWidget, FilterBehavior):
76 float_layout = properties.ObjectProperty() 115 float_layout = properties.ObjectProperty()
77 layout = properties.ObjectProperty() 116 layout = properties.ObjectProperty()
83 self._wid_map = {} # (profile, bare_jid) to widget map 122 self._wid_map = {} # (profile, bare_jid) to widget map
84 self.postInit() 123 self.postInit()
85 if len(self.profiles) != 1: 124 if len(self.profiles) != 1:
86 raise NotImplementedError('multi profiles is not implemented yet') 125 raise NotImplementedError('multi profiles is not implemented yet')
87 self.update(profile=next(iter(self.profiles))) 126 self.update(profile=next(iter(self.profiles)))
127
128 def addContactMenu(self):
129 """Show the "add a contact" menu"""
130 # FIXME: for now we add contact to the first profile we find
131 profile = next(iter(self.profiles))
132 AddContactMenu(profile=profile).show()
88 133
89 def onHeaderInputComplete(self, wid, text): 134 def onHeaderInputComplete(self, wid, text):
90 self.do_filter(self.layout.children, 135 self.do_filter(self.layout.children,
91 text, 136 text,
92 lambda c: c.jid, 137 lambda c: c.jid,
100 item will be added in a sorted position 145 item will be added in a sorted position
101 @param bare_jid(jid.JID): entity bare JID 146 @param bare_jid(jid.JID): entity bare JID
102 @param profile(unicode): profile where the contact is 147 @param profile(unicode): profile where the contact is
103 """ 148 """
104 data = G.host.contact_lists[profile].getItem(bare_jid) 149 data = G.host.contact_lists[profile].getItem(bare_jid)
105 wid = ContactItem(data=data, jid=bare_jid) 150 wid = ContactItem(profile=profile, data=data, jid=bare_jid)
106 child_jids = [c.jid for c in reversed(self.layout.children)] 151 child_jids = [c.jid for c in reversed(self.layout.children)]
107 idx = bisect.bisect_right(child_jids, bare_jid) 152 idx = bisect.bisect_right(child_jids, bare_jid)
108 self.layout.add_widget(wid, -idx) 153 self.layout.add_widget(wid, -idx)
109 self._wid_map[(profile, bare_jid)] = wid 154 self._wid_map[(profile, bare_jid)] = wid
110 155
112 log.debug("update: %s %s %s" % (entities, type_, profile)) 157 log.debug("update: %s %s %s" % (entities, type_, profile))
113 if type_ == None or type_ == C.UPDATE_STRUCTURE: 158 if type_ == None or type_ == C.UPDATE_STRUCTURE:
114 log.debug("full contact list update") 159 log.debug("full contact list update")
115 self.layout.clear_widgets() 160 self.layout.clear_widgets()
116 for bare_jid, data in self.items_sorted.iteritems(): 161 for bare_jid, data in self.items_sorted.iteritems():
117 wid = ContactItem(data=data, jid=bare_jid) 162 wid = ContactItem(profile=profile, data=data, jid=bare_jid)
118 self.layout.add_widget(wid) 163 self.layout.add_widget(wid)
119 self._wid_map[(profile, bare_jid)] = wid 164 self._wid_map[(profile, bare_jid)] = wid
120 elif type_ == C.UPDATE_MODIFY: 165 elif type_ == C.UPDATE_MODIFY:
121 for entity in entities: 166 for entity in entities:
122 entity_bare = entity.bare 167 entity_bare = entity.bare