@@ -345,56 +345,128 @@ <h2 class="mobile-menu-title">REFLECTIONS</h2>
345345 }
346346 }
347347
348- function saveReplay ( ) {
348+ // Check if on mobile device
349+ function isMobile ( ) {
350+ return / i P h o n e | i P a d | i P o d | A n d r o i d / i. test ( navigator . userAgent ) ;
351+ }
352+
353+ // Save replay video - MP4 to camera roll on mobile, WebM download on desktop
354+ async function saveReplay ( ) {
349355 if ( ! window . game || ! window . game . replayRecorder . hasReplay ( ) ) {
350356 console . warn ( 'No replay available' ) ;
351357 return ;
352358 }
353359
354360 const time = document . getElementById ( 'finalTime' ) . textContent . replace ( / : / g, '-' ) . replace ( / \. / g, '-' ) ;
355- window . game . replayRecorder . downloadVideo ( `reflections-${ time } .webm` ) ;
361+
362+ // On mobile, convert to MP4 and save to camera roll via share API
363+ if ( isMobile ( ) ) {
364+ const saveButtons = document . querySelectorAll ( '.btn-save' ) ;
365+ const originalContents = [ ] ;
366+
367+ // Show loading state
368+ saveButtons . forEach ( ( btn , i ) => {
369+ originalContents [ i ] = btn . innerHTML ;
370+ btn . innerHTML = '<i class="iconoir-hourglass"></i> Saving...' ;
371+ btn . disabled = true ;
372+ btn . classList . add ( 'converting' ) ;
373+ } ) ;
374+
375+ try {
376+ const filename = `reflections-replay-${ time } .mp4` ;
377+
378+ // Convert to MP4
379+ const mp4Blob = await window . game . replayRecorder . getMP4Blob ( ) ;
380+ if ( ! mp4Blob ) {
381+ throw new Error ( 'Failed to convert video' ) ;
382+ }
383+
384+ // Use share API to save to camera roll (only files, no text)
385+ const file = new File ( [ mp4Blob ] , filename , { type : 'video/mp4' } ) ;
386+
387+ if ( navigator . share && navigator . canShare && navigator . canShare ( { files : [ file ] } ) ) {
388+ await navigator . share ( { files : [ file ] } ) ;
389+ } else {
390+ // Fallback: download the MP4
391+ await window . game . replayRecorder . downloadMP4 ( filename ) ;
392+ }
393+ } catch ( error ) {
394+ if ( error . name !== 'AbortError' ) {
395+ console . error ( 'Save failed:' , error ) ;
396+ alert ( 'Unable to save video. Please try again.' ) ;
397+ }
398+ } finally {
399+ // Restore button state
400+ saveButtons . forEach ( ( btn , i ) => {
401+ btn . innerHTML = originalContents [ i ] ;
402+ btn . disabled = false ;
403+ btn . classList . remove ( 'converting' ) ;
404+ } ) ;
405+ }
406+ } else {
407+ // Desktop: download WebM directly
408+ window . game . replayRecorder . downloadVideo ( `reflections-replay-${ time } .webm` ) ;
409+ }
356410 }
357411
412+ // Share screenshot with score
358413 async function shareReplay ( ) {
359- if ( ! window . game || ! window . game . replayRecorder . hasReplay ( ) ) {
360- console . warn ( 'No replay available' ) ;
361- alert ( 'No replay available to share.' ) ;
414+ const snapshotImg = document . getElementById ( 'gameOverSnapshot' ) || document . getElementById ( 'victorySnapshot' ) ;
415+
416+ if ( ! snapshotImg || ! snapshotImg . src ) {
417+ console . warn ( 'No snapshot available' ) ;
418+ alert ( 'No screenshot available to share.' ) ;
362419 return ;
363420 }
364421
365- // Get all share buttons and update their state
366422 const shareButtons = document . querySelectorAll ( '.btn-share' ) ;
367423 const originalContents = [ ] ;
368424
369425 // Show loading state
370426 shareButtons . forEach ( ( btn , i ) => {
371427 originalContents [ i ] = btn . innerHTML ;
372- btn . innerHTML = '<i class="iconoir-hourglass"></i> <span class="share-text">Converting ...</span> ' ;
428+ btn . innerHTML = '<i class="iconoir-hourglass"></i> Sharing ...' ;
373429 btn . disabled = true ;
374- btn . classList . add ( 'converting' ) ;
375430 } ) ;
376431
377432 try {
378- const time = document . getElementById ( 'finalTime' ) . textContent . replace ( / : / g, '-' ) . replace ( / \. / g, '-' ) ;
379- const filename = `reflections-${ time } .mp4` ;
380-
381- // Try to share using native share API
382- const shared = await window . game . replayRecorder . shareVideo ( filename ) ;
383-
384- if ( ! shared ) {
385- // Fallback: try to download MP4 instead
386- console . log ( 'Share not supported, falling back to MP4 download' ) ;
387- await window . game . replayRecorder . downloadMP4 ( filename ) ;
433+ // Get the score
434+ const scoreEl = document . getElementById ( 'finalTime' ) || document . getElementById ( 'victoryTime' ) ;
435+ const score = scoreEl ? scoreEl . textContent : 'Unknown' ;
436+ const time = score . replace ( / : / g, '-' ) . replace ( / \. / g, '-' ) ;
437+
438+ // Convert the snapshot image to a blob
439+ const response = await fetch ( snapshotImg . src ) ;
440+ const blob = await response . blob ( ) ;
441+ const file = new File ( [ blob ] , `reflections-score-${ time } .png` , { type : 'image/png' } ) ;
442+
443+ // Share with image and text
444+ if ( navigator . share && navigator . canShare && navigator . canShare ( { files : [ file ] } ) ) {
445+ await navigator . share ( {
446+ files : [ file ] ,
447+ title : 'REFLECTIONS' ,
448+ text : `I survived ${ score } in REFLECTIONS! Can you beat my score?`
449+ } ) ;
450+ } else if ( navigator . share ) {
451+ // Fallback: share without file
452+ await navigator . share ( {
453+ title : 'REFLECTIONS' ,
454+ text : `I survived ${ score } in REFLECTIONS! Can you beat my score?` ,
455+ url : window . location . href
456+ } ) ;
457+ } else {
458+ alert ( 'Sharing is not supported on this device.' ) ;
388459 }
389460 } catch ( error ) {
390- console . error ( 'Share failed:' , error ) ;
391- alert ( 'Unable to share video. Try using the download option on desktop.' ) ;
461+ if ( error . name !== 'AbortError' ) {
462+ console . error ( 'Share failed:' , error ) ;
463+ alert ( 'Unable to share. Please try again.' ) ;
464+ }
392465 } finally {
393466 // Restore button state
394467 shareButtons . forEach ( ( btn , i ) => {
395468 btn . innerHTML = originalContents [ i ] ;
396469 btn . disabled = false ;
397- btn . classList . remove ( 'converting' ) ;
398470 } ) ;
399471 }
400472 }
0 commit comments