Skip to content

Commit d04dcad

Browse files
committed
Fix for #62
- Added blocking loading screen that doesn't freeze the UI when blocking is required. - Before closing #62, be sure to test on macOS that the multithreading isn't a problem
1 parent 9e125e6 commit d04dcad

File tree

2 files changed

+203
-22
lines changed

2 files changed

+203
-22
lines changed

source/locales.json

+60
Original file line numberDiff line numberDiff line change
@@ -13088,5 +13088,65 @@
1308813088
"pt": "Revis\u00e3o do CreateServer",
1308913089
"sv": "CreateServerReview",
1309013090
"fi": "CreateServerReview"
13091+
},
13092+
"error: failed to set dpi context": {
13093+
"fr": "Erreur\u00a0: \u00e9chec de la d\u00e9finition du contexte DPI",
13094+
"it": "Errore: impossibile impostare il contesto DPI",
13095+
"es": "Error: no se pudo establecer el contexto DPI",
13096+
"de": "Fehler: DPI-Kontext konnte nicht festgelegt werden",
13097+
"nl": "Fout: kan de DPI-context niet instellen",
13098+
"pt": "Erro: falha ao definir o contexto de DPI",
13099+
"sv": "Fel: Det gick inte att st\u00e4lla in DPI-kontext",
13100+
"fi": "Virhe: DPI-kontekstin asettaminen ep\u00e4onnistui"
13101+
},
13102+
"broadcast()": {
13103+
"es": "transmisi\u00f3n()",
13104+
"fr": "diffuser()",
13105+
"it": "trasmissione()",
13106+
"de": "\u00fcbertragen()",
13107+
"nl": "uitzending()",
13108+
"pt": "transmiss\u00e3o()",
13109+
"sv": "uts\u00e4nda()",
13110+
"fi": "l\u00e4hett\u00e4\u00e4()"
13111+
},
13112+
"error deleting file/folder during restore:": {
13113+
"es": "Error al eliminar el archivo/carpeta durante la restauraci\u00f3n:",
13114+
"fr": "Erreur lors de la suppression du fichier/dossier lors de la restauration\u00a0:",
13115+
"it": "Errore durante l'eliminazione di file/cartelle durante il ripristino:",
13116+
"de": "Fehler beim L\u00f6schen der Datei/des Ordners w\u00e4hrend der Wiederherstellung:",
13117+
"nl": "Fout bij verwijderen van bestand/map tijdens herstel:",
13118+
"pt": "Erro ao excluir arquivo/pasta durante a restaura\u00e7\u00e3o:",
13119+
"sv": "Fel vid borttagning av fil/mapp under \u00e5terst\u00e4llning:",
13120+
"fi": "Virhe poistettaessa tiedostoa/kansiota palautuksen aikana:"
13121+
},
13122+
"auto-mcs was updated to v\\$\\$ successfully!": {
13123+
"es": "\u00a1auto-mcs se actualiz\u00f3 a v\\$\\$ exitosamente!",
13124+
"fr": "auto-mcs a \u00e9t\u00e9 mis \u00e0 jour vers v\\$\\$ avec succ\u00e8s !",
13125+
"it": "auto-mcs \u00e8 stato aggiornato con successo a v\\$\\$!",
13126+
"de": "auto-mcs wurde erfolgreich auf v\\$\\$ aktualisiert!",
13127+
"nl": "auto-mcs is succesvol bijgewerkt naar v\\$\\$!",
13128+
"pt": "auto-mcs foi atualizado para v\\$\\$ com sucesso!",
13129+
"sv": "auto-mcs uppdaterades till v\\$\\$ framg\u00e5ngsrikt!",
13130+
"fi": "auto-mcs p\u00e4ivitettiin muotoon v\\$\\$ onnistuneesti!"
13131+
},
13132+
"success": {
13133+
"es": "\u00e9xito",
13134+
"fr": "succ\u00e8s",
13135+
"it": "successo",
13136+
"de": "Erfolg",
13137+
"nl": "succes",
13138+
"pt": "sucesso",
13139+
"sv": "Framg\u00e5ng",
13140+
"fi": "menestys"
13141+
},
13142+
"initialized ngrok connection '": {
13143+
"es": "Conexi\u00f3n ngrok inicializada '",
13144+
"fr": "Connexion ngrok initialis\u00e9e '",
13145+
"it": "Connessione ngrok inizializzata '",
13146+
"de": "Ngrok-Verbindung initialisiert '",
13147+
"nl": "Ge\u00efnitialiseerde ngrok-verbinding '",
13148+
"pt": "Conex\u00e3o ngrok inicializada '",
13149+
"sv": "Initialiserad ngrok-anslutning '",
13150+
"fi": "Aloitettu ngrok-yhteys '"
1309113151
}
1309213152
}

source/menu.py

+143-22
Original file line numberDiff line numberDiff line change
@@ -7790,6 +7790,9 @@ def show_search(self):
77907790
if "ProgressScreen" in self.__class__.__name__:
77917791
return
77927792

7793+
if "BlurredLoadingScreen" in self.__class__.__name__:
7794+
return
7795+
77937796
if self.context_menu:
77947797
self.context_menu.hide()
77957798

@@ -8485,6 +8488,101 @@ def __init__(self, **kwargs):
84858488
self.timer = threading.Timer(0, self.execute_steps)
84868489
self.timer.start()
84878490

8491+
# Blurred loading screen for blocking operations
8492+
class BlurredLoadingScreen(MenuBackground):
8493+
8494+
def __init__(self, **kwargs):
8495+
super().__init__(**kwargs)
8496+
self.name = self.__class__.__name__
8497+
self.menu = 'init'
8498+
self._ignore_tree = True
8499+
8500+
self.generating_background = False
8501+
self.blur_background = None
8502+
self.load_icon = None
8503+
self.load_label = None
8504+
8505+
def generate_blur_background(self, *args):
8506+
image_path = os.path.join(constants.gui_assets, 'live', 'blur_background.png')
8507+
constants.folder_check(os.path.join(constants.gui_assets, 'live'))
8508+
8509+
if not self.generating_background:
8510+
self.generating_background = True
8511+
self.blur_background.opacity = 0
8512+
8513+
screen_manager.get_screen(constants.screen_tree[-1]).export_to_png(image_path)
8514+
im = PILImage.open(image_path)
8515+
im = ImageEnhance.Brightness(im)
8516+
im = im.enhance(popup_blur_darkness)
8517+
im1 = im.filter(GaussianBlur(popup_blur_amount))
8518+
im1.save(image_path)
8519+
self.blur_background.reload()
8520+
8521+
self.blur_background.opacity = 1
8522+
8523+
def on_pre_enter(self, *args):
8524+
super().on_pre_enter()
8525+
constants.ignore_close = True
8526+
8527+
def on_leave(self, *args):
8528+
super().on_leave()
8529+
constants.ignore_close = False
8530+
8531+
def resize_self(self, *args):
8532+
self.load_label.x = (Window.width / 2) - 75
8533+
self.load_icon.x = (Window.width / 2) - 160
8534+
8535+
8536+
def generate_menu(self, **kwargs):
8537+
# Generate buttons on page load
8538+
8539+
float_layout = FloatLayout()
8540+
float_layout.id = 'content'
8541+
8542+
# Blurred background
8543+
self.blur_background = Image()
8544+
self.blur_background.opacity = 0
8545+
self.blur_background.id = "blur_background"
8546+
self.blur_background.source = os.path.join(constants.gui_assets, 'live', 'blur_background.png')
8547+
self.blur_background.allow_stretch = True
8548+
self.blur_background.keep_ratio = False
8549+
self.generating_background = False
8550+
float_layout.add_widget(self.blur_background)
8551+
Clock.schedule_once(self.generate_blur_background, -1)
8552+
8553+
8554+
# Loading icon to swap button
8555+
self.load_icon = AsyncImage()
8556+
self.load_icon.id = "load_icon"
8557+
self.load_icon.source = os.path.join(constants.gui_assets, 'animations', 'loading_pickaxe.gif')
8558+
self.load_icon.size_hint_max = (65, 65)
8559+
self.load_icon.color = (0.8, 0.8, 1, 1)
8560+
self.load_icon.pos_hint = {"center_y": 0.5}
8561+
self.load_icon.allow_stretch = True
8562+
self.load_icon.anim_delay = constants.anim_speed * 0.02
8563+
float_layout.add_widget(self.load_icon)
8564+
8565+
8566+
# Loading label
8567+
self.load_label = AlignLabel()
8568+
self.load_label.halign = 'left'
8569+
self.load_label.valign = 'center'
8570+
self.load_label.id = 'label'
8571+
self.load_label.size_hint_max = (300, 50)
8572+
self.load_label.pos_hint = {"center_y": 0.5}
8573+
self.load_label.text = 'please wait...'
8574+
self.load_label.font_size = sp(35)
8575+
self.load_label.font_name = os.path.join(constants.gui_assets, 'fonts', f'{constants.fonts["bold"]}.ttf')
8576+
self.load_label.color = (0.8, 0.8, 1, 1)
8577+
float_layout.add_widget(self.load_label)
8578+
8579+
8580+
self.blur_background.size_hint_min = Window.size
8581+
float_layout.bind(pos=self.resize_self, size=self.resize_self)
8582+
8583+
self.add_widget(float_layout)
8584+
8585+
84888586
# </editor-fold> ///////////////////////////////////////////////////////////////////////////////////////////////////////
84898587

84908588

@@ -21791,37 +21889,54 @@ def migrate_server(*a):
2179121889
transilience_layout = GridLayout(cols=1, spacing=10, size_hint_max_x=1050, size_hint_y=None, padding=[0, 0, 0, 0])
2179221890

2179321891
def rename_server(name, *args):
21892+
def loading_screen(*a):
21893+
screen_manager.current = 'BlurredLoadingScreen'
21894+
Clock.schedule_once(loading_screen, 0)
2179421895

2179521896
# Actually rename the server files
2179621897
server_obj.rename(name)
2179721898

2179821899
# Change header and footer text to reflect change
21799-
self.remove_widget(self.title_widget)
21800-
self.remove_widget(self.footer_widget)
21801-
del self.title_widget
21802-
del self.footer_widget
21803-
self.title_widget = generate_title(f"Server Settings: '{name}'")
21804-
self.footer_widget = generate_footer(f"{name}, Settings", color='EFD49E')
21805-
self.add_widget(self.title_widget)
21806-
self.add_widget(self.footer_widget)
21807-
21808-
# Display banner to show success
21809-
Clock.schedule_once(
21810-
functools.partial(
21811-
screen_manager.current_screen.show_banner,
21812-
(0.553, 0.902, 0.675, 1),
21813-
f"Server renamed to '${name}$' successfully!",
21814-
"rename.png",
21815-
2.5,
21816-
{"center_x": 0.5, "center_y": 0.965}
21817-
), 0
21818-
)
21900+
def change_data(*a):
21901+
def go_back(*a):
21902+
screen_manager.current = 'ServerSettingsScreen'
21903+
effect_y = screen_manager.current_screen.scroll_widget.effect_y
21904+
screen_manager.current_screen.scroll_widget.effect_y = None
21905+
screen_manager.current_screen.scroll_widget.scroll_y = 0
21906+
def reset_effect(*a):
21907+
screen_manager.current_screen.scroll_widget.effect_y = effect_y
21908+
Clock.schedule_once(reset_effect, 0)
21909+
Clock.schedule_once(go_back, 0)
21910+
21911+
self.remove_widget(self.title_widget)
21912+
self.remove_widget(self.footer_widget)
21913+
del self.title_widget
21914+
del self.footer_widget
21915+
self.title_widget = generate_title(f"Server Settings: '{name}'")
21916+
self.footer_widget = generate_footer(f"{name}, Settings", color='EFD49E')
21917+
self.add_widget(self.title_widget)
21918+
self.add_widget(self.footer_widget)
21919+
21920+
# Display banner to show success
21921+
Clock.schedule_once(
21922+
functools.partial(
21923+
screen_manager.current_screen.show_banner,
21924+
(0.553, 0.902, 0.675, 1),
21925+
f"Server renamed to '${name}$' successfully!",
21926+
"rename.png",
21927+
2.5,
21928+
{"center_x": 0.5, "center_y": 0.965}
21929+
), 0
21930+
)
21931+
Clock.schedule_once(change_data, 0)
21932+
def rename_thread(name, *a):
21933+
threading.Timer(0, functools.partial(rename_server, name)).start()
2181921934

2182021935
# Rename server input
2182121936
sub_layout = ScrollItem()
2182221937
input_label = InputLabel(pos_hint={"center_x": 0.5, "center_y": 1.2})
2182321938
sub_layout.add_widget(input_label)
21824-
self.rename_input = ServerRenameInput(pos_hint={'center_x': 0.5, 'center_y': 0.5}, text=server_obj.name, on_validate=rename_server, disabled=server_obj.running)
21939+
self.rename_input = ServerRenameInput(pos_hint={'center_x': 0.5, 'center_y': 0.5}, text=server_obj.name, on_validate=rename_thread, disabled=server_obj.running)
2182521940
self.rename_input.size_hint_max_x = 435
2182621941
sub_layout.add_widget(self.rename_input)
2182721942
transilience_layout.add_widget(sub_layout)
@@ -21843,6 +21958,10 @@ def change_world(*a):
2184321958

2184421959
# Delete server button
2184521960
def delete_server(*args):
21961+
def loading_screen(*a):
21962+
screen_manager.current = 'BlurredLoadingScreen'
21963+
Clock.schedule_once(loading_screen, 0)
21964+
2184621965
server_name = server_obj.name
2184721966
server_obj.delete()
2184821967
constants.server_manager.current_server = None
@@ -21866,14 +21985,16 @@ def switch_screens(*a):
2186621985
), 0.1
2186721986
)
2186821987
Clock.schedule_once(switch_screens, 0.5)
21988+
def timer_delete(*a):
21989+
threading.Timer(0, delete_server).start()
2186921990
def prompt_delete(*args):
2187021991
Clock.schedule_once(
2187121992
functools.partial(
2187221993
screen_manager.current_screen.show_popup,
2187321994
"warning_query",
2187421995
f"Delete '${server_obj.name}$'",
2187521996
"Do you want to permanently delete this server?\n\nThis action cannot be undone\n(Your server can be re-imported from a back-up later)",
21876-
(None, functools.partial(Clock.schedule_once, delete_server, 0.5))
21997+
(None, functools.partial(Clock.schedule_once, timer_delete, 0.5))
2187721998
),
2187821999
0
2187922000
)

0 commit comments

Comments
 (0)