Mercurial > libervia-desktop-kivy
comparison src/cagou/core/cagou_main.py @ 29:8b5827c43155
notes first draft:
Implementation of XMLUI notes. There is a new header on top of root widget which display notifications, and notes are shown for a couple of seconds.
A blue Cagou head appear when there are notes, and user can display 10 last when clicking on it.
This header will probably not be present on platforms such as Android, because there is already a system-wide notifications handler which can be used instead (saving visual space).
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 21 Aug 2016 15:15:25 +0200 |
parents | 9f9532eb835f |
children | 4f9e701d76b4 |
comparison
equal
deleted
inserted
replaced
28:9f9532eb835f | 29:8b5827c43155 |
---|---|
30 kivy.require('1.9.1') | 30 kivy.require('1.9.1') |
31 import kivy.support | 31 import kivy.support |
32 kivy.support.install_gobject_iteration() | 32 kivy.support.install_gobject_iteration() |
33 from kivy.app import App | 33 from kivy.app import App |
34 from kivy.lang import Builder | 34 from kivy.lang import Builder |
35 from kivy import properties | |
35 import xmlui | 36 import xmlui |
36 from profile_manager import ProfileManager | 37 from profile_manager import ProfileManager |
37 from widgets_handler import WidgetsHandler | 38 from widgets_handler import WidgetsHandler |
39 from kivy.clock import Clock | |
40 from kivy.uix.label import Label | |
38 from kivy.uix.boxlayout import BoxLayout | 41 from kivy.uix.boxlayout import BoxLayout |
42 from kivy.uix.screenmanager import ScreenManager, Screen | |
43 from kivy.uix.dropdown import DropDown | |
39 from cagou_widget import CagouWidget | 44 from cagou_widget import CagouWidget |
45 from .common import IconButton | |
40 from importlib import import_module | 46 from importlib import import_module |
41 import os.path | 47 import os.path |
42 import glob | 48 import glob |
43 import cagou.plugins | 49 import cagou.plugins |
44 import cagou.kv | 50 import cagou.kv |
45 | 51 |
46 | 52 |
53 class NotifIcon(IconButton): | |
54 | |
55 def __init__(self, callback, callback_args): | |
56 self._callback = callback | |
57 self._callback_args = callback_args | |
58 super(NotifIcon, self).__init__() | |
59 | |
60 def on_release(self): | |
61 self.parent.remove_widget(self) | |
62 self._callback(*self._callback_args) | |
63 | |
64 | |
65 class Note(Label): | |
66 title = properties.StringProperty() | |
67 message = properties.StringProperty() | |
68 level = properties.OptionProperty(C.XMLUI_DATA_LVL_DEFAULT, options=list(C.XMLUI_DATA_LVLS)) | |
69 | |
70 | |
71 class NoteDrop(Note): | |
72 pass | |
73 | |
74 | |
75 class NotesDrop(DropDown): | |
76 clear_btn = properties.ObjectProperty() | |
77 | |
78 def __init__(self, notes): | |
79 super(NotesDrop, self).__init__() | |
80 self.notes = notes | |
81 | |
82 def open(self, widget): | |
83 self.clear_widgets() | |
84 for n in self.notes: | |
85 self.add_widget(NoteDrop(title=n.title, message=n.message, level=n.level)) | |
86 self.add_widget(self.clear_btn) | |
87 super(NotesDrop, self).open(widget) | |
88 | |
89 | |
90 class RootHeadWidget(BoxLayout): | |
91 """Notifications widget""" | |
92 manager = properties.ObjectProperty() | |
93 notes = properties.ListProperty() | |
94 | |
95 def __init__(self): | |
96 super(RootHeadWidget, self).__init__() | |
97 self.notes_last = None | |
98 self.notes_event = None | |
99 self.notes_drop = NotesDrop(self.notes) # auto_with=False, width=100) | |
100 | |
101 def addNotif(self, callback, *args): | |
102 icon = NotifIcon(callback, args) | |
103 self.add_widget(icon) | |
104 | |
105 def addNote(self, title, message, level): | |
106 note = Note(title=title, message=message, level=level) | |
107 self.notes.append(note) | |
108 if len(self.notes) > 10: | |
109 del self.notes[:-10] | |
110 if self.notes_event is None: | |
111 self.notes_event = Clock.schedule_interval(self._displayNextNote, 5) | |
112 self._displayNextNote() | |
113 | |
114 def _displayNextNote(self, dummy=None): | |
115 screen = Screen() | |
116 try: | |
117 idx = self.notes.index(self.notes_last) + 1 | |
118 except ValueError: | |
119 idx = 0 | |
120 try: | |
121 note = self.notes_last = self.notes[idx] | |
122 except IndexError: | |
123 self.notes_event.cancel() | |
124 self.notes_event = None | |
125 else: | |
126 screen.add_widget(note) | |
127 self.manager.switch_to(screen) | |
128 | |
129 | |
47 class CagouRootWidget(BoxLayout): | 130 class CagouRootWidget(BoxLayout): |
48 | 131 |
49 def __init__(self, widgets): | 132 def __init__(self, main_widget): |
50 super(CagouRootWidget, self).__init__(orientation=("vertical")) | 133 super(CagouRootWidget, self).__init__(orientation=("vertical")) |
51 for wid in widgets: | 134 # header |
52 self.add_widget(wid) | 135 self._head_widget = RootHeadWidget() |
53 | 136 self.add_widget(self._head_widget) |
54 def change_widgets(self, widgets): | 137 |
55 self.clear_widgets() | 138 # body |
56 for wid in widgets: | 139 self._manager = ScreenManager() |
57 self.add_widget(wid) | 140 main_screen = Screen(name='main') |
141 main_screen.add_widget(main_widget) | |
142 self._manager.add_widget(main_screen) | |
143 self.add_widget(self._manager) | |
144 self.change_widget(main_widget) | |
145 | |
146 def change_widget(self, main_widget, screen="main"): | |
147 """change main widget""" | |
148 main_screen = self._manager.get_screen(screen) | |
149 main_screen.clear_widgets() | |
150 main_screen.add_widget(main_widget) | |
151 | |
152 def newAction(self, handler, action_data, id_, security_limit, profile): | |
153 """Add a notification for an action""" | |
154 self._head_widget.addNotif(handler, action_data, id_, security_limit, profile) | |
155 | |
156 def addNote(self, title, message, level): | |
157 self._head_widget.addNote(title, message, level) | |
58 | 158 |
59 | 159 |
60 class CagouApp(App): | 160 class CagouApp(App): |
61 """Kivy App for Cagou""" | 161 """Kivy App for Cagou""" |
62 | 162 |
63 def build(self): | 163 def build(self): |
64 return CagouRootWidget([ProfileManager()]) | 164 return CagouRootWidget(ProfileManager()) |
65 | 165 |
66 def expand(self, path): | 166 def expand(self, path): |
67 """expand path and replace known values | 167 """expand path and replace known values |
68 | 168 |
69 useful in kv. Values which can be used: | 169 useful in kv. Values which can be used: |
77 | 177 |
78 def __init__(self): | 178 def __init__(self): |
79 super(Cagou, self).__init__(create_bridge=DBusBridgeFrontend, xmlui=xmlui) | 179 super(Cagou, self).__init__(create_bridge=DBusBridgeFrontend, xmlui=xmlui) |
80 self._import_kv() | 180 self._import_kv() |
81 self.app = CagouApp() | 181 self.app = CagouApp() |
182 self.app.host = self | |
82 self.media_dir = self.app.media_dir = self.bridge.getConfig("", "media_dir") | 183 self.media_dir = self.app.media_dir = self.bridge.getConfig("", "media_dir") |
83 self.app.default_avatar = os.path.join(self.media_dir, "misc/default_avatar.png") | 184 self.app.default_avatar = os.path.join(self.media_dir, "misc/default_avatar.png") |
84 self._plg_wids = [] # widget plugins | 185 self._plg_wids = [] # widget plugins |
85 self._import_plugins() | 186 self._import_plugins() |
86 | 187 |
89 | 190 |
90 def _defaultFactory(self, plugin_info, target, profiles): | 191 def _defaultFactory(self, plugin_info, target, profiles): |
91 """factory used to create widget instance when PLUGIN_INFO["factory"] is not set""" | 192 """factory used to create widget instance when PLUGIN_INFO["factory"] is not set""" |
92 main_cls = plugin_info['main'] | 193 main_cls = plugin_info['main'] |
93 return self.widgets.getOrCreateWidget(main_cls, target, on_new_widget=None, profiles=iter(self.profiles)) | 194 return self.widgets.getOrCreateWidget(main_cls, target, on_new_widget=None, profiles=iter(self.profiles)) |
195 | |
196 ## plugins & kv import ## | |
94 | 197 |
95 def _import_kv(self): | 198 def _import_kv(self): |
96 """import all kv files in cagou.kv""" | 199 """import all kv files in cagou.kv""" |
97 path = os.path.dirname(cagou.kv.__file__) | 200 path = os.path.dirname(cagou.kv.__file__) |
98 for kv_path in glob.glob(os.path.join(path, "*.kv")): | 201 for kv_path in glob.glob(os.path.join(path, "*.kv")): |
178 for plugin_data in self._plg_wids: | 281 for plugin_data in self._plg_wids: |
179 if plugin_data['main'] == except_cls: | 282 if plugin_data['main'] == except_cls: |
180 continue | 283 continue |
181 yield plugin_data | 284 yield plugin_data |
182 | 285 |
183 def plugging_profiles(self): | 286 ## widgets handling |
184 self.app.root.change_widgets([WidgetsHandler()]) | |
185 | |
186 def setPresenceStatus(self, show='', status=None, profile=C.PROF_KEY_NONE): | |
187 log.info(u"Profile presence status set to {show}/{status}".format(show=show, status=status)) | |
188 | 287 |
189 def switchWidget(self, old, new): | 288 def switchWidget(self, old, new): |
190 """Replace old widget by new one | 289 """Replace old widget by new one |
191 | 290 |
192 old(CagouWidget): CagouWidget instance or a child | 291 old(CagouWidget): CagouWidget instance or a child |
206 else: | 305 else: |
207 parent = to_change.parent | 306 parent = to_change.parent |
208 idx = parent.children.index(to_change) | 307 idx = parent.children.index(to_change) |
209 parent.remove_widget(to_change) | 308 parent.remove_widget(to_change) |
210 parent.add_widget(new, index=idx) | 309 parent.add_widget(new, index=idx) |
310 | |
311 ## misc ## | |
312 | |
313 def plugging_profiles(self): | |
314 self.app.root.change_widget(WidgetsHandler()) | |
315 | |
316 def setPresenceStatus(self, show='', status=None, profile=C.PROF_KEY_NONE): | |
317 log.info(u"Profile presence status set to {show}/{status}".format(show=show, status=status)) | |
318 | |
319 def addNote(self, title, message, level): | |
320 """add a note (message which disappear) to root widget's header""" | |
321 self.app.root.addNote(title, message, level) | |
322 | |
323 ## signals handling ## | |
324 | |
325 def actionNewHandler(self, action_data, id_, security_limit, profile): | |
326 handler = super(Cagou, self).actionNewHandler | |
327 # FIXME: temporarily deactivated | |
328 # if 'xmlui' in action_data: | |
329 # self.app.root.newAction(handler, action_data, id_, security_limit, profile) | |
330 # else: | |
331 # handler(action_data, id_, security_limit, profile) | |
332 handler(action_data, id_, security_limit, profile) |