Skip to content

Commit 1700765

Browse files
suhailsaqanjb55
authored andcommitted
change the camera view to the new custom camera
Closes: #1254 Reviewed-by: William Casarin <[email protected]> Signed-off-by: William Casarin <[email protected]>
1 parent 75a9b4d commit 1700765

File tree

3 files changed

+240
-20
lines changed

3 files changed

+240
-20
lines changed

damus.xcodeproj/project.pbxproj

+6
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@
435435
BA4AB0AE2A63B9270070A32A /* AddEmojiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AB0AD2A63B9270070A32A /* AddEmojiView.swift */; };
436436
BA4AB0B02A63B94D0070A32A /* EmojiListItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AB0AF2A63B94D0070A32A /* EmojiListItemView.swift */; };
437437
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; };
438+
BAA578D52AED7F4000EA8BE3 /* CameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAA578D42AED7F4000EA8BE3 /* CameraView.swift */; };
438439
BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */; };
439440
D2277EEA2A089BD5006C3807 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2277EE92A089BD5006C3807 /* Router.swift */; };
440441
D70A3B172B02DCE5008BD568 /* NotificationFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70A3B162B02DCE5008BD568 /* NotificationFormatter.swift */; };
@@ -1323,6 +1324,7 @@
13231324
BA4AB0AD2A63B9270070A32A /* AddEmojiView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEmojiView.swift; sourceTree = "<group>"; };
13241325
BA4AB0AF2A63B94D0070A32A /* EmojiListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiListItemView.swift; sourceTree = "<group>"; };
13251326
BA693073295D649800ADDB87 /* UserSettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsStore.swift; sourceTree = "<group>"; };
1327+
BAA578D42AED7F4000EA8BE3 /* CameraView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraView.swift; sourceTree = "<group>"; };
13261328
BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectWalletView.swift; sourceTree = "<group>"; };
13271329
D2277EE92A089BD5006C3807 /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = "<group>"; };
13281330
D70A3B162B02DCE5008BD568 /* NotificationFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationFormatter.swift; sourceTree = "<group>"; };
@@ -2604,6 +2606,7 @@
26042606
isa = PBXGroup;
26052607
children = (
26062608
BA3759962ABCCF360018D73B /* CameraPreview.swift */,
2609+
BAA578D42AED7F4000EA8BE3 /* CameraView.swift */,
26072610
);
26082611
path = Camera;
26092612
sourceTree = "<group>";
@@ -2613,6 +2616,8 @@
26132616
children = (
26142617
D72A2D042AD9C1B5002AFF62 /* MockDamusState.swift */,
26152618
D72A2D062AD9C1FB002AFF62 /* MockProfiles.swift */,
2619+
BAA8C3262AEC570800696158 /* CameraView.swift */,
2620+
BA3759962ABCCF360018D73B /* CameraPreview.swift */,
26162621
);
26172622
path = Mocking;
26182623
sourceTree = "<group>";
@@ -3109,6 +3114,7 @@
31093114
4CC7AAF8297F1CEE00430951 /* EventProfile.swift in Sources */,
31103115
5CF2DCCC2AA3AF0B00984B8D /* RelayPicView.swift in Sources */,
31113116
4C687C242A5FA86D0092C550 /* SearchHeaderView.swift in Sources */,
3117+
BAA578D52AED7F4000EA8BE3 /* CameraView.swift in Sources */,
31123118
64FBD06F296255C400D9D3B2 /* Theme.swift in Sources */,
31133119
4C1A9A2329DDDB8100516EAC /* IconLabel.swift in Sources */,
31143120
4CA352AC2A76C07F003BB08B /* NewUnmutesNotify.swift in Sources */,

damus/Views/Camera/CameraView.swift

+212
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
//
2+
// CameraView.swift
3+
// damus
4+
//
5+
// Created by Suhail Saqan on 8/5/23.
6+
//
7+
8+
import SwiftUI
9+
import Combine
10+
import AVFoundation
11+
12+
struct CameraView: View {
13+
let damus_state: DamusState
14+
let action: (([MediaItem]) -> Void)
15+
16+
@Environment(\.presentationMode) var presentationMode
17+
18+
@StateObject var model: CameraModel
19+
20+
@State var currentZoomFactor: CGFloat = 1.0
21+
22+
public init(damus_state: DamusState, action: @escaping (([MediaItem]) -> Void)) {
23+
self.damus_state = damus_state
24+
self.action = action
25+
_model = StateObject(wrappedValue: CameraModel())
26+
}
27+
28+
var captureButton: some View {
29+
Button {
30+
if model.isRecording {
31+
withAnimation {
32+
model.stopRecording()
33+
}
34+
} else {
35+
withAnimation {
36+
model.capturePhoto()
37+
}
38+
}
39+
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
40+
} label: {
41+
ZStack {
42+
Circle()
43+
.fill( model.isRecording ? .red : DamusColors.black)
44+
.frame(width: model.isRecording ? 85 : 65, height: model.isRecording ? 85 : 65, alignment: .center)
45+
46+
Circle()
47+
.stroke( model.isRecording ? .red : DamusColors.white, lineWidth: 4)
48+
.frame(width: model.isRecording ? 95 : 75, height: model.isRecording ? 95 : 75, alignment: .center)
49+
}
50+
.frame(alignment: .center)
51+
}
52+
.simultaneousGesture(
53+
LongPressGesture(minimumDuration: 0.5).onEnded({ value in
54+
if (!model.isCameraButtonDisabled) {
55+
withAnimation {
56+
model.startRecording()
57+
model.captureMode = .video
58+
}
59+
}
60+
})
61+
)
62+
.buttonStyle(.plain)
63+
}
64+
65+
var capturedPhotoThumbnail: some View {
66+
ZStack {
67+
if model.thumbnail != nil {
68+
Image(uiImage: model.thumbnail.thumbnailImage!)
69+
.resizable()
70+
.aspectRatio(contentMode: .fill)
71+
.frame(width: 60, height: 60)
72+
.clipShape(RoundedRectangle(cornerRadius: 10, style: .continuous))
73+
}
74+
if model.isPhotoProcessing {
75+
ProgressView()
76+
.progressViewStyle(CircularProgressViewStyle(tint: DamusColors.white))
77+
}
78+
}
79+
}
80+
81+
var closeButton: some View {
82+
Button {
83+
presentationMode.wrappedValue.dismiss()
84+
model.stop()
85+
} label: {
86+
HStack {
87+
Image(systemName: "xmark")
88+
.font(.system(size: 24))
89+
}
90+
.frame(minWidth: 40, minHeight: 40)
91+
}
92+
.accentColor(DamusColors.white)
93+
}
94+
95+
var flipCameraButton: some View {
96+
Button(action: {
97+
model.flipCamera()
98+
}, label: {
99+
HStack {
100+
Image(systemName: "camera.rotate.fill")
101+
.font(.system(size: 20))
102+
}
103+
.frame(minWidth: 40, minHeight: 40)
104+
})
105+
.accentColor(DamusColors.white)
106+
}
107+
108+
var toggleFlashButton: some View {
109+
Button(action: {
110+
model.switchFlash()
111+
}, label: {
112+
HStack {
113+
Image(systemName: model.isFlashOn ? "bolt.fill" : "bolt.slash.fill")
114+
.font(.system(size: 20))
115+
}
116+
.frame(minWidth: 40, minHeight: 40)
117+
})
118+
.accentColor(model.isFlashOn ? .yellow : DamusColors.white)
119+
}
120+
121+
var body: some View {
122+
NavigationView {
123+
GeometryReader { reader in
124+
ZStack {
125+
DamusColors.black.edgesIgnoringSafeArea(.all)
126+
127+
CameraPreview(session: model.session)
128+
.padding(.bottom, 175)
129+
.edgesIgnoringSafeArea(.all)
130+
.gesture(
131+
DragGesture().onChanged({ (val) in
132+
if abs(val.translation.height) > abs(val.translation.width) {
133+
let percentage: CGFloat = -(val.translation.height / reader.size.height)
134+
let calc = currentZoomFactor + percentage
135+
let zoomFactor: CGFloat = min(max(calc, 1), 5)
136+
137+
currentZoomFactor = zoomFactor
138+
model.zoom(with: zoomFactor)
139+
}
140+
})
141+
)
142+
.onAppear {
143+
model.configure()
144+
}
145+
.alert(isPresented: $model.showAlertError, content: {
146+
Alert(title: Text(model.alertError.title), message: Text(model.alertError.message), dismissButton: .default(Text(model.alertError.primaryButtonTitle), action: {
147+
model.alertError.primaryAction?()
148+
}))
149+
})
150+
.overlay(
151+
Group {
152+
if model.willCapturePhoto {
153+
Color.black
154+
}
155+
}
156+
)
157+
158+
VStack {
159+
if !model.isRecording {
160+
HStack {
161+
closeButton
162+
163+
Spacer()
164+
165+
HStack {
166+
flipCameraButton
167+
toggleFlashButton
168+
}
169+
}
170+
.padding(.horizontal, 20)
171+
}
172+
173+
Spacer()
174+
175+
HStack(alignment: .center) {
176+
if !model.mediaItems.isEmpty {
177+
NavigationLink(destination: Text(model.mediaItems.map { $0.url.absoluteString }.joined(separator: ", "))) {
178+
capturedPhotoThumbnail
179+
}
180+
.frame(width: 100, alignment: .leading)
181+
}
182+
183+
Spacer()
184+
185+
captureButton
186+
187+
Spacer()
188+
189+
if !model.mediaItems.isEmpty {
190+
Button(action: {
191+
action(model.mediaItems)
192+
presentationMode.wrappedValue.dismiss()
193+
model.stop()
194+
}) {
195+
Text("Upload")
196+
.frame(width: 100, height: 40, alignment: .center)
197+
.foregroundColor(DamusColors.white)
198+
.overlay {
199+
RoundedRectangle(cornerRadius: 24)
200+
.stroke(DamusColors.white, lineWidth: 2)
201+
}
202+
}
203+
}
204+
}
205+
.frame(height: 100)
206+
.padding([.horizontal, .vertical], 20)
207+
}
208+
}
209+
}
210+
}
211+
}
212+
}

damus/Views/PostView.swift

+22-20
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ struct PostView: View {
5757
@State var newCursorIndex: Int?
5858
@State var textHeight: CGFloat? = nil
5959

60-
@State var mediaToUpload: MediaUpload? = nil
60+
@State var mediaToUpload: [MediaUpload] = []
6161

6262
@StateObject var image_upload: ImageUploadModel = ImageUploadModel()
6363
@StateObject var tagModel: TagModel = TagModel()
@@ -379,6 +379,15 @@ struct PostView: View {
379379
pks.append(pk)
380380
}
381381
}
382+
383+
func addToMediaToUpload(mediaItem: MediaItem) {
384+
switch mediaItem.type {
385+
case .image:
386+
mediaToUpload.append(.image(mediaItem.url))
387+
case .video:
388+
mediaToUpload.append(.video(mediaItem.url))
389+
}
390+
}
382391

383392
var body: some View {
384393
GeometryReader { (deviceSize: GeometryProxy) in
@@ -421,36 +430,29 @@ struct PostView: View {
421430
.background(DamusColors.adaptableWhite.edgesIgnoringSafeArea(.all))
422431
.sheet(isPresented: $attach_media) {
423432
ImagePicker(uploader: damus_state.settings.default_media_uploader, sourceType: .photoLibrary, pubkey: damus_state.pubkey, image_upload_confirm: $image_upload_confirm) { img in
424-
self.mediaToUpload = .image(img)
433+
self.mediaToUpload.append(.image(img))
425434
} onVideoPicked: { url in
426-
self.mediaToUpload = .video(url)
435+
self.mediaToUpload.append(.video(url))
427436
}
428437
.alert(NSLocalizedString("Are you sure you want to upload this media?", comment: "Alert message asking if the user wants to upload media."), isPresented: $image_upload_confirm) {
429438
Button(NSLocalizedString("Upload", comment: "Button to proceed with uploading."), role: .none) {
430-
if let mediaToUpload {
431-
self.handle_upload(media: mediaToUpload)
439+
if !mediaToUpload.isEmpty {
440+
self.handle_upload(media: mediaToUpload[0])
432441
self.attach_media = false
433442
}
434443
}
435444
Button(NSLocalizedString("Cancel", comment: "Button to cancel the upload."), role: .cancel) {}
436445
}
437446
}
438-
.sheet(isPresented: $attach_camera) {
439-
440-
ImagePicker(uploader: damus_state.settings.default_media_uploader, sourceType: .camera, pubkey: damus_state.pubkey, image_upload_confirm: $image_upload_confirm) { img in
441-
self.mediaToUpload = .image(img)
442-
} onVideoPicked: { url in
443-
self.mediaToUpload = .video(url)
444-
}
445-
.alert(NSLocalizedString("Are you sure you want to upload this media?", comment: "Alert message asking if the user wants to upload media."), isPresented: $image_upload_confirm) {
446-
Button(NSLocalizedString("Upload", comment: "Button to proceed with uploading."), role: .none) {
447-
if let mediaToUpload {
448-
self.handle_upload(media: mediaToUpload)
449-
self.attach_camera = false
450-
}
447+
.fullScreenCover(isPresented: $attach_camera) {
448+
CameraView(damus_state: damus_state, action: { items in
449+
for item in items {
450+
addToMediaToUpload(mediaItem: item)
451451
}
452-
Button(NSLocalizedString("Cancel", comment: "Button to cancel the upload."), role: .cancel) {}
453-
}
452+
for media in mediaToUpload {
453+
self.handle_upload(media: media)
454+
}
455+
})
454456
}
455457
.onAppear() {
456458
let loaded_draft = load_draft()

0 commit comments

Comments
 (0)