Skip to content

Commit 6fc6033

Browse files
committed
add CameraPreview for displaying the view the camera is reading
1 parent ee9ca5d commit 6fc6033

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

damus.xcodeproj/project.pbxproj

+12
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@
383383
BA3759922ABCCEBA0018D73B /* CameraService+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA37598F2ABCCEBA0018D73B /* CameraService+Extensions.swift */; };
384384
BA3759932ABCCEBA0018D73B /* CameraModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759902ABCCEBA0018D73B /* CameraModel.swift */; };
385385
BA3759942ABCCEBA0018D73B /* CameraService.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759912ABCCEBA0018D73B /* CameraService.swift */; };
386+
BA3759972ABCCF360018D73B /* CameraPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759962ABCCF360018D73B /* CameraPreview.swift */; };
386387
BA4AB0AE2A63B9270070A32A /* AddEmojiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AB0AD2A63B9270070A32A /* AddEmojiView.swift */; };
387388
BA4AB0B02A63B94D0070A32A /* EmojiListItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AB0AF2A63B94D0070A32A /* EmojiListItemView.swift */; };
388389
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; };
@@ -940,6 +941,7 @@
940941
BA37598F2ABCCEBA0018D73B /* CameraService+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CameraService+Extensions.swift"; sourceTree = "<group>"; };
941942
BA3759902ABCCEBA0018D73B /* CameraModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraModel.swift; sourceTree = "<group>"; };
942943
BA3759912ABCCEBA0018D73B /* CameraService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraService.swift; sourceTree = "<group>"; };
944+
BA3759962ABCCF360018D73B /* CameraPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraPreview.swift; sourceTree = "<group>"; };
943945
BA4AB0AD2A63B9270070A32A /* AddEmojiView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEmojiView.swift; sourceTree = "<group>"; };
944946
BA4AB0AF2A63B94D0070A32A /* EmojiListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiListItemView.swift; sourceTree = "<group>"; };
945947
BA693073295D649800ADDB87 /* UserSettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsStore.swift; sourceTree = "<group>"; };
@@ -1247,6 +1249,7 @@
12471249
4C75EFA227FA576C0006080F /* Views */ = {
12481250
isa = PBXGroup;
12491251
children = (
1252+
BA3759952ABCCF360018D73B /* Camera */,
12501253
F71694E82A66221E001F4053 /* Onboarding */,
12511254
4C190F232A547D1700027FD5 /* NostrScript */,
12521255
4C7D09692A0AEA0400943473 /* CodeScanner */,
@@ -1886,6 +1889,14 @@
18861889
path = Camera;
18871890
sourceTree = "<group>";
18881891
};
1892+
BA3759952ABCCF360018D73B /* Camera */ = {
1893+
isa = PBXGroup;
1894+
children = (
1895+
BA3759962ABCCF360018D73B /* CameraPreview.swift */,
1896+
);
1897+
path = Camera;
1898+
sourceTree = "<group>";
1899+
};
18891900
F71694E82A66221E001F4053 /* Onboarding */ = {
18901901
isa = PBXGroup;
18911902
children = (
@@ -2209,6 +2220,7 @@
22092220
4C75EFB328049D640006080F /* NostrEvent.swift in Sources */,
22102221
4CA2EFA0280E37AC0044ACD8 /* TimelineView.swift in Sources */,
22112222
4C30AC7629A5770900E2BD5A /* NotificationItemView.swift in Sources */,
2223+
BA3759972ABCCF360018D73B /* CameraPreview.swift in Sources */,
22122224
4C86F7C42A76C44C00EC0817 /* ZappingNotify.swift in Sources */,
22132225
4C363A8428233689006E126D /* Parser.swift in Sources */,
22142226
3AAA95CA298DF87B00F3D526 /* TranslationService.swift in Sources */,
+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//
2+
// CameraPreview.swift
3+
// damus
4+
//
5+
// Created by Suhail Saqan on 8/5/23.
6+
//
7+
8+
import UIKit
9+
import AVFoundation
10+
import SwiftUI
11+
12+
public struct CameraPreview: UIViewRepresentable {
13+
public class VideoPreviewView: UIView {
14+
public override class var layerClass: AnyClass {
15+
AVCaptureVideoPreviewLayer.self
16+
}
17+
18+
var videoPreviewLayer: AVCaptureVideoPreviewLayer {
19+
return layer as! AVCaptureVideoPreviewLayer
20+
}
21+
22+
let focusView: UIView = {
23+
let focusView = UIView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
24+
focusView.layer.borderColor = UIColor.white.cgColor
25+
focusView.layer.borderWidth = 1.5
26+
focusView.layer.cornerRadius = 15
27+
focusView.layer.opacity = 0
28+
focusView.backgroundColor = .clear
29+
return focusView
30+
}()
31+
32+
@objc func focusAndExposeTap(gestureRecognizer: UITapGestureRecognizer) {
33+
let layerPoint = gestureRecognizer.location(in: gestureRecognizer.view)
34+
35+
guard layerPoint.x >= 0 && layerPoint.x <= bounds.width &&
36+
layerPoint.y >= 0 && layerPoint.y <= bounds.height else {
37+
return
38+
}
39+
40+
let devicePoint = videoPreviewLayer.captureDevicePointConverted(fromLayerPoint: layerPoint)
41+
42+
self.focusView.layer.frame = CGRect(origin: layerPoint, size: CGSize(width: 30, height: 30))
43+
44+
NotificationCenter.default.post(.init(name: .init("UserDidRequestNewFocusPoint"), object: nil, userInfo: ["devicePoint": devicePoint] as [AnyHashable: Any]))
45+
46+
UIView.animate(withDuration: 0.3, animations: {
47+
self.focusView.layer.opacity = 1
48+
}) { (completed) in
49+
if completed {
50+
UIView.animate(withDuration: 0.3) {
51+
self.focusView.layer.opacity = 0
52+
}
53+
}
54+
}
55+
}
56+
57+
public override func layoutSubviews() {
58+
super.layoutSubviews()
59+
60+
videoPreviewLayer.videoGravity = .resizeAspectFill
61+
62+
self.layer.addSublayer(focusView.layer)
63+
64+
let gRecognizer = UITapGestureRecognizer(target: self, action: #selector(VideoPreviewView.focusAndExposeTap(gestureRecognizer:)))
65+
self.addGestureRecognizer(gRecognizer)
66+
}
67+
}
68+
69+
public let session: AVCaptureSession
70+
71+
public init(session: AVCaptureSession) {
72+
self.session = session
73+
}
74+
75+
public func makeUIView(context: Context) -> VideoPreviewView {
76+
let viewFinder = VideoPreviewView()
77+
viewFinder.backgroundColor = .black
78+
viewFinder.videoPreviewLayer.cornerRadius = 20
79+
viewFinder.videoPreviewLayer.session = session
80+
viewFinder.videoPreviewLayer.connection?.videoOrientation = .portrait
81+
82+
return viewFinder
83+
}
84+
85+
public func updateUIView(_ uiView: VideoPreviewView, context: Context) {
86+
87+
}
88+
}
89+
90+
struct CameraPreview_Previews: PreviewProvider {
91+
static var previews: some View {
92+
CameraPreview(session: AVCaptureSession())
93+
.frame(height: 300)
94+
}
95+
}

0 commit comments

Comments
 (0)