feat: add stop method to Login class and implement button handling in base.py

This commit is contained in:
2026-07-05 18:09:57 +08:00
parent 24e9bde5c7
commit 5ffaec0fb1
5 changed files with 110 additions and 11 deletions
+4
View File
@@ -11,6 +11,10 @@ class ArisuAutoSweeper(AzurLaneAutoScript):
from tasks.login.login import Login from tasks.login.login import Login
Login(self.config, device=self.device).app_start() Login(self.config, device=self.device).app_start()
def stop(self):
from tasks.login.login import Login
Login(self.config, device=self.device).app_stop()
def goto_main(self): def goto_main(self):
from tasks.login.login import Login from tasks.login.login import Login
from tasks.base.ui import UI from tasks.base.ui import UI
+13 -1
View File
@@ -62,6 +62,18 @@ class AzurLaneAutoScript:
logger.exception(e) logger.exception(e)
exit(1) exit(1)
def restart(self):
raise NotImplemented
def start(self):
raise NotImplemented
def stop(self):
raise NotImplemented
def goto_main(self):
raise NotImplemented
def run(self, command): def run(self, command):
try: try:
self.device.screenshot() self.device.screenshot()
@@ -211,7 +223,7 @@ class AzurLaneAutoScript:
method = self.config.Optimization_WhenTaskQueueEmpty method = self.config.Optimization_WhenTaskQueueEmpty
if method == 'close_game': if method == 'close_game':
logger.info('Close game during wait') logger.info('Close game during wait')
self.device.app_stop() self.run('stop')
release_resources() release_resources()
self.device.release_during_wait() self.device.release_during_wait()
if not self.wait_until(task.next_run): if not self.wait_until(task.next_run):
+50 -2
View File
@@ -6,6 +6,7 @@ from module.base.timer import Timer
from module.base.utils import * from module.base.utils import *
from module.config.config import AzurLaneConfig from module.config.config import AzurLaneConfig
from module.device.device import Device from module.device.device import Device
from module.device.method.utils import HierarchyButton
from module.logger import logger from module.logger import logger
from module.webui.setting import cached_class_property from module.webui.setting import cached_class_property
@@ -132,9 +133,56 @@ class ModuleBase:
return appear return appear
appear = match_template def xpath(self, xpath) -> HierarchyButton:
if isinstance(xpath, str):
return HierarchyButton(self.device.hierarchy, xpath)
else:
return xpath
def xpath_appear(self, xpath: str, interval=0):
button = self.xpath(xpath)
self.device.stuck_record_add(button)
if interval and not self.interval_is_reached(button, interval=interval):
return False
appear = bool(button)
if appear and interval:
self.interval_reset(button, interval=interval)
return appear
def appear(self, button, interval=0, similarity=0.85):
"""
Args:
button (Button, ButtonWrapper, HierarchyButton, str):
interval (int, float): interval between two active events.
Returns:
bool:
Examples:
Template match:
```
self.device.screenshot()
self.appear(POPUP_CONFIRM)
```
Hierarchy detection (detect elements with xpath):
```
self.device.dump_hierarchy()
self.appear('//*[@resource-id="..."]')
```
"""
if isinstance(button, (HierarchyButton, str)):
return self.xpath_appear(button, interval=interval)
else:
return self.match_template(button, interval=interval, similarity=similarity)
def appear_then_click(self, button, interval=5, similarity=0.85): def appear_then_click(self, button, interval=5, similarity=0.85):
button = self.xpath(button)
appear = self.appear(button, interval=interval, similarity=similarity) appear = self.appear(button, interval=interval, similarity=similarity)
if appear: if appear:
self.device.click(button) self.device.click(button)
@@ -309,7 +357,7 @@ class ModuleBase:
""" """
if not self.config.Error_SaveError: if not self.config.Error_SaveError:
return return
logger.info('screenshot_tracking_add') logger.info('screenshot_tracking_add')
data = self.device.screenshot_deque[-1] data = self.device.screenshot_deque[-1]
image = data['image'] image = data['image']
+8 -5
View File
@@ -49,11 +49,14 @@ class AppControl(Adb, WSA, Uiautomator2):
Returns: Returns:
etree._Element: Select elements with `self.hierarchy.xpath('//*[@text="Hermit"]')` for example. etree._Element: Select elements with `self.hierarchy.xpath('//*[@text="Hermit"]')` for example.
""" """
method = self.config.Emulator_ControlMethod # method = self.config.Emulator_ControlMethod
if method in AppControl._app_u2_family: # if method in AppControl._app_u2_family:
self.hierarchy = self.dump_hierarchy_uiautomator2() # self.hierarchy = self.dump_hierarchy_uiautomator2()
else: # else:
self.hierarchy = self.dump_hierarchy_adb() # self.hierarchy = self.dump_hierarchy_adb()
# Using uiautomator2
self.hierarchy = self.dump_hierarchy_uiautomator2()
return self.hierarchy return self.hierarchy
def xpath_to_button(self, xpath: str) -> HierarchyButton: def xpath_to_button(self, xpath: str) -> HierarchyButton:
+35 -3
View File
@@ -18,9 +18,11 @@ except ImportError:
# We expect `screencap | nc 192.168.0.1 20298` instead of `screencap '|' nc 192.168.80.1 20298` # We expect `screencap | nc 192.168.0.1 20298` instead of `screencap '|' nc 192.168.80.1 20298`
import adbutils import adbutils
import subprocess import subprocess
adbutils._utils.list2cmdline = subprocess.list2cmdline adbutils._utils.list2cmdline = subprocess.list2cmdline
adbutils._device.list2cmdline = subprocess.list2cmdline adbutils._device.list2cmdline = subprocess.list2cmdline
# BaseDevice.shell() is missing a check_okay() call before reading output, # BaseDevice.shell() is missing a check_okay() call before reading output,
# resulting in an `OKAY` prefix in output. # resulting in an `OKAY` prefix in output.
def shell(self, def shell(self,
@@ -40,6 +42,7 @@ except ImportError:
output = c.read_until_close() output = c.read_until_close()
return output.rstrip() if rstrip else output return output.rstrip() if rstrip else output
adbutils._device.BaseDevice.shell = shell adbutils._device.BaseDevice.shell = shell
from module.base.decorator import cached_property from module.base.decorator import cached_property
@@ -323,7 +326,7 @@ class HierarchyButton:
if res: if res:
return res[0] return res[0]
else: else:
return 'HierarchyButton' return self.xpath
@cached_property @cached_property
def count(self): def count(self):
@@ -333,10 +336,17 @@ class HierarchyButton:
def exist(self): def exist(self):
return self.count == 1 return self.count == 1
@cached_property
def attrib(self):
if self.exist:
return self.nodes[0].attrib
else:
return {}
@cached_property @cached_property
def area(self): def area(self):
if self.exist: if self.exist:
bounds = self.nodes[0].attrib.get("bounds") bounds = self.attrib.get("bounds")
lx, ly, rx, ry = map(int, re.findall(r"\d+", bounds)) lx, ly, rx, ry = map(int, re.findall(r"\d+", bounds))
return lx, ly, rx, ry return lx, ly, rx, ry
else: else:
@@ -355,6 +365,28 @@ class HierarchyButton:
@cached_property @cached_property
def focused(self): def focused(self):
if self.exist: if self.exist:
return self.nodes[0].attrib.get("focused").lower() == 'true' return self.attrib.get("focused").lower() == 'true'
else: else:
return False return False
@cached_property
def text(self):
if self.exist:
return self.attrib.get("text").strip()
else:
return ""
class AreaButton:
def __init__(self, area, name='AREA_BUTTON'):
self.area = area
self.color = ()
self.name = name
self.button = area
def __str__(self):
return self.name
def __bool__(self):
# Cannot appear
return False