11import type { RefObject } from "react" ;
22
33import type { SimulatorMetadata } from "../../api/types" ;
4+ import type {
5+ StreamConfig ,
6+ StreamEncoder ,
7+ StreamFps ,
8+ StreamQualityPreset ,
9+ } from "../stream/streamTypes" ;
410import { SimulatorRow } from "./SimulatorRow" ;
511
612interface SimulatorMenuProps {
@@ -16,13 +22,17 @@ interface SimulatorMenuProps {
1622 onOpenBundlePrompt : ( ) => void ;
1723 onOpenUrlPrompt : ( ) => void ;
1824 onRotateLeft : ( ) => void ;
25+ onStreamEncoderChange : ( encoder : StreamEncoder ) => void ;
26+ onStreamFpsChange : ( fps : StreamFps ) => void ;
27+ onStreamQualityChange : ( quality : StreamQualityPreset ) => void ;
1928 onToggleAppearance : ( ) => void ;
2029 onToggleDebug : ( ) => void ;
2130 onToggleMenu : ( ) => void ;
2231 onToggleTouchOverlay : ( ) => void ;
2332 search : string ;
2433 selectedSimulator : SimulatorMetadata | null ;
2534 setSelectedUDID : ( udid : string ) => void ;
35+ streamConfig : StreamConfig ;
2636 touchOverlayVisible : boolean ;
2737}
2838
@@ -39,13 +49,17 @@ export function SimulatorMenu({
3949 onOpenBundlePrompt,
4050 onOpenUrlPrompt,
4151 onRotateLeft,
52+ onStreamEncoderChange,
53+ onStreamFpsChange,
54+ onStreamQualityChange,
4255 onToggleAppearance,
4356 onToggleDebug,
4457 onToggleMenu,
4558 onToggleTouchOverlay,
4659 search,
4760 selectedSimulator,
4861 setSelectedUDID,
62+ streamConfig,
4963 touchOverlayVisible,
5064} : SimulatorMenuProps ) {
5165 return (
@@ -94,6 +108,46 @@ export function SimulatorMenu({
94108 ) : null }
95109 { selectedSimulator ? (
96110 < >
111+ < div className = "menu-divider" />
112+ < div className = "menu-section" >
113+ < span className = "menu-section-title" > Stream</ span >
114+ < div aria-label = "Encoder" className = "menu-segment two" >
115+ { STREAM_ENCODERS . map ( ( option ) => (
116+ < button
117+ className = { `menu-option ${ streamConfig . encoder === option . value ? "active" : "" } ` }
118+ key = { option . value }
119+ onClick = { ( ) => onStreamEncoderChange ( option . value ) }
120+ type = "button"
121+ >
122+ { option . label }
123+ </ button >
124+ ) ) }
125+ </ div >
126+ < div aria-label = "Frame rate" className = "menu-segment" >
127+ { STREAM_FPS_OPTIONS . map ( ( option ) => (
128+ < button
129+ className = { `menu-option ${ streamConfig . fps === option . value ? "active" : "" } ` }
130+ key = { option . value }
131+ onClick = { ( ) => onStreamFpsChange ( option . value ) }
132+ type = "button"
133+ >
134+ { option . label }
135+ </ button >
136+ ) ) }
137+ </ div >
138+ < div aria-label = "Quality" className = "menu-segment" >
139+ { STREAM_QUALITY_OPTIONS . map ( ( option ) => (
140+ < button
141+ className = { `menu-option ${ streamConfig . quality === option . value ? "active" : "" } ` }
142+ key = { option . value }
143+ onClick = { ( ) => onStreamQualityChange ( option . value ) }
144+ type = "button"
145+ >
146+ { option . label }
147+ </ button >
148+ ) ) }
149+ </ div >
150+ </ div >
97151 < div className = "menu-divider" />
98152 < div className = "menu-actions" >
99153 < button className = "menu-action" onClick = { onOpenUrlPrompt } >
@@ -148,6 +202,26 @@ export function SimulatorMenu({
148202 ) ;
149203}
150204
205+ const STREAM_ENCODERS : Array < { label : string ; value : StreamEncoder } > = [
206+ { label : "Hardware" , value : "hardware" } ,
207+ { label : "Software" , value : "software" } ,
208+ ] ;
209+
210+ const STREAM_FPS_OPTIONS : Array < { label : string ; value : StreamFps } > = [
211+ { label : "30" , value : 30 } ,
212+ { label : "60" , value : 60 } ,
213+ { label : "120" , value : 120 } ,
214+ ] ;
215+
216+ const STREAM_QUALITY_OPTIONS : Array < {
217+ label : string ;
218+ value : StreamQualityPreset ;
219+ } > = [
220+ { label : "Quality" , value : "quality" } ,
221+ { label : "Balanced" , value : "balanced" } ,
222+ { label : "Fast" , value : "fast" } ,
223+ ] ;
224+
151225function MenuIcon ( ) {
152226 return (
153227 < svg fill = "currentColor" height = "16" viewBox = "0 0 16 16" width = "16" >
0 commit comments