Skip to content

Commit

Permalink
camera: add CameraPreview for displaying the view the camera is reading
Browse files Browse the repository at this point in the history
  • Loading branch information
suhailsaqan authored and jb55 committed Oct 2, 2023
1 parent c0d775b commit 9ade0f2
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 0 deletions.
12 changes: 12 additions & 0 deletions damus.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@
501F8C822A0224EB001AFC1D /* KeychainStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 501F8C812A0224EB001AFC1D /* KeychainStorageTests.swift */; };
504323A72A34915F006AE6DC /* RelayModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504323A62A34915F006AE6DC /* RelayModel.swift */; };
504323A92A3495B6006AE6DC /* RelayModelCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504323A82A3495B6006AE6DC /* RelayModelCache.swift */; };
BA3759972ABCCF360018D73B /* CameraPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759962ABCCF360018D73B /* CameraPreview.swift */; };
5053ACA72A56DF3B00851AE3 /* DeveloperSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5053ACA62A56DF3B00851AE3 /* DeveloperSettingsView.swift */; };
50A16FFB2AA6C06600DFEC1F /* AVPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFA2AA6C06600DFEC1F /* AVPlayerView.swift */; };
50A16FFD2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A16FFC2AA7525700DFEC1F /* DamusVideoPlayerViewModel.swift */; };
Expand Down Expand Up @@ -943,6 +944,7 @@
4CA352A92A76BF3A003BB08B /* LocalNotificationNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNotificationNotify.swift; sourceTree = "<group>"; };
4CA352AB2A76C07F003BB08B /* NewUnmutesNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewUnmutesNotify.swift; sourceTree = "<group>"; };
4CA352AD2A76C1AC003BB08B /* FollowedNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowedNotify.swift; sourceTree = "<group>"; };
BA3759962ABCCF360018D73B /* CameraPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraPreview.swift; sourceTree = "<group>"; };
4CA3FA0F29F593D000FDB3C3 /* ZapTypePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZapTypePicker.swift; sourceTree = "<group>"; };
4CA5588229F33F5B00DC6A45 /* StringCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringCodable.swift; sourceTree = "<group>"; };
4CA9275C2A28FF630098A105 /* LongformView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LongformView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1629,6 +1631,7 @@
4C75EFA227FA576C0006080F /* Views */ = {
isa = PBXGroup;
children = (
BA3759952ABCCF360018D73B /* Camera */,
F71694E82A66221E001F4053 /* Onboarding */,
4C190F232A547D1700027FD5 /* NostrScript */,
4C7D09692A0AEA0400943473 /* CodeScanner */,
Expand Down Expand Up @@ -2277,6 +2280,14 @@
path = Camera;
sourceTree = "<group>";
};
BA3759952ABCCF360018D73B /* Camera */ = {
isa = PBXGroup;
children = (
BA3759962ABCCF360018D73B /* CameraPreview.swift */,
);
path = Camera;
sourceTree = "<group>";
};
F71694E82A66221E001F4053 /* Onboarding */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2620,6 +2631,7 @@
4C32B9582A9AD44700DC3548 /* VeriferOptions.swift in Sources */,
4CA2EFA0280E37AC0044ACD8 /* TimelineView.swift in Sources */,
4C30AC7629A5770900E2BD5A /* NotificationItemView.swift in Sources */,
BA3759972ABCCF360018D73B /* CameraPreview.swift in Sources */,
4C86F7C42A76C44C00EC0817 /* ZappingNotify.swift in Sources */,
4C363A8428233689006E126D /* Parser.swift in Sources */,
3AAA95CA298DF87B00F3D526 /* TranslationService.swift in Sources */,
Expand Down
95 changes: 95 additions & 0 deletions damus/Views/Camera/CameraPreview.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//
// CameraPreview.swift
// damus
//
// Created by Suhail Saqan on 8/5/23.
//

import UIKit
import AVFoundation
import SwiftUI

public struct CameraPreview: UIViewRepresentable {
public class VideoPreviewView: UIView {
public override class var layerClass: AnyClass {
AVCaptureVideoPreviewLayer.self
}

var videoPreviewLayer: AVCaptureVideoPreviewLayer {
return layer as! AVCaptureVideoPreviewLayer
}

let focusView: UIView = {
let focusView = UIView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
focusView.layer.borderColor = UIColor.white.cgColor
focusView.layer.borderWidth = 1.5
focusView.layer.cornerRadius = 15
focusView.layer.opacity = 0
focusView.backgroundColor = .clear
return focusView
}()

@objc func focusAndExposeTap(gestureRecognizer: UITapGestureRecognizer) {
let layerPoint = gestureRecognizer.location(in: gestureRecognizer.view)

guard layerPoint.x >= 0 && layerPoint.x <= bounds.width &&
layerPoint.y >= 0 && layerPoint.y <= bounds.height else {
return
}

let devicePoint = videoPreviewLayer.captureDevicePointConverted(fromLayerPoint: layerPoint)

self.focusView.layer.frame = CGRect(origin: layerPoint, size: CGSize(width: 30, height: 30))

NotificationCenter.default.post(.init(name: .init("UserDidRequestNewFocusPoint"), object: nil, userInfo: ["devicePoint": devicePoint] as [AnyHashable: Any]))

UIView.animate(withDuration: 0.3, animations: {
self.focusView.layer.opacity = 1
}) { (completed) in
if completed {
UIView.animate(withDuration: 0.3) {
self.focusView.layer.opacity = 0
}
}
}
}

public override func layoutSubviews() {
super.layoutSubviews()

videoPreviewLayer.videoGravity = .resizeAspectFill

self.layer.addSublayer(focusView.layer)

let gRecognizer = UITapGestureRecognizer(target: self, action: #selector(VideoPreviewView.focusAndExposeTap(gestureRecognizer:)))
self.addGestureRecognizer(gRecognizer)
}
}

public let session: AVCaptureSession

public init(session: AVCaptureSession) {
self.session = session
}

public func makeUIView(context: Context) -> VideoPreviewView {
let viewFinder = VideoPreviewView()
viewFinder.backgroundColor = .black
viewFinder.videoPreviewLayer.cornerRadius = 20
viewFinder.videoPreviewLayer.session = session
viewFinder.videoPreviewLayer.connection?.videoOrientation = .portrait

return viewFinder
}

public func updateUIView(_ uiView: VideoPreviewView, context: Context) {

}
}

struct CameraPreview_Previews: PreviewProvider {
static var previews: some View {
CameraPreview(session: AVCaptureSession())
.frame(height: 300)
}
}

0 comments on commit 9ade0f2

Please sign in to comment.