44 Group ,
55 HStack ,
66 Image ,
7- List ,
87 NavigationStack ,
98 Section ,
109 Script ,
@@ -63,7 +62,12 @@ const TAB_FAVORITES = 0
6362const TAB_CLIPS = 1
6463const TAB_SETTINGS = 2
6564const APP_GROUP_PAGE_SIZE = 300
65+ const TOAST_DURATION_MS = 1200
6666const CAIS_APP_RESUME_HANDLER = "__CAIS_APP_RESUME_HANDLER__"
67+ const APP_SCROLL_CONTENT_MARGINS = {
68+ insets : { top : 0 , bottom : 0 , leading : 0 , trailing : 0 } ,
69+ placement : "scrollContent" as const ,
70+ }
6771type ClearScope = "favorites" | ClipboardClearRange
6872let intentionalMinimize = false
6973let appRefreshGeneration = 0
@@ -192,6 +196,7 @@ export function AppRoot() {
192196 const settingsRef = useRef ( settings )
193197 const queryRef = useRef ( query )
194198 const lastObservedPasteboardChangeCount = useRef < number | null > ( null )
199+ const toastHideTimer = useRef < any > ( null )
195200 const [ appFullscreen , setAppFullscreen ] = useState ( ( ) => readAppFullscreen ( false ) )
196201 const [ loading , setLoading ] = useState ( false )
197202 const [ toastMessage , setToastMessage ] = useState ( "" )
@@ -233,6 +238,7 @@ export function AppRoot() {
233238 delete ( globalThis as any ) [ CAIS_APP_RESUME_HANDLER ]
234239 }
235240 removeMinimize ?.( )
241+ clearToastHideTimer ( )
236242 stopPipMonitor ( )
237243 }
238244 } , [ ] )
@@ -386,19 +392,31 @@ export function AppRoot() {
386392 void refresh ( true , next )
387393 }
388394
395+ function clearToastHideTimer ( ) {
396+ if ( toastHideTimer . current ) {
397+ ; ( globalThis as any ) . clearTimeout ?.( toastHideTimer . current )
398+ toastHideTimer . current = null
399+ }
400+ }
401+
389402 function showToast ( message : string ) {
403+ clearToastHideTimer ( )
390404 setToastMessage ( message )
391405 toastPresented . setValue ( false )
392406 ; ( globalThis as any ) . setTimeout ?.( ( ) => {
393407 toastPresented . setValue ( true )
394408 } , 0 )
409+ toastHideTimer . current = ( globalThis as any ) . setTimeout ?.( ( ) => {
410+ toastPresented . setValue ( false )
411+ toastHideTimer . current = null
412+ } , TOAST_DURATION_MS )
395413 }
396414
397415 function toastOptions ( ) {
398416 return {
399417 isPresented : toastPresented ,
400418 message : toastMessage ,
401- duration : 1.2 ,
419+ duration : TOAST_DURATION_MS / 1000 ,
402420 position : "bottom" as any ,
403421 }
404422 }
@@ -933,6 +951,9 @@ export function AppRoot() {
933951 < VStack
934952 frame = { { maxWidth : "infinity" , alignment : "topLeading" as any } }
935953 padding = { { top : 10 , bottom : 6 , leading : 16 , trailing : 16 } }
954+ listRowInsets = { { top : 0 , bottom : 0 , leading : 0 , trailing : 0 } }
955+ listRowSeparator = "hidden"
956+ listRowBackground = { < EmptyView /> }
936957 >
937958 < VStack
938959 frame = { { maxWidth : "infinity" , alignment : "leading" as any } }
@@ -951,6 +972,9 @@ export function AppRoot() {
951972 < VStack
952973 frame = { { maxWidth : "infinity" , alignment : "topLeading" as any } }
953974 padding = { { top : 10 , bottom : 6 , leading : 16 , trailing : 16 } }
975+ listRowInsets = { { top : 0 , bottom : 0 , leading : 0 , trailing : 0 } }
976+ listRowSeparator = "hidden"
977+ listRowBackground = { < EmptyView /> }
954978 >
955979 < VStack
956980 spacing = { 8 }
@@ -998,52 +1022,38 @@ export function AppRoot() {
9981022 >
9991023 < Tab title = "收藏" systemImage = "star" value = { TAB_FAVORITES } >
10001024 < NavigationStack >
1001- < VStack
1002- frame = { { maxWidth : "infinity" , maxHeight : "infinity" , alignment : "top" as any } }
1003- background = "systemGroupedBackground"
1004- ignoresSafeArea = { { regions : "keyboard" , edges : "bottom" } }
1025+ < Form
1026+ formStyle = "grouped"
1027+ listRowSpacing = { 10 }
1028+ contentMargins = { APP_SCROLL_CONTENT_MARGINS }
1029+ frame = { { maxWidth : "infinity" , maxHeight : "infinity" } }
10051030 toolbar = { { topBarLeading : toolbarLeading ( ) , topBarTrailing : favoriteToolbarButtons ( ) } }
10061031 toast = { toastOptions ( ) }
10071032 >
10081033 { searchPanel ( ) }
1009- < List
1010- listStyle = "plain"
1011- scrollContentBackground = "hidden"
1012- listRowSpacing = { 10 }
1013- background = "systemGroupedBackground"
1014- frame = { { maxWidth : "infinity" , maxHeight : "infinity" } }
1015- >
1016- { renderGroupedClipList ( favoriteGroups , query . trim ( ) ? "没有匹配的收藏内容。" : "点击右上角添加常用语,或右滑剪贴板条目点星标。" ) }
1017- </ List >
1018- </ VStack >
1034+ { renderGroupedClipList ( favoriteGroups , query . trim ( ) ? "没有匹配的收藏内容。" : "点击右上角添加常用语,或右滑剪贴板条目点星标。" ) }
1035+ </ Form >
10191036 </ NavigationStack >
10201037 </ Tab >
10211038
10221039 < Tab title = "剪贴板" systemImage = "doc.on.clipboard" value = { TAB_CLIPS } >
10231040 < NavigationStack >
1024- < VStack
1025- frame = { { maxWidth : "infinity" , maxHeight : "infinity" , alignment : "top" as any } }
1026- background = "systemGroupedBackground"
1027- ignoresSafeArea = { { regions : "keyboard" , edges : "bottom" } }
1041+ < Form
1042+ formStyle = "grouped"
1043+ listRowSpacing = { 10 }
1044+ contentMargins = { APP_SCROLL_CONTENT_MARGINS }
1045+ frame = { { maxWidth : "infinity" , maxHeight : "infinity" } }
10281046 toolbar = { { topBarLeading : toolbarLeading ( ) , topBarTrailing : clipToolbarButtons ( ) } }
10291047 toast = { toastOptions ( ) }
10301048 >
10311049 { pipControlPanel ( ) }
10321050 { searchPanel ( ) }
1033- < List
1034- listStyle = "plain"
1035- scrollContentBackground = "hidden"
1036- listRowSpacing = { 10 }
1037- background = "systemGroupedBackground"
1038- frame = { { maxWidth : "infinity" , maxHeight : "infinity" } }
1039- >
1040- { renderGroupedClipList (
1041- clipboardGroups ,
1042- query . trim ( ) ? "没有匹配的剪贴板内容。" : "点击右上角采集按钮,或开启 PiP 监听。" ,
1043- { allowDelete : ( item ) => ! item . manualFavorite }
1044- ) }
1045- </ List >
1046- </ VStack >
1051+ { renderGroupedClipList (
1052+ clipboardGroups ,
1053+ query . trim ( ) ? "没有匹配的剪贴板内容。" : "点击右上角采集按钮,或开启 PiP 监听。" ,
1054+ { allowDelete : ( item ) => ! item . manualFavorite }
1055+ ) }
1056+ </ Form >
10471057 </ NavigationStack >
10481058 </ Tab >
10491059
0 commit comments