ReviewOS

also looking at this

stacks/wildloop

feat: native trail maps and complete native mobile screens

#1017
Draft chris wants to merge codex/trail-experience into main
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.

.maestro/native-trail/appearance.yamladded+43-0
Changes to .maestro/native-trail/appearance.yaml
@@ -0,0 +1,43 @@
1appId: ${APP_ID}
2name: Native trail maps and sticky controls in system dark appearance
3---
4- launchApp
5- openLink: wildloop://trail/${TRAIL_ID}
6- extendedWaitUntil:
7 visible: ${TRAIL_NAME}
8 timeout: 30000
9- assertVisible:
10 id: trail-sticky-actions
11- takeScreenshot: android-native-dark-trail-overview
12- scrollUntilVisible:
13 element:
14 id: trail-profile-toggle
15 direction: DOWN
16- takeScreenshot: android-native-dark-inline-profile
17- scrollUntilVisible:
18 element:
19 id: trail-map-fullscreen
20 direction: DOWN
21- tapOn:
22 id: trail-map-fullscreen
23- extendedWaitUntil:
24 visible:
25 id: trail-full-map
26 timeout: 15000
27- takeScreenshot: android-native-dark-full-map
28- tapOn:
29 id: map-profile-toggle
30- takeScreenshot: android-native-dark-collapsed-profile
31- back
32- scrollUntilVisible:
33 element:
34 id: trail-weather-heading
35 direction: DOWN
36- takeScreenshot: android-native-dark-weather
37- scrollUntilVisible:
38 element:
39 id: trail-surfaces-heading
40 direction: DOWN
41- takeScreenshot: android-native-dark-surfaces
42- assertVisible:
43 id: trail-sticky-actions
resources/native/TrailDetail.stxmodified+1-1
Changes to resources/native/TrailDetail.stx
@@ -331,7 +331,7 @@ onMount(() => onNativeAccountChange(craft, () => {
331331 </View>
332332 <Text :show="!profile().some(point => point.ft !== null)" :class="ui.caption">Elevation data is unavailable for this route.</Text>
333333 <Text :show="profile().some(point => point.ft !== null)" :text="profileFigures().miles.toFixed(1) + ' mi · ' + Math.round(profileFigures().low) + '–' + Math.round(profileFigures().high) + ' ft'" :class="ui.caption" />
334 <Slider :show="profile().length > 1" testID="trail-elevation-slider" accessibilityLabel="Explore elevation and position along the route" :value="profilePosition" :minimumValue="0" :maximumValue="profile().length - 1" :step="1" @change="inspect($event)" />
334 <Slider :show="profile().length > 1" testID="trail-elevation-slider" accessibilityLabel="Explore elevation and position along the route" :value="profilePosition" :minimumValue="0" :maximumValue="Math.max(0,profile().length - 1)" :step="1" @change="inspect($event)" />
335335 <Text :show="inspected()" :text="inspected()?.mi.toFixed(2) + ' mi, ' + (inspected()?.ft === null ? 'elevation unavailable' : inspected()?.ft + ' ft')" :class="ui.caption" />
336336 </View>
337337 </View>
scripts/run-native-trail-android-e2e.tsmodified+2-1
Changes to scripts/run-native-trail-android-e2e.ts
@@ -114,8 +114,9 @@ export async function runNativeTrailAndroidE2e(): Promise<void> {
114114 GPX_NAME: `${trail.name.replace(/[^a-z0-9]+/gi, '-').replace(/^-|-$/g, '').slice(0, 80)}.gpx`,
115115 }
116116 let reviewId: number | undefined
117 for (const phase of ['maps', 'utilities', 'sharing', 'directions', 'directions-map', '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', 'appearance'] as const) {
118118 const report = join(root, `${phase}.xml`)
119 if (phase === 'appearance') await adb(['shell', 'cmd', 'uimode', 'night', 'yes'], 'system-dark-appearance')
119120 await command([
120121 'maestro', `--device=${device}`, '--no-ansi', 'test',
121122 ...Object.entries(variables).flatMap(([key, value]) => ['--env', `${key}=${value}`]),
scripts/run-native-trail-e2e.tsmodified+5-0
Changes to scripts/run-native-trail-e2e.ts
@@ -92,6 +92,11 @@ export async function runNativeTrailE2e(): Promise<void> {
9292 throw new Error('The native edit did not retain the review identity and persist its new text and rating.')
9393 return new Response('PASS edited review retained its identity and persisted')
9494 }
95 if(hook==='appearance-dark' || hook==='appearance-light') {
96 const appearance=hook==='appearance-dark' ? 'dark' : 'light'
97 await command(['xcrun','simctl','ui',device,'appearance',appearance],`${hook}.log`)
98 return new Response(`PASS platform appearance ${appearance}`)
99 }
95100 if(hook==='seed-location') {
96101 const first=primaryRoutePart([...decodeRouteParts(trail.geometry),...(Array.isArray(trail.pieceRoutes)?trail.pieceRoutes:[])])[0]
97102 if(!first)throw new Error('The seeded trail has no recorded route start.')
tests/native/trail-journey.tsmodified+23-0
Changes to tests/native/trail-journey.ts
@@ -267,5 +267,28 @@ return [
267267 {name:'gpx',steps:gpx,completion:'exec verify-gpx: PASS exported GPX contains the recorded route'},
268268 {name:'planner',steps:planner,completion:'PASS expectid trail-full-map'},
269269 {name:'location',steps:location,completion:'PASS expect Your location is shown'},
270 {name:'appearance',steps:[
271 {command:'exec',name:'appearance-dark'},
272 {command:'launch'},
273 {command:'openurl',url:`wildloop://trail/${input.trailId}`},
274 {command:'expect',text:input.trailName,seconds:30},
275 {command:'expectid',text:'trail-sticky-actions',seconds:15},
276 {command:'shot',name:'native-dark-trail-overview'},
277 {command:'scrollto',text:'Toggle elevation profile'},
278 {command:'shot',name:'native-dark-inline-profile'},
279 {command:'scrollto',text:'Expand map'},
280 {command:'tapid',text:'trail-map-fullscreen'},
281 {command:'expectid',text:'trail-full-map',seconds:15},
282 {command:'shot',name:'native-dark-full-map'},
283 {command:'tapid',text:'map-profile-toggle'},
284 {command:'shot',name:'native-dark-collapsed-profile'},
285 {command:'back'},
286 {command:'scrollto',text:'Weather'},
287 {command:'shot',name:'native-dark-weather'},
288 {command:'scrollto',text:'Surface types'},
289 {command:'shot',name:'native-dark-surfaces'},
290 {command:'expectid',text:'trail-sticky-actions',seconds:15},
291 {command:'exec',name:'appearance-light'},
292 ],completion:'exec appearance-light: PASS platform appearance light'},
270293]
271294}