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.
This commit is contained in:
parent
655f287d42
commit
c1d7abd06e
|
@ -218,6 +218,12 @@ class CommonContext:
|
||||||
# execution
|
# execution
|
||||||
self.keep_alive_task = asyncio.create_task(keep_alive(self), name="Bouncy")
|
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
|
@functools.cached_property
|
||||||
def raw_text_parser(self) -> RawJSONtoTextParser:
|
def raw_text_parser(self) -> RawJSONtoTextParser:
|
||||||
return RawJSONtoTextParser(self)
|
return RawJSONtoTextParser(self)
|
||||||
|
@ -229,9 +235,9 @@ class CommonContext:
|
||||||
return len(self.checked_locations | self.missing_locations)
|
return len(self.checked_locations | self.missing_locations)
|
||||||
|
|
||||||
async def connection_closed(self):
|
async def connection_closed(self):
|
||||||
self.reset_server_state()
|
|
||||||
if self.server and self.server.socket is not None:
|
if self.server and self.server.socket is not None:
|
||||||
await self.server.socket.close()
|
await self.server.socket.close()
|
||||||
|
self.reset_server_state()
|
||||||
|
|
||||||
def reset_server_state(self):
|
def reset_server_state(self):
|
||||||
self.auth = None
|
self.auth = None
|
||||||
|
@ -297,6 +303,8 @@ class CommonContext:
|
||||||
await self.send_msgs([payload])
|
await self.send_msgs([payload])
|
||||||
|
|
||||||
async def console_input(self) -> str:
|
async def console_input(self) -> str:
|
||||||
|
if self.ui:
|
||||||
|
self.ui.focus_textinput()
|
||||||
self.input_requests += 1
|
self.input_requests += 1
|
||||||
return await self.input_queue.get()
|
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.checked_locations = set(args["checked_locations"])
|
||||||
ctx.server_locations = ctx.missing_locations | ctx. 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':
|
elif cmd == 'ReceivedItems':
|
||||||
start_index = args["index"]
|
start_index = args["index"]
|
||||||
|
|
||||||
|
@ -775,7 +786,6 @@ if __name__ == '__main__':
|
||||||
async def main(args):
|
async def main(args):
|
||||||
ctx = TextContext(args.connect, args.password)
|
ctx = TextContext(args.connect, args.password)
|
||||||
ctx.auth = args.name
|
ctx.auth = args.name
|
||||||
ctx.server_address = args.connect
|
|
||||||
ctx.server_task = asyncio.create_task(server_loop(ctx), name="server loop")
|
ctx.server_task = asyncio.create_task(server_loop(ctx), name="server loop")
|
||||||
|
|
||||||
if gui_enabled:
|
if gui_enabled:
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
<UILog>:
|
<UILog>:
|
||||||
viewclass: 'SelectableLabel'
|
viewclass: 'SelectableLabel'
|
||||||
scroll_y: 0
|
scroll_y: 0
|
||||||
|
scroll_type: ["content", "bars"]
|
||||||
|
bar_width: dp(12)
|
||||||
effect_cls: "ScrollEffect"
|
effect_cls: "ScrollEffect"
|
||||||
SelectableRecycleBoxLayout:
|
SelectableRecycleBoxLayout:
|
||||||
default_size: None, dp(20)
|
default_size: None, dp(20)
|
||||||
|
|
29
kvui.py
29
kvui.py
|
@ -338,9 +338,12 @@ class GameManager(App):
|
||||||
# top part
|
# top part
|
||||||
server_label = ServerLabel()
|
server_label = ServerLabel()
|
||||||
self.connect_layout.add_widget(server_label)
|
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)
|
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.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 = 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)
|
self.server_connect_button.bind(on_press=self.connect_button_action)
|
||||||
|
@ -381,17 +384,19 @@ class GameManager(App):
|
||||||
bottom_layout.add_widget(info_button)
|
bottom_layout.add_widget(info_button)
|
||||||
self.textinput = TextInput(size_hint_y=None, height=30, multiline=False, write_tab=False)
|
self.textinput = TextInput(size_hint_y=None, height=30, multiline=False, write_tab=False)
|
||||||
self.textinput.bind(on_text_validate=self.on_message)
|
self.textinput.bind(on_text_validate=self.on_message)
|
||||||
|
self.textinput.text_validate_unfocus = False
|
||||||
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
|
|
||||||
bottom_layout.add_widget(self.textinput)
|
bottom_layout.add_widget(self.textinput)
|
||||||
self.grid.add_widget(bottom_layout)
|
self.grid.add_widget(bottom_layout)
|
||||||
self.commandprocessor("/help")
|
self.commandprocessor("/help")
|
||||||
Clock.schedule_interval(self.update_texts, 1 / 30)
|
Clock.schedule_interval(self.update_texts, 1 / 30)
|
||||||
self.container.add_widget(self.grid)
|
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
|
return self.container
|
||||||
|
|
||||||
def update_texts(self, dt):
|
def update_texts(self, dt):
|
||||||
|
@ -402,10 +407,12 @@ class GameManager(App):
|
||||||
f" | Connected to: {self.ctx.server_address} " \
|
f" | Connected to: {self.ctx.server_address} " \
|
||||||
f"{'.'.join(str(e) for e in self.ctx.server_version)}"
|
f"{'.'.join(str(e) for e in self.ctx.server_version)}"
|
||||||
self.server_connect_button.text = "Disconnect"
|
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.max = len(self.ctx.checked_locations) + len(self.ctx.missing_locations)
|
||||||
self.progressbar.value = len(self.ctx.checked_locations)
|
self.progressbar.value = len(self.ctx.checked_locations)
|
||||||
else:
|
else:
|
||||||
self.server_connect_button.text = "Connect"
|
self.server_connect_button.text = "Connect"
|
||||||
|
self.server_connect_bar.readonly = False
|
||||||
self.title = self.base_title + " " + Utils.__version__
|
self.title = self.base_title + " " + Utils.__version__
|
||||||
self.progressbar.value = 0
|
self.progressbar.value = 0
|
||||||
|
|
||||||
|
@ -443,8 +450,6 @@ class GameManager(App):
|
||||||
elif input_text:
|
elif input_text:
|
||||||
self.commandprocessor(input_text)
|
self.commandprocessor(input_text)
|
||||||
|
|
||||||
Clock.schedule_once(textinput.text_focus)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.getLogger("Client").exception(e)
|
logging.getLogger("Client").exception(e)
|
||||||
|
|
||||||
|
@ -453,6 +458,10 @@ class GameManager(App):
|
||||||
self.log_panels["Archipelago"].on_message_markup(text)
|
self.log_panels["Archipelago"].on_message_markup(text)
|
||||||
self.log_panels["All"].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):
|
def update_address_bar(self, text: str):
|
||||||
if hasattr(self, "server_connect_bar"):
|
if hasattr(self, "server_connect_bar"):
|
||||||
self.server_connect_bar.text = text
|
self.server_connect_bar.text = text
|
||||||
|
|
Loading…
Reference in New Issue