diff --git a/apps/toolbox/src/pages/list-page-model-sticky.ts b/apps/toolbox/src/pages/list-page-model-sticky.ts index cf8b3cb9c1..fc7c764b41 100644 --- a/apps/toolbox/src/pages/list-page-model-sticky.ts +++ b/apps/toolbox/src/pages/list-page-model-sticky.ts @@ -1,5 +1,4 @@ import { Observable, Dialogs, DialogStrings, View, EventData, SearchEventData } from '@nativescript/core'; -import { getItemCallbacks } from '../split-view/split-view-root'; type CountryListType = Array<{ title: string; items: Array<{ name: string; code: string; flag: string; isVisible?: boolean }> }>; export class ListPageModelSticky extends Observable { countries: CountryListType = [ @@ -1386,8 +1385,6 @@ export class ListPageModelSticky extends Observable { if (letter.items?.length) { const country = letter.items[args.index]; console.log('Tapped on country: ' + country.name); - // used in splitview demo - getItemCallbacks().forEach((callback) => callback(`${country.name} was selected.`)); } } diff --git a/apps/toolbox/src/split-view/split-view-inspector.ts b/apps/toolbox/src/split-view/split-view-inspector.ts new file mode 100644 index 0000000000..b5ae7a9304 --- /dev/null +++ b/apps/toolbox/src/split-view/split-view-inspector.ts @@ -0,0 +1,23 @@ +import { Observable, EventData, Page } from '@nativescript/core'; +import { SplitViewBrief, setItemCallbacks } from './split-view-root'; + +let page: Page; + +export function navigatingTo(args: EventData) { + page = args.object; + page.bindingContext = new SplitViewInspectorModel(); +} + +export class SplitViewInspectorModel extends Observable { + selectedBrief: SplitViewBrief | null = null; + + constructor() { + super(); + setItemCallbacks([this.syncBrief.bind(this)]); + } + + syncBrief(brief: SplitViewBrief) { + this.selectedBrief = brief; + this.notifyPropertyChange('selectedBrief', brief); + } +} diff --git a/apps/toolbox/src/split-view/split-view-inspector.xml b/apps/toolbox/src/split-view/split-view-inspector.xml new file mode 100644 index 0000000000..9ef5ff7daf --- /dev/null +++ b/apps/toolbox/src/split-view/split-view-inspector.xml @@ -0,0 +1,45 @@ + + + + + + + + + diff --git a/apps/toolbox/src/split-view/split-view-primary.ts b/apps/toolbox/src/split-view/split-view-primary.ts index 3f5748cb28..a4bb6fb513 100644 --- a/apps/toolbox/src/split-view/split-view-primary.ts +++ b/apps/toolbox/src/split-view/split-view-primary.ts @@ -1,23 +1,152 @@ import { Observable, EventData, Page, SplitView, ItemEventData } from '@nativescript/core'; -import { getItemCallbacks } from './split-view-root'; +import { SplitViewBrief, broadcastSelection } from './split-view-root'; + let page: Page; +const briefData: SplitViewBrief[] = [ + { + id: 'brief-morning', + title: 'Morning Briefing', + category: 'Operations', + status: 'Prep', + summary: 'Snapshot of overnight metrics and open questions for the ops pod.', + owner: 'Taylor Brooks', + updated: 'Updated 9:41 AM', + accent: '#0A84FF', + tagline: 'Send digest to the exec channel by 11:00 AM.', + notes: 'Pull final revenue numbers, plug in the refreshed engagement chart, and make sure automation stays enabled before the noon lock.', + actions: ['Drop the updated charts into the keynote deck.', 'Verify Siri Shortcut triggers run on the new data set.', 'Line up quick talking points for the 11:00 AM call.'], + highlights: [ + { label: 'Focus', value: 'Engagement + device health' }, + { label: 'Next Check-in', value: 'Ops sync at 2:30 PM' }, + ], + metrics: [ + { label: 'Priority', value: 'High' }, + { label: 'Delivery', value: 'Exec brief' }, + { label: 'Attachments', value: '4 files' }, + { label: 'Watchers', value: '6 people' }, + ], + contributors: ['Taylor', 'Morgan', 'Priya'], + tags: ['Ops', 'Daily', 'Exec'], + }, + { + id: 'brief-design', + title: 'Audit', + category: 'Design', + status: 'Assets', + summary: 'Interaction audit for the compact-to-regular transition on iPadOS.', + owner: 'Isla Raymond', + updated: 'Updated 8:12 AM', + accent: '#FF9F0A', + tagline: 'Need sign-off from Brandon before handoff.', + notes: 'Finalize the inspector column metrics cards and verify the peek gesture targets. Attach the quick recording from TestFlight build 4120.', + actions: ['Export motion specs for the spring animation.', 'Confirm hit targets with accessibility review.', 'Share the color tokens with web once approved.'], + highlights: [ + { label: 'Focus', value: 'Regular width interactions' }, + { label: 'Blocked by', value: 'Motion review @ 3:00 PM' }, + ], + metrics: [ + { label: 'Priority', value: 'Medium' }, + { label: 'Delivery', value: 'Design QA' }, + { label: 'Attachments', value: '6 files' }, + { label: 'Watchers', value: '4 people' }, + ], + contributors: ['Isla', 'Brandon', 'Nova'], + tags: ['Design', 'QA'], + }, + { + id: 'brief-field', + title: 'Research', + category: 'Research', + status: 'Synthesize', + summary: 'Notes from three in-store sessions about the new onboarding.', + owner: 'Sam Park', + updated: 'Updated yesterday', + accent: '#32D74B', + tagline: 'Clips already in the shared Photos album.', + notes: 'Pull direct quotes for friction points around quick actions, and pair with the heat map captures for the appendix slide.', + actions: ['Flag standout clips for the highlight reel.', 'Post the transcript summary in #research.', 'Open follow-up tasks for the onboarding squad.'], + highlights: [ + { label: 'Focus', value: 'Onboarding swipes' }, + { label: 'Next Check-in', value: 'Squad sync Friday' }, + ], + metrics: [ + { label: 'Priority', value: 'Medium' }, + { label: 'Delivery', value: 'Research recap' }, + { label: 'Attachments', value: '9 clips' }, + { label: 'Watchers', value: '3 people' }, + ], + contributors: ['Sam', 'Kaia'], + tags: ['Research', 'Clips', 'Onboarding'], + }, + { + id: 'brief-gallery', + title: 'Shortcuts', + category: 'Product', + status: 'Ready', + summary: 'Curated cards for the iPad productivity spotlight next week.', + owner: 'Luca Nguyen', + updated: 'Updated Monday', + accent: '#BF5AF2', + tagline: 'Publishing window opens Thursday morning.', + notes: 'Verify icon treatments render crisply on mini + 12.9 screens, and double-check localized copy for DE/JA.', + actions: ['Ping localization for the remaining strings.', 'Preview the curated set on device.', 'Coordinate push copy with marketing.'], + highlights: [ + { label: 'Focus', value: 'Automation + Productivity' }, + { label: 'Blocked by', value: 'Awaiting DE copy' }, + ], + metrics: [ + { label: 'Priority', value: 'High' }, + { label: 'Delivery', value: 'App Store' }, + { label: 'Attachments', value: '12 shortcuts' }, + { label: 'Watchers', value: '5 people' }, + ], + contributors: ['Luca', 'Amelia', 'Jo'], + tags: ['Launch', 'Localization'], + }, + { + id: 'brief-incident', + title: 'Incident Review', + category: 'Engineering', + status: 'Investigate', + summary: "Postmortem on last night's crash spike affecting iPad split mode.", + owner: 'Jordan Lee', + updated: 'Updated 10 minutes ago', + accent: '#FF453A', + tagline: 'Root cause draft due by end of day.', + notes: 'Correlate analytics events with OS version and displayMode usage. Reproduce with toolbox sample and capture sysdiagnose on iOS 17.5. Prepare a rollback plan for the converter change if needed.', + actions: ['Add unit coverage around displayMode parsing for legacy values.', 'Record steps to reproduce on iPad mini + Stage Manager.', 'Compile candidate patch and run smoke on device farm.'], + highlights: [ + { label: 'Focus', value: 'Stability + Parsing' }, + { label: 'Next Check-in', value: 'Eng sync at 4:00 PM' }, + ], + metrics: [ + { label: 'Priority', value: 'Critical' }, + { label: 'Delivery', value: 'Postmortem' }, + { label: 'Attachments', value: '3 logs' }, + { label: 'Watchers', value: '8 people' }, + ], + contributors: ['Jordan', 'Avery', 'Mina'], + tags: ['Stability', 'iOS', 'SplitView'], + }, +]; + export function navigatingTo(args: EventData) { page = args.object; page.bindingContext = new SplitViewPrimaryModel(); } export class SplitViewPrimaryModel extends Observable { - items: string[] = []; + briefs: SplitViewBrief[] = briefData; constructor() { super(); - this.items = Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`); + broadcastSelection(this.briefs[0]); } onItemTap(args: ItemEventData) { - console.log('args.index', args.index); + const selectedBrief = this.briefs[args.index]; SplitView.getInstance()?.showSecondary(); - getItemCallbacks().forEach((callback) => callback(this.items[args.index])); + broadcastSelection(selectedBrief); } } diff --git a/apps/toolbox/src/split-view/split-view-primary.xml b/apps/toolbox/src/split-view/split-view-primary.xml index 915ff7e692..400da454ea 100644 --- a/apps/toolbox/src/split-view/split-view-primary.xml +++ b/apps/toolbox/src/split-view/split-view-primary.xml @@ -1,16 +1,24 @@ - - + + - - - - + - - - - \ No newline at end of file + diff --git a/apps/toolbox/src/split-view/split-view-root.ts b/apps/toolbox/src/split-view/split-view-root.ts index 9cb11fce71..ecfe15fe15 100644 --- a/apps/toolbox/src/split-view/split-view-root.ts +++ b/apps/toolbox/src/split-view/split-view-root.ts @@ -1,4 +1,23 @@ import { Observable, EventData, Page } from '@nativescript/core'; + +export interface SplitViewBrief { + id: string; + title: string; + category: string; + status: string; + summary: string; + owner: string; + updated: string; + accent: string; + tagline: string; + notes: string; + actions: string[]; + highlights: Array<{ label: string; value: string }>; + metrics: Array<{ label: string; value: string }>; + contributors: string[]; + tags: string[]; +} + let page: Page; export function navigatingTo(args: EventData) { @@ -8,10 +27,23 @@ export function navigatingTo(args: EventData) { export class SplitViewModel extends Observable {} -let itemCallbacks: Array<(item: any) => void> = []; -export function setItemCallbacks(changeItem: Array<(item: any) => void>) { - itemCallbacks.push(...changeItem); +type SelectionCallback = (item: SplitViewBrief) => void; + +let itemCallbacks: SelectionCallback[] = []; +let hasSelection = false; +let latestSelection: SplitViewBrief; + +export function setItemCallbacks(changeItem: SelectionCallback[]) { + changeItem.forEach((callback) => { + itemCallbacks.push(callback); + if (hasSelection) { + callback(latestSelection); + } + }); } -export function getItemCallbacks() { - return itemCallbacks; + +export function broadcastSelection(item: SplitViewBrief) { + latestSelection = item; + hasSelection = true; + itemCallbacks.forEach((callback) => callback(item)); } diff --git a/apps/toolbox/src/split-view/split-view-root.xml b/apps/toolbox/src/split-view/split-view-root.xml index 02d1ae3da9..887c7b6308 100644 --- a/apps/toolbox/src/split-view/split-view-root.xml +++ b/apps/toolbox/src/split-view/split-view-root.xml @@ -1,19 +1,16 @@ - - + - + - + - + - + - - - - - - - \ No newline at end of file + diff --git a/apps/toolbox/src/split-view/split-view-secondary.ts b/apps/toolbox/src/split-view/split-view-secondary.ts index cb0a624182..a2396f3a1a 100644 --- a/apps/toolbox/src/split-view/split-view-secondary.ts +++ b/apps/toolbox/src/split-view/split-view-secondary.ts @@ -1,5 +1,5 @@ import { Observable, EventData, Page, SplitView } from '@nativescript/core'; -import { setItemCallbacks } from './split-view-root'; +import { SplitViewBrief, setItemCallbacks } from './split-view-root'; let page: Page; export function navigatingTo(args: EventData) { @@ -8,7 +8,7 @@ export function navigatingTo(args: EventData) { } export class SplitViewSecondaryModel extends Observable { - selectedItem = `Select an item from Primary.`; + selectedBrief: SplitViewBrief | null = null; showInspectorButton = false; constructor() { @@ -28,8 +28,8 @@ export class SplitViewSecondaryModel extends Observable { SplitView.getInstance()?.showInspector(); } - changeItem(item: any) { - this.selectedItem = item; - this.notifyPropertyChange('selectedItem', item); + changeItem(item: SplitViewBrief) { + this.selectedBrief = item; + this.notifyPropertyChange('selectedBrief', item); } } diff --git a/apps/toolbox/src/split-view/split-view-secondary.xml b/apps/toolbox/src/split-view/split-view-secondary.xml index 75328de39f..19a93cf339 100644 --- a/apps/toolbox/src/split-view/split-view-secondary.xml +++ b/apps/toolbox/src/split-view/split-view-secondary.xml @@ -1,11 +1,33 @@ - - - - - - - \ No newline at end of file + + + + +