# HG changeset patch # User Goffi # Date 1527103648 -7200 # Node ID c7d15ef4bfa8babbff19461b94e731601f322fea # Parent 519b3a29743cc93f5579257e512fd88039089b24 core (menu): new EntitiesSelectorMenu: TransferMenu base has been moved to a "SlideMenu" base class, which is used to create a new "EntitiesSelectorMenu". This later widget allows user to select entities from her roster, and the selected jids are then sent back to user. diff -r 519b3a29743c -r c7d15ef4bfa8 cagou/core/menu.py --- a/cagou/core/menu.py Wed May 23 21:25:08 2018 +0200 +++ b/cagou/core/menu.py Wed May 23 21:27:28 2018 +0200 @@ -22,14 +22,17 @@ from sat.core import log as logging log = logging.getLogger(__name__) from cagou.core.constants import Const as C +from cagou.core.common import JidToggle from kivy.uix.boxlayout import BoxLayout from kivy.uix.label import Label from kivy.uix.popup import Popup +from cagou.core.utils import FilterBehavior from kivy import properties from kivy.garden import contextmenu from sat_frontends.quick_frontend import quick_menus from kivy.core.window import Window from kivy.animation import Animation +from kivy.metrics import dp from cagou import G import webbrowser @@ -175,42 +178,35 @@ return True -class TransferMenu(BoxLayout): - """transfer menu which handle display and callbacks""" - # callback will be called with path to file to transfer +class SideMenu(BoxLayout): + base_size_hint_close = (0, 1) + base_size_hint_open = (0.4, 1) + bg_color = properties.ListProperty([0, 0, 0, 1]) + # callback will be called with arguments relevant to menu callback = properties.ObjectProperty() + # call do_callback even when menu is cancelled + callback_on_close = properties.BooleanProperty(False) # cancel callback need to remove the widget for UI # will be called with the widget to remove as argument cancel_cb = properties.ObjectProperty() - # profiles if set will be sent to transfer widget, may be used to get specific files - profiles = properties.ObjectProperty() - transfer_txt = _(u"Beware! The file will be sent to your server and stay unencrypted there\nServer admin(s) can see the file, and they choose how, when and if it will be deleted") - send_txt = _(u"The file will be sent unencrypted directly to your contact (without transiting by the server), except in some cases") - items_layout = properties.ObjectProperty() def __init__(self, **kwargs): - super(TransferMenu, self).__init__(**kwargs) + super(SideMenu, self).__init__(**kwargs) if self.cancel_cb is None: - self.cancel_cb = self.onTransferCancelled - if self.profiles is None: - self.profiles = iter(G.host.profiles) - for plug_info in G.host.getPluggedWidgets(type_=C.PLUG_TYPE_TRANSFER): - item = TransferItem( - plug_info = plug_info - ) - self.items_layout.add_widget(item) + self.cancel_cb = self.onMenuCancelled def show(self, caller_wid=None): - self.size_hint_y = 0 Window.bind(on_keyboard=self.key_input) G.host.app.root.add_widget(self) - Animation(size_hint_y=0.5, d=0.3, t='out_back').start(self) + Animation(size_hint=self.base_size_hint_open, d=0.3, t='out_back').start(self) def hide(self): Window.unbind(on_keyboard=self.key_input) - anim = Animation(size_hint_y=0, d=0.2) + anim = Animation(size_hint=self.base_size_hint_close, d=0.2) anim.bind(on_complete=lambda anim, menu: self.parent.remove_widget(self)) anim.start(self) + if self.callback_on_close: + self.do_callback() def on_touch_down(self, touch): # we remove the menu if we click outside @@ -219,7 +215,7 @@ if not self.collide_point(*touch.pos): self.hide() else: - return super(TransferMenu, self).on_touch_down(touch) + return super(SideMenu, self).on_touch_down(touch) return True def key_input(self, window, key, scancode, codepoint, modifier): @@ -227,13 +223,38 @@ self.hide() return True + def onMenuCancelled(self, wid, cleaning_cb=None): + self._closeUI(wid) + if cleaning_cb is not None: + cleaning_cb() + def _closeUI(self, wid): G.host.closeUI() - def onTransferCancelled(self, wid, cleaning_cb=None): - self._closeUI(wid) - if cleaning_cb is not None: - cleaning_cb() + def do_callback(self, *args, **kwargs): + log.warning(u"callback not implemented") + + +class TransferMenu(SideMenu): + """transfer menu which handle display and callbacks""" + # callback will be called with path to file to transfer + # profiles if set will be sent to transfer widget, may be used to get specific files + profiles = properties.ObjectProperty() + transfer_txt = _(u"Beware! The file will be sent to your server and stay unencrypted there\nServer admin(s) can see the file, and they choose how, when and if it will be deleted") + send_txt = _(u"The file will be sent unencrypted directly to your contact (without transiting by the server), except in some cases") + items_layout = properties.ObjectProperty() + base_size_hint_close = (1, 0) + base_size_hint_open = (1, 0.5) + + def __init__(self, **kwargs): + super(TransferMenu, self).__init__(**kwargs) + if self.profiles is None: + self.profiles = iter(G.host.profiles) + for plug_info in G.host.getPluggedWidgets(type_=C.PLUG_TYPE_TRANSFER): + item = TransferItem( + plug_info = plug_info + ) + self.items_layout.add_widget(item) def do_callback(self, plug_info): self.parent.remove_widget(self) @@ -252,3 +273,36 @@ wid = plug_info['factory'](plug_info, onTransferCb, self.cancel_cb, self.profiles) if not external: G.host.showExtraUI(wid) + + +class EntitiesSelectorMenu(SideMenu, FilterBehavior): + """allow to select entities from roster""" + profiles = properties.ObjectProperty() + layout = properties.ObjectProperty() + instructions = properties.StringProperty(_(u"Please select entities")) + filter_input = properties.ObjectProperty() + + def __init__(self, **kwargs): + super(EntitiesSelectorMenu, self).__init__(**kwargs) + self.filter_input.bind(text=self.do_filter_input) + if self.profiles is None: + self.profiles = iter(G.host.profiles) + for profile in self.profiles: + for jid_, jid_data in G.host.contact_lists[profile].all_iter: + jid_wid = JidToggle( + jid=jid_, + profile=profile) + self.layout.add_widget(jid_wid) + + def do_callback(self): + if self.callback is not None: + jids = [c.jid for c in self.layout.children if c.state == 'down'] + self.callback(jids) + + def do_filter_input(self, filter_input, text): + self.layout.spacing = 0 if text else dp(5) + self.do_filter(self.layout.children, + text, + lambda c: c.jid, + width_cb=lambda c: c.width, + height_cb=lambda c: dp(70)) diff -r 519b3a29743c -r c7d15ef4bfa8 cagou/kv/menu.kv --- a/cagou/kv/menu.kv Wed May 23 21:25:08 2018 +0200 +++ b/cagou/kv/menu.kv Wed May 23 21:27:28 2018 +0200 @@ -91,3 +91,43 @@ text_size: self.size halign: "center" valign: "top" + + +: + orientation: "vertical" + size_hint: self.base_size_hint_close + canvas.before: + Color: + rgba: self.bg_color + Rectangle: + pos: self.pos + size: self.size + + +: + bg_color: 0, 0, 0, 0.9 + filter_input: filter_input + layout: layout + callback_on_close: True + Label: + size_hint: 1, None + text_size: root.width, None + size: self.texture_size + padding: dp(5), dp(5) + color: 1, 1, 1, 1 + text: root.instructions + halign: "center" + TextInput: + id: filter_input + size_hint: 1, None + height: dp(32) + multiline: False + hint_text: _(u"enter filter here") + ScrollView: + size_hint: 1, 1 + BoxLayout: + id: layout + orientation: "vertical" + size_hint: 1, None + height: self.minimum_height + spacing: dp(5)