@leejungkiin/awkit 1.7.1 → 1.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/awk.js +576 -84
- package/core/CLAUDE.md +1 -1
- package/core/GEMINI.md +148 -167
- package/core/GEMINI.md.bak +149 -116
- package/core/skill-runtime-manifest.json +3 -0
- package/docs/Claude Fable 5.md +3826 -0
- package/docs/android_kotlin_system_instruction.md +210 -0
- package/docs/brainstorm_ponytail_integration.md +146 -0
- package/docs/brainstorm_smart_setup.md +113 -0
- package/docs/deep-research-report (1).md +293 -0
- package/docs/history/GEMINI.v1.md +135 -0
- package/docs/history/brainstorm_antigravity_unified_architecture.v1.md +105 -0
- package/docs/history/implementation_plan.v1.md +58 -0
- package/package.json +4 -1
- package/scripts/artifact-storage.js +130 -0
- package/scripts/automation-gate.js +35 -2
- package/scripts/claude-plan.js +76 -0
- package/scripts/dependency-manager.js +210 -0
- package/scripts/exec-rtk.js +11 -5
- package/scripts/i18n-helper.js +381 -0
- package/scripts/multi-model-pipeline.js +144 -0
- package/skill-packs/mobile-ios/pack.json +4 -2
- package/skill-packs/reverse-engineering/pack.json +1 -0
- package/skills/CATALOG.md +20 -0
- package/skills/GEMINI.md +9 -1
- package/skills/TRIGGER_INDEX.md +10 -0
- package/skills/ai-music/SKILL.md +275 -0
- package/skills/android-re-analyzer/SKILL.md +238 -0
- package/skills/android-re-analyzer/references/api-extraction-patterns.md +119 -0
- package/skills/android-re-analyzer/references/call-flow-analysis.md +176 -0
- package/skills/android-re-analyzer/references/fernflower-usage.md +115 -0
- package/skills/android-re-analyzer/references/jadx-usage.md +116 -0
- package/skills/android-re-analyzer/references/setup-guide.md +221 -0
- package/skills/android-re-analyzer/scripts/check-deps.sh +129 -0
- package/skills/android-re-analyzer/scripts/decompile.sh +375 -0
- package/skills/android-re-analyzer/scripts/find-api-calls.sh +118 -0
- package/skills/android-re-analyzer/scripts/install-dep.sh +448 -0
- package/skills/animal-island-ui-style/SKILL.md +1450 -0
- package/skills/app-store-review-agent/SKILL.md +164 -0
- package/skills/app-store-review-agent/references/guidelines/README.md +154 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/ai_apps.md +37 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/all_apps.md +50 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/crypto_finance.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/games.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/health_fitness.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/kids.md +27 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/macos.md +38 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/social_ugc.md +32 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/subscription_iap.md +34 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/vpn.md +18 -0
- package/skills/app-store-review-agent/references/rules/design/minimum_functionality.md +96 -0
- package/skills/app-store-review-agent/references/rules/design/sign_in_with_apple.md +54 -0
- package/skills/app-store-review-agent/references/rules/entitlements/unused_entitlements.md +83 -0
- package/skills/app-store-review-agent/references/rules/metadata/accurate_metadata.md +54 -0
- package/skills/app-store-review-agent/references/rules/metadata/apple_trademark.md +99 -0
- package/skills/app-store-review-agent/references/rules/metadata/china_storefront.md +72 -0
- package/skills/app-store-review-agent/references/rules/metadata/competitor_terms.md +56 -0
- package/skills/app-store-review-agent/references/rules/metadata/subscription_metadata.md +81 -0
- package/skills/app-store-review-agent/references/rules/privacy/privacy_manifest.md +84 -0
- package/skills/app-store-review-agent/references/rules/privacy/unnecessary_data.md +60 -0
- package/skills/app-store-review-agent/references/rules/subscription/misleading_pricing.md +63 -0
- package/skills/app-store-review-agent/references/rules/subscription/missing_tos_pp.md +54 -0
- package/skills/awf-ponytail/SKILL.md +91 -0
- package/skills/awf-ponytail-review/SKILL.md +67 -0
- package/skills/awf-session-restore/SKILL.md +3 -3
- package/skills/brainstorm-agent/SKILL.md +11 -2
- package/skills/brainstorm-agent/templates/brief-template.md +8 -0
- package/skills/claude-planner/SKILL.md +47 -0
- package/skills/code-review/SKILL.md +87 -0
- package/skills/expo-game-development/SKILL.md +163 -0
- package/skills/flutter/LICENSE.txt +202 -0
- package/skills/flutter/SKILL.md +127 -0
- package/skills/flutter-project-creater/LICENSE.txt +202 -0
- package/skills/flutter-project-creater/SKILL.md +106 -0
- package/skills/game-developer/SKILL.md +163 -0
- package/skills/game-developer/references/ecs-patterns.md +501 -0
- package/skills/game-developer/references/multiplayer-networking.md +475 -0
- package/skills/game-developer/references/performance-optimization.md +422 -0
- package/skills/game-developer/references/unity-patterns.md +271 -0
- package/skills/game-developer/references/unreal-cpp.md +352 -0
- package/skills/generate-gui-assets/SKILL.md +305 -0
- package/skills/generate-gui-assets/agents/openai.yaml +4 -0
- package/skills/generate-gui-assets/references/catalog-schema.md +58 -0
- package/skills/generate-gui-assets/references/extraction-techniques.md +21 -0
- package/skills/generate-gui-assets/references/prompt-patterns.md +58 -0
- package/skills/generate-gui-assets/scripts/__pycache__/clean_chroma_edges.cpython-311.pyc +0 -0
- package/skills/generate-gui-assets/scripts/build_gui_contact_sheet.py +51 -0
- package/skills/generate-gui-assets/scripts/clean_chroma_edges.py +262 -0
- package/skills/generate-gui-assets/scripts/copy_approved_icons.py +64 -0
- package/skills/generate-gui-assets/scripts/prepare_gui_asset_run.py +91 -0
- package/skills/generate-gui-assets/scripts/suggest_grid_options.py +63 -0
- package/skills/generate-gui-assets/scripts/validate_gui_catalog.py +50 -0
- package/skills/godot-game-development/SKILL.md +142 -0
- package/skills/hatch-pet/LICENSE.txt +201 -0
- package/skills/hatch-pet/SKILL.md +420 -0
- package/skills/hatch-pet/agents/openai.yaml +4 -0
- package/skills/hatch-pet/references/animation-rows.md +29 -0
- package/skills/hatch-pet/references/codex-pet-contract.md +35 -0
- package/skills/hatch-pet/references/qa-rubric.md +60 -0
- package/skills/hatch-pet/scripts/__pycache__/clean_chroma_edges.cpython-311.pyc +0 -0
- package/skills/hatch-pet/scripts/clean_chroma_edges.py +262 -0
- package/skills/hatch-pet/scripts/compose_atlas.py +150 -0
- package/skills/hatch-pet/scripts/derive_running_left_from_running_right.py +143 -0
- package/skills/hatch-pet/scripts/extract_strip_frames.py +323 -0
- package/skills/hatch-pet/scripts/finalize_pet_run.py +382 -0
- package/skills/hatch-pet/scripts/generate_pet_images.py +287 -0
- package/skills/hatch-pet/scripts/inspect_frames.py +246 -0
- package/skills/hatch-pet/scripts/make_contact_sheet.py +96 -0
- package/skills/hatch-pet/scripts/package_custom_pet.py +108 -0
- package/skills/hatch-pet/scripts/pet_job_status.py +117 -0
- package/skills/hatch-pet/scripts/prepare_pet_run.py +673 -0
- package/skills/hatch-pet/scripts/queue_pet_repairs.py +172 -0
- package/skills/hatch-pet/scripts/record_imagegen_result.py +250 -0
- package/skills/hatch-pet/scripts/render_animation_videos.py +134 -0
- package/skills/hatch-pet/scripts/render_animation_videos.sh +5 -0
- package/skills/hatch-pet/scripts/validate_atlas.py +139 -0
- package/skills/i18n-orchestrator/SKILL.md +37 -0
- package/skills/ios-simulator-skill/SKILL.md +390 -0
- package/skills/ios-simulator-skill/scripts/accessibility_audit.py +300 -0
- package/skills/ios-simulator-skill/scripts/app_launcher.py +326 -0
- package/skills/ios-simulator-skill/scripts/app_state_capture.py +400 -0
- package/skills/ios-simulator-skill/scripts/appearance.py +385 -0
- package/skills/ios-simulator-skill/scripts/build_and_test.py +348 -0
- package/skills/ios-simulator-skill/scripts/clipboard.py +103 -0
- package/skills/ios-simulator-skill/scripts/common/__init__.py +61 -0
- package/skills/ios-simulator-skill/scripts/common/cache_utils.py +289 -0
- package/skills/ios-simulator-skill/scripts/common/device_utils.py +462 -0
- package/skills/ios-simulator-skill/scripts/common/env_config.py +35 -0
- package/skills/ios-simulator-skill/scripts/common/hang_pipeline.py +862 -0
- package/skills/ios-simulator-skill/scripts/common/hang_sessions.py +490 -0
- package/skills/ios-simulator-skill/scripts/common/idb_utils.py +180 -0
- package/skills/ios-simulator-skill/scripts/common/screenshot_utils.py +338 -0
- package/skills/ios-simulator-skill/scripts/container.py +668 -0
- package/skills/ios-simulator-skill/scripts/gesture.py +394 -0
- package/skills/ios-simulator-skill/scripts/hang_watcher.py +1533 -0
- package/skills/ios-simulator-skill/scripts/keyboard.py +391 -0
- package/skills/ios-simulator-skill/scripts/localization_audit.py +483 -0
- package/skills/ios-simulator-skill/scripts/location.py +467 -0
- package/skills/ios-simulator-skill/scripts/log_monitor.py +493 -0
- package/skills/ios-simulator-skill/scripts/model_inspector.py +645 -0
- package/skills/ios-simulator-skill/scripts/navigator.py +461 -0
- package/skills/ios-simulator-skill/scripts/privacy_manager.py +310 -0
- package/skills/ios-simulator-skill/scripts/push_notification.py +240 -0
- package/skills/ios-simulator-skill/scripts/screen_mapper.py +296 -0
- package/skills/ios-simulator-skill/scripts/sim_health_check.sh +245 -0
- package/skills/ios-simulator-skill/scripts/sim_list.py +299 -0
- package/skills/ios-simulator-skill/scripts/simctl_boot.py +312 -0
- package/skills/ios-simulator-skill/scripts/simctl_create.py +316 -0
- package/skills/ios-simulator-skill/scripts/simctl_delete.py +357 -0
- package/skills/ios-simulator-skill/scripts/simctl_erase.py +351 -0
- package/skills/ios-simulator-skill/scripts/simctl_shutdown.py +290 -0
- package/skills/ios-simulator-skill/scripts/simulator_selector.py +375 -0
- package/skills/ios-simulator-skill/scripts/status_bar.py +250 -0
- package/skills/ios-simulator-skill/scripts/test_recorder.py +323 -0
- package/skills/ios-simulator-skill/scripts/visual_diff.py +235 -0
- package/skills/ios-simulator-skill/scripts/xcode/__init__.py +13 -0
- package/skills/ios-simulator-skill/scripts/xcode/builder.py +397 -0
- package/skills/ios-simulator-skill/scripts/xcode/cache.py +204 -0
- package/skills/ios-simulator-skill/scripts/xcode/config.py +178 -0
- package/skills/ios-simulator-skill/scripts/xcode/reporter.py +343 -0
- package/skills/ios-simulator-skill/scripts/xcode/xcresult.py +451 -0
- package/skills/ios-visual-qa-strategist/SKILL.md +111 -0
- package/skills/ios-visual-qa-strategist/agents/openai.yaml +4 -0
- package/skills/ios-visual-qa-strategist/references/ios-tool-selection.md +61 -0
- package/skills/ios-visual-qa-strategist/references/minimal-capture-policy.md +56 -0
- package/skills/ios-visual-qa-strategist/references/visual-reasoning-heuristics.md +53 -0
- package/skills/orchestrator/SKILL.md +0 -20
- package/skills/persistent-storage/SKILL.md +55 -0
- package/skills/short-maker/SKILL.md +23 -0
- package/skills/short-maker/scripts/effects.js +56 -0
- package/skills/short-maker/scripts/shortmaker-bridge.js +332 -0
- package/skills/short-maker/scripts/videomix.js +601 -0
- package/skills/short-maker/templates/hyperframes/cinematic-character.template.html +172 -0
- package/skills/short-maker/templates/hyperframes/index.template.html +194 -0
- package/skills/smali-to-kotlin/SKILL.md +128 -0
- package/skills/smali-to-kotlin/examples/getting-started/tech-stack.md +58 -0
- package/skills/smali-to-kotlin/examples/pipeline/data-ui-parity.md +118 -0
- package/skills/smali-to-kotlin/examples/pipeline/scanner-and-bootstrap.md +106 -0
- package/skills/smali-to-kotlin/library-patterns.md +189 -0
- package/skills/smali-to-kotlin/phase-0-discovery.md +128 -0
- package/skills/smali-to-kotlin/phase-1-architecture.md +166 -0
- package/skills/smali-to-kotlin/phase-2-blueprint-ui.md +347 -0
- package/skills/smali-to-kotlin/phase-2-blueprint.md +228 -0
- package/skills/smali-to-kotlin/phase-3-build.md +248 -0
- package/skills/smali-to-kotlin/phase-3-logic-build.md +268 -0
- package/skills/smali-to-kotlin/smali-reading-guide.md +310 -0
- package/skills/smali-to-kotlin/templates/app-map.md +101 -0
- package/skills/smali-to-kotlin/templates/architecture.md +142 -0
- package/skills/smali-to-kotlin/templates/blueprint.md +145 -0
- package/skills/spec-gate/SKILL.md +6 -2
- package/skills/symphony-enforcer/SKILL.md +8 -0
- package/skills/symphony-enforcer/examples/mindful-stop.md +2 -0
- package/skills/symphony-enforcer/examples/three-phase.md +16 -0
- package/skills/symphony-enforcer/examples/trigger-points.md +7 -1
- package/skills/unity-game-development/SKILL.md +231 -0
- package/skills/video-edit/SKILL.md +36 -0
- package/skills/video-edit/scripts/video_edit.py +324 -0
- package/templates/project-identity/android.json +2 -2
- package/templates/project-identity/backend-nestjs.json +2 -2
- package/templates/project-identity/expo.json +2 -2
- package/templates/project-identity/ios.json +2 -2
- package/templates/project-identity/web-nextjs.json +2 -2
- package/templates/setup-mapping.json +48 -0
- package/templates/specs/design-template.md +161 -71
- package/templates/specs/requirements-template.md +65 -133
- package/templates/specs/task-spec-template.xml +3 -0
- package/workflows/_uncategorized/critic.md +40 -0
- package/workflows/_uncategorized/git-rebase-flow.md +81 -0
- package/workflows/_uncategorized/image-gen.md +118 -0
- package/workflows/_uncategorized/multi-model-pipeline.md +60 -0
- package/workflows/_uncategorized/pixel-gen.md +86 -0
- package/workflows/_uncategorized/pixel-setup.md +90 -0
- package/workflows/_uncategorized/ponytail-review.md +59 -0
- package/workflows/_uncategorized/reverse-android-build.md +222 -0
- package/workflows/_uncategorized/reverse-android-design.md +139 -0
- package/workflows/_uncategorized/reverse-android-discover.md +150 -0
- package/workflows/_uncategorized/reverse-android-scan.md +158 -0
- package/workflows/_uncategorized/reverse-android.md +143 -0
- package/workflows/_uncategorized/reverse-ios-build.md +240 -0
- package/workflows/_uncategorized/reverse-ios-design.md +112 -0
- package/workflows/_uncategorized/reverse-ios-discover.md +120 -0
- package/workflows/_uncategorized/reverse-ios-scan.md +155 -0
- package/workflows/_uncategorized/reverse-ios.md +152 -0
- package/workflows/_uncategorized/safety-router.md +34 -0
- package/workflows/_uncategorized/teach.md +89 -0
- package/workflows/_uncategorized/verify-ui.md +53 -0
- package/workflows/_uncategorized/visualize-screenshots.md +34 -0
- package/workflows/ads/ads-analyst.md +201 -0
- package/workflows/ads/ads-audit.md +106 -0
- package/workflows/ads/ads-optimize.md +97 -0
- package/workflows/ads/ads-targeting.md +241 -0
- package/workflows/ads/adsExpert.md +160 -0
- package/workflows/ads/smali-ads-config.md +400 -0
- package/workflows/ads/smali-ads-flow.md +331 -0
- package/workflows/ads/smali-ads-interstitial.md +377 -0
- package/workflows/ads/smali-ads-native.md +382 -0
- package/workflows/context/teach.md +89 -0
- package/workflows/gitnexus.md +8 -8
- package/workflows/lifecycle/brainstorm.md +43 -0
- package/workflows/lifecycle/code.md +5 -0
- package/workflows/lifecycle/init.md +23 -5
- package/workflows/lifecycle/multi-model-pipeline.md +60 -0
- package/workflows/quality/ponytail-review.md +59 -0
- package/workflows/roles/critic.md +40 -0
- package/workflows/roles/safety-router.md +34 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
iOS Gesture Controller - Swipes and Complex Gestures
|
|
4
|
+
|
|
5
|
+
Performs navigation gestures like swipes, scrolls, and pinches.
|
|
6
|
+
Token-efficient output for common navigation patterns.
|
|
7
|
+
|
|
8
|
+
This script handles touch gestures for iOS simulator automation. It provides
|
|
9
|
+
directional swipes, multi-swipe scrolling, pull-to-refresh, and pinch gestures.
|
|
10
|
+
Automatically detects screen size from the device for accurate gesture positioning.
|
|
11
|
+
|
|
12
|
+
Key Features:
|
|
13
|
+
- Directional swipes (up, down, left, right)
|
|
14
|
+
- Multi-swipe scrolling with customizable amount
|
|
15
|
+
- Pull-to-refresh gesture
|
|
16
|
+
- Pinch to zoom (in/out)
|
|
17
|
+
- Custom swipe between any two points
|
|
18
|
+
- Drag and drop simulation
|
|
19
|
+
- Auto-detects screen dimensions from device
|
|
20
|
+
|
|
21
|
+
Usage Examples:
|
|
22
|
+
# Simple directional swipe
|
|
23
|
+
python scripts/gesture.py --swipe up --udid <device-id>
|
|
24
|
+
|
|
25
|
+
# Scroll down multiple times
|
|
26
|
+
python scripts/gesture.py --scroll down --scroll-amount 3 --udid <device-id>
|
|
27
|
+
|
|
28
|
+
# Pull to refresh
|
|
29
|
+
python scripts/gesture.py --refresh --udid <device-id>
|
|
30
|
+
|
|
31
|
+
# Custom swipe coordinates
|
|
32
|
+
python scripts/gesture.py --swipe-from 100,500 --swipe-to 100,100 --udid <device-id>
|
|
33
|
+
|
|
34
|
+
# Pinch to zoom
|
|
35
|
+
python scripts/gesture.py --pinch out --udid <device-id>
|
|
36
|
+
|
|
37
|
+
# Long press at coordinates
|
|
38
|
+
python scripts/gesture.py --long-press 200,300 --duration 2.0 --udid <device-id>
|
|
39
|
+
|
|
40
|
+
Output Format:
|
|
41
|
+
Swiped up
|
|
42
|
+
Scrolled down (3x)
|
|
43
|
+
Performed pull to refresh
|
|
44
|
+
|
|
45
|
+
Gesture Details:
|
|
46
|
+
- Swipes use 70% of screen by default (configurable)
|
|
47
|
+
- Scrolls are multiple small 30% swipes with delays
|
|
48
|
+
- Start points are offset from edges for reliability
|
|
49
|
+
- Screen size auto-detected from accessibility tree root element
|
|
50
|
+
- Falls back to iPhone 14 dimensions (390x844) if detection fails
|
|
51
|
+
|
|
52
|
+
Technical Details:
|
|
53
|
+
- Uses `idb ui swipe x1 y1 x2 y2` for gesture execution
|
|
54
|
+
- Duration parameter converts to milliseconds for IDB
|
|
55
|
+
- Automatically fetches screen size on initialization
|
|
56
|
+
- Parses IDB accessibility tree to get root frame dimensions
|
|
57
|
+
- All coordinates calculated as fractions of screen size for device independence
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
import argparse
|
|
61
|
+
import subprocess
|
|
62
|
+
import sys
|
|
63
|
+
import time
|
|
64
|
+
|
|
65
|
+
from common import (
|
|
66
|
+
get_device_screen_size,
|
|
67
|
+
get_screen_size,
|
|
68
|
+
resolve_udid,
|
|
69
|
+
transform_screenshot_coords,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class GestureController:
|
|
74
|
+
"""Performs gestures on iOS simulator."""
|
|
75
|
+
|
|
76
|
+
# Standard screen dimensions (will be detected if possible)
|
|
77
|
+
DEFAULT_WIDTH = 390 # iPhone 14
|
|
78
|
+
DEFAULT_HEIGHT = 844
|
|
79
|
+
|
|
80
|
+
def __init__(self, udid: str | None = None):
|
|
81
|
+
"""Initialize gesture controller."""
|
|
82
|
+
self.udid = udid
|
|
83
|
+
self.screen_size = self._get_screen_size()
|
|
84
|
+
|
|
85
|
+
def _get_screen_size(self) -> tuple[int, int]:
|
|
86
|
+
"""Try to detect screen size from device using shared utility."""
|
|
87
|
+
return get_screen_size(self.udid)
|
|
88
|
+
|
|
89
|
+
def swipe(self, direction: str, distance_ratio: float = 0.7) -> bool:
|
|
90
|
+
"""
|
|
91
|
+
Perform directional swipe.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
direction: up, down, left, right
|
|
95
|
+
distance_ratio: How far to swipe (0.0-1.0 of screen)
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
Success status
|
|
99
|
+
"""
|
|
100
|
+
width, height = self.screen_size
|
|
101
|
+
center_x = width // 2
|
|
102
|
+
center_y = height // 2
|
|
103
|
+
|
|
104
|
+
# Calculate swipe coordinates based on direction
|
|
105
|
+
if direction == "up":
|
|
106
|
+
start = (center_x, int(height * 0.7))
|
|
107
|
+
end = (center_x, int(height * (1 - distance_ratio + 0.3)))
|
|
108
|
+
elif direction == "down":
|
|
109
|
+
start = (center_x, int(height * 0.3))
|
|
110
|
+
end = (center_x, int(height * (distance_ratio - 0.3 + 0.3)))
|
|
111
|
+
elif direction == "left":
|
|
112
|
+
start = (int(width * 0.8), center_y)
|
|
113
|
+
end = (int(width * (1 - distance_ratio + 0.2)), center_y)
|
|
114
|
+
elif direction == "right":
|
|
115
|
+
start = (int(width * 0.2), center_y)
|
|
116
|
+
end = (int(width * (distance_ratio - 0.2 + 0.2)), center_y)
|
|
117
|
+
else:
|
|
118
|
+
return False
|
|
119
|
+
|
|
120
|
+
return self.swipe_between(start, end)
|
|
121
|
+
|
|
122
|
+
def swipe_between(
|
|
123
|
+
self, start: tuple[int, int], end: tuple[int, int], duration: float = 0.3
|
|
124
|
+
) -> bool:
|
|
125
|
+
"""
|
|
126
|
+
Swipe between two points.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
start: Starting coordinates (x, y)
|
|
130
|
+
end: Ending coordinates (x, y)
|
|
131
|
+
duration: Swipe duration in seconds
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Success status
|
|
135
|
+
"""
|
|
136
|
+
cmd = ["idb", "ui", "swipe"]
|
|
137
|
+
cmd.extend([str(start[0]), str(start[1]), str(end[0]), str(end[1])])
|
|
138
|
+
|
|
139
|
+
# IDB doesn't support duration directly, but we can add delay
|
|
140
|
+
if duration != 0.3:
|
|
141
|
+
cmd.extend(["--duration", str(int(duration * 1000))])
|
|
142
|
+
|
|
143
|
+
if self.udid:
|
|
144
|
+
cmd.extend(["--udid", self.udid])
|
|
145
|
+
|
|
146
|
+
try:
|
|
147
|
+
subprocess.run(cmd, capture_output=True, check=True)
|
|
148
|
+
return True
|
|
149
|
+
except subprocess.CalledProcessError:
|
|
150
|
+
return False
|
|
151
|
+
|
|
152
|
+
def scroll(self, direction: str, amount: int = 3) -> bool:
|
|
153
|
+
"""
|
|
154
|
+
Perform multiple small swipes to scroll.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
direction: up, down
|
|
158
|
+
amount: Number of small swipes
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
Success status
|
|
162
|
+
"""
|
|
163
|
+
for _ in range(amount):
|
|
164
|
+
if not self.swipe(direction, distance_ratio=0.3):
|
|
165
|
+
return False
|
|
166
|
+
time.sleep(0.2) # Small delay between swipes
|
|
167
|
+
return True
|
|
168
|
+
|
|
169
|
+
def tap_and_hold(self, x: int, y: int, duration: float = 2.0) -> bool:
|
|
170
|
+
"""
|
|
171
|
+
Long press at coordinates.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
x, y: Coordinates
|
|
175
|
+
duration: Hold duration in seconds
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
Success status
|
|
179
|
+
"""
|
|
180
|
+
# IDB doesn't have native long press, simulate with tap
|
|
181
|
+
# In real implementation, might need to use different approach
|
|
182
|
+
cmd = ["idb", "ui", "tap", str(x), str(y)]
|
|
183
|
+
|
|
184
|
+
if self.udid:
|
|
185
|
+
cmd.extend(["--udid", self.udid])
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
subprocess.run(cmd, capture_output=True, check=True)
|
|
189
|
+
# Simulate hold with delay
|
|
190
|
+
time.sleep(duration)
|
|
191
|
+
return True
|
|
192
|
+
except subprocess.CalledProcessError:
|
|
193
|
+
return False
|
|
194
|
+
|
|
195
|
+
def pinch(self, direction: str = "out", center: tuple[int, int] | None = None) -> bool:
|
|
196
|
+
"""
|
|
197
|
+
Perform pinch gesture (zoom in/out).
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
direction: 'in' (zoom out) or 'out' (zoom in)
|
|
201
|
+
center: Center point for pinch
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
Success status
|
|
205
|
+
"""
|
|
206
|
+
if not center:
|
|
207
|
+
width, height = self.screen_size
|
|
208
|
+
center = (width // 2, height // 2)
|
|
209
|
+
|
|
210
|
+
# Calculate pinch points
|
|
211
|
+
offset = 100 if direction == "out" else 50
|
|
212
|
+
|
|
213
|
+
if direction == "out":
|
|
214
|
+
# Zoom in - fingers move apart
|
|
215
|
+
start1 = (center[0] - 20, center[1] - 20)
|
|
216
|
+
end1 = (center[0] - offset, center[1] - offset)
|
|
217
|
+
start2 = (center[0] + 20, center[1] + 20)
|
|
218
|
+
end2 = (center[0] + offset, center[1] + offset)
|
|
219
|
+
else:
|
|
220
|
+
# Zoom out - fingers move together
|
|
221
|
+
start1 = (center[0] - offset, center[1] - offset)
|
|
222
|
+
end1 = (center[0] - 20, center[1] - 20)
|
|
223
|
+
start2 = (center[0] + offset, center[1] + offset)
|
|
224
|
+
end2 = (center[0] + 20, center[1] + 20)
|
|
225
|
+
|
|
226
|
+
# Perform two swipes simultaneously (simulated)
|
|
227
|
+
success1 = self.swipe_between(start1, end1)
|
|
228
|
+
success2 = self.swipe_between(start2, end2)
|
|
229
|
+
|
|
230
|
+
return success1 and success2
|
|
231
|
+
|
|
232
|
+
def drag_and_drop(self, start: tuple[int, int], end: tuple[int, int]) -> bool:
|
|
233
|
+
"""
|
|
234
|
+
Drag element from one position to another.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
start: Starting coordinates
|
|
238
|
+
end: Ending coordinates
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
Success status
|
|
242
|
+
"""
|
|
243
|
+
# Use slow swipe to simulate drag
|
|
244
|
+
return self.swipe_between(start, end, duration=1.0)
|
|
245
|
+
|
|
246
|
+
def refresh(self) -> bool:
|
|
247
|
+
"""Pull to refresh gesture."""
|
|
248
|
+
width, _ = self.screen_size
|
|
249
|
+
start = (width // 2, 100)
|
|
250
|
+
end = (width // 2, 400)
|
|
251
|
+
return self.swipe_between(start, end)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def main():
|
|
255
|
+
"""Main entry point."""
|
|
256
|
+
parser = argparse.ArgumentParser(description="Perform gestures on iOS simulator")
|
|
257
|
+
|
|
258
|
+
# Gesture options
|
|
259
|
+
parser.add_argument(
|
|
260
|
+
"--swipe", choices=["up", "down", "left", "right"], help="Perform directional swipe"
|
|
261
|
+
)
|
|
262
|
+
parser.add_argument("--swipe-from", help="Custom swipe start coordinates (x,y)")
|
|
263
|
+
parser.add_argument("--swipe-to", help="Custom swipe end coordinates (x,y)")
|
|
264
|
+
parser.add_argument(
|
|
265
|
+
"--scroll", choices=["up", "down"], help="Scroll in direction (multiple small swipes)"
|
|
266
|
+
)
|
|
267
|
+
parser.add_argument(
|
|
268
|
+
"--scroll-amount", type=int, default=3, help="Number of scroll swipes (default: 3)"
|
|
269
|
+
)
|
|
270
|
+
parser.add_argument("--long-press", help="Long press at coordinates (x,y)")
|
|
271
|
+
parser.add_argument(
|
|
272
|
+
"--duration", type=float, default=2.0, help="Duration for long press in seconds"
|
|
273
|
+
)
|
|
274
|
+
parser.add_argument(
|
|
275
|
+
"--pinch", choices=["in", "out"], help="Pinch gesture (in=zoom out, out=zoom in)"
|
|
276
|
+
)
|
|
277
|
+
parser.add_argument("--refresh", action="store_true", help="Pull to refresh gesture")
|
|
278
|
+
|
|
279
|
+
# Coordinate transformation
|
|
280
|
+
parser.add_argument(
|
|
281
|
+
"--screenshot-coords",
|
|
282
|
+
action="store_true",
|
|
283
|
+
help="Interpret swipe coordinates as from a screenshot (requires --screenshot-width/height)",
|
|
284
|
+
)
|
|
285
|
+
parser.add_argument(
|
|
286
|
+
"--screenshot-width",
|
|
287
|
+
type=int,
|
|
288
|
+
help="Screenshot width for coordinate transformation",
|
|
289
|
+
)
|
|
290
|
+
parser.add_argument(
|
|
291
|
+
"--screenshot-height",
|
|
292
|
+
type=int,
|
|
293
|
+
help="Screenshot height for coordinate transformation",
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
parser.add_argument(
|
|
297
|
+
"--udid",
|
|
298
|
+
help="Device UDID (auto-detects booted simulator if not provided)",
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
args = parser.parse_args()
|
|
302
|
+
|
|
303
|
+
# Resolve UDID with auto-detection
|
|
304
|
+
try:
|
|
305
|
+
udid = resolve_udid(args.udid)
|
|
306
|
+
except RuntimeError as e:
|
|
307
|
+
print(f"Error: {e}")
|
|
308
|
+
sys.exit(1)
|
|
309
|
+
|
|
310
|
+
controller = GestureController(udid=udid)
|
|
311
|
+
|
|
312
|
+
# Execute requested gesture
|
|
313
|
+
if args.swipe:
|
|
314
|
+
if controller.swipe(args.swipe):
|
|
315
|
+
print(f"Swiped {args.swipe}")
|
|
316
|
+
else:
|
|
317
|
+
print(f"Failed to swipe {args.swipe}")
|
|
318
|
+
sys.exit(1)
|
|
319
|
+
|
|
320
|
+
elif args.swipe_from and args.swipe_to:
|
|
321
|
+
# Custom swipe
|
|
322
|
+
start = tuple(map(int, args.swipe_from.split(",")))
|
|
323
|
+
end = tuple(map(int, args.swipe_to.split(",")))
|
|
324
|
+
|
|
325
|
+
# Handle coordinate transformation if requested
|
|
326
|
+
if args.screenshot_coords:
|
|
327
|
+
if not args.screenshot_width or not args.screenshot_height:
|
|
328
|
+
print(
|
|
329
|
+
"Error: --screenshot-coords requires --screenshot-width and --screenshot-height"
|
|
330
|
+
)
|
|
331
|
+
sys.exit(1)
|
|
332
|
+
|
|
333
|
+
device_w, device_h = get_device_screen_size(udid)
|
|
334
|
+
start = transform_screenshot_coords(
|
|
335
|
+
start[0],
|
|
336
|
+
start[1],
|
|
337
|
+
args.screenshot_width,
|
|
338
|
+
args.screenshot_height,
|
|
339
|
+
device_w,
|
|
340
|
+
device_h,
|
|
341
|
+
)
|
|
342
|
+
end = transform_screenshot_coords(
|
|
343
|
+
end[0],
|
|
344
|
+
end[1],
|
|
345
|
+
args.screenshot_width,
|
|
346
|
+
args.screenshot_height,
|
|
347
|
+
device_w,
|
|
348
|
+
device_h,
|
|
349
|
+
)
|
|
350
|
+
print("Transformed screenshot coords to device coords")
|
|
351
|
+
|
|
352
|
+
if controller.swipe_between(start, end):
|
|
353
|
+
print(f"Swiped from {start} to {end}")
|
|
354
|
+
else:
|
|
355
|
+
print("Failed to swipe")
|
|
356
|
+
sys.exit(1)
|
|
357
|
+
|
|
358
|
+
elif args.scroll:
|
|
359
|
+
if controller.scroll(args.scroll, args.scroll_amount):
|
|
360
|
+
print(f"Scrolled {args.scroll} ({args.scroll_amount}x)")
|
|
361
|
+
else:
|
|
362
|
+
print(f"Failed to scroll {args.scroll}")
|
|
363
|
+
sys.exit(1)
|
|
364
|
+
|
|
365
|
+
elif args.long_press:
|
|
366
|
+
coords = tuple(map(int, args.long_press.split(",")))
|
|
367
|
+
if controller.tap_and_hold(coords[0], coords[1], args.duration):
|
|
368
|
+
print(f"Long pressed at {coords} for {args.duration}s")
|
|
369
|
+
else:
|
|
370
|
+
print("Failed to long press")
|
|
371
|
+
sys.exit(1)
|
|
372
|
+
|
|
373
|
+
elif args.pinch:
|
|
374
|
+
if controller.pinch(args.pinch):
|
|
375
|
+
action = "Zoomed in" if args.pinch == "out" else "Zoomed out"
|
|
376
|
+
print(action)
|
|
377
|
+
else:
|
|
378
|
+
print(f"Failed to pinch {args.pinch}")
|
|
379
|
+
sys.exit(1)
|
|
380
|
+
|
|
381
|
+
elif args.refresh:
|
|
382
|
+
if controller.refresh():
|
|
383
|
+
print("Performed pull to refresh")
|
|
384
|
+
else:
|
|
385
|
+
print("Failed to refresh")
|
|
386
|
+
sys.exit(1)
|
|
387
|
+
|
|
388
|
+
else:
|
|
389
|
+
parser.print_help()
|
|
390
|
+
sys.exit(1)
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
if __name__ == "__main__":
|
|
394
|
+
main()
|