@@ -74,6 +74,7 @@ let saveTimeout;
7474let reload ;
7575let palettePicker ;
7676let pendingFile = null ;
77+ let navFullscreen ;
7778
7879const $$$$ = ( ) => {
7980 htmlDoc = $$ ( 'html' ) ;
@@ -101,6 +102,7 @@ const $$$$ = () => {
101102 metaTheme = $$ ( 'meta[name="theme-color"]' ) ;
102103 saveTimeout = null ;
103104 reload = $ ( 'updateReload' ) ;
105+ navFullscreen = $ ( 'fullscreen' ) ;
104106} ;
105107
106108const openHandler = file => {
@@ -164,9 +166,16 @@ const handleLaunchFiles = () => {
164166 const fileHandle = launchParams . files [ 0 ] ;
165167 try {
166168 const file = await fileHandle . getFile ( ) ;
167- console . log ( `[Launch] File queued: ${ file . name } (${ file . size } bytes)` ) ;
168- // Store the file to open after initialization
169- pendingFile = file ;
169+ // If app is already initialized, open immediately
170+ if (
171+ State . textArtCanvas &&
172+ ! bodyContainer ?. classList . contains ( 'loading' )
173+ ) {
174+ openHandler ( file ) ;
175+ } else {
176+ // Otherwise store for later
177+ pendingFile = file ;
178+ }
170179 } catch ( error ) {
171180 console . error ( '[App] Error reading launched file:' , error ) ;
172181 }
@@ -209,7 +218,23 @@ const save = () => {
209218 } , 300 ) ;
210219} ;
211220
212- const isIOS = ( ) => ( / i P a d | i P h o n e | i P o d / ) . test ( navigator . userAgent ) ;
221+ const isIOS = ( / i P a d | i P h o n e | i P o d / ) . test ( navigator . userAgent ) ;
222+
223+ const handleIOS = ( ) => {
224+ const isWindowed =
225+ window . navigator . standalone ||
226+ window . matchMedia ( '(display-mode: standalone)' ) . matches ||
227+ window . matchMedia ( '(display-mode: window-controls-overlay)' ) . matches ;
228+ const isMaximized =
229+ window . innerWidth >= window . screen . availWidth &&
230+ window . innerHeight >= window . screen . availHeight * 0.95 ;
231+ const isWebkitFullscreen = ! ! (
232+ document . webkitFullscreenElement || document . webkitCurrentFullScreenElement
233+ ) ;
234+ const needsPadding = isWebkitFullscreen || ( isWindowed && ! isMaximized ) ;
235+ htmlDoc . classList . toggle ( 'ios' , needsPadding ) ;
236+ navFullscreen . classList . toggle ( 'disabled' , isWindowed ) ;
237+ } ;
213238
214239document . addEventListener ( 'DOMContentLoaded' , async ( ) => {
215240 // Initialize service worker
@@ -230,6 +255,39 @@ document.addEventListener('DOMContentLoaded', async () => {
230255 } ;
231256 } ;
232257 } ) ;
258+
259+ // Listen for shared file messages from service worker
260+ navigator . serviceWorker . addEventListener ( 'message' , async event => {
261+ if ( event . data . type === 'SHARED_FILE_READY' ) {
262+ console . log ( '[Share] File shared:' , event . data . filename ) ;
263+ // Wait for app to be ready
264+ const waitForApp = ( ) => {
265+ return new Promise ( resolve => {
266+ if ( State . textArtCanvas && openHandler ) {
267+ resolve ( ) ;
268+ } else {
269+ setTimeout ( ( ) => waitForApp ( ) . then ( resolve ) , 100 ) ;
270+ }
271+ } ) ;
272+ } ;
273+ await waitForApp ( ) ;
274+ const sharedFileData = await handleFileShare ( ) ;
275+ if ( sharedFileData ) {
276+ pendingFile = sharedFileData . file ;
277+ openHandler ( pendingFile ) ;
278+ pendingFile = null ;
279+ // Clean up the cached file
280+ caches
281+ . open ( CACHE_ID )
282+ . then ( cache => cache . delete ( CACHE_DATA ) )
283+ . catch ( error =>
284+ console . error (
285+ '[Error] Failed to cleanup shared file cache:' ,
286+ error ,
287+ ) ) ;
288+ }
289+ }
290+ } ) ;
233291 }
234292
235293 try {
@@ -312,6 +370,16 @@ const initializeAppComponents = async () => {
312370 if ( ! pendingFile ) {
313371 State . restoreStateFromLocalStorage ( ) ;
314372 }
373+ // iOS quirks
374+ if ( isIOS ) {
375+ // Make file picker accept all files on iOS
376+ openFile . setAttribute ( 'accept' , '*/*' ) ;
377+ // track state to offset traffic lights
378+ handleIOS ( ) ;
379+ document . addEventListener ( 'webkitfullscreenchange' , handleIOS ) ;
380+ window . addEventListener ( 'resize' , handleIOS ) ;
381+ }
382+
315383 document . addEventListener ( 'keydown' , undoAndRedo ) ;
316384 createResolutionController (
317385 $ ( 'resolutionLabel' ) ,
@@ -404,11 +472,6 @@ const initializeAppComponents = async () => {
404472 onFileChange ( openFile , openHandler ) ;
405473 createDragDropController ( openHandler , $ ( 'dragdrop' ) ) ;
406474
407- if ( isIOS ( ) ) {
408- // Make file picker accept all files on iOS
409- openFile . setAttribute ( 'accept' , '*/*' ) ;
410- }
411-
412475 onClick ( navSauce , ( ) => {
413476 State . menus . close ( ) ;
414477 State . modal . open ( 'sauce' ) ;
@@ -500,7 +563,7 @@ const initializeAppComponents = async () => {
500563 onClick ( $ ( 'eraseColumn' ) , keyboard . eraseColumn ) ;
501564 onClick ( $ ( 'eraseColumnStart' ) , keyboard . eraseToStartOfColumn ) ;
502565 onClick ( $ ( 'eraseColumnEnd' ) , keyboard . eraseToEndOfColumn ) ;
503- onClick ( $ ( 'fullscreen' ) , toggleFullscreen ) ;
566+ onClick ( navFullscreen , toggleFullscreen ) ;
504567
505568 onClick ( $ ( 'defaultColor' ) , ( ) => {
506569 State . palette . setForegroundColor ( 7 ) ;
@@ -827,25 +890,28 @@ const initializeAppComponents = async () => {
827890 document . addEventListener ( 'onIceColorsChange' , save ) ;
828891 document . addEventListener ( 'onOpenedFile' , save ) ;
829892
830- // Handle pending launched file
893+ // Handle pending launchQueue file
831894 if ( pendingFile ) {
832- console . log ( `[Launch] Opening launched file: ${ pendingFile . name } ` ) ;
833895 openHandler ( pendingFile ) ;
834896 pendingFile = null ;
835897 return ; // Exit early, don't check for shared files
836898 }
837899
838- // Check for shared files
839- const sharedFileData = await handleFileShare ( ) ;
840- if ( sharedFileData ) {
841- console . log ( `[Share] Opening shared file: ${ sharedFileData . filename } ` ) ;
842- openHandler ( sharedFileData . file ) ;
843- // Clean up the cached file
844- caches
845- . open ( CACHE_ID )
846- . then ( cache => cache . delete ( CACHE_DATA ) )
847- . catch ( error =>
848- console . error ( '[Error] Failed to cleanup shared file cache:' , error ) ) ;
900+ // Handle share target files
901+ const urlParams = new URLSearchParams ( window . location . search ) ;
902+ const source = urlParams . get ( 'source' ) ;
903+ if ( source === 'share' ) {
904+ const sharedFileData = await handleFileShare ( ) ;
905+ if ( sharedFileData ) {
906+ console . log ( `[Share] Opening shared file: ${ sharedFileData . filename } ` ) ;
907+ openHandler ( sharedFileData . file ) ;
908+ // Clean up the cached file
909+ caches
910+ . open ( CACHE_ID )
911+ . then ( cache => cache . delete ( CACHE_DATA ) )
912+ . catch ( error =>
913+ console . error ( '[Error] Failed to cleanup shared file cache:' , error ) ) ;
914+ }
849915 }
850916} ;
851917
0 commit comments