fix: 收窄颜色方向识别范围 (#264)
This commit is contained in:
@@ -194,6 +194,45 @@ def _heading_bounds(root: ET.Element) -> Optional[Bounds]:
|
||||
return fuzzy_match or package_fallback
|
||||
|
||||
|
||||
def _scrollable_region_node(
|
||||
root: ET.Element,
|
||||
region: Bounds,
|
||||
) -> Optional[ET.Element]:
|
||||
"""返回边界与目标区域一致的最内层可滚动容器。"""
|
||||
|
||||
parents = _parent_map(root)
|
||||
candidates = [
|
||||
node
|
||||
for node in root.iter("node")
|
||||
if node.get("scrollable") == "true"
|
||||
and _is_available(node)
|
||||
and _parse_bounds(node.get("bounds", "")) == region
|
||||
]
|
||||
if not candidates:
|
||||
return None
|
||||
|
||||
def depth(node: ET.Element) -> int:
|
||||
result = 0
|
||||
current = parents.get(node)
|
||||
while current is not None:
|
||||
result += 1
|
||||
current = parents.get(current)
|
||||
return result
|
||||
|
||||
return max(candidates, key=depth)
|
||||
|
||||
|
||||
def _color_heading_in_region(root: ET.Element, region: Bounds) -> bool:
|
||||
"""只在当前颜色滚动容器内寻找标题,忽略背后商品页文字。"""
|
||||
|
||||
container = _scrollable_region_node(root, region)
|
||||
if container is not None:
|
||||
return _heading_bounds(container) is not None
|
||||
|
||||
heading = _heading_bounds(root)
|
||||
return heading is not None and _center_in(heading, region)
|
||||
|
||||
|
||||
def _target_scrollable_ancestor(
|
||||
root: ET.Element,
|
||||
target: str,
|
||||
@@ -237,6 +276,19 @@ def _horizontal_color_region(
|
||||
|
||||
width = bounds[2] - bounds[0]
|
||||
height = bounds[3] - bounds[1]
|
||||
contained_heading = _heading_bounds(node)
|
||||
|
||||
if (
|
||||
contained_heading is not None
|
||||
and screen is not None
|
||||
and _center_in(contained_heading, bounds)
|
||||
and width >= screen[2] * 0.60
|
||||
):
|
||||
# 纵向长列表的颜色标题位于滚动容器内部;页面背后的同名
|
||||
# 文本不能参与定位。面积较小的内层容器优先。
|
||||
score = 50_000.0 - width * height / 1_000_000
|
||||
candidates.append((score, bounds))
|
||||
continue
|
||||
|
||||
if heading is not None and screen is not None:
|
||||
distance_below_heading = bounds[1] - heading[3]
|
||||
@@ -659,14 +711,17 @@ def _color_scroll_direction(
|
||||
) -> Optional[str]:
|
||||
"""判断颜色容器的主要滚动方向;证据不足时不猜测。"""
|
||||
|
||||
container = _scrollable_region_node(root, region)
|
||||
nodes = container.iter("node") if container is not None else root.iter("node")
|
||||
option_bounds: list[Bounds] = []
|
||||
for node in root.iter("node"):
|
||||
for node in nodes:
|
||||
if node.get("clickable") != "true" or not _is_available(node):
|
||||
continue
|
||||
bounds = _parse_bounds(node.get("bounds", ""))
|
||||
if bounds is None or not _center_in(bounds, region):
|
||||
continue
|
||||
if _intersection_area(bounds, region) <= 0:
|
||||
area = (bounds[2] - bounds[0]) * (bounds[3] - bounds[1])
|
||||
if area <= 0 or _intersection_area(bounds, region) != area:
|
||||
continue
|
||||
option_bounds.append(bounds)
|
||||
|
||||
@@ -784,7 +839,7 @@ def select_color(
|
||||
if direction == "vertical":
|
||||
# Adapter 正常会先把颜色标题恢复到顶部;独立调用若标题已经
|
||||
# 滚出视口,则先有界回到起点,随后只向下扫描一次。
|
||||
if _heading_bounds(root) is None:
|
||||
if not _color_heading_in_region(root, region):
|
||||
previous_signature = _visible_signature(root, region)
|
||||
unchanged_count = 0
|
||||
for _ in range(max_swipes):
|
||||
@@ -792,7 +847,7 @@ def select_color(
|
||||
time.sleep(action_delay)
|
||||
root = _parse_xml(device.dump_hierarchy())
|
||||
region = _target_scrollable_ancestor(root, target_color) or region
|
||||
if _heading_bounds(root) is not None:
|
||||
if _color_heading_in_region(root, region):
|
||||
break
|
||||
signature = _visible_signature(root, region)
|
||||
unchanged_count = (
|
||||
|
||||
Reference in New Issue
Block a user