Skip to content

Commit 7c86f3c

Browse files
Update changelog for version 0.2.0
1 parent f6c9d69 commit 7c86f3c

File tree

2 files changed

+104
-12
lines changed

2 files changed

+104
-12
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## [0.2.0] - 2025-09-17
4+
### Destaques da release
5+
- **Nova funcionalidade**: Adicionado recurso para visualizar takes gravados anteriormente
6+
- **Melhoria de design**: Aumentado o tamanho do preview dos takes para melhor experiência do usuário
7+
8+
> Esta é a versão "Release: Visualização de takes gravados".
9+
310
## [1.0.0] - 2025-09-16
411
### Destaques da release
512
- **Teleprompter redesenhado** com visual em vidro, gradientes sutis, barra inferior compacta de controles e botões de play/pause, mover e redimensionar dedicados para um fluxo de uso mais limpo.

Camera/ContentView.swift

Lines changed: 97 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import SwiftUI
99
import AVFoundation
10+
import AVKit
1011

1112
struct 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+
425510
struct FilterMenu: View {
426511
let selected: CameraViewModel.VideoFilter
427512
let onSelect: (CameraViewModel.VideoFilter) -> Void

0 commit comments

Comments
 (0)