-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #37 from YvoElling/feature/rewrite-startup-procedure
Rewrite startup screen to use event-driven updates instead of waiting…
- Loading branch information
Showing
5 changed files
with
104 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,59 +1,96 @@ | ||
import sys | ||
|
||
from kivy import Logger | ||
from kivy.app import App | ||
from kivy.clock import Clock | ||
from kivy.lang import Builder | ||
from kivy.properties import ObjectProperty | ||
from kivy.uix.screenmanager import Screen | ||
|
||
# Load KV file for this screen | ||
from utils.Screens import Screens | ||
from utils.async_requests.AsyncResult import AsyncResult | ||
|
||
Builder.load_file('kvs/StartupScreen.kv') | ||
|
||
|
||
class StartupScreen(Screen): | ||
users_loaded: AsyncResult = ObjectProperty() | ||
categories_loaded: AsyncResult = ObjectProperty() | ||
products_loaded: AsyncResult = ObjectProperty() | ||
|
||
def __init__(self, **kwargs): | ||
# call to user with arguments | ||
super(StartupScreen, self).__init__(**kwargs) | ||
|
||
# Keep track of when data is loaded | ||
self.users_loaded = False | ||
self.categories_loaded = False | ||
self.products_loaded = False | ||
|
||
# Calls upon entry of this screen | ||
# | ||
def on_enter(self, *args): | ||
self.ids.loading_text.text = "Waiting for data to load..." | ||
|
||
App.get_running_app().loop.call_soon_threadsafe(self.wait_for_data_to_load) | ||
App.get_running_app().loop.call_soon_threadsafe(self.check_if_all_data_is_loaded) | ||
|
||
# Called when all data has loaded | ||
def finished_loading(self, dt): | ||
self.manager.current = Screens.DEFAULT_SCREEN.value | ||
|
||
# Called when we're waiting for the data to load | ||
def wait_for_data_to_load(self): | ||
def on_users_loaded(self, _, _2): | ||
self.check_if_all_data_is_loaded() | ||
|
||
all_data_loaded = True | ||
def on_categories_loaded(self, _, _2): | ||
self.check_if_all_data_is_loaded() | ||
|
||
if not self.users_loaded: | ||
all_data_loaded = False | ||
def on_products_loaded(self, _, _2): | ||
self.check_if_all_data_is_loaded() | ||
|
||
def check_if_all_data_is_loaded(self) -> None: | ||
|
||
self.set_loading_text("Waiting for data to load... (0/3)") | ||
|
||
if self.users_loaded is None or self.users_loaded.result is None: | ||
Logger.debug("StellaPayUI: Waiting for users to load..") | ||
return | ||
elif self.users_loaded.received_result is False or self.users_loaded.result.data is False: | ||
self.set_loading_text("Failed to retrieve user data!") | ||
self.on_failed_to_load() | ||
return | ||
elif self.users_loaded.result.data is True: | ||
Logger.debug("StellaPayUI: Loaded user data!") | ||
|
||
if not self.products_loaded: | ||
all_data_loaded = False | ||
Logger.debug("StellaPayUI: Waiting for products to load..") | ||
self.set_loading_text("Waiting for data to load... (1/3)") | ||
|
||
if not self.categories_loaded: | ||
all_data_loaded = False | ||
if self.categories_loaded is None or self.categories_loaded.result is None: | ||
Logger.debug("StellaPayUI: Waiting for categories to load..") | ||
return | ||
elif self.categories_loaded.received_result is False or self.categories_loaded.result.data is False: | ||
self.set_loading_text("Failed to retrieve category data!") | ||
self.on_failed_to_load() | ||
return | ||
elif self.categories_loaded.result.data is True: | ||
Logger.debug("StellaPayUI: Loaded categories data!") | ||
|
||
self.set_loading_text("Waiting for data to load... (2/3)") | ||
|
||
if self.products_loaded is None or self.products_loaded.result is None: | ||
Logger.debug("StellaPayUI: Waiting for products to load..") | ||
return | ||
elif self.products_loaded.received_result is False or self.products_loaded.result.data is False: | ||
self.set_loading_text("Failed to retrieve products data!") | ||
self.on_failed_to_load() | ||
return | ||
elif self.products_loaded.result.data is True: | ||
Logger.debug("StellaPayUI: Loaded products data!") | ||
|
||
self.set_loading_text("Data has loaded!") | ||
|
||
self.set_loading_spinner(False) | ||
|
||
Clock.schedule_once(self.finished_loading, 1) | ||
|
||
def on_failed_to_load(self): | ||
self.set_loading_spinner(False) | ||
Clock.schedule_once(lambda: sys.exit(1), 3) | ||
|
||
if all_data_loaded: | ||
# After everything has been loaded. | ||
self.ids.loading_text.text = "Data has loaded!" | ||
def set_loading_spinner(self, active: bool): | ||
self.ids.spinner_startup.active = active | ||
|
||
# Done loading, so call callback in one second. | ||
Clock.schedule_once(self.finished_loading, 1) | ||
else: | ||
# Run the check again | ||
App.get_running_app().loop.call_later(0.5, self.wait_for_data_to_load) | ||
def set_loading_text(self, text: str): | ||
self.ids.loading_text.text = text |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from typing import Any | ||
|
||
|
||
class AsyncData: | ||
def __init__(self, data: Any): | ||
self.data = data |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
class AsyncError: | ||
def __init__(self, message: str): | ||
self.message = message |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from typing import Any, Union | ||
|
||
from utils.async_requests.AsyncData import AsyncData | ||
from utils.async_requests.AsyncError import AsyncError | ||
|
||
|
||
class AsyncResult: | ||
""" | ||
An object of this class represents a result that is received after some time. The result will indicate whether a | ||
result was successfully obtained or not using the ``received_result`` member variable. If this variable is False, | ||
you can expect ``result`` to be of type `AsyncError`. Otherwise, it will be of type `AsyncData`. | ||
""" | ||
|
||
def __init__(self, success: bool, data: Any = None, error_message: str = ""): | ||
self.received_result = success | ||
self.result: Union[AsyncData, AsyncError, None] = AsyncData(data) if success else AsyncError(error_message) |