# HG changeset patch # User Goffi # Date 1581534178 -3600 # Node ID f7476818f9fb1f1407bf20fbc76619a76e03266c # Parent b0af45a9205588a1a006b8591c4f02c42916d33e core (common): JidSelector + behaviors various improvments: - renamed *Behaviour => *Behavior to be consistent with Kivy + moved to new "core.behaviors" modules - use a dedicated property in ContactItem for notification counter (which is now named "badge") - in JidSelector, well-known strings now create use a dedicated layout, add separator (except if new `add_separators` property is set to False), and are added to attribute of the same name - a new `item_class` property is now used to indicate the class to instanciate for items (by default it's a ContactItem) - FilterBahavior.do_filter now expect the parent layout instead of directly the children, this is to allow a FilterBahavior to manage several children layout at once (used with JidSelector) - core.utils has been removed, as the behavior there has been moved to core.behaviors diff -r b0af45a92055 -r f7476818f9fb cagou/core/behaviors.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cagou/core/behaviors.py Wed Feb 12 20:02:58 2020 +0100 @@ -0,0 +1,173 @@ +#!/usr/bin/env python3 + + +# Cagou: desktop/mobile frontend for Salut à Toi XMPP client +# Copyright (C) 2016-2020 Jérôme Poisson (goffi@goffi.org) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from kivy import properties +from kivy.animation import Animation +from kivy.clock import Clock +from kivy_garden import modernmenu +from functools import partial + + +class TouchMenu(modernmenu.ModernMenu): + pass + + +class TouchMenuItemBehavior: + """Class to use on every item where a menu may appear + + main_wid attribute must be set to the class inheriting from TouchMenuBehavior + do_item_action is the method called on simple click + getMenuChoices must return a list of menus for long press + menus there are dict as expected by ModernMenu + (translated text, index and callback) + """ + main_wid = properties.ObjectProperty() + click_timeout = properties.NumericProperty(0.4) + + def on_touch_down(self, touch): + if not self.collide_point(*touch.pos): + return + t = partial(self.open_menu, touch) + touch.ud['menu_timeout'] = t + Clock.schedule_once(t, self.click_timeout) + return super(TouchMenuItemBehavior, self).on_touch_down(touch) + + def do_item_action(self, touch): + pass + + def on_touch_up(self, touch): + if touch.ud.get('menu_timeout'): + Clock.unschedule(touch.ud['menu_timeout']) + if self.collide_point(*touch.pos) and self.main_wid.menu is None: + self.do_item_action(touch) + return super(TouchMenuItemBehavior, self).on_touch_up(touch) + + def open_menu(self, touch, dt): + self.main_wid.open_menu(self, touch) + del touch.ud['menu_timeout'] + + def getMenuChoices(self): + """return choice adapted to selected item + + @return (list[dict]): choices ad expected by ModernMenu + """ + return [] + + +class TouchMenuBehavior: + """Class to handle a menu appearing on long press on items + + classes using this behaviour need to have a float_layout property + pointing the main FloatLayout. + """ + float_layout = properties.ObjectProperty() + + def __init__(self, *args, **kwargs): + super(TouchMenuBehavior, self).__init__(*args, **kwargs) + self.menu = None + self.menu_item = None + + ## menu methods ## + + def clean_fl_children(self, layout, children): + """insure that self.menu and self.menu_item are None when menu is dimissed""" + if self.menu is not None and self.menu not in children: + self.menu = self.menu_item = None + + def clear_menu(self): + """remove menu if there is one""" + if self.menu is not None: + self.menu.dismiss() + self.menu = None + self.menu_item = None + + def open_menu(self, item, touch): + """open menu for item + + @param item(PathWidget): item when the menu has been requested + @param touch(kivy.input.MotionEvent): touch data + """ + if self.menu_item == item: + return + self.clear_menu() + pos = self.to_widget(*touch.pos) + choices = item.getMenuChoices() + if not choices: + return + self.menu = TouchMenu(choices=choices, + center=pos, + size_hint=(None, None)) + self.float_layout.add_widget(self.menu) + self.menu.start_display(touch) + self.menu_item = item + + def on_float_layout(self, wid, float_layout): + float_layout.bind(children=self.clean_fl_children) + + +class FilterBehavior(object): + """class to handle items filtering with animation""" + + def __init__(self, *args, **kwargs): + super(FilterBehavior, self).__init__(*args, **kwargs) + self._filter_last = {} + self._filter_anim = Animation(width = 0, + height = 0, + opacity = 0, + d = 0.5) + + def do_filter(self, parent, text, get_child_text, width_cb, height_cb, + continue_tests=None): + """filter the children + + filtered children will have a animation to set width, height and opacity to 0 + @param parent(kivy.uix.widget.Widget): parent layout of the widgets to filter + @param text(unicode): filter text (if this text is not present in a child, + the child is filtered out) + @param get_child_text(callable): must retrieve child text + child is used as sole argument + @param width_cb(callable, int, None): method to retrieve width when opened + child is used as sole argument, int can be used instead of callable + @param height_cb(callable, int, None): method to retrieve height when opened + child is used as sole argument, int can be used instead of callable + @param continue_tests(list[callable]): list of test to skip the item + all callables take child as sole argument. + if any of the callable return True, the child is skipped (i.e. not filtered) + """ + text = text.strip().lower() + filtering = len(text)>len(self._filter_last.get(parent, '')) + self._filter_last[parent] = text + for child in parent.children: + if continue_tests is not None and any((t(child) for t in continue_tests)): + continue + if text in get_child_text(child).lower(): + self._filter_anim.cancel(child) + for key, method in (('width', width_cb), + ('height', height_cb), + ('opacity', lambda c: 1)): + try: + setattr(child, key, method(child)) + except TypeError: + # method is not a callable, must be an int + setattr(child, key, method) + elif (filtering + and child.opacity > 0 + and not self._filter_anim.have_properties_to_animate(child)): + self._filter_anim.start(child) diff -r b0af45a92055 -r f7476818f9fb cagou/core/common.py --- a/cagou/core/common.py Wed Feb 12 20:02:58 2020 +0100 +++ b/cagou/core/common.py Wed Feb 12 20:02:58 2020 +0100 @@ -27,13 +27,15 @@ from kivy.uix.label import Label from kivy.uix.behaviors import ButtonBehavior from kivy.uix.behaviors import ToggleButtonBehavior +from kivy.uix.stacklayout import StackLayout from kivy.uix.boxlayout import BoxLayout from kivy.uix.scrollview import ScrollView from kivy.event import EventDispatcher from kivy.metrics import dp from kivy import properties from sat_frontends.quick_frontend import quick_chat -from cagou.core.constants import Const as C +from .constants import Const as C +from .common_widgets import CategorySeparator from cagou import G log = logging.getLogger(__name__) @@ -63,17 +65,26 @@ base_width = dp(150) avatar_layout = properties.ObjectProperty() avatar = properties.ObjectProperty() + badge = properties.ObjectProperty(allownone=True) + badge_text = properties.StringProperty('') profile = properties.StringProperty() data = properties.DictProperty() jid = properties.StringProperty('') - def on_kv_post(self, __): - if self.data and self.data.get('notifs'): - notif = NotifLabel( - pos_hint={"right": 0.8, "y": 0}, - text=str(len(self.data['notifs'])) - ) - self.avatar_layout.add_widget(notif) + def on_badge_text(self, wid, text): + if text: + if self.badge is not None: + self.badge.text = text + else: + self.badge = NotifLabel( + pos_hint={"right": 0.8, "y": 0}, + text=text, + ) + self.avatar_layout.add_widget(self.badge) + else: + if self.badge is not None: + self.avatar_layout.remove_widget(self.badge) + self.badge = None class ContactButton(ButtonBehavior, ContactItem): @@ -174,12 +185,25 @@ self.add_widget(icon_wid) +class JidSelectorCategoryLayout(StackLayout): + pass + + class JidSelector(ScrollView, EventDispatcher): layout = properties.ObjectProperty(None) + # if item_class is changed, the properties must be the same as for ContactButton + # and ordering must be supported + item_class = properties.ObjectProperty(ContactButton) + add_separators = properties.ObjectProperty(True) # list of item to show, can be: - # - a well-known string like: - # * "roster": to show all roster jids - # * "opened_chats": to show jids of all opened chat widgets + # - a well-known string which can be: + # * "roster": all roster jids + # * "opened_chats": all opened chat widgets + # * "bookmarks": MUC bookmarks + # A layout will be created each time and stored in the attribute of the same + # name. + # If add_separators is True, a CategorySeparator will be added on top of each + # layout. # - a kivy Widget, which will be added to the layout (notable useful with # common_widgets.CategorySeparator) # - a callable, which must return an iterable of kwargs for ContactButton @@ -190,6 +214,10 @@ def __init__(self, **kwargs): self.register_event_type('on_select') + # list of layouts containing items + self.items_layouts = [] + # jid to list of ContactButton instances map + self.items_map = {} super().__init__(**kwargs) def on_kv_post(self, wid): @@ -210,6 +238,13 @@ log.debug("onContactsFilled event received") self.update() + + def _createItem(self, **kwargs): + item = self.item_class(**kwargs) + jid = kwargs['jid'] + self.items_map.setdefault(jid, []).append(item) + return item + def update(self): log.debug("starting update") self.layout.clear_widgets() @@ -228,52 +263,69 @@ elif callable(item): items_kwargs = item() for item_kwargs in items_kwargs: - item = ContactButton(**item_kwargs) + item = self._createItem(**items_kwargs) item.bind(on_press=partial(self.dispatch, 'on_select')) self.layout.add_widget(item) else: log.error(f"unmanaged to_show item type: {item!r}") - def addOpenedChatsItems(self): - opened_chats = G.host.widgets.getWidgets( - quick_chat.QuickChat, - profiles = G.host.profiles) + def addCategoryLayout(self, label=None): + category_layout = JidSelectorCategoryLayout() + + if label and self.add_separators: + category_layout.add_widget(CategorySeparator(text=label)) + + self.layout.add_widget(category_layout) + self.items_layouts.append(category_layout) + return category_layout - for wid in opened_chats: - contact_list = G.host.contact_lists[wid.profile] - data=contact_list.getItem(wid.target) - notifs = list(G.host.getNotifs(wid.target, profile=wid.profile)) - if notifs: - # we shallow copy the dict to have the notification displayed only with - # opened chats (otherwise, the counter would appear on each other - # instance of ContactButton for this entity, i.e. in roster too). - data = data.copy() - data['notifs'] = notifs - try: - item = ContactButton( - jid=wid.target, - data=data, - profile=wid.profile, - ) - except Exception as e: - log.warning(f"Can't add contact {wid.target}: {e}") + def getItemFromWid(self, wid): + """create JidSelector item from QuickChat widget""" + contact_list = G.host.contact_lists[wid.profile] + data=contact_list.getItem(wid.target) + try: + item = self._createItem( + jid=wid.target, + data=data, + profile=wid.profile, + ) + except Exception as e: + log.warning(f"Can't add contact {wid.target}: {e}") + return + notifs = list(G.host.getNotifs(wid.target, profile=wid.profile)) + if notifs: + item.badge_text = str(len(notifs)) + item.bind(on_press=partial(self.dispatch, 'on_select')) + return item + + def addOpenedChatsItems(self): + self.opened_chats = category_layout = self.addCategoryLayout(_("Opened chats")) + widgets = sorted(G.host.widgets.getWidgets( + quick_chat.QuickChat, + profiles = G.host.profiles, + with_duplicates=False)) + + for wid in widgets: + item = self.getItemFromWid(wid) + if item is None: continue - item.bind(on_press=partial(self.dispatch, 'on_select')) - self.layout.add_widget(item) + category_layout.add_widget(item) def addRosterItems(self): + self.roster = category_layout = self.addCategoryLayout(_("Your contacts")) for profile in G.host.profiles: contact_list = G.host.contact_lists[profile] for entity_jid in sorted(contact_list.roster): - item = ContactButton( + item = self._createItem( jid=entity_jid, data=contact_list.getItem(entity_jid), profile=profile, ) item.bind(on_press=partial(self.dispatch, 'on_select')) - self.layout.add_widget(item) + category_layout.add_widget(item) def addBookmarksItems(self): + self.bookmarks = category_layout = self.addCategoryLayout(_("Your chat rooms")) for profile in G.host.profiles: profile_manager = G.host.profiles[profile] try: @@ -288,10 +340,10 @@ cache = contact_list.getItem(entity_jid) except KeyError: cache = {} - item = ContactButton( + item = self._createItem( jid=entity_jid, data=cache, profile=profile, ) item.bind(on_press=partial(self.dispatch, 'on_select')) - self.layout.add_widget(item) + category_layout.add_widget(item) diff -r b0af45a92055 -r f7476818f9fb cagou/core/common_widgets.py --- a/cagou/core/common_widgets.py Wed Feb 12 20:02:58 2020 +0100 +++ b/cagou/core/common_widgets.py Wed Feb 12 20:02:58 2020 +0100 @@ -22,7 +22,7 @@ from sat.core.i18n import _ from kivy.uix.label import Label from kivy.uix.boxlayout import BoxLayout -from cagou.core.menu import TouchMenuItemBehaviour +from .behaviors import TouchMenuItemBehavior from kivy import properties from kivy.metrics import dp from kivy.clock import Clock @@ -82,7 +82,7 @@ return names[0] -class ItemWidget(TouchMenuItemBehaviour, BoxLayout): +class ItemWidget(TouchMenuItemBehavior, BoxLayout): name = properties.StringProperty() base_width = properties.NumericProperty(dp(100)) diff -r b0af45a92055 -r f7476818f9fb cagou/core/menu.py --- a/cagou/core/menu.py Wed Feb 12 20:02:58 2020 +0100 +++ b/cagou/core/menu.py Wed Feb 12 20:02:58 2020 +0100 @@ -26,13 +26,11 @@ from kivy.uix.label import Label from kivy.uix.button import Button from kivy.uix.popup import Popup -from cagou.core.utils import FilterBehavior +from .behaviors import FilterBehavior from kivy import properties -from kivy_garden import modernmenu from kivy.core.window import Window from kivy.animation import Animation from kivy.metrics import dp -from kivy.clock import Clock from cagou import G from functools import partial import webbrowser @@ -295,105 +293,8 @@ def do_filter_input(self, filter_input, text): self.layout.spacing = 0 if text else dp(5) - self.do_filter(self.layout.children, + self.do_filter(self.layout, text, lambda c: c.jid, width_cb=lambda c: c.width, height_cb=lambda c: dp(70)) - - -class TouchMenu(modernmenu.ModernMenu): - pass - - -class TouchMenuItemBehaviour(object): - """Class to use on every item where a menu may appear - - main_wid attribute must be set to the class inheriting from TouchMenuBehaviour - do_item_action is the method called on simple click - getMenuChoices must return a list of menus for long press - menus there are dict as expected by ModernMenu - (translated text, index and callback) - """ - main_wid = properties.ObjectProperty() - click_timeout = properties.NumericProperty(0.4) - - def on_touch_down(self, touch): - if not self.collide_point(*touch.pos): - return - t = partial(self.open_menu, touch) - touch.ud['menu_timeout'] = t - Clock.schedule_once(t, self.click_timeout) - return super(TouchMenuItemBehaviour, self).on_touch_down(touch) - - def do_item_action(self, touch): - pass - - def on_touch_up(self, touch): - if touch.ud.get('menu_timeout'): - Clock.unschedule(touch.ud['menu_timeout']) - if self.collide_point(*touch.pos) and self.main_wid.menu is None: - self.do_item_action(touch) - return super(TouchMenuItemBehaviour, self).on_touch_up(touch) - - def open_menu(self, touch, dt): - self.main_wid.open_menu(self, touch) - del touch.ud['menu_timeout'] - - def getMenuChoices(self): - """return choice adapted to selected item - - @return (list[dict]): choices ad expected by ModernMenu - """ - return [] - - -class TouchMenuBehaviour(object): - """Class to handle a menu appearing on long press on items - - classes using this behaviour need to have a float_layout property - pointing the main FloatLayout. - """ - float_layout = properties.ObjectProperty() - - def __init__(self, *args, **kwargs): - super(TouchMenuBehaviour, self).__init__(*args, **kwargs) - self.menu = None - self.menu_item = None - - ## menu methods ## - - def clean_fl_children(self, layout, children): - """insure that self.menu and self.menu_item are None when menu is dimissed""" - if self.menu is not None and self.menu not in children: - self.menu = self.menu_item = None - - def clear_menu(self): - """remove menu if there is one""" - if self.menu is not None: - self.menu.dismiss() - self.menu = None - self.menu_item = None - - def open_menu(self, item, touch): - """open menu for item - - @param item(PathWidget): item when the menu has been requested - @param touch(kivy.input.MotionEvent): touch data - """ - if self.menu_item == item: - return - self.clear_menu() - pos = self.to_widget(*touch.pos) - choices = item.getMenuChoices() - if not choices: - return - self.menu = TouchMenu(choices=choices, - center=pos, - size_hint=(None, None)) - self.float_layout.add_widget(self.menu) - self.menu.start_display(touch) - self.menu_item = item - - def on_float_layout(self, wid, float_layout): - float_layout.bind(children=self.clean_fl_children) diff -r b0af45a92055 -r f7476818f9fb cagou/core/utils.py --- a/cagou/core/utils.py Wed Feb 12 20:02:58 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -#!/usr//bin/env python2 - - -# Cagou: desktop/mobile frontend for Salut à Toi XMPP client -# Copyright (C) 2016-2020 Jérôme Poisson (goffi@goffi.org) - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -"""misc utils/behaviors""" - - -from kivy.animation import Animation - - -class FilterBehavior(object): - """class to handle items filtering with animation""" - - def __init__(self, *args, **kwargs): - super(FilterBehavior, self).__init__(*args, **kwargs) - self._filter_last = '' - self._filter_anim = Animation(width = 0, - height = 0, - opacity = 0, - d = 0.5) - - def do_filter(self, children, text, get_child_text, width_cb, height_cb, - continue_tests=None): - """filter the children - - filtered children will have a animation to set width, height and opacity to 0 - @param children(kivy.uix.widget.Widget): widgets to filter - @param text(unicode): filter text (if this text is not present in a child, - the child is filtered out) - @param get_child_text(callable): must retrieve child text - child is used as sole argument - @param width_cb(callable, int, None): method to retrieve width when opened - child is used as sole argument, int can be used instead of callable - @param height_cb(callable, int, None): method to retrieve height when opened - child is used as sole argument, int can be used instead of callable - @param continue_tests(list[callable]): list of test to skip the item - all callables take child as sole argument. - if any of the callable return True, the child is skipped (i.e. not filtered) - """ - text = text.strip().lower() - filtering = len(text)>len(self._filter_last) - self._filter_last = text - for child in children: - if continue_tests is not None and any((t(child) for t in continue_tests)): - continue - if text in get_child_text(child).lower(): - self._filter_anim.cancel(child) - for key, method in (('width', width_cb), - ('height', height_cb), - ('opacity', lambda c: 1)): - try: - setattr(child, key, method(child)) - except TypeError: - # method is not a callable, must be an int - setattr(child, key, method) - elif (filtering - and child.opacity > 0 - and not self._filter_anim.have_properties_to_animate(child)): - self._filter_anim.start(child) diff -r b0af45a92055 -r f7476818f9fb cagou/kv/behaviors.kv --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cagou/kv/behaviors.kv Wed Feb 12 20:02:58 2020 +0100 @@ -0,0 +1,28 @@ +# Cagou: desktop/mobile frontend for Salut à Toi XMPP client +# Copyright (C) 2016-2019 Jérôme Poisson (goffi@goffi.org) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +: + creation_direction: -1 + radius: dp(25) + creation_timeout: .4 + cancel_color: app.c_sec_light[:3] + [0.3] + color: app.c_sec + line_width: dp(2) + +: + bg_color: app.c_sec[:3] + [0.9] + padding: dp(5), dp(5) + radius: dp(100) diff -r b0af45a92055 -r f7476818f9fb cagou/kv/common.kv --- a/cagou/kv/common.kv Wed Feb 12 20:02:58 2020 +0100 +++ b/cagou/kv/common.kv Wed Feb 12 20:02:58 2020 +0100 @@ -136,6 +136,11 @@ color: app.c_sec_light +: + size_hint: 1, None + height: self.minimum_height + spacing: 0 + : layout: layout StackLayout: diff -r b0af45a92055 -r f7476818f9fb cagou/kv/menu.kv --- a/cagou/kv/menu.kv Wed Feb 12 20:02:58 2020 +0100 +++ b/cagou/kv/menu.kv Wed Feb 12 20:02:58 2020 +0100 @@ -131,17 +131,3 @@ size_hint: 1, None height: self.minimum_height spacing: dp(5) - - -: - creation_direction: -1 - radius: dp(25) - creation_timeout: .4 - cancel_color: app.c_sec_light[:3] + [0.3] - color: app.c_sec - line_width: dp(2) - -: - bg_color: app.c_sec[:3] + [0.9] - padding: dp(5), dp(5) - radius: dp(100) diff -r b0af45a92055 -r f7476818f9fb cagou/plugins/plugin_wid_chat.kv --- a/cagou/plugins/plugin_wid_chat.kv Wed Feb 12 20:02:58 2020 +0100 +++ b/cagou/plugins/plugin_wid_chat.kv Wed Feb 12 20:02:58 2020 +0100 @@ -224,13 +224,5 @@ # we call update() explicitly in on_pre_enter implicit_update: False on_select: root.on_select(args[1]) - to_show: - [ - CategorySeparator(text=_("Opened chats")), - "opened_chats", - CategorySeparator(text=_("Your contacts")), - "roster", - CategorySeparator(text=_("Your chat rooms")), - "bookmarks", - ] + to_show: ["opened_chats", "roster", "bookmarks"] diff -r b0af45a92055 -r f7476818f9fb cagou/plugins/plugin_wid_chat.py --- a/cagou/plugins/plugin_wid_chat.py Wed Feb 12 20:02:58 2020 +0100 +++ b/cagou/plugins/plugin_wid_chat.py Wed Feb 12 20:02:58 2020 +0100 @@ -38,14 +38,14 @@ from sat_frontends.quick_frontend import quick_chat from sat_frontends.tools import jid from cagou import G -from cagou.core.constants import Const as C -from cagou.core import cagou_widget -from cagou.core import xmlui -from cagou.core.image import Image -from cagou.core.common import SymbolButton, JidButton -from cagou.core.utils import FilterBehavior -from cagou.core import menu -from cagou.core.common import ContactButton +from ..core.constants import Const as C +from ..core import cagou_widget +from ..core import xmlui +from ..core.image import Image +from ..core.common import SymbolButton, JidButton +from ..core.behaviors import FilterBehavior +from ..core import menu +from ..core.common import ContactButton log = logging.getLogger(__name__) @@ -949,14 +949,15 @@ def onHeaderInputComplete(self, wid, text, **kwargs): """we filter items when text is entered in input box""" - self.do_filter( - self.jid_selector.children[0].children, - text, - # we append nick to jid to filter on both - lambda c: c.jid + c.data.get('nick', ''), - width_cb=lambda c: c.base_width, - height_cb=lambda c: c.minimum_height, - continue_tests=[lambda c: not isinstance(c, ContactButton)]) + for layout in self.jid_selector.items_layouts: + self.do_filter( + layout, + text, + # we append nick to jid to filter on both + lambda c: c.jid + c.data.get('nick', ''), + width_cb=lambda c: c.base_width, + height_cb=lambda c: c.minimum_height, + continue_tests=[lambda c: not isinstance(c, ContactButton)]) PLUGIN_INFO["factory"] = Chat.factory diff -r b0af45a92055 -r f7476818f9fb cagou/plugins/plugin_wid_contact_list.py --- a/cagou/plugins/plugin_wid_contact_list.py Wed Feb 12 20:02:58 2020 +0100 +++ b/cagou/plugins/plugin_wid_contact_list.py Wed Feb 12 20:02:58 2020 +0100 @@ -30,8 +30,8 @@ from ..core import cagou_widget from ..core.constants import Const as C from ..core.common import ContactItem -from ..core.utils import FilterBehavior -from ..core.menu import SideMenu, TouchMenuBehaviour, TouchMenuItemBehaviour +from ..core.behaviors import FilterBehavior, TouchMenuBehavior, TouchMenuItemBehavior +from ..core.menu import SideMenu log = logging.getLogger(__name__) @@ -99,7 +99,7 @@ message=_("error while trying to remove contact: {msg}"))) -class CLContactItem(TouchMenuItemBehaviour, ContactItem): +class CLContactItem(TouchMenuItemBehavior, ContactItem): def do_item_action(self, touch): assert self.profile @@ -116,7 +116,7 @@ class ContactList(QuickContactList, cagou_widget.CagouWidget, FilterBehavior, - TouchMenuBehaviour): + TouchMenuBehavior): float_layout = properties.ObjectProperty() layout = properties.ObjectProperty() use_header_input = True @@ -143,7 +143,7 @@ DelContactMenu(contact_item=item).show() def onHeaderInputComplete(self, wid, text): - self.do_filter(self.layout.children, + self.do_filter(self.layout, text, lambda c: c.jid, width_cb=lambda c: c.base_width, diff -r b0af45a92055 -r f7476818f9fb cagou/plugins/plugin_wid_file_sharing.py --- a/cagou/plugins/plugin_wid_file_sharing.py Wed Feb 12 20:02:58 2020 +0100 +++ b/cagou/plugins/plugin_wid_file_sharing.py Wed Feb 12 20:02:58 2020 +0100 @@ -26,11 +26,11 @@ from sat.tools.common import files_utils from sat_frontends.quick_frontend import quick_widgets from sat_frontends.tools import jid -from cagou.core.constants import Const as C -from cagou.core import cagou_widget -from cagou.core.menu import EntitiesSelectorMenu, TouchMenuBehaviour -from cagou.core.utils import FilterBehavior -from cagou.core.common_widgets import (Identities, ItemWidget, DeviceWidget, +from ..core.constants import Const as C +from ..core import cagou_widget +from ..core.menu import EntitiesSelectorMenu +from ..core.behaviors import TouchMenuBehavior, FilterBehavior +from ..core.common_widgets import (Identities, ItemWidget, DeviceWidget, CategorySeparator) from cagou import G from kivy import properties @@ -148,7 +148,7 @@ class FileSharing(quick_widgets.QuickWidget, cagou_widget.CagouWidget, FilterBehavior, - TouchMenuBehaviour): + TouchMenuBehavior): SINGLE=False layout = properties.ObjectProperty() mode = properties.OptionProperty(MODE_VIEW, options=[MODE_VIEW, MODE_LOCAL]) @@ -163,7 +163,7 @@ quick_widgets.QuickWidget.__init__(self, host, target, profiles) cagou_widget.CagouWidget.__init__(self) FilterBehavior.__init__(self) - TouchMenuBehaviour.__init__(self) + TouchMenuBehavior.__init__(self) self.mode_btn = ModeBtn(self) self.mode_btn.bind(on_release=self.change_mode) self.headerInputAddExtra(self.mode_btn) @@ -216,7 +216,7 @@ """we filter items when text is entered in input box""" if '/' in text: return - self.do_filter(self.layout.children, + self.do_filter(self.layout, text, lambda c: c.name, width_cb=lambda c: c.base_width, diff -r b0af45a92055 -r f7476818f9fb cagou/plugins/plugin_wid_remote.py --- a/cagou/plugins/plugin_wid_remote.py Wed Feb 12 20:02:58 2020 +0100 +++ b/cagou/plugins/plugin_wid_remote.py Wed Feb 12 20:02:58 2020 +0100 @@ -21,11 +21,10 @@ from sat.core import log as logging from sat.core.i18n import _ from sat_frontends.quick_frontend import quick_widgets -from cagou.core import cagou_widget -from cagou.core.constants import Const as C -from cagou.core.menu import TouchMenuBehaviour -from cagou.core.utils import FilterBehavior -from cagou.core.common_widgets import (Identities, ItemWidget, DeviceWidget, +from ..core import cagou_widget +from ..core.constants import Const as C +from ..core.behaviors import TouchMenuBehavior, FilterBehavior +from ..core.common_widgets import (Identities, ItemWidget, DeviceWidget, CategorySeparator) from sat.tools.common import template_xmlui from cagou.core import xmlui @@ -177,7 +176,7 @@ class RemoteControl(quick_widgets.QuickWidget, cagou_widget.CagouWidget, FilterBehavior, - TouchMenuBehaviour): + TouchMenuBehavior): SINGLE=False layout = properties.ObjectProperty() @@ -185,7 +184,7 @@ quick_widgets.QuickWidget.__init__(self, host, target, profiles) cagou_widget.CagouWidget.__init__(self) FilterBehavior.__init__(self) - TouchMenuBehaviour.__init__(self) + TouchMenuBehavior.__init__(self) self.stack_layout = None self.showRootWidget()