mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-07-10 17:09:35 -07:00
Android: working clients
This commit is contained in:
+23
-6
@@ -806,8 +806,17 @@ class CommonContext:
|
||||
def run_gui(self):
|
||||
"""Import kivy UI system from make_gui() and start running it as self.ui_task."""
|
||||
ui_class = self.make_gui()
|
||||
self.ui = ui_class(self)
|
||||
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
|
||||
if Utils.is_kivy_running():
|
||||
from kivy.app import App
|
||||
app = App.get_running_app()
|
||||
self.ui = ui_class(self)
|
||||
app.add_screen(self.ui)
|
||||
else:
|
||||
from kvui import GameApp
|
||||
self.ui_app = GameApp(None)
|
||||
self.ui = ui_class(self)
|
||||
self.ui_app.update_ui(self.ui)
|
||||
self.ui_task = asyncio.create_task(self.ui_app.async_run(), name="UI")
|
||||
|
||||
def run_cli(self):
|
||||
if sys.stdin:
|
||||
@@ -1215,15 +1224,23 @@ def run_as_textclient(*args):
|
||||
parser = get_base_parser(description="Gameless Archipelago Client, for text interfacing.")
|
||||
parser.add_argument('--name', default=None, help="Slot Name to connect as.")
|
||||
parser.add_argument("url", nargs="?", help="Archipelago connection url")
|
||||
args = parser.parse_args(args)
|
||||
parsed_args = parser.parse_args(args)
|
||||
|
||||
args = handle_url_arg(args, parser=parser)
|
||||
parsed_args = handle_url_arg(parsed_args, parser=parser)
|
||||
|
||||
# use colorama to display colored text highlighting on windows
|
||||
colorama.just_fix_windows_console()
|
||||
|
||||
asyncio.run(main(args))
|
||||
colorama.deinit()
|
||||
try:
|
||||
loop = asyncio.get_running_loop()
|
||||
except RuntimeError:
|
||||
loop = None
|
||||
|
||||
if loop:
|
||||
return loop.create_task(main(parsed_args), name="TextClient Main")
|
||||
else:
|
||||
asyncio.run(main(parsed_args))
|
||||
colorama.deinit()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
+37
-12
@@ -9,6 +9,7 @@ Additional components can be added to worlds.LauncherComponents.components.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
@@ -240,7 +241,7 @@ refresh_components: Callable[[], None] | None = None
|
||||
|
||||
|
||||
def run_gui(launch_components: list[Component], args: Any) -> None:
|
||||
from kvui import (ThemedApp, MDFloatLayout, MDGridLayout, ScrollBox)
|
||||
from kvui import (ThemedApp, MDScreenManager, MDScreen, MDFloatLayout, MDGridLayout, ScrollBox)
|
||||
from kivy.properties import ObjectProperty
|
||||
from kivy.core.window import Window
|
||||
from kivy.metrics import dp
|
||||
@@ -255,7 +256,7 @@ def run_gui(launch_components: list[Component], args: Any) -> None:
|
||||
class LauncherCard(MDCard):
|
||||
component: Component | None
|
||||
image: str
|
||||
context_button: MDIconButton = ObjectProperty(None)
|
||||
context_button: MDIconButton = ObjectProperty(None, allownone=True)
|
||||
|
||||
def __init__(self, *args, component: Component | None = None, image_path: str = "", **kwargs):
|
||||
self.component = component
|
||||
@@ -264,17 +265,23 @@ def run_gui(launch_components: list[Component], args: Any) -> None:
|
||||
|
||||
class Launcher(ThemedApp):
|
||||
base_title: str = "Archipelago Launcher"
|
||||
top_screen: MDFloatLayout = ObjectProperty(None)
|
||||
navigation: MDGridLayout = ObjectProperty(None)
|
||||
grid: MDGridLayout = ObjectProperty(None)
|
||||
button_layout: ScrollBox = ObjectProperty(None)
|
||||
search_box: MDTextField = ObjectProperty(None)
|
||||
sm: MDScreenManager
|
||||
|
||||
@property
|
||||
def active_manager(self):
|
||||
return getattr(getattr(self, "sm", None), "current_screen", None)
|
||||
|
||||
launcher_screen: MDScreen
|
||||
top_screen: MDFloatLayout = ObjectProperty(None, allownone=True)
|
||||
navigation: MDGridLayout = ObjectProperty(None, allownone=True)
|
||||
grid: MDGridLayout = ObjectProperty(None, allownone=True)
|
||||
button_layout: ScrollBox = ObjectProperty(None, allownone=True)
|
||||
search_box: MDTextField = ObjectProperty(None, allownone=True)
|
||||
cards: list[LauncherCard]
|
||||
current_filter: Sequence[str | Type] | None
|
||||
|
||||
def __init__(self, ctx=None, components=None, args=None):
|
||||
def __init__(self, components=None, args=None):
|
||||
self.title = self.base_title + " " + Utils.__version__
|
||||
self.ctx = ctx
|
||||
self.icon = r"data/icon.png"
|
||||
self.favorites = []
|
||||
self.launch_components = components
|
||||
@@ -372,6 +379,9 @@ def run_gui(launch_components: list[Component], args: Any) -> None:
|
||||
self.button_layout.layout.add_widget(card)
|
||||
|
||||
def build(self):
|
||||
self.sm = MDScreenManager()
|
||||
self.launcher_screen = MDScreen(name='launcher')
|
||||
|
||||
self.top_screen = Builder.load_file(Utils.local_path("data/launcher.kv"))
|
||||
self.grid = self.top_screen.ids.grid
|
||||
self.navigation = self.top_screen.ids.navigation
|
||||
@@ -380,6 +390,9 @@ def run_gui(launch_components: list[Component], args: Any) -> None:
|
||||
self.set_colors()
|
||||
self.top_screen.md_bg_color = self.theme_cls.backgroundColor
|
||||
|
||||
self.launcher_screen.add_widget(self.top_screen)
|
||||
self.sm.add_widget(self.launcher_screen)
|
||||
|
||||
global refresh_components
|
||||
refresh_components = self._refresh_components
|
||||
|
||||
@@ -396,7 +409,19 @@ def run_gui(launch_components: list[Component], args: Any) -> None:
|
||||
# from kivy.modules.console import create_console
|
||||
# create_console(Window, self.top_screen)
|
||||
|
||||
return self.top_screen
|
||||
return self.sm
|
||||
|
||||
def add_screen(self, screen: MDScreen):
|
||||
if self.sm.has_screen(screen.name):
|
||||
self.sm.remove_widget(self.sm.get_screen(screen.name))
|
||||
screen.build()
|
||||
self.sm.add_widget(screen)
|
||||
self.sm.current = screen.name
|
||||
screen.on_start()
|
||||
|
||||
def remove_screen(self, screen: MDScreen):
|
||||
self.sm.current = 'launcher'
|
||||
self.sm.remove_widget(screen)
|
||||
|
||||
def on_start(self):
|
||||
if self.launch_components:
|
||||
@@ -425,7 +450,7 @@ def run_gui(launch_components: list[Component], args: Any) -> None:
|
||||
# Activate search as soon as we start typing, no matter if we are focused on the search box or not.
|
||||
# Focus first, then capture the first character we type, otherwise it gets swallowed and lost.
|
||||
# Limit text input to ASCII non-control characters (space bar to tilde).
|
||||
if not self.search_box.focus:
|
||||
if self.sm.current == 'launcher' and not self.search_box.focus:
|
||||
self.search_box.focus = True
|
||||
if key in range(32, 126):
|
||||
self.search_box.text += codepoint
|
||||
@@ -442,7 +467,7 @@ def run_gui(launch_components: list[Component], args: Any) -> None:
|
||||
for filter in self.current_filter))
|
||||
super().on_stop()
|
||||
|
||||
Launcher(components=launch_components, args=args).run()
|
||||
asyncio.run(Launcher(components=launch_components, args=args).async_run())
|
||||
|
||||
# avoiding Launcher reference leak
|
||||
# and don't try to do something with widgets after window closed
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ _skip_update = bool(
|
||||
getattr(sys, "frozen", False) or
|
||||
multiprocessing.parent_process() or
|
||||
os.environ.get("SKIP_REQUIREMENTS_UPDATE", "").lower() in ("1", "true", "yes") or
|
||||
sys.platform in ("ios", "android")
|
||||
sys.platform in ("ios", "android") or "P4A_BOOTSTRAP" in os.environ or "ANDROID_ARGUMENT" in os.environ
|
||||
)
|
||||
update_ran = _skip_update
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ version_tuple = tuplize_version(__version__)
|
||||
is_linux = sys.platform.startswith("linux")
|
||||
is_macos = sys.platform == "darwin"
|
||||
is_windows = sys.platform in ("win32", "cygwin", "msys")
|
||||
is_android = sys.platform == "android"
|
||||
is_android = sys.platform == "android" or "P4A_BOOTSTRAP" in os.environ or "ANDROID_ARGUMENT" in os.environ
|
||||
is_ios = sys.platform == "ios"
|
||||
is_mobile = is_android or is_ios
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# purely for python4android
|
||||
+2
-2
@@ -3,7 +3,7 @@ title = Archipelago
|
||||
package.name = archipelago
|
||||
package.domain = gg.archipelago
|
||||
source.dir = .
|
||||
source.include_exts = py,png,jpg,kv,atlas,json,yml,txt,lua
|
||||
source.include_exts = py,png,jpg,kv,atlas,json,yml,txt,lua,ogg,csv,dsv,dat
|
||||
source.include_patterns = data/*, *.kv, *.py
|
||||
source.exclude_dirs = factorio,test,docs,.github,.git, deploy, bin, build, __pycache__
|
||||
source.exclude_patterns = test,*.pyc,*.pyo,__pycache__,*.egg-info,*.dist-info,docs,examples,build,dist,.git,.github
|
||||
@@ -18,7 +18,7 @@ requirements = python3==3.11.14, hostpython3==3.11.14,pip==24.3.1, kivy==2.3.1,k
|
||||
|
||||
# Android settings
|
||||
orientation = portrait, landscape, portrait-reverse, landscape-reverse
|
||||
fullscreen = 0
|
||||
fullscreen = 1
|
||||
android.gradle_properties = org.gradle.jvmargs=-Xmx8192m -XX:MaxMetaspaceSize=512m
|
||||
android.permissions = INTERNET,ACCESS_NETWORK_STATE,WRITE_EXTERNAL_STORAGE,READ_EXTERNAL_STORAGE
|
||||
android.api = 34
|
||||
|
||||
@@ -98,6 +98,17 @@ from kivymd.uix.progressindicator import MDLinearProgressIndicator
|
||||
from kivymd.uix.scrollview import MDScrollView
|
||||
from kivymd.uix.tooltip import MDTooltip, MDTooltipPlain
|
||||
|
||||
from kivy.effects.scroll import ScrollEffect
|
||||
from kivy.effects.dampedscroll import DampedScrollEffect
|
||||
|
||||
# Despite the same version on desktop and android, these don't exist on android. I don't know why.
|
||||
# But making them exist as empty stubs makes the app launch successfully.
|
||||
for effect_cls in (ScrollEffect, DampedScrollEffect):
|
||||
if not hasattr(effect_cls, "reset_scale"):
|
||||
effect_cls.reset_scale = lambda *args: None
|
||||
if not hasattr(effect_cls, "convert_overscroll"):
|
||||
effect_cls.convert_overscroll = lambda *args: None
|
||||
|
||||
fade_in_animation = Animation(opacity=0, duration=0) + Animation(opacity=1, duration=0.25)
|
||||
|
||||
from NetUtils import JSONtoTextParser, JSONMessagePart, SlotType, HintStatus
|
||||
@@ -114,6 +125,46 @@ remove_between_brackets = re.compile(r"\[.*?]")
|
||||
|
||||
|
||||
class ThemedApp(MDApp):
|
||||
# Empty properties that only become useful in a Client.
|
||||
@property
|
||||
def active_manager(self) -> typing.Optional["GameManager"]:
|
||||
return None
|
||||
|
||||
@property
|
||||
def ctx(self) -> typing.Optional[context_type]:
|
||||
manager = self.active_manager
|
||||
return manager.ctx if manager else None
|
||||
|
||||
@property
|
||||
def textinput(self):
|
||||
manager = self.active_manager
|
||||
return manager.textinput if manager else None
|
||||
|
||||
@property
|
||||
def commandprocessor(self):
|
||||
manager = self.active_manager
|
||||
return manager.commandprocessor if manager else None
|
||||
|
||||
@property
|
||||
def last_autofillable_command(self):
|
||||
manager = self.active_manager
|
||||
return manager.last_autofillable_command if manager else None
|
||||
|
||||
@property
|
||||
def screens(self):
|
||||
manager = self.active_manager
|
||||
return manager.screens if manager else None
|
||||
|
||||
@property
|
||||
def tabs(self):
|
||||
manager = self.active_manager
|
||||
return manager.tabs if manager else None
|
||||
|
||||
def update_hints(self):
|
||||
manager = self.active_manager
|
||||
if manager:
|
||||
manager.update_hints()
|
||||
|
||||
def set_colors(self):
|
||||
text_colors = KivyJSONtoTextParser.TextColors()
|
||||
self.theme_cls.theme_style = text_colors.theme_style
|
||||
@@ -154,7 +205,7 @@ class ImageButton(MDIconButton):
|
||||
|
||||
|
||||
class ScrollBox(MDScrollView):
|
||||
layout: MDBoxLayout = ObjectProperty(None)
|
||||
layout: MDBoxLayout = ObjectProperty(None, allownone=True)
|
||||
box_height: int = NumericProperty(dp(100))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -225,7 +276,7 @@ MDButton.on_release = on_release
|
||||
class HoverBehavior(object):
|
||||
"""originally from https://stackoverflow.com/a/605348110"""
|
||||
hovered = BooleanProperty(False)
|
||||
border_point = ObjectProperty(None)
|
||||
border_point = ObjectProperty(None, allownone=True)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.register_event_type("on_enter")
|
||||
@@ -252,8 +303,8 @@ class HoverBehavior(object):
|
||||
|
||||
def on_cursor_leave(self, *args):
|
||||
# if the mouse left the window, it is obviously no longer inside the hover label.
|
||||
self.hovered = BooleanProperty(False)
|
||||
self.border_point = ObjectProperty(None)
|
||||
self.hovered = False
|
||||
self.border_point = None
|
||||
self.dispatch("on_leave")
|
||||
|
||||
|
||||
@@ -327,8 +378,9 @@ class ServerLabel(HoverBehavior, MDTooltip, MDBoxLayout):
|
||||
tooltip_display_delay = 0.1
|
||||
text: str = StringProperty("Server:")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
def __init__(self, ctx, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.ctx = ctx
|
||||
self.add_widget(MDIcon(icon="information", font_size=sp(15)))
|
||||
self.add_widget(TooltipLabel(text=self.text, pos_hint={"center_x": 0.5, "center_y": 0.5},
|
||||
font_size=sp(15)))
|
||||
@@ -341,10 +393,6 @@ class ServerLabel(HoverBehavior, MDTooltip, MDBoxLayout):
|
||||
def on_leave(self):
|
||||
self.animation_tooltip_dismiss()
|
||||
|
||||
@property
|
||||
def ctx(self) -> context_type:
|
||||
return MDApp.get_running_app().ctx
|
||||
|
||||
def get_text(self):
|
||||
if self.ctx.server:
|
||||
ctx = self.ctx
|
||||
@@ -524,20 +572,22 @@ class MarkupDropdown(MDDropdownMenu):
|
||||
class AutocompleteHintInput(ResizableTextField):
|
||||
min_chars = NumericProperty(3)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
def __init__(self, ctx, commandprocessor, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.ctx = ctx
|
||||
self.commandprocessor = commandprocessor
|
||||
|
||||
self.dropdown = MarkupDropdown(caller=self, position="bottom", border_margin=dp(2), width=self.width)
|
||||
self.bind(on_text_validate=self.on_message)
|
||||
self.bind(width=lambda instance, x: setattr(self.dropdown, "width", x))
|
||||
|
||||
def on_message(self, instance):
|
||||
MDApp.get_running_app().commandprocessor("!hint "+instance.text)
|
||||
self.commandprocessor("!hint "+instance.text)
|
||||
|
||||
def on_text(self, instance, value):
|
||||
if len(value) >= self.min_chars:
|
||||
self.dropdown.items.clear()
|
||||
ctx: context_type = MDApp.get_running_app().ctx
|
||||
ctx: context_type = self.ctx
|
||||
if not ctx.game:
|
||||
return
|
||||
item_names = ctx.item_names._game_store[ctx.game].values()
|
||||
@@ -592,7 +642,6 @@ class HintLabel(RecycleDataViewBehavior, MDBoxLayout):
|
||||
self.status_text = ""
|
||||
self.hint = {}
|
||||
|
||||
ctx = MDApp.get_running_app().ctx
|
||||
menu_items = []
|
||||
|
||||
for status in (HintStatus.HINT_NO_PRIORITY, HintStatus.HINT_PRIORITY, HintStatus.HINT_AVOID):
|
||||
@@ -608,7 +657,7 @@ class HintLabel(RecycleDataViewBehavior, MDBoxLayout):
|
||||
self.dropdown = MDDropdownMenu(caller=self.ids["status"], items=menu_items)
|
||||
|
||||
def select(instance, data):
|
||||
ctx.update_hint(self.hint["location"],
|
||||
self.ctx.update_hint(self.hint["location"],
|
||||
self.hint["finding_player"],
|
||||
data)
|
||||
|
||||
@@ -618,6 +667,7 @@ class HintLabel(RecycleDataViewBehavior, MDBoxLayout):
|
||||
self.height = max([child.texture_size[1] for child in self.children])
|
||||
|
||||
def refresh_view_attrs(self, rv, index, data):
|
||||
self.ctx = rv.ctx
|
||||
self.index = index
|
||||
self.striped = data.get("striped", False)
|
||||
self.receiving_text = data["receiving"]["text"]
|
||||
@@ -639,8 +689,7 @@ class HintLabel(RecycleDataViewBehavior, MDBoxLayout):
|
||||
if status_label.collide_point(*touch.pos):
|
||||
if self.hint["status"] == HintStatus.HINT_FOUND:
|
||||
return
|
||||
ctx = MDApp.get_running_app().ctx
|
||||
if ctx.slot_concerns_self(self.hint["receiving_player"]): # If this player owns this hint
|
||||
if self.ctx.slot_concerns_self(self.hint["receiving_player"]): # If this player owns this hint
|
||||
# open a dropdown
|
||||
self.dropdown.open()
|
||||
elif self.selected:
|
||||
@@ -754,7 +803,7 @@ class MessageBox(Popup):
|
||||
|
||||
|
||||
class MDNavigationItemBase(MDNavigationItem):
|
||||
text = StringProperty(None)
|
||||
text = StringProperty(None, allownone=True)
|
||||
|
||||
|
||||
class ButtonsPrompt(MDDialog):
|
||||
@@ -842,7 +891,37 @@ class CommandButton(MDButton, MDTooltip):
|
||||
self.animation_tooltip_dismiss()
|
||||
|
||||
|
||||
class GameManager(ThemedApp):
|
||||
class GameApp(ThemedApp):
|
||||
@property
|
||||
def active_manager(self) -> typing.Optional["GameManager"]:
|
||||
return self.ui_screen
|
||||
|
||||
def __init__(self, ui_screen: typing.Optional["GameManager"] = None):
|
||||
if ui_screen:
|
||||
self.title = ui_screen.title
|
||||
self.icon = ui_screen.icon
|
||||
self.ui_screen = ui_screen
|
||||
super().__init__()
|
||||
|
||||
def update_ui(self, ui_screen: "GameManager"):
|
||||
self.ui_screen = ui_screen
|
||||
self.title = ui_screen.title
|
||||
self.icon = ui_screen.icon
|
||||
|
||||
def build(self) -> Layout:
|
||||
self.ui_screen.build()
|
||||
return self.ui_screen
|
||||
|
||||
def on_start(self):
|
||||
super().on_start()
|
||||
self.ui_screen.on_start()
|
||||
|
||||
def on_stop(self):
|
||||
self.ui_screen.on_stop()
|
||||
super().on_stop()
|
||||
|
||||
|
||||
class GameManager(MDScreen):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago"),
|
||||
]
|
||||
@@ -855,7 +934,7 @@ class GameManager(ThemedApp):
|
||||
tabs: MDNavigationBar
|
||||
screens: MDScreenManagerBase
|
||||
|
||||
def __init__(self, ctx: context_type):
|
||||
def __init__(self, ctx: context_type, **kwargs):
|
||||
self.title = self.base_title
|
||||
self.ctx = ctx
|
||||
self.commandprocessor = ctx.command_processor(ctx)
|
||||
@@ -879,7 +958,14 @@ class GameManager(ThemedApp):
|
||||
|
||||
ctx.on_user_say = intercept_say
|
||||
|
||||
super(GameManager, self).__init__()
|
||||
super().__init__(**kwargs)
|
||||
|
||||
@property
|
||||
def theme_cls(self):
|
||||
app = MDApp.get_running_app()
|
||||
if app:
|
||||
return app.theme_cls
|
||||
return None
|
||||
|
||||
@property
|
||||
def tab_count(self):
|
||||
@@ -889,10 +975,15 @@ class GameManager(ThemedApp):
|
||||
|
||||
def on_start(self):
|
||||
def on_start(*args):
|
||||
self.root.md_bg_color = self.theme_cls.backgroundColor
|
||||
super().on_start()
|
||||
if hasattr(self, "container"):
|
||||
self.container.md_bg_color = self.theme_cls.backgroundColor
|
||||
Clock.schedule_once(on_start)
|
||||
|
||||
def set_colors(self):
|
||||
app = MDApp.get_running_app()
|
||||
if hasattr(app, "set_colors"):
|
||||
app.set_colors()
|
||||
|
||||
def build(self) -> Layout:
|
||||
self.set_colors()
|
||||
self.container = ContainerLayout()
|
||||
@@ -902,7 +993,7 @@ class GameManager(ThemedApp):
|
||||
self.connect_layout = MDBoxLayout(orientation="horizontal", size_hint_y=None, height=dp(40),
|
||||
spacing=5, padding=(5, 10))
|
||||
# top part
|
||||
server_label = ServerLabel(width=dp(75))
|
||||
server_label = ServerLabel(self.ctx, width=dp(75))
|
||||
self.connect_layout.add_widget(server_label)
|
||||
self.server_connect_bar = ConnectBarTextInput(text=self.ctx.suggested_address or "archipelago.gg:",
|
||||
pos_hint={"center_x": 0.5, "center_y": 0.5})
|
||||
@@ -941,8 +1032,8 @@ class GameManager(ThemedApp):
|
||||
if len(self.logging_pairs) > 1:
|
||||
self.add_client_tab(display_name, self.log_panels[display_name])
|
||||
|
||||
self.hint_log = HintLog(self.json_to_kivy_parser)
|
||||
hint_panel = self.add_client_tab("Hints", HintLayout(self.hint_log))
|
||||
self.hint_log = HintLog(self.ctx, self.json_to_kivy_parser)
|
||||
hint_panel = self.add_client_tab("Hints", HintLayout(self.ctx, self.commandprocessor, self.hint_log))
|
||||
self.log_panels["Hints"] = hint_panel.content
|
||||
|
||||
self.main_area_container = MDGridLayout(size_hint_y=1, rows=1)
|
||||
@@ -969,6 +1060,7 @@ class GameManager(ThemedApp):
|
||||
self.commandprocessor("/help")
|
||||
Clock.schedule_interval(self.update_texts, 1 / 30)
|
||||
self.container.add_widget(self.grid)
|
||||
self.add_widget(self.container)
|
||||
|
||||
# If the address contains a port, select it; otherwise, select the host.
|
||||
s = self.server_connect_bar.text
|
||||
@@ -1078,6 +1170,18 @@ class GameManager(ThemedApp):
|
||||
|
||||
self.ctx.exit_event.set()
|
||||
|
||||
def stop(self):
|
||||
"""Stops the current "top" App. On Desktop that's a full quit,
|
||||
on Android it quits to Launcher and calling again on Launcher then exits fully."""
|
||||
from kivy.app import App
|
||||
app = App.get_running_app()
|
||||
if app:
|
||||
if hasattr(app, "remove_screen"):
|
||||
app.remove_screen(self)
|
||||
self.on_stop()
|
||||
else:
|
||||
app.stop()
|
||||
|
||||
def on_message(self, textinput: CommandPromptTextInput):
|
||||
try:
|
||||
input_text = textinput.text.strip()
|
||||
@@ -1178,12 +1282,12 @@ class UILog(MDRecycleView):
|
||||
class HintLayout(MDBoxLayout):
|
||||
orientation = "vertical"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
def __init__(self, ctx, commandprocessor, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
boxlayout = MDBoxLayout(orientation="horizontal", size_hint_y=None, height=dp(40))
|
||||
boxlayout.add_widget(MDLabel(text="New Hint:", size_hint_x=None, size_hint_y=None,
|
||||
height=dp(40), width=dp(75), halign="center", valign="center"))
|
||||
boxlayout.add_widget(AutocompleteHintInput())
|
||||
boxlayout.add_widget(AutocompleteHintInput(ctx, commandprocessor))
|
||||
self.add_widget(boxlayout)
|
||||
|
||||
def fix_heights(self):
|
||||
@@ -1230,8 +1334,9 @@ class HintLog(MDRecycleView):
|
||||
sort_key: str = ""
|
||||
reversed: bool = True
|
||||
|
||||
def __init__(self, parser):
|
||||
def __init__(self, ctx, parser):
|
||||
super(HintLog, self).__init__()
|
||||
self.ctx = ctx
|
||||
self.data = [self.header]
|
||||
self.parser = parser
|
||||
|
||||
@@ -1239,7 +1344,7 @@ class HintLog(MDRecycleView):
|
||||
if not hints: # Fix the scrolling looking visually wrong in some edge cases
|
||||
self.scroll_y = 1.0
|
||||
data = []
|
||||
ctx = MDApp.get_running_app().ctx
|
||||
ctx = self.ctx
|
||||
for hint in hints:
|
||||
if not hint.get("status"): # Allows connecting to old servers
|
||||
hint["status"] = HintStatus.HINT_FOUND if hint["found"] else HintStatus.HINT_UNSPECIFIED
|
||||
|
||||
@@ -98,8 +98,9 @@ def launch_subprocess(func: Callable, name: str | None = None, args: Tuple[str,
|
||||
|
||||
|
||||
def launch(func: Callable, name: str | None = None, args: Tuple[str, ...] = ()) -> None:
|
||||
from Utils import is_kivy_running
|
||||
if is_kivy_running():
|
||||
if is_mobile:
|
||||
func(*args)
|
||||
elif is_kivy_running():
|
||||
launch_subprocess(func, name, args)
|
||||
else:
|
||||
func(*args)
|
||||
|
||||
@@ -23,5 +23,10 @@ def launch_ap_quest_client(*args: Sequence[str]) -> None:
|
||||
|
||||
colorama.just_fix_windows_console()
|
||||
|
||||
asyncio.run(main(launch_args))
|
||||
colorama.deinit()
|
||||
try:
|
||||
loop = asyncio.get_running_loop()
|
||||
except RuntimeError:
|
||||
asyncio.run(main(launch_args))
|
||||
colorama.deinit()
|
||||
else:
|
||||
loop.create_task(main(launch_args), name="APQuest Main")
|
||||
|
||||
Reference in New Issue
Block a user