@@ -48,6 +48,10 @@ const WAVEFORM_ROWS = 5
4848const WAVEFORM_CELL_SIZE = 8
4949const WAVEFORM_CELL_GAP = 2
5050const DROPDOWN_VISIBLE_ROWS = 6
51+ const DROPDOWN_ROW_HEIGHT = 42
52+ const SERVER_MENU_SECTION_HEIGHT = 56
53+ const SERVER_MENU_ENTRY_HEIGHT = 36
54+ const SERVER_MENU_FOOTER_HEIGHT = 28
5155// If the press duration is shorter than this, treat it as a tap (toggle)
5256const TAP_THRESHOLD_MS = 300
5357const SERVER_STATE_FILE = `${ FileSystem . documentDirectory } mobile-voice-servers.json`
@@ -591,6 +595,10 @@ export default function DictationScreen() {
591595 const [ readerModeRendered , setReaderModeRendered ] = useState ( false )
592596 const [ dropdownMode , setDropdownMode ] = useState < DropdownMode > ( "none" )
593597 const [ dropdownRenderMode , setDropdownRenderMode ] = useState < Exclude < DropdownMode , "none" > > ( "server" )
598+ const [ serverMenuListHeight , setServerMenuListHeight ] = useState ( 0 )
599+ const [ sessionMenuListHeight , setSessionMenuListHeight ] = useState ( 0 )
600+ const [ serverMenuFooterHeight , setServerMenuFooterHeight ] = useState ( 0 )
601+ const [ sessionMenuFooterHeight , setSessionMenuFooterHeight ] = useState ( 0 )
594602 const [ sessionCreateMode , setSessionCreateMode ] = useState < "same" | "root" | null > ( null )
595603 const [ scanOpen , setScanOpen ] = useState ( false )
596604 const [ pairSelectionOpen , setPairSelectionOpen ] = useState ( false )
@@ -633,6 +641,8 @@ export default function DictationScreen() {
633641 setDropdownMode ( "none" )
634642 } , [ ] )
635643
644+ const discoveryEnabled = onboardingComplete && localNetworkPermissionState !== "denied" && dropdownMode === "server"
645+
636646 const {
637647 servers,
638648 serversRef,
@@ -655,7 +665,7 @@ export default function DictationScreen() {
655665
656666 const { discoveredServers, discoveryStatus, discoveryError, discoveryAvailable, refreshDiscovery } = useMdnsDiscovery (
657667 {
658- enabled : onboardingComplete && localNetworkPermissionState !== "denied" ,
668+ enabled : discoveryEnabled ,
659669 } ,
660670 )
661671
@@ -2000,17 +2010,29 @@ export default function DictationScreen() {
20002010 ] ,
20012011 } ) )
20022012
2003- const serverMenuRows = 2 + Math . max ( servers . length , 1 ) + Math . max ( discoveredServerOptions . length , 1 )
2004- const menuRows = effectiveDropdownMode === "server" ? serverMenuRows : Math . max ( activeServer ?. sessions . length ?? 0 , 1 )
2005- const expandedRowsHeight = Math . min ( menuRows , DROPDOWN_VISIBLE_ROWS ) * 42
2013+ const maxDropdownListHeight = DROPDOWN_VISIBLE_ROWS * DROPDOWN_ROW_HEIGHT
2014+ const serverMenuEntries = Math . max ( servers . length , 1 ) + Math . max ( discoveredServerOptions . length , 1 )
2015+ const estimatedServerMenuRowsHeight = Math . min (
2016+ SERVER_MENU_SECTION_HEIGHT + serverMenuEntries * SERVER_MENU_ENTRY_HEIGHT ,
2017+ maxDropdownListHeight ,
2018+ )
2019+ const sessionMenuRows = Math . max ( activeServer ?. sessions . length ?? 0 , 1 )
2020+ const estimatedSessionMenuRowsHeight = Math . min ( sessionMenuRows , DROPDOWN_VISIBLE_ROWS ) * DROPDOWN_ROW_HEIGHT
2021+ const serverMenuRowsHeight = Math . min ( serverMenuListHeight || estimatedServerMenuRowsHeight , maxDropdownListHeight )
2022+ const sessionMenuRowsHeight = Math . min ( sessionMenuListHeight || estimatedSessionMenuRowsHeight , maxDropdownListHeight )
2023+ const expandedRowsHeight = effectiveDropdownMode === "server" ? serverMenuRowsHeight : sessionMenuRowsHeight
2024+
2025+ const estimatedSessionFooterHeight = sessionCreationChoiceCount === 2 ? 72 : sessionCreationChoiceCount === 1 ? 38 : 8
2026+
2027+ const measuredServerFooterHeight = serverMenuFooterHeight || SERVER_MENU_FOOTER_HEIGHT
2028+ const measuredSessionFooterHeight = sessionMenuFooterHeight || estimatedSessionFooterHeight
2029+
20062030 const dropdownFooterExtraHeight =
20072031 effectiveDropdownMode === "server"
2008- ? 38
2009- : sessionCreationChoiceCount === 2
2010- ? 72
2011- : sessionCreationChoiceCount === 1
2012- ? 38
2013- : 8
2032+ ? measuredServerFooterHeight
2033+ : showSessionCreationChoices
2034+ ? measuredSessionFooterHeight
2035+ : 8
20142036 const expandedHeaderHeight = 51 + 12 + expandedRowsHeight + dropdownFooterExtraHeight
20152037
20162038 const animatedHeaderStyle = useAnimatedStyle ( ( ) => ( {
@@ -2104,6 +2126,26 @@ export default function DictationScreen() {
21042126 setWaveformLevels ( next )
21052127 } , [ ] )
21062128
2129+ const handleServerMenuListLayout = useCallback ( ( event : LayoutChangeEvent ) => {
2130+ const next = Math . ceil ( event . nativeEvent . layout . height )
2131+ setServerMenuListHeight ( ( prev ) => ( prev === next ? prev : next ) )
2132+ } , [ ] )
2133+
2134+ const handleSessionMenuListLayout = useCallback ( ( event : LayoutChangeEvent ) => {
2135+ const next = Math . ceil ( event . nativeEvent . layout . height )
2136+ setSessionMenuListHeight ( ( prev ) => ( prev === next ? prev : next ) )
2137+ } , [ ] )
2138+
2139+ const handleServerMenuFooterLayout = useCallback ( ( event : LayoutChangeEvent ) => {
2140+ const next = Math . ceil ( event . nativeEvent . layout . height )
2141+ setServerMenuFooterHeight ( ( prev ) => ( prev === next ? prev : next ) )
2142+ } , [ ] )
2143+
2144+ const handleSessionMenuFooterLayout = useCallback ( ( event : LayoutChangeEvent ) => {
2145+ const next = Math . ceil ( event . nativeEvent . layout . height )
2146+ setSessionMenuFooterHeight ( ( prev ) => ( prev === next ? prev : next ) )
2147+ } , [ ] )
2148+
21072149 const toggleServerMenu = useCallback ( ( ) => {
21082150 void Haptics . selectionAsync ( ) . catch ( ( ) => { } )
21092151 setDropdownMode ( ( prev ) => {
@@ -2764,7 +2806,7 @@ export default function DictationScreen() {
27642806 bounces = { false }
27652807 >
27662808 { effectiveDropdownMode === "server" ? (
2767- < >
2809+ < View onLayout = { handleServerMenuListLayout } >
27682810 < Text style = { styles . serverGroupLabel } > Saved:</ Text >
27692811
27702812 { servers . length === 0 ? (
@@ -2833,9 +2875,9 @@ export default function DictationScreen() {
28332875 { discoveryError }
28342876 </ Text >
28352877 ) : null }
2836- </ >
2878+ </ View >
28372879 ) : activeServer ? (
2838- < >
2880+ < View onLayout = { handleSessionMenuListLayout } >
28392881 { activeSession ? (
28402882 < >
28412883 < View style = { styles . currentSessionSummary } >
@@ -2890,18 +2932,20 @@ export default function DictationScreen() {
28902932 </ Pressable >
28912933 ) )
28922934 ) }
2893- </ >
2935+ </ View >
28942936 ) : (
28952937 < Text style = { styles . serverEmptyText } > Select a server first</ Text >
28962938 ) }
28972939 </ ScrollView >
28982940
28992941 { effectiveDropdownMode === "server" ? (
2900- < Pressable onPress = { ( ) => void handleStartScan ( ) } style = { styles . addServerButton } >
2901- < Text style = { styles . addServerButtonText } > Add server by scanning QR code</ Text >
2902- </ Pressable >
2942+ < View onLayout = { handleServerMenuFooterLayout } >
2943+ < Pressable onPress = { ( ) => void handleStartScan ( ) } style = { styles . addServerButton } >
2944+ < Text style = { styles . addServerButtonText } > Add server by scanning QR code</ Text >
2945+ </ Pressable >
2946+ </ View >
29032947 ) : effectiveDropdownMode === "session" && activeServer ?. status === "online" ? (
2904- < View style = { styles . sessionMenuActions } >
2948+ < View style = { styles . sessionMenuActions } onLayout = { handleSessionMenuFooterLayout } >
29052949 { activeSession ? (
29062950 < Pressable
29072951 onPress = { handleCreateSessionLikeCurrent }
@@ -3887,14 +3931,14 @@ const styles = StyleSheet.create({
38873931 } ,
38883932 serverMenuInline : {
38893933 marginTop : 8 ,
3890- paddingBottom : 8 ,
3934+ paddingBottom : 2 ,
38913935 gap : 4 ,
38923936 } ,
38933937 dropdownListViewport : {
3894- maxHeight : DROPDOWN_VISIBLE_ROWS * 42 ,
3938+ maxHeight : DROPDOWN_VISIBLE_ROWS * DROPDOWN_ROW_HEIGHT ,
38953939 } ,
38963940 dropdownListContent : {
3897- paddingBottom : 2 ,
3941+ paddingBottom : 0 ,
38983942 } ,
38993943 currentSessionSummary : {
39003944 paddingHorizontal : 4 ,
@@ -4026,10 +4070,11 @@ const styles = StyleSheet.create({
40264070 fontWeight : "700" ,
40274071 } ,
40284072 addServerButton : {
4029- marginTop : 10 ,
4073+ marginTop : 4 ,
40304074 alignSelf : "center" ,
40314075 paddingHorizontal : 8 ,
4032- paddingVertical : 6 ,
4076+ paddingTop : 2 ,
4077+ paddingBottom : 10 ,
40334078 } ,
40344079 addServerButtonText : {
40354080 color : "#B8BDC9" ,
0 commit comments