From c1d7abd06e42a23b37ae49311c68173ef2f446ff Mon Sep 17 00:00:00 2001 From: recklesscoder <57289227+recklesscoder@users.noreply.github.com> Date: Tue, 1 Nov 2022 06:54:40 +0100 Subject: [PATCH] CommonClient: Some GUI polish (#1139) * CommonClient: Focus text field when requesting input. * CommonClient: Store and prefill last server address. * CommonClient: Focus and select portion of server address upon start. * CommonClient: Don't allow editing of address while connected. * CommonClient: Don't make pressing Enter in the address bar disconnect you. * CommonClient: Use TextInput.text_validate_unfocus over jank workaround. * CommonClient: Fixed hang when closing after failed handshake. * CommonClient: Made scrollbar wider and interactable. --- CommonClient.py | 14 ++++++++++++-- data/client.kv | 2 ++ kvui.py | 29 +++++++++++++++++++---------- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/CommonClient.py b/CommonClient.py index 4fc82b5e..3703a581 100644 --- a/CommonClient.py +++ b/CommonClient.py @@ -218,6 +218,12 @@ class CommonContext: # execution self.keep_alive_task = asyncio.create_task(keep_alive(self), name="Bouncy") + @property + def suggested_address(self) -> str: + if self.server_address: + return self.server_address + return Utils.persistent_load().get("client", {}).get("last_server_address", "") + @functools.cached_property def raw_text_parser(self) -> RawJSONtoTextParser: return RawJSONtoTextParser(self) @@ -229,9 +235,9 @@ class CommonContext: return len(self.checked_locations | self.missing_locations) async def connection_closed(self): - self.reset_server_state() if self.server and self.server.socket is not None: await self.server.socket.close() + self.reset_server_state() def reset_server_state(self): self.auth = None @@ -297,6 +303,8 @@ class CommonContext: await self.send_msgs([payload]) async def console_input(self) -> str: + if self.ui: + self.ui.focus_textinput() self.input_requests += 1 return await self.input_queue.get() @@ -665,6 +673,9 @@ async def process_server_cmd(ctx: CommonContext, args: dict): ctx.checked_locations = set(args["checked_locations"]) ctx.server_locations = ctx.missing_locations | ctx. checked_locations + server_url = urllib.parse.urlparse(ctx.server_address) + Utils.persistent_store("client", "last_server_address", server_url.netloc) + elif cmd == 'ReceivedItems': start_index = args["index"] @@ -775,7 +786,6 @@ if __name__ == '__main__': async def main(args): ctx = TextContext(args.connect, args.password) ctx.auth = args.name - ctx.server_address = args.connect ctx.server_task = asyncio.create_task(server_loop(ctx), name="server loop") if gui_enabled: diff --git a/data/client.kv b/data/client.kv index 4f924896..0b33cda0 100644 --- a/data/client.kv +++ b/data/client.kv @@ -15,6 +15,8 @@ : viewclass: 'SelectableLabel' scroll_y: 0 + scroll_type: ["content", "bars"] + bar_width: dp(12) effect_cls: "ScrollEffect" SelectableRecycleBoxLayout: default_size: None, dp(20) diff --git a/kvui.py b/kvui.py index 38208645..94e0a091 100644 --- a/kvui.py +++ b/kvui.py @@ -338,9 +338,12 @@ class GameManager(App): # top part server_label = ServerLabel() self.connect_layout.add_widget(server_label) - self.server_connect_bar = ConnectBarTextInput(text=self.ctx.server_address or "archipelago.gg", size_hint_y=None, + self.server_connect_bar = ConnectBarTextInput(text=self.ctx.suggested_address or "archipelago.gg:", size_hint_y=None, height=30, multiline=False, write_tab=False) - self.server_connect_bar.bind(on_text_validate=self.connect_button_action) + def connect_bar_validate(sender): + if not self.ctx.server: + self.connect_button_action(sender) + self.server_connect_bar.bind(on_text_validate=connect_bar_validate) self.connect_layout.add_widget(self.server_connect_bar) self.server_connect_button = Button(text="Connect", size=(100, 30), size_hint_y=None, size_hint_x=None) self.server_connect_button.bind(on_press=self.connect_button_action) @@ -381,17 +384,19 @@ class GameManager(App): bottom_layout.add_widget(info_button) self.textinput = TextInput(size_hint_y=None, height=30, multiline=False, write_tab=False) self.textinput.bind(on_text_validate=self.on_message) - - def text_focus(event): - """Needs to be set via delay, as unfocusing happens after on_message""" - self.textinput.focus = True - - self.textinput.text_focus = text_focus + self.textinput.text_validate_unfocus = False bottom_layout.add_widget(self.textinput) self.grid.add_widget(bottom_layout) self.commandprocessor("/help") Clock.schedule_interval(self.update_texts, 1 / 30) self.container.add_widget(self.grid) + + self.server_connect_bar.focus = True + self.server_connect_bar.select_text( + self.server_connect_bar.text.find(":") + 1, + len(self.server_connect_bar.text) + ) + return self.container def update_texts(self, dt): @@ -402,10 +407,12 @@ class GameManager(App): f" | Connected to: {self.ctx.server_address} " \ f"{'.'.join(str(e) for e in self.ctx.server_version)}" self.server_connect_button.text = "Disconnect" + self.server_connect_bar.readonly = True self.progressbar.max = len(self.ctx.checked_locations) + len(self.ctx.missing_locations) self.progressbar.value = len(self.ctx.checked_locations) else: self.server_connect_button.text = "Connect" + self.server_connect_bar.readonly = False self.title = self.base_title + " " + Utils.__version__ self.progressbar.value = 0 @@ -443,8 +450,6 @@ class GameManager(App): elif input_text: self.commandprocessor(input_text) - Clock.schedule_once(textinput.text_focus) - except Exception as e: logging.getLogger("Client").exception(e) @@ -453,6 +458,10 @@ class GameManager(App): self.log_panels["Archipelago"].on_message_markup(text) self.log_panels["All"].on_message_markup(text) + def focus_textinput(self): + if hasattr(self, "textinput"): + self.textinput.focus = True + def update_address_bar(self, text: str): if hasattr(self, "server_connect_bar"): self.server_connect_bar.text = text