also looking at this
feat: native trail maps and complete native mobile screens
#1017
60 files
+2505
-823
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -0,0 +1,16 @@ | ||
| 1 | appId: ${APP_ID} | |
| 2 | name: Open trailhead directions from the full native map | |
| 3 | --- | |
| 4 | - launchApp | |
| 5 | - openLink: wildloop://trail/${TRAIL_ID}/map | |
| 6 | - extendedWaitUntil: | |
| 7 | visible: | |
| 8 | id: map-directions | |
| 9 | timeout: 30000 | |
| 10 | - tapOn: | |
| 11 | id: map-directions | |
| 12 | - extendedWaitUntil: | |
| 13 | notVisible: | |
| 14 | id: trail-full-map | |
| 15 | timeout: 15000 | |
| 16 | - takeScreenshot: android-native-full-map-directions-handoff | |
| @@ -41,6 +41,33 @@ name: Native Android trail maps and sticky save | ||
| 41 | 41 | visible: ${INLINE_PROFILE_END_TEXT} |
| 42 | 42 | timeout: 15000 |
| 43 | 43 | - takeScreenshot: android-native-inline-elevation-selection |
| 44 | - scrollUntilVisible: | |
| 45 | element: | |
| 46 | id: trail-zoom-in | |
| 47 | direction: DOWN | |
| 48 | - tapOn: | |
| 49 | id: trail-zoom-in | |
| 50 | - tapOn: | |
| 51 | id: trail-zoom-out | |
| 52 | - tapOn: | |
| 53 | id: trail-fit-route | |
| 54 | - tapOn: | |
| 55 | id: trail-map-3d | |
| 56 | - assertVisible: '^2D$' | |
| 57 | - tapOn: '^North$' | |
| 58 | - scrollUntilVisible: | |
| 59 | element: | |
| 60 | id: trail-map-layer | |
| 61 | direction: DOWN | |
| 62 | - tapOn: | |
| 63 | id: trail-map-layer | |
| 64 | - tapOn: '^Satellite$' | |
| 65 | - assertVisible: 'Map layer, Satellite' | |
| 66 | - takeScreenshot: android-native-inline-map-satellite | |
| 67 | - tapOn: | |
| 68 | id: trail-map-layer | |
| 69 | - tapOn: '^Outdoors$' | |
| 70 | - assertVisible: 'Map layer, Outdoors' | |
| 44 | 71 | - scrollUntilVisible: |
| 45 | 72 | element: |
| 46 | 73 | id: trail-map-fullscreen |
| @@ -18,7 +18,7 @@ name: Native location, route customization and GPX sharing | ||
| 18 | 18 | - tapOn: |
| 19 | 19 | id: '.*permission_allow_foreground_only_button' |
| 20 | 20 | - extendedWaitUntil: |
| 21 | visible: 'Your location is shown' | |
| 21 | visible: 'My location, Your location is shown' | |
| 22 | 22 | timeout: 30000 |
| 23 | 23 | - takeScreenshot: android-native-map-location |
| 24 | 24 | - tapOn: |
| @@ -41,3 +41,33 @@ name: Native location, route customization and GPX sharing | ||
| 41 | 41 | - back |
| 42 | 42 | - assertVisible: |
| 43 | 43 | id: trail-full-map |
| 44 | - openLink: wildloop://trail/${TRAIL_ID} | |
| 45 | - extendedWaitUntil: | |
| 46 | visible: | |
| 47 | id: trail-sticky-actions | |
| 48 | timeout: 30000 | |
| 49 | - scrollUntilVisible: | |
| 50 | element: | |
| 51 | id: trail-map-locate | |
| 52 | direction: DOWN | |
| 53 | - tapOn: | |
| 54 | id: trail-map-locate | |
| 55 | - extendedWaitUntil: | |
| 56 | visible: 'My location, Your location is shown' | |
| 57 | timeout: 30000 | |
| 58 | - assertNotVisible: | |
| 59 | id: '.*permission_allow_foreground_only_button' | |
| 60 | - takeScreenshot: android-native-inline-map-location | |
| 61 | - scrollUntilVisible: | |
| 62 | element: | |
| 63 | id: trail-map-export | |
| 64 | direction: DOWN | |
| 65 | - tapOn: | |
| 66 | id: trail-map-export | |
| 67 | - extendedWaitUntil: | |
| 68 | visible: ${GPX_NAME} | |
| 69 | timeout: 15000 | |
| 70 | - takeScreenshot: android-native-inline-gpx-share-sheet | |
| 71 | - back | |
| 72 | - assertVisible: | |
| 73 | id: trail-sticky-actions | |
| @@ -321,7 +321,7 @@ onMount(() => onNativeAccountChange(craft, () => { viewer.set(0); saved.set(fals | ||
| 321 | 321 | <View class="mt-2 flex-row flex-wrap gap-2"> |
| 322 | 322 | <Button testID="trail-map-3d" :class="ui.secondary" @click="pitch.set(pitch() > 0 ? 0 : 45)" :text="pitch() > 0 ? '2D' : '3D'" /> |
| 323 | 323 | <Button :class="ui.secondary" @click="heading.set(0)">North</Button> |
| 324 | <Button testID="trail-map-locate" :class="ui.secondary" @click="locate()">My location</Button> | |
| 324 | <Button testID="trail-map-locate" :class="ui.secondary" accessibilityLabel="My location" :accessibilityValue="showLocation() ? 'Your location is shown' : ''" @click="locate()">My location</Button> | |
| 325 | 325 | <Button testID="trail-map-fullscreen" :class="ui.secondary" @click="craft.navigation.open('/trail/' + wanted + '/map')">Expand map</Button> |
| 326 | 326 | </View> |
| 327 | 327 | <Button testID="trail-map-export" :disabled="!routeAvailable()" :class="ui.secondary" class="mt-2" @click="exportRoute()">Export GPX</Button> |
| @@ -138,7 +138,7 @@ onMount(() => { void load(); return () => { alive = false } }) | ||
| 138 | 138 | <Button testID="map-fit" class="flex-1" :class="ui.secondary" @click="fit()">Fit route</Button> |
| 139 | 139 | <Button testID="map-zoom-in" class="w-11" :class="ui.secondary" @click="region.set(nativeZoomRegion(currentRegion(),0.5))" accessibilityLabel="Zoom in">+</Button> |
| 140 | 140 | <Button testID="map-zoom-out" class="w-11" :class="ui.secondary" @click="region.set(nativeZoomRegion(currentRegion(),2))" accessibilityLabel="Zoom out">−</Button> |
| 141 | <Button testID="map-locate" class="flex-1" :class="ui.secondary" :accessibilityValue="showLocation() ? 'Your location is shown' : ''" @click="locate()">My location</Button> | |
| 141 | <Button testID="map-locate" class="flex-1" :class="ui.secondary" accessibilityLabel="My location" :accessibilityValue="showLocation() ? 'Your location is shown' : ''" @click="locate()">My location</Button> | |
| 142 | 142 | </View> |
| 143 | 143 | <View class="flex-row gap-2"> |
| 144 | 144 | <Button testID="map-export" class="flex-1" :class="ui.secondary" @click="exportRoute()">Export GPX</Button> |
| @@ -114,7 +114,7 @@ export async function runNativeTrailAndroidE2e(): Promise<void> { | ||
| 114 | 114 | GPX_NAME: `${trail.name.replace(/[^a-z0-9]+/gi, '-').replace(/^-|-$/g, '').slice(0, 80)}.gpx`, |
| 115 | 115 | } |
| 116 | 116 | let reviewId: number | undefined |
| 117 | for (const phase of ['maps', 'utilities', 'sharing', 'directions', 'review-create', 'review-edit', 'review-delete'] as const) { | |
| 117 | for (const phase of ['maps', 'utilities', 'sharing', 'directions', 'directions-map', 'review-create', 'review-edit', 'review-delete'] as const) { | |
| 118 | 118 | const report = join(root, `${phase}.xml`) |
| 119 | 119 | await command([ |
| 120 | 120 | 'maestro', `--device=${device}`, '--no-ansi', 'test', |
| @@ -140,8 +140,8 @@ export async function runNativeTrailAndroidE2e(): Promise<void> { | ||
| 140 | 140 | } |
| 141 | 141 | if (!exported) throw new Error('The native GPX export did not contain the recorded route coordinates.') |
| 142 | 142 | } |
| 143 | if (phase === 'directions') { | |
| 144 | const activities = await adb(['shell', 'dumpsys', 'activity', 'activities'], 'directions-activities') | |
| 143 | if (phase === 'directions' || phase === 'directions-map') { | |
| 144 | const activities = await adb(['shell', 'dumpsys', 'activity', 'activities'], `${phase}-activities`) | |
| 145 | 145 | const resumed = activities.split('\n').filter(line => /(?:mResumedActivity|topResumedActivity):/.test(line)) |
| 146 | 146 | if (!resumed.length || resumed.some(line => line.includes(`${mobile.android.packageName}/`))) |
| 147 | 147 | throw new Error('Directions did not hand off to an external Android activity.') |