@@ -15,13 +15,15 @@ import { useStateManager } from '../../../../stores/StateManager/StateManager.js
1515import './MissionControlUI.css' ;
1616import MissionManager from '../MissionManager/MissionManager.jsx' ;
1717
18- const FADE_DURATION = 300 ; // CSS fade timing (ms)
19- const SLIDE_DURATION = 300 ; // overview slide timing (ms)
20- const OPEN_DELAY = 200 ; // delay before fade (ms)
18+ const FADE_DURATION = 300 ; // CSS fade timing (ms)
19+ const SLIDE_DURATION = 300 ; // overview slide timing (ms)
20+ const OPEN_DELAY = 200 ; // delay before fade (ms)
21+ // must match your CSS --desktop-slide-duration: 0.55s
22+ const DESKTOP_SLIDE_DURATION = 550 ; // ms
2123
2224// Hint / touch config
2325const EDGE_THRESHOLD = 20 ; // px from either edge to trigger
24- const HOVER_DELAY = 200 ; // ms to hold before hint (1 s)
26+ const HOVER_DELAY = 200 ; // ms to hold before hint / touch‐hold
2527const TOUCH_HINT_OFFSET = 30 ; // px touch‐hold peek
2628const MOUSE_HINT_OFFSET = 10 ; // px hover peek
2729const HINT_SLIDE_DURATION = 200 ; // ms for hover‐hint ease
@@ -31,12 +33,57 @@ const DESKTOP_SPACING = 60; // px extra between desktops
3133const MissionControlUI = ( ) => {
3234 // —— Context & stores ——
3335 const {
34- createDesktop, addDesktop, switchDesktop,
35- deleteDesktop, reorderDesktops,
36- activeIndex, desktops
36+ createDesktop,
37+ addDesktop,
38+ switchDesktop : rawSwitchDesktop ,
39+ deleteDesktop : contextDeleteDesktop ,
40+ reorderDesktops,
41+ activeIndex,
42+ desktops
3743 } = useContext ( MissionControlContext ) ;
38- const { state, addState, editStateValue } = useStateManager ( ) ;
44+ const { state, editStateValue } = useStateManager ( ) ;
45+
3946 const overlayVisible = state . groups . missionControl ?. overlayVisible === 'true' ;
47+ const stateOpened = state . groups . missionControl ?. isOpened === 'true' ;
48+
49+ // —— Initialize currentDesktopID on mount (runs exactly once) ——
50+ useEffect ( ( ) => {
51+ const desktop = desktops [ activeIndex ] ;
52+ if ( desktop ?. id != null ) {
53+ editStateValue (
54+ 'missionControl' ,
55+ 'currentDesktopID' ,
56+ String ( desktop . id )
57+ ) ;
58+ }
59+ // only on mount:
60+ // eslint-disable-next-line react-hooks/exhaustive-deps
61+ } , [ ] ) ;
62+
63+ // —— Wrap switchDesktop so it also writes currentDesktopID when the user actually switches ——
64+ const switchDesktop = useCallback ( ( i ) => {
65+ rawSwitchDesktop ( i ) ;
66+ const desktop = desktops [ i ] ;
67+ if ( desktop ?. id != null ) {
68+ editStateValue (
69+ 'missionControl' ,
70+ 'currentDesktopID' ,
71+ String ( desktop . id )
72+ ) ;
73+ }
74+ } , [ rawSwitchDesktop , desktops , editStateValue ] ) ;
75+
76+ // Keep activeIndex valid after delete
77+ const handleDeleteDesktop = useCallback ( ( index ) => {
78+ contextDeleteDesktop ( index ) ;
79+ let newIndex = activeIndex ;
80+ if ( index === activeIndex ) {
81+ newIndex = index > 0 ? index - 1 : 0 ;
82+ } else if ( index < activeIndex ) {
83+ newIndex = activeIndex - 1 ;
84+ }
85+ switchDesktop ( newIndex ) ;
86+ } , [ contextDeleteDesktop , switchDesktop , activeIndex ] ) ;
4087
4188 // —— Wallpaper / portal readiness ——
4289 const [ showWallpaperPlaceholder , setShowWallpaperPlaceholder ] = useState ( false ) ;
@@ -51,14 +98,14 @@ const MissionControlUI = () => {
5198 const hintTimerRef = useRef ( null ) ;
5299 const hoverSideRef = useRef ( null ) ;
53100
54- // —— Touch- drag state ——
101+ // —— Touch‐ drag state ——
55102 const [ touching , setTouching ] = useState ( false ) ;
56103 const [ touchDelta , setTouchDelta ] = useState ( 0 ) ;
57104 const touchStartRef = useRef ( { timer : null , active : false , x0 : 0 , initialOffset : 0 } ) ;
105+ const initialDragRef = useRef ( false ) ;
58106
59107 // —— One-time initial-drag easing ——
60108 const [ dragTransition , setDragTransition ] = useState ( false ) ;
61- const initialDragRef = useRef ( false ) ;
62109
63110 // —— Release animations ——
64111 const [ releaseInProgress , setReleaseInProgress ] = useState ( false ) ;
@@ -78,6 +125,12 @@ const MissionControlUI = () => {
78125 const [ barExpanded , setBarExpanded ] = useState ( false ) ;
79126 const [ prevIndex , setPrevIndex ] = useState ( 0 ) ;
80127
128+ // instant switch (no transition)
129+ const instantSwitchDesktop = useCallback ( i => {
130+ setDisableSlideTransition ( true ) ;
131+ switchDesktop ( i ) ;
132+ } , [ switchDesktop ] ) ;
133+
81134 // —— Sync portalReady on desktop changes ——
82135 useEffect ( ( ) => {
83136 const prev = prevDesktopsRef . current ;
@@ -111,29 +164,9 @@ const MissionControlUI = () => {
111164 }
112165 } ) ;
113166
114- // —— Manage 'opened' flag in stateManager ——
115- useEffect ( ( ) => {
116- if ( ! state . groups . missionControl . hasOwnProperty ( 'opened' ) ) {
117- addState ( 'missionControl' , 'opened' , 'false' ) ;
118- }
119- } , [ addState , state . groups . missionControl ] ) ;
120-
121- // —— Clear lingering 'opened' on first mount ——
122- const initialMount = useRef ( true ) ;
123- useEffect ( ( ) => {
124- if ( ! initialMount . current ) return ;
125- initialMount . current = false ;
126- if ( state . groups . missionControl . opened === 'true' ) {
127- editStateValue ( 'desktop' , 'iconVisible' , 'true' ) ;
128- editStateValue ( 'desktop' , 'menubarVisible' , 'true' ) ;
129- editStateValue ( 'missionControl' , 'opened' , 'false' ) ;
130- }
131- } , [ ] ) ;
132-
133- // —— Track viewport resize & disable transition on orientation change ——
167+ // —— Track viewport resize & orientation change ——
134168 useEffect ( ( ) => {
135169 const handleResize = ( ) => {
136- // disable the smooth slide one tick
137170 setDisableSlideTransition ( true ) ;
138171 setViewport ( { width : window . innerWidth , height : window . innerHeight } ) ;
139172 } ;
@@ -145,7 +178,7 @@ const MissionControlUI = () => {
145178 } ;
146179 } , [ ] ) ;
147180
148- // —— Reset transition disabling immediately after render ——
181+ // —— Reset transition disabling after one render ——
149182 useEffect ( ( ) => {
150183 if ( ! disableSlideTransition ) return ;
151184 const t = setTimeout ( ( ) => setDisableSlideTransition ( false ) , 0 ) ;
@@ -165,12 +198,14 @@ const MissionControlUI = () => {
165198
166199 if ( atRight && hoverSideRef . current !== 'right' ) {
167200 clearTimeout ( hintTimerRef . current ) ;
168- setShowLeftHint ( false ) ; setShowRightHint ( false ) ;
201+ setShowLeftHint ( false ) ;
202+ setShowRightHint ( false ) ;
169203 hoverSideRef . current = 'right' ;
170204 hintTimerRef . current = setTimeout ( ( ) => setShowRightHint ( true ) , HOVER_DELAY ) ;
171205 } else if ( atLeft && hoverSideRef . current !== 'left' ) {
172206 clearTimeout ( hintTimerRef . current ) ;
173- setShowRightHint ( false ) ; setShowLeftHint ( false ) ;
207+ setShowRightHint ( false ) ;
208+ setShowLeftHint ( false ) ;
174209 hoverSideRef . current = 'left' ;
175210 hintTimerRef . current = setTimeout ( ( ) => setShowLeftHint ( true ) , HOVER_DELAY ) ;
176211 } else if ( ! atRight && ! atLeft && hoverSideRef . current ) {
@@ -206,7 +241,7 @@ const MissionControlUI = () => {
206241 return ( ) => window . removeEventListener ( 'click' , onClick ) ;
207242 } , [ showRightHint , showLeftHint , viewport . width , activeIndex , switchDesktop ] ) ;
208243
209- // —— Touch‐hold + draggable swipe ——
244+ // —— Touch‐hold + draggable swipe (copied verbatim) ——
210245 useEffect ( ( ) => {
211246 if ( overviewOpen ) return ;
212247 const canRight = desktops . length > activeIndex + 1 ;
@@ -257,7 +292,7 @@ const MissionControlUI = () => {
257292 if ( hoverSideRef . current === 'right' ) {
258293 newDelta = Math . max ( newDelta , - slideAmount ) ;
259294 } else {
260- newDelta = Math . min ( newDelta , slideAmount ) ;
295+ newDelta = Math . min ( newDelta , slideAmount ) ;
261296 }
262297
263298 setTouchDelta ( newDelta ) ;
@@ -285,7 +320,7 @@ const MissionControlUI = () => {
285320 const threshold = viewport . width / 6 ;
286321 const willSwitch =
287322 ( hoverSideRef . current === 'right' && finalDx < - threshold ) ||
288- ( hoverSideRef . current === 'left' && finalDx > threshold ) ;
323+ ( hoverSideRef . current === 'left' && finalDx > threshold ) ;
289324
290325 if ( willSwitch ) {
291326 const nextIdx = activeIndex + ( finalDx < 0 ? 1 : - 1 ) ;
@@ -352,42 +387,56 @@ const MissionControlUI = () => {
352387 const t = setTimeout ( ( ) => {
353388 editStateValue ( 'desktop' , 'iconVisible' , 'false' ) ;
354389 editStateValue ( 'desktop' , 'menubarVisible' , 'false' ) ;
355- editStateValue ( 'missionControl' , 'opened' , 'true' ) ;
356390 setIsFading ( true ) ;
357391 } , OPEN_DELAY ) ;
358392 return ( ) => clearTimeout ( t ) ;
359393 } , [ activeIndex , editStateValue ] ) ;
360394
361- const instantSwitchDesktop = useCallback ( i => {
362- setDisableSlideTransition ( true ) ;
363- switchDesktop ( i ) ;
364- } , [ switchDesktop ] ) ;
365-
366395 const exitOverview = useCallback ( ( restore = true ) => {
367- setShowWallpaperPlaceholder ( false ) ;
368396 setOverviewOpen ( false ) ;
369397 setIsFading ( false ) ;
370398 setBarExpanded ( false ) ;
371- if ( state . groups . missionControl . opened === 'true' ) {
372- editStateValue ( 'desktop' , 'iconVisible' , 'true' ) ;
373- editStateValue ( 'desktop' , 'menubarVisible' , 'true' ) ;
374- editStateValue ( 'missionControl' , 'opened' , 'false' ) ;
399+ editStateValue ( 'desktop' , 'iconVisible' , 'true' ) ;
400+ editStateValue ( 'desktop' , 'menubarVisible' , 'true' ) ;
401+ editStateValue ( 'missionControl' , 'isOpened' , 'false' ) ;
402+
403+ if ( restore ) {
404+ setDisableSlideTransition ( false ) ;
405+ switchDesktop ( prevIndex ) ;
406+ setTimeout ( ( ) => {
407+ setShowWallpaperPlaceholder ( false ) ;
408+ } , DESKTOP_SLIDE_DURATION ) ;
409+ } else {
410+ setShowWallpaperPlaceholder ( false ) ;
375411 }
376- if ( restore ) instantSwitchDesktop ( prevIndex ) ;
377- } , [ prevIndex , editStateValue , state . groups . missionControl . opened , instantSwitchDesktop ] ) ;
412+ } , [ prevIndex , editStateValue , switchDesktop ] ) ;
413+
414+ // —— Click handler for the UI button ——
415+ const handleOpenClick = useCallback ( ( ) => {
416+ editStateValue ( 'missionControl' , 'isOpened' , 'true' ) ;
417+ openOverview ( ) ;
418+ } , [ editStateValue , openOverview ] ) ;
419+
420+ // —— External open/close triggers ——
421+ useEffect ( ( ) => {
422+ if ( stateOpened && ! overviewOpen ) openOverview ( ) ;
423+ } , [ stateOpened , overviewOpen , openOverview ] ) ;
424+ useEffect ( ( ) => {
425+ if ( ! stateOpened && overviewOpen ) exitOverview ( ) ;
426+ } , [ stateOpened , overviewOpen , exitOverview ] ) ;
378427
379- // —— Drag- drop reorder ——
380- const onDragStart = useCallback ( ( e , i ) => {
428+ // —— Drag‐ drop reorder ——
429+ const onDragStart = useCallback ( ( e , i ) => {
381430 e . dataTransfer . setData ( 'text/plain' , String ( i ) ) ;
382431 } , [ ] ) ;
383- const onDragOver = useCallback ( e => {
432+ const onDragOver = useCallback ( e => {
384433 e . preventDefault ( ) ;
385434 e . dataTransfer . dropEffect = 'move' ;
386435 } , [ ] ) ;
387- const onDrop = useCallback ( ( e , to ) => {
436+ const onDrop = useCallback ( ( e , to ) => {
388437 e . preventDefault ( ) ;
389- const from = parseInt ( e . dataTransfer . getData ( 'text/plain' ) , 10 ) ;
390- if ( ! isNaN ( from ) && from !== to ) reorderDesktops ( from , to ) ;
438+ const from = parseInt ( e . dataTransfer . getData ( 'text/plain' ) , 10 ) ;
439+ if ( ! isNaN ( from ) && from !== to ) reorderDesktops ( from , to ) ;
391440 } , [ reorderDesktops ] ) ;
392441
393442 // —— Compute wrapper transform & style ——
@@ -457,10 +506,10 @@ const MissionControlUI = () => {
457506 disabled = { desktops . length === 1 }
458507 > Next ›</ button >
459508 < button
460- onClick = { ( ) => deleteDesktop ( activeIndex ) }
509+ onClick = { ( ) => handleDeleteDesktop ( activeIndex ) }
461510 disabled = { desktops . length === 1 }
462511 > 🗑 Delete</ button >
463- < button onClick = { openOverview } > Mission Control</ button >
512+ < button onClick = { handleOpenClick } > Mission Control</ button >
464513 </ div >
465514 ) }
466515
@@ -481,7 +530,7 @@ const MissionControlUI = () => {
481530 onDrop = { onDrop }
482531 viewport = { viewport }
483532 createDesktop = { addDesktop }
484- deleteDesktop = { deleteDesktop }
533+ deleteDesktop = { handleDeleteDesktop }
485534 />
486535 </ div >
487536 ) ;
0 commit comments