77
88import  SwiftUI
99import  AVFoundation
10+ import  AVKit
1011
1112struct  ContentView :  View  { 
1213    @Environment ( \. dismiss)   private  var  dismiss 
@@ -15,6 +16,7 @@ struct ContentView: View {
1516    @State   private  var  countdownTimer :  Timer ? 
1617    @State   private  var  showDeleteConfirm :  Bool  =  false 
1718    @State   private  var  segmentToDelete :  CameraViewModel . RecordedSegment ? =  nil 
19+     @State   private  var  previewSegment :  CameraViewModel . RecordedSegment ? 
1820    @State   private  var  showFilterPicker :  Bool  =  false 
1921
2022    var  body :  some  View  { 
@@ -214,30 +216,35 @@ struct ContentView: View {
214216                        HStack ( spacing:  6 )  { 
215217                            ForEach ( model. segments)  {  seg in 
216218                                ZStack ( alignment:  . topTrailing)  { 
217-                                     Image ( uiImage:  seg. thumbnail) 
218-                                         . resizable ( ) 
219-                                         . scaledToFill ( ) 
220-                                         . frame ( width:  34 ,  height:  44 ) 
221-                                         . clipShape ( RoundedRectangle ( cornerRadius:  6 ,  style:  . continuous) ) 
222-                                         . overlay ( 
223-                                             RoundedRectangle ( cornerRadius:  6 ,  style:  . continuous) 
224-                                                 . stroke ( Color . white. opacity ( 0.6 ) ,  lineWidth:  0.8 ) 
225-                                         ) 
219+                                     Button  { 
220+                                         previewSegment =  seg
221+                                     }  label:  { 
222+                                         Image ( uiImage:  seg. thumbnail) 
223+                                             . resizable ( ) 
224+                                             . scaledToFill ( ) 
225+                                             . frame ( width:  44 ,  height:  58 ) 
226+                                             . clipShape ( RoundedRectangle ( cornerRadius:  8 ,  style:  . continuous) ) 
227+                                             . overlay ( 
228+                                                 RoundedRectangle ( cornerRadius:  8 ,  style:  . continuous) 
229+                                                     . stroke ( Color . white. opacity ( 0.6 ) ,  lineWidth:  0.8 ) 
230+                                             ) 
231+                                     } 
232+                                     . buttonStyle ( . plain) 
226233
227234                                    Button ( action:  { 
228235                                        segmentToDelete =  seg
229236                                        showDeleteConfirm =  true 
230237                                    } )  { 
231238                                        Image ( systemName:  " xmark " ) 
232-                                             . font ( . system( size:  8 ,  weight:  . bold) ) 
239+                                             . font ( . system( size:  7 ,  weight:  . bold) ) 
233240                                            . foregroundColor ( . white) 
234-                                             . frame ( width:  14 ,  height:  14 ) 
241+                                             . frame ( width:  12 ,  height:  12 ) 
235242                                            . background ( Color . black. opacity ( 0.75 ) ) 
236243                                            . clipShape ( Circle ( ) ) 
237244                                    } 
238245                                    . padding ( 2 ) 
239246                                } 
240-                                 . frame ( width:  34 ,  height:  44 ) 
247+                                 . frame ( width:  44 ,  height:  58 ) 
241248                            } 
242249                        } 
243250                        . padding ( . horizontal,  10 ) 
@@ -336,6 +343,18 @@ struct ContentView: View {
336343        . onChange ( of:  model. isTeleprompterOn)  {  _ in 
337344            withAnimation ( . easeOut( duration:  0.2 ) )  {  showFilterPicker =  false  } 
338345        } 
346+         . sheet ( item:  $previewSegment)  {  segment in 
347+             SegmentPlaybackView ( 
348+                 segment:  segment, 
349+                 onDelete:  { 
350+                     model. deleteSegment ( segment) 
351+                     previewSegment =  nil 
352+                 } , 
353+                 onClose:  { 
354+                     previewSegment =  nil 
355+                 } 
356+             ) 
357+         } 
339358        . alert ( " Deseja apagar esse take? " ,  isPresented:  $showDeleteConfirm)  { 
340359            Button ( " Apagar " ,  role:  . destructive)  { 
341360                if  let  seg =  segmentToDelete { 
@@ -422,6 +441,72 @@ extension ContentView {
422441    } 
423442} 
424443
444+ struct  SegmentPlaybackView :  View  { 
445+     let  segment :  CameraViewModel . RecordedSegment 
446+     let  onDelete :  ( )  ->  Void 
447+     let  onClose :  ( )  ->  Void 
448+ 
449+     @State   private  var  player =  AVPlayer ( ) 
450+     @State   private  var  showDeleteDialog =  false 
451+ 
452+     var  body :  some  View  { 
453+         NavigationStack  { 
454+             ZStack  { 
455+                 Color . black
456+                     . ignoresSafeArea ( ) 
457+ 
458+                 VStack ( spacing:  24 )  { 
459+                     VideoPlayer ( player:  player) 
460+                         . aspectRatio ( 9.0  /  16.0 ,  contentMode:  . fit) 
461+                         . clipShape ( RoundedRectangle ( cornerRadius:  18 ,  style:  . continuous) ) 
462+                         . shadow ( color:  Color . black. opacity ( 0.4 ) ,  radius:  18 ,  x:  0 ,  y:  12 ) 
463+ 
464+                     Button ( role:  . destructive)  { 
465+                         showDeleteDialog =  true 
466+                     }  label:  { 
467+                         Label ( " Apagar take " ,  systemImage:  " trash " ) 
468+                             . font ( . system( size:  17 ,  weight:  . semibold) ) 
469+                             . padding ( . vertical,  12 ) 
470+                             . frame ( maxWidth:  . infinity) 
471+                     } 
472+                     . buttonStyle ( . borderedProminent) 
473+                     . tint ( . red) 
474+ 
475+                     Spacer ( ) 
476+                 } 
477+                 . padding ( ) 
478+             } 
479+             . navigationTitle ( " Pré-visualização " ) 
480+             . navigationBarTitleDisplayMode ( . inline) 
481+             . toolbar  { 
482+                 ToolbarItem ( placement:  . topBarLeading)  { 
483+                     Button ( " Fechar " ,  action:  onClose) 
484+                 } 
485+             } 
486+             . confirmationDialog ( 
487+                 " Apagar este take? " , 
488+                 isPresented:  $showDeleteDialog, 
489+                 titleVisibility:  . visible
490+             )  { 
491+                 Button ( " Apagar " ,  role:  . destructive)  { 
492+                     player. pause ( ) 
493+                     onDelete ( ) 
494+                 } 
495+                 Button ( " Cancelar " ,  role:  . cancel)  {  } 
496+             } 
497+         } 
498+         . interactiveDismissDisabled ( true ) 
499+         . onAppear  { 
500+             player. replaceCurrentItem ( with:  AVPlayerItem ( url:  segment. url) ) 
501+             player. play ( ) 
502+         } 
503+         . onDisappear  { 
504+             player. pause ( ) 
505+             player. replaceCurrentItem ( with:  nil ) 
506+         } 
507+     } 
508+ } 
509+ 
425510struct  FilterMenu :  View  { 
426511    let  selected :  CameraViewModel . VideoFilter 
427512    let  onSelect :  ( CameraViewModel . VideoFilter )  ->  Void 
0 commit comments