comparison cagou/core/cagou_main.py @ 250:ff1efdeff53f

core: notifs can now have a custom icon and be clickable: - new host.doAction method, to open a specific widget/target (chat only for now) - when adding a notif, symbol can now be specified - an action can be linked to a notification - notifs design improvments - plugins contact list and chat use the new doAction/notif action - if None is given as old widget in SwitchWidget, the new getWidgetToSwitch method is used to select one to switch.
author Goffi <goffi@goffi.org>
date Sat, 26 Jan 2019 20:24:48 +0100
parents 5d69e4cab925
children 4601793b0dee
comparison
equal deleted inserted replaced
249:5d69e4cab925 250:ff1efdeff53f
52 from kivy.uix.boxlayout import BoxLayout 52 from kivy.uix.boxlayout import BoxLayout
53 from kivy.uix.floatlayout import FloatLayout 53 from kivy.uix.floatlayout import FloatLayout
54 from kivy.uix.screenmanager import (ScreenManager, Screen, 54 from kivy.uix.screenmanager import (ScreenManager, Screen,
55 FallOutTransition, RiseInTransition) 55 FallOutTransition, RiseInTransition)
56 from kivy.uix.dropdown import DropDown 56 from kivy.uix.dropdown import DropDown
57 from kivy.uix.behaviors import ButtonBehavior
57 from kivy.core.window import Window 58 from kivy.core.window import Window
58 from kivy.animation import Animation 59 from kivy.animation import Animation
59 from kivy.metrics import dp 60 from kivy.metrics import dp
60 from cagou_widget import CagouWidget 61 from cagou_widget import CagouWidget
61 from . import widgets_handler 62 from . import widgets_handler
102 class Note(Label): 103 class Note(Label):
103 title = properties.StringProperty() 104 title = properties.StringProperty()
104 message = properties.StringProperty() 105 message = properties.StringProperty()
105 level = properties.OptionProperty(C.XMLUI_DATA_LVL_DEFAULT, 106 level = properties.OptionProperty(C.XMLUI_DATA_LVL_DEFAULT,
106 options=list(C.XMLUI_DATA_LVLS)) 107 options=list(C.XMLUI_DATA_LVLS))
107 108 symbol = properties.StringProperty()
108 109 action = properties.ObjectProperty()
109 class NoteDrop(BoxLayout): 110
111
112 class NoteDrop(ButtonBehavior, BoxLayout):
110 title = properties.StringProperty() 113 title = properties.StringProperty()
111 message = properties.StringProperty() 114 message = properties.StringProperty()
112 level = properties.OptionProperty(C.XMLUI_DATA_LVL_DEFAULT, 115 level = properties.OptionProperty(C.XMLUI_DATA_LVL_DEFAULT,
113 options=list(C.XMLUI_DATA_LVLS)) 116 options=list(C.XMLUI_DATA_LVLS))
117 symbol = properties.StringProperty()
118 action = properties.ObjectProperty()
119
120 def on_press(self):
121 if self.action is not None:
122 self.parent.parent.select(self.action)
114 123
115 124
116 class NotesDrop(DropDown): 125 class NotesDrop(DropDown):
117 clear_btn = properties.ObjectProperty() 126 clear_btn = properties.ObjectProperty()
118 127
121 self.notes = notes 130 self.notes = notes
122 131
123 def open(self, widget): 132 def open(self, widget):
124 self.clear_widgets() 133 self.clear_widgets()
125 for n in self.notes: 134 for n in self.notes:
126 self.add_widget(NoteDrop(title=n.title, message=n.message, level=n.level)) 135 kwargs = {
136 u'title': n.title,
137 u'message': n.message,
138 u'level': n.level
139 }
140 if n.symbol is not None:
141 kwargs[u'symbol'] = n.symbol
142 if n.action is not None:
143 kwargs[u'action'] = n.action
144 self.add_widget(NoteDrop(title=n.title, message=n.message, level=n.level,
145 symbol=n.symbol, action=n.action))
127 self.add_widget(self.clear_btn) 146 self.add_widget(self.clear_btn)
128 super(NotesDrop, self).open(widget) 147 super(NotesDrop, self).open(widget)
148
149 def on_select(self, action_kwargs):
150 app = App.get_running_app()
151 app.host.doAction(**action_kwargs)
129 152
130 153
131 class RootHeadWidget(BoxLayout): 154 class RootHeadWidget(BoxLayout):
132 """Notifications widget""" 155 """Notifications widget"""
133 manager = properties.ObjectProperty() 156 manager = properties.ObjectProperty()
147 when notification is pressed, callback is called 170 when notification is pressed, callback is called
148 @param *args, **kwargs: arguments of callback 171 @param *args, **kwargs: arguments of callback
149 """ 172 """
150 self.notifs_icon.addNotif(callback, *args, **kwargs) 173 self.notifs_icon.addNotif(callback, *args, **kwargs)
151 174
152 def addNote(self, title, message, level): 175 def addNote(self, title, message, level, symbol, action):
153 note = Note(title=title, message=message, level=level) 176 kwargs = {
177 u'title': title,
178 u'message': message,
179 u'level': level
180 }
181 if symbol is not None:
182 kwargs[u'symbol'] = symbol
183 if action is not None:
184 kwargs[u'action'] = action
185 note = Note(**kwargs)
154 self.notes.append(note) 186 self.notes.append(note)
155 if self.notes_event is None: 187 if self.notes_event is None:
156 self.notes_event = Clock.schedule_interval(self._displayNextNote, 5) 188 self.notes_event = Clock.schedule_interval(self._displayNextNote, 5)
157 self._displayNextNote() 189 self._displayNextNote()
158 190
235 267
236 def newAction(self, handler, action_data, id_, security_limit, profile): 268 def newAction(self, handler, action_data, id_, security_limit, profile):
237 """Add a notification for an action""" 269 """Add a notification for an action"""
238 self.head_widget.addNotif(handler, action_data, id_, security_limit, profile) 270 self.head_widget.addNotif(handler, action_data, id_, security_limit, profile)
239 271
240 def addNote(self, title, message, level): 272 def addNote(self, title, message, level, symbol, action):
241 self.head_widget.addNote(title, message, level) 273 self.head_widget.addNote(title, message, level, symbol, action)
242 274
243 def addNotifUI(self, ui): 275 def addNotifUI(self, ui):
244 self.head_widget.addNotifUI(ui) 276 self.head_widget.addNotifUI(ui)
245 277
246 def addNotifWidget(self, widget): 278 def addNotifWidget(self, widget):
660 self.addNote(u"", _(u"room {} has been joined").format(widget.target)) 692 self.addNote(u"", _(u"room {} has been joined").format(widget.target))
661 693
662 def switchWidget(self, old, new): 694 def switchWidget(self, old, new):
663 """Replace old widget by new one 695 """Replace old widget by new one
664 696
665 old(CagouWidget): CagouWidget instance or a child 697 old(CagouWidgetn None): CagouWidget instance or a child
698 None to select automatically widget to switch
666 new(CagouWidget): new widget instance 699 new(CagouWidget): new widget instance
667 """ 700 """
701 if old is None:
702 old = self.getWidgetToSwitch()
668 to_change = None 703 to_change = None
669 if isinstance(old, CagouWidget): 704 if isinstance(old, CagouWidget):
670 to_change = old 705 to_change = old
671 else: 706 else:
672 for w in old.walk_reverse(): 707 for w in old.walk_reverse():
728 profiles=widget.profiles) 763 profiles=widget.profiles)
729 for t in targets[1:]: 764 for t in targets[1:]:
730 w.addTarget(t) 765 w.addTarget(t)
731 return w 766 return w
732 767
768 def getWidgetToSwitch(self):
769 """Choose best candidate when we need to switch widget and old is not specified
770
771 @return (CagouWidget): widget to switch
772 """
773 if self.selected_widget is not None:
774 return self.selected_widget
775 # no widget is selected we check if we have any default widget
776 default_cls = self.default_wid['main']
777 for w in self.visible_widgets:
778 if isinstance(w, default_cls):
779 return w
780
781 # no default widget found, we return the first widget
782 return next(iter(self.visible_widgets))
783
784 def doAction(self, action, target, profiles):
785 """Launch an action handler by a plugin
786
787 @param action(unicode): action to do, can be:
788 - chat: open a chat widget
789 @param target(unicode): target of the action
790 @param profiles(list[unicode]): profiles to use
791 """
792 try:
793 # FIXME: Q&D way to get chat plugin, should be replaced by a clean method
794 # in host
795 plg_infos = [p for p in self.getPluggedWidgets()
796 if action in p['import_name']][0]
797 except IndexError:
798 log.warning(u"No plugin widget found to do {action}".format(action=action))
799 else:
800 factory = plg_infos['factory']
801 self.switchWidget(None,
802 factory(plg_infos, target=target, profiles=profiles))
803
733 ## menus ## 804 ## menus ##
734 805
735 def _menusGetCb(self, backend_menus): 806 def _menusGetCb(self, backend_menus):
736 main_menu = self.app.root.root_menus 807 main_menu = self.app.root.root_menus
737 self.menus.addMenus(backend_menus) 808 self.menus.addMenus(backend_menus)
764 835
765 def errback(self, failure_, title=_('error'), 836 def errback(self, failure_, title=_('error'),
766 message=_(u'error while processing: {msg}')): 837 message=_(u'error while processing: {msg}')):
767 self.addNote(title, message.format(msg=failure_), level=C.XMLUI_DATA_LVL_WARNING) 838 self.addNote(title, message.format(msg=failure_), level=C.XMLUI_DATA_LVL_WARNING)
768 839
769 def addNote(self, title, message, level=C.XMLUI_DATA_LVL_INFO): 840 def addNote(self, title, message, level=C.XMLUI_DATA_LVL_INFO, symbol=None,
841 action=None):
770 """add a note (message which disappear) to root widget's header""" 842 """add a note (message which disappear) to root widget's header"""
771 self.app.root.addNote(title, message, level) 843 self.app.root.addNote(title, message, level, symbol, action)
772 844
773 def addNotifUI(self, ui): 845 def addNotifUI(self, ui):
774 """add a notification with a XMLUI attached 846 """add a notification with a XMLUI attached
775 847
776 @param ui(xmlui.XMLUIPanel): XMLUI instance to show when notification is selected 848 @param ui(xmlui.XMLUIPanel): XMLUI instance to show when notification is selected