comparison cagou/plugins/plugin_wid_remote.py @ 312:772c170b47a9

Python3 port: /!\ Cagou now runs with Python 3.6+ Port has been done in the same way as for backend (check backend commit b2d067339de3 message for details).
author Goffi <goffi@goffi.org>
date Tue, 13 Aug 2019 19:14:22 +0200
parents e2afbec1d178
children e2b51663d8b8
comparison
equal deleted inserted replaced
311:a0d978d3ce84 312:772c170b47a9
39 from cagou import G 39 from cagou import G
40 from functools import partial 40 from functools import partial
41 41
42 42
43 PLUGIN_INFO = { 43 PLUGIN_INFO = {
44 "name": _(u"remote control"), 44 "name": _("remote control"),
45 "main": "RemoteControl", 45 "main": "RemoteControl",
46 "description": _(u"universal remote control"), 46 "description": _("universal remote control"),
47 "icon_symbol": u"signal", 47 "icon_symbol": "signal",
48 } 48 }
49 49
50 NOTE_TITLE = _(u"Media Player Remote Control") 50 NOTE_TITLE = _("Media Player Remote Control")
51 51
52 52
53 class RemoteItemWidget(ItemWidget): 53 class RemoteItemWidget(ItemWidget):
54 54
55 def __init__(self, device_jid, node, name, main_wid, **kw): 55 def __init__(self, device_jid, node, name, main_wid, **kw):
64 64
65 65
66 class MediaPlayerControlWidget(BoxLayout): 66 class MediaPlayerControlWidget(BoxLayout):
67 main_wid = properties.ObjectProperty() 67 main_wid = properties.ObjectProperty()
68 remote_item = properties.ObjectProperty() 68 remote_item = properties.ObjectProperty()
69 status = properties.OptionProperty(u"play", options=(u"play", u"pause", u"stop")) 69 status = properties.OptionProperty("play", options=("play", "pause", "stop"))
70 title = properties.StringProperty() 70 title = properties.StringProperty()
71 identity = properties.StringProperty() 71 identity = properties.StringProperty()
72 command = properties.DictProperty() 72 command = properties.DictProperty()
73 ui_tpl = properties.ObjectProperty() 73 ui_tpl = properties.ObjectProperty()
74 74
82 self.ui_tpl = ui_tpl 82 self.ui_tpl = ui_tpl
83 for prop in ('Title', 'Identity'): 83 for prop in ('Title', 'Identity'):
84 try: 84 try:
85 setattr(self, prop.lower(), ui_tpl.widgets[prop].value) 85 setattr(self, prop.lower(), ui_tpl.widgets[prop].value)
86 except KeyError: 86 except KeyError:
87 log.warning(_(u"Missing field: {name}").format(name=prop)) 87 log.warning(_("Missing field: {name}").format(name=prop))
88 playback_status = self.ui_tpl.widgets['PlaybackStatus'].value 88 playback_status = self.ui_tpl.widgets['PlaybackStatus'].value
89 if playback_status == u"Playing": 89 if playback_status == "Playing":
90 self.status = u"pause" 90 self.status = "pause"
91 elif playback_status == u"Paused": 91 elif playback_status == "Paused":
92 self.status = u"play" 92 self.status = "play"
93 elif playback_status == u"Stopped": 93 elif playback_status == "Stopped":
94 self.status = u"play" 94 self.status = "play"
95 else: 95 else:
96 G.host.addNote( 96 G.host.addNote(
97 title=NOTE_TITLE, 97 title=NOTE_TITLE,
98 message=_(u"Unknown playback status: playback_status") 98 message=_("Unknown playback status: playback_status")
99 .format(playback_status=playback_status), 99 .format(playback_status=playback_status),
100 level=C.XMLUI_DATA_LVL_WARNING) 100 level=C.XMLUI_DATA_LVL_WARNING)
101 self.commands = {v:k for k,v in ui_tpl.widgets['command'].options} 101 self.commands = {v:k for k,v in ui_tpl.widgets['command'].options}
102 102
103 def adHocRunCb(self, xmlui_raw): 103 def adHocRunCb(self, xmlui_raw):
104 ui_tpl = template_xmlui.create(G.host, xmlui_raw) 104 ui_tpl = template_xmlui.create(G.host, xmlui_raw)
105 data = {xmlui.XMLUIPanel.escape(u"media_player"): self.remote_item.node, 105 data = {xmlui.XMLUIPanel.escape("media_player"): self.remote_item.node,
106 u"session_id": ui_tpl.session_id} 106 "session_id": ui_tpl.session_id}
107 G.host.bridge.launchAction( 107 G.host.bridge.launchAction(
108 ui_tpl.submit_id, data, self.profile, 108 ui_tpl.submit_id, data, self.profile,
109 callback=self.updateUI, 109 callback=self.updateUI,
110 errback=self.main_wid.errback) 110 errback=self.main_wid.errback)
111 111
112 def on_remote_item(self, __, remote): 112 def on_remote_item(self, __, remote):
113 NS_MEDIA_PLAYER = G.host.ns_map[u"mediaplayer"] 113 NS_MEDIA_PLAYER = G.host.ns_map["mediaplayer"]
114 G.host.bridge.adHocRun(unicode(remote.device_jid), NS_MEDIA_PLAYER, self.profile, 114 G.host.bridge.adHocRun(str(remote.device_jid), NS_MEDIA_PLAYER, self.profile,
115 callback=self.adHocRunCb, 115 callback=self.adHocRunCb,
116 errback=self.main_wid.errback) 116 errback=self.main_wid.errback)
117 117
118 def do_cmd(self, command): 118 def do_cmd(self, command):
119 try: 119 try:
120 cmd_value = self.commands[command] 120 cmd_value = self.commands[command]
121 except KeyError: 121 except KeyError:
122 G.host.addNote( 122 G.host.addNote(
123 title=NOTE_TITLE, 123 title=NOTE_TITLE,
124 message=_(u"{command} command is not managed").format(command=command), 124 message=_("{command} command is not managed").format(command=command),
125 level=C.XMLUI_DATA_LVL_WARNING) 125 level=C.XMLUI_DATA_LVL_WARNING)
126 else: 126 else:
127 data = {xmlui.XMLUIPanel.escape(u"command"): cmd_value, 127 data = {xmlui.XMLUIPanel.escape("command"): cmd_value,
128 u"session_id": self.ui_tpl.session_id} 128 "session_id": self.ui_tpl.session_id}
129 # hidden values are normally transparently managed by XMLUIPanel 129 # hidden values are normally transparently managed by XMLUIPanel
130 # but here we have to add them by hand 130 # but here we have to add them by hand
131 hidden = {xmlui.XMLUIPanel.escape(k):v 131 hidden = {xmlui.XMLUIPanel.escape(k):v
132 for k,v in self.ui_tpl.hidden.iteritems()} 132 for k,v in self.ui_tpl.hidden.items()}
133 data.update(hidden) 133 data.update(hidden)
134 G.host.bridge.launchAction( 134 G.host.bridge.launchAction(
135 self.ui_tpl.submit_id, data, self.profile, 135 self.ui_tpl.submit_id, data, self.profile,
136 callback=self.updateUI, 136 callback=self.updateUI,
137 errback=self.main_wid.errback) 137 errback=self.main_wid.errback)
138 138
139 139
140 class RemoteDeviceWidget(DeviceWidget): 140 class RemoteDeviceWidget(DeviceWidget):
141 141
142 def xmluiCb(self, data, cb_id, profile): 142 def xmluiCb(self, data, cb_id, profile):
143 if u'xmlui' in data: 143 if 'xmlui' in data:
144 xml_ui = xmlui.create( 144 xml_ui = xmlui.create(
145 G.host, data[u'xmlui'], callback=self.xmluiCb, profile=profile) 145 G.host, data['xmlui'], callback=self.xmluiCb, profile=profile)
146 if isinstance(xml_ui, xmlui.XMLUIDialog): 146 if isinstance(xml_ui, xmlui.XMLUIDialog):
147 self.main_wid.showRootWidget() 147 self.main_wid.showRootWidget()
148 xml_ui.show() 148 xml_ui.show()
149 else: 149 else:
150 xml_ui.setCloseCb(self.onClose) 150 xml_ui.setCloseCb(self.onClose)
151 self.main_wid.layout.add_widget(xml_ui) 151 self.main_wid.layout.add_widget(xml_ui)
152 else: 152 else:
153 if data: 153 if data:
154 log.warning(_(u"Unhandled data: {data}").format(data=data)) 154 log.warning(_("Unhandled data: {data}").format(data=data))
155 self.main_wid.showRootWidget() 155 self.main_wid.showRootWidget()
156 156
157 def onClose(self, __, reason): 157 def onClose(self, __, reason):
158 if reason == C.XMLUI_DATA_CANCELLED: 158 if reason == C.XMLUI_DATA_CANCELLED:
159 self.main_wid.showRootWidget() 159 self.main_wid.showRootWidget()
165 xml_ui.setCloseCb(self.onClose) 165 xml_ui.setCloseCb(self.onClose)
166 self.main_wid.layout.add_widget(xml_ui) 166 self.main_wid.layout.add_widget(xml_ui)
167 167
168 def do_item_action(self, touch): 168 def do_item_action(self, touch):
169 self.main_wid.layout.clear_widgets() 169 self.main_wid.layout.clear_widgets()
170 G.host.bridge.adHocRun(unicode(self.entity_jid), u'', self.profile, 170 G.host.bridge.adHocRun(str(self.entity_jid), '', self.profile,
171 callback=self.adHocRunCb, errback=self.main_wid.errback) 171 callback=self.adHocRunCb, errback=self.main_wid.errback)
172 172
173 173
174 class DevicesLayout(FloatLayout): 174 class DevicesLayout(FloatLayout):
175 """Layout used to show devices""" 175 """Layout used to show devices"""
192 192
193 def errback(self, failure_): 193 def errback(self, failure_):
194 """Generic errback which add a warning note and go back to root widget""" 194 """Generic errback which add a warning note and go back to root widget"""
195 G.host.addNote( 195 G.host.addNote(
196 title=NOTE_TITLE, 196 title=NOTE_TITLE,
197 message=_(u"Can't use remote control: {reason}").format(reason=failure_), 197 message=_("Can't use remote control: {reason}").format(reason=failure_),
198 level=C.XMLUI_DATA_LVL_WARNING) 198 level=C.XMLUI_DATA_LVL_WARNING)
199 self.showRootWidget() 199 self.showRootWidget()
200 200
201 def key_input(self, window, key, scancode, codepoint, modifier): 201 def key_input(self, window, key, scancode, codepoint, modifier):
202 if key == 27: 202 if key == 27:
216 found.insert(0, remotes_data) 216 found.insert(0, remotes_data)
217 if len(found) == 2: 217 if len(found) == 2:
218 self.show_devices(found) 218 self.show_devices(found)
219 219
220 def adHocRemotesGetEb(self, failure_, found): 220 def adHocRemotesGetEb(self, failure_, found):
221 G.host.errback(failure_, title=_(u"discovery error"), 221 G.host.errback(failure_, title=_("discovery error"),
222 message=_(u"can't check remote controllers: {msg}")) 222 message=_("can't check remote controllers: {msg}"))
223 found.insert(0, []) 223 found.insert(0, [])
224 if len(found) == 2: 224 if len(found) == 2:
225 self.show_devices(found) 225 self.show_devices(found)
226 226
227 def get_remotes(self, found): 227 def get_remotes(self, found):
234 found.append(data) 234 found.append(data)
235 if len(found) == 2: 235 if len(found) == 2:
236 self.show_devices(found) 236 self.show_devices(found)
237 237
238 def _discoFindByFeaturesEb(self, failure_, found): 238 def _discoFindByFeaturesEb(self, failure_, found):
239 G.host.errback(failure_, title=_(u"discovery error"), 239 G.host.errback(failure_, title=_("discovery error"),
240 message=_(u"can't check devices: {msg}")) 240 message=_("can't check devices: {msg}"))
241 found.append(({}, {}, {})) 241 found.append(({}, {}, {}))
242 if len(found) == 2: 242 if len(found) == 2:
243 self.show_devices(found) 243 self.show_devices(found)
244 244
245 def discover_devices(self, found): 245 def discover_devices(self, found):
246 """Looks for devices handling file "File Information Sharing" and display them""" 246 """Looks for devices handling file "File Information Sharing" and display them"""
247 try: 247 try:
248 namespace = self.host.ns_map['commands'] 248 namespace = self.host.ns_map['commands']
249 except KeyError: 249 except KeyError:
250 msg = _(u"can't find ad-hoc commands namespace, is the plugin running?") 250 msg = _("can't find ad-hoc commands namespace, is the plugin running?")
251 log.warning(msg) 251 log.warning(msg)
252 G.host.addNote(_(u"missing plugin"), msg, C.XMLUI_DATA_LVL_ERROR) 252 G.host.addNote(_("missing plugin"), msg, C.XMLUI_DATA_LVL_ERROR)
253 return 253 return
254 self.host.bridge.discoFindByFeatures( 254 self.host.bridge.discoFindByFeatures(
255 [namespace], [], False, True, True, True, False, self.profile, 255 [namespace], [], False, True, True, True, False, self.profile,
256 callback=partial(self._discoFindByFeaturesCb, found=found), 256 callback=partial(self._discoFindByFeaturesCb, found=found),
257 errback=partial(self._discoFindByFeaturesEb, found=found)) 257 errback=partial(self._discoFindByFeaturesEb, found=found))
258 258
259 def show_devices(self, found): 259 def show_devices(self, found):
260 remotes_data, (entities_services, entities_own, entities_roster) = found 260 remotes_data, (entities_services, entities_own, entities_roster) = found
261 if remotes_data: 261 if remotes_data:
262 title = _(u"media players remote controls") 262 title = _("media players remote controls")
263 self.stack_layout.add_widget(CategorySeparator(text=title)) 263 self.stack_layout.add_widget(CategorySeparator(text=title))
264 264
265 for remote_data in remotes_data: 265 for remote_data in remotes_data:
266 device_jid, node, name = remote_data 266 device_jid, node, name = remote_data
267 wid = RemoteItemWidget(device_jid, node, name, self) 267 wid = RemoteItemWidget(device_jid, node, name, self)
268 self.stack_layout.add_widget(wid) 268 self.stack_layout.add_widget(wid)
269 269
270 for entities_map, title in ((entities_services, 270 for entities_map, title in ((entities_services,
271 _(u'services')), 271 _('services')),
272 (entities_own, 272 (entities_own,
273 _(u'your devices')), 273 _('your devices')),
274 (entities_roster, 274 (entities_roster,
275 _(u'your contacts devices'))): 275 _('your contacts devices'))):
276 if entities_map: 276 if entities_map:
277 self.stack_layout.add_widget(CategorySeparator(text=title)) 277 self.stack_layout.add_widget(CategorySeparator(text=title))
278 for entity_str, entity_ids in entities_map.iteritems(): 278 for entity_str, entity_ids in entities_map.items():
279 entity_jid = jid.JID(entity_str) 279 entity_jid = jid.JID(entity_str)
280 item = RemoteDeviceWidget( 280 item = RemoteDeviceWidget(
281 self, entity_jid, Identities(entity_ids)) 281 self, entity_jid, Identities(entity_ids))
282 self.stack_layout.add_widget(item) 282 self.stack_layout.add_widget(item)
283 if (not remotes_data and not entities_services and not entities_own 283 if (not remotes_data and not entities_services and not entities_own
284 and not entities_roster): 284 and not entities_roster):
285 self.stack_layout.add_widget(Label( 285 self.stack_layout.add_widget(Label(
286 size_hint=(1, 1), 286 size_hint=(1, 1),
287 halign='center', 287 halign='center',
288 text_size=self.size, 288 text_size=self.size,
289 text=_(u"No sharing device found"))) 289 text=_("No sharing device found")))