GUI Remove pages/namespaces (#2002)
* Add remove page methods * Implement SkillGUI.clear() The method will now remove the namespace entirely from the gui. This adds the message gui.clear.namespace * Remove debug prints from SkillGUI * Correcting docstring * More docstring changes * Remove whitespace added by Github webUIpull/2024/head
parent
8e495870c2
commit
d3e6a10ecc
|
@ -34,6 +34,29 @@ write_lock = Lock()
|
|||
RESERVED_KEYS = ['__from', '__idle']
|
||||
|
||||
|
||||
def _get_page_data(message):
|
||||
""" Extract page related data from a message.
|
||||
|
||||
Args:
|
||||
message: messagebus message object
|
||||
Returns:
|
||||
tuple (page, namespace, index)
|
||||
Raises:
|
||||
ValueError if value is missing.
|
||||
"""
|
||||
data = message.data
|
||||
# Note: 'page' can be either a string or a list of strings
|
||||
if 'page' not in data:
|
||||
raise ValueError("Page missing in data")
|
||||
if 'index' in data:
|
||||
index = data['index']
|
||||
else:
|
||||
index = 0
|
||||
page = data.get("page", "")
|
||||
namespace = data.get("__from", "")
|
||||
return page, namespace, index
|
||||
|
||||
|
||||
class Enclosure:
|
||||
def __init__(self):
|
||||
# Establish Enclosure's websocket connection to the messagebus
|
||||
|
@ -77,6 +100,8 @@ class Enclosure:
|
|||
# First send any data:
|
||||
self.bus.on("gui.value.set", self.on_gui_set_value)
|
||||
self.bus.on("gui.page.show", self.on_gui_show_page)
|
||||
self.bus.on("gui.page.delete", self.on_gui_delete_page)
|
||||
self.bus.on("gui.clear.namespace", self.on_gui_delete_namespace)
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
|
@ -122,19 +147,26 @@ class Enclosure:
|
|||
"data": {name: value}}
|
||||
self.send(msg)
|
||||
|
||||
def on_gui_show_page(self, message):
|
||||
data = message.data
|
||||
# Note: 'page' can be either a string or a list of strings
|
||||
if 'page' not in data:
|
||||
return
|
||||
if 'index' in data:
|
||||
index = data['index']
|
||||
else:
|
||||
index = 0
|
||||
page = data.get("page", "")
|
||||
namespace = data.get("__from", "")
|
||||
# Pass the request to the GUI(s) to pull up a page template
|
||||
def on_gui_delete_page(self, message):
|
||||
""" Bus handler for removing pages. """
|
||||
page, namespace, _ = _get_page_data(message)
|
||||
try:
|
||||
self.remove_pages(namespace, page)
|
||||
except Exception as e:
|
||||
LOG.exception(repr(e))
|
||||
|
||||
def on_gui_delete_namespace(self, message):
|
||||
""" Bus handler for removing namespace. """
|
||||
try:
|
||||
namespace = message.data['__from']
|
||||
self.remove_namespace(namespace)
|
||||
except Exception as e:
|
||||
LOG.exception(repr(e))
|
||||
|
||||
def on_gui_show_page(self, message):
|
||||
try:
|
||||
page, namespace, index = _get_page_data(message)
|
||||
# Pass the request to the GUI(s) to pull up a page template
|
||||
self.show(namespace, page, index)
|
||||
except Exception as e:
|
||||
LOG.exception(repr(e))
|
||||
|
@ -146,7 +178,12 @@ class Enclosure:
|
|||
return None
|
||||
|
||||
def __insert_pages(self, namespace, pages):
|
||||
""" Insert pages into the """
|
||||
""" Insert pages into the namespace
|
||||
|
||||
Args:
|
||||
namespace (str): Namespace to add to
|
||||
pages (list): Pages (str) to insert
|
||||
"""
|
||||
LOG.debug("Inserting new pages")
|
||||
if not isinstance(pages, list):
|
||||
raise ValueError('Argument must be list of pages')
|
||||
|
@ -157,19 +194,31 @@ class Enclosure:
|
|||
"data": [{"url": p} for p in pages]
|
||||
})
|
||||
|
||||
# append pages to local representation
|
||||
for p in pages:
|
||||
self.loaded[0].pages.append(p)
|
||||
def __remove_page(self, namespace, pos):
|
||||
""" Delete page.
|
||||
|
||||
Args:
|
||||
namespace (str): Namespace to remove from
|
||||
pos (int): Page position to remove
|
||||
"""
|
||||
LOG.debug("Deleting {} from {}".format(pos, namespace))
|
||||
self.send({"type": "mycroft.gui.list.remove",
|
||||
"namespace": namespace,
|
||||
"position": pos,
|
||||
"items_number": 1
|
||||
})
|
||||
# Remove the page from the local reprensentation as well.
|
||||
self.loaded[0].pages.pop(pos)
|
||||
|
||||
def __insert_new_namespace(self, namespace, pages):
|
||||
""" Insert new namespace and pages.
|
||||
|
||||
This first sends a message adding a new namespace at the
|
||||
highest priority (position 0 in the namespace stack)
|
||||
This first sends a message adding a new namespace at the
|
||||
highest priority (position 0 in the namespace stack)
|
||||
|
||||
Arguments:
|
||||
namespace: The skill namespace to create
|
||||
pages: Pages to insert
|
||||
Args:
|
||||
namespace (str): The skill namespace to create
|
||||
pages (str): Pages to insert (name matches QML)
|
||||
"""
|
||||
LOG.debug("Inserting new namespace")
|
||||
self.send({"type": "mycroft.session.list.insert",
|
||||
|
@ -198,9 +247,9 @@ class Enclosure:
|
|||
def __move_namespace(self, from_pos, to_pos):
|
||||
""" Move an existing namespace to a new position in the stack.
|
||||
|
||||
Arguments:
|
||||
from_pos: Position in the stack to move from
|
||||
to_pos: Position to move to
|
||||
Args:
|
||||
from_pos (int): Position in the stack to move from
|
||||
to_pos (int): Position to move to
|
||||
"""
|
||||
LOG.debug("Activating existing namespace")
|
||||
# Seems like the namespace is moved to the top automatically when
|
||||
|
@ -218,9 +267,9 @@ class Enclosure:
|
|||
def __switch_page(self, namespace, pages):
|
||||
""" Switch page to an already loaded page.
|
||||
|
||||
Arguments:
|
||||
pages: pages to switch to
|
||||
namespace: skill namespace
|
||||
Args:
|
||||
pages (list): pages (str) to switch to
|
||||
namespace (str): skill namespace
|
||||
"""
|
||||
try:
|
||||
num = self.loaded[0].pages.index(pages[0])
|
||||
|
@ -238,8 +287,13 @@ class Enclosure:
|
|||
def show(self, namespace, page, index):
|
||||
""" Show a page and load it as needed.
|
||||
|
||||
TODO: - Update sync to match.
|
||||
- Separate into multiple functions/methods
|
||||
Args:
|
||||
page (str or list): page(s) to show
|
||||
namespace (str): skill namespace
|
||||
index (int): ??? TODO: Unused in code ???
|
||||
|
||||
TODO: - Update sync to match.
|
||||
- Separate into multiple functions/methods
|
||||
"""
|
||||
|
||||
LOG.debug("GUIConnection activating: " + namespace)
|
||||
|
@ -269,6 +323,48 @@ class Enclosure:
|
|||
except Exception as e:
|
||||
LOG.exception(repr(e))
|
||||
|
||||
def remove_namespace(self, namespace):
|
||||
""" Remove namespace.
|
||||
|
||||
Args:
|
||||
namespace (str): namespace to remove
|
||||
"""
|
||||
index = self.__find_namespace(namespace)
|
||||
if index is None:
|
||||
return
|
||||
else:
|
||||
LOG.debug("Removing namespace {} at {}".format(namespace, index))
|
||||
self.send({"type": "mycroft.session.list.remove",
|
||||
"namespace": "mycroft.system.active_skills",
|
||||
"position": index,
|
||||
"items_number": 1
|
||||
})
|
||||
# Remove namespace from loaded namespaces
|
||||
self.loaded.pop(index)
|
||||
|
||||
def remove_pages(self, namespace, pages):
|
||||
""" Remove the listed pages from the provided namespace.
|
||||
|
||||
Args:
|
||||
namespace (str): The namespace to modify
|
||||
pages (list): List of page names (str) to delete
|
||||
"""
|
||||
try:
|
||||
index = self.__find_namespace(namespace)
|
||||
if index is None:
|
||||
return
|
||||
else:
|
||||
# Remove any pages that doesn't exist in the namespace
|
||||
pages = [p for p in pages if p in self.loaded[index].pages]
|
||||
# Make sure to remove pages from the back
|
||||
indexes = [self.loaded[index].pages.index(p) for p in pages]
|
||||
indexes = sorted(indexes)
|
||||
indexes.reverse()
|
||||
for page_index in indexes:
|
||||
self.__remove_page(namespace, page_index)
|
||||
except Exception as e:
|
||||
LOG.exception(repr(e))
|
||||
|
||||
######################################################################
|
||||
# GUI client socket
|
||||
#
|
||||
|
|
|
@ -240,7 +240,6 @@ class SkillGUI:
|
|||
def setup_default_handlers(self):
|
||||
""" Sets the handlers for the default messages. """
|
||||
msg_type = self.build_message_type('set')
|
||||
print("LISTENING FOR {}".format(msg_type))
|
||||
self.skill.add_event(msg_type, self.gui_set)
|
||||
|
||||
def register_handler(self, event, handler):
|
||||
|
@ -267,7 +266,6 @@ class SkillGUI:
|
|||
|
||||
def gui_set(self, message):
|
||||
for key in message.data:
|
||||
print("SETTING {} TO {}".format(key, message.data[key]))
|
||||
self[key] = message.data[key]
|
||||
if self.on_gui_changed_callback:
|
||||
self.on_gui_changed_callback()
|
||||
|
@ -288,9 +286,11 @@ class SkillGUI:
|
|||
return self.__session_data.__contains__(key)
|
||||
|
||||
def clear(self):
|
||||
""" Reset the value dictionary """
|
||||
""" Reset the value dictionary, and remove namespace from gui """
|
||||
self.__session_data = {}
|
||||
self.page = None
|
||||
self.skill.bus.emit(Message("gui.clear.namespace",
|
||||
{"__from": self.skill.skill_id}))
|
||||
|
||||
def show_page(self, name, override_idle=None):
|
||||
"""
|
||||
|
@ -341,6 +341,37 @@ class SkillGUI:
|
|||
"__from": self.skill.skill_id,
|
||||
"__idle": override_idle}))
|
||||
|
||||
def remove_page(self, page):
|
||||
""" Remove a single page from the gui.
|
||||
|
||||
Args:
|
||||
page (str): Page to remove from the GUI
|
||||
"""
|
||||
return self.remove_pages([page])
|
||||
|
||||
def remove_pages(self, page_names):
|
||||
""" Remove a list of pages in the GUI.
|
||||
|
||||
Args:
|
||||
page_names (list): List of page names (str) to display, such as
|
||||
["Weather.qml", "Forecast.qml", "Other.qml"]
|
||||
"""
|
||||
if not isinstance(page_names, list):
|
||||
raise ValueError('page_names must be a list')
|
||||
|
||||
# Convert pages to full reference
|
||||
page_urls = []
|
||||
for name in page_names:
|
||||
page = self.skill.find_resource(name, 'ui')
|
||||
if page:
|
||||
page_urls.append("file://" + page)
|
||||
else:
|
||||
raise FileNotFoundError("Unable to find page: {}".format(name))
|
||||
|
||||
self.skill.bus.emit(Message("gui.page.delete",
|
||||
{"page": page_urls,
|
||||
"__from": self.skill.skill_id}))
|
||||
|
||||
def show_text(self, text, title=None):
|
||||
""" Display a GUI page for viewing simple text
|
||||
|
||||
|
@ -1410,6 +1441,10 @@ class MycroftSkill:
|
|||
if exists(self._dir):
|
||||
self.settings.store()
|
||||
self.settings.stop_polling()
|
||||
|
||||
# Clear skill from gui
|
||||
self.gui.clear()
|
||||
|
||||
# removing events
|
||||
self.cancel_all_repeating_events()
|
||||
for e, f in self.events:
|
||||
|
|
Loading…
Reference in New Issue