diff --git a/NADA-iOS-forRelease/Info.plist b/NADA-iOS-forRelease/Info.plist index 8301cb5a..d3196978 100644 --- a/NADA-iOS-forRelease/Info.plist +++ b/NADA-iOS-forRelease/Info.plist @@ -2,6 +2,14 @@ + NSPhotoLibraryAddUsageDescription + 명함을 이미지로 저장하기 위해 갤러리 권한 허용이 필요해요. + NSPhotoLibraryUsageDescription + 명함 배경을 설정하기 위해 갤러리 권한 허용이 필요해요. + NSCameraUsageDescription + QR코드를 인식하여 명함을 추가하기 위해 카메라 권한 허용이 필요해요. + UIUserInterfaceStyle + UIAppFonts NotoSansCJKkr-Bold.otf @@ -10,6 +18,8 @@ Spoqa Han Sans Neo Bold.otf Spoqa Han Sans Neo Regular.otf + LSApplicationCategoryType + NSAppTransportSecurity NSAllowsArbitraryLoads diff --git a/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/iconQRClear.imageset/Contents.json b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/iconQRClear.imageset/Contents.json new file mode 100644 index 00000000..8dc2d194 --- /dev/null +++ b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/iconQRClear.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "iconQRClear.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "iconQRClear@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "iconQRClear@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/iconQRClear.imageset/iconQRClear.png b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/iconQRClear.imageset/iconQRClear.png new file mode 100644 index 00000000..26b12e7b Binary files /dev/null and b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/iconQRClear.imageset/iconQRClear.png differ diff --git a/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/iconQRClear.imageset/iconQRClear@2x.png b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/iconQRClear.imageset/iconQRClear@2x.png new file mode 100644 index 00000000..178fa3ca Binary files /dev/null and b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/iconQRClear.imageset/iconQRClear@2x.png differ diff --git a/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/iconQRClear.imageset/iconQRClear@3x.png b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/iconQRClear.imageset/iconQRClear@3x.png new file mode 100644 index 00000000..2a88d187 Binary files /dev/null and b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/iconQRClear.imageset/iconQRClear@3x.png differ diff --git a/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/subtract.imageset/Contents.json b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/subtract.imageset/Contents.json new file mode 100644 index 00000000..55fd977f --- /dev/null +++ b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/subtract.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "subtract.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "subtract@2x.png", + "scale" : "2x" + }, + { + "scale" : "3x", + "idiom" : "universal", + "filename" : "subtract@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/subtract.imageset/subtract.png b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/subtract.imageset/subtract.png new file mode 100644 index 00000000..9c356568 Binary files /dev/null and b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/subtract.imageset/subtract.png differ diff --git a/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/subtract.imageset/subtract@2x.png b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/subtract.imageset/subtract@2x.png new file mode 100644 index 00000000..ae06e8cf Binary files /dev/null and b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/subtract.imageset/subtract@2x.png differ diff --git a/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/subtract.imageset/subtract@3x.png b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/subtract.imageset/subtract@3x.png new file mode 100644 index 00000000..4d6a654f Binary files /dev/null and b/NADA-iOS-forRelease/Resouces/Assets/Assets.xcassets/subtract.imageset/subtract@3x.png differ diff --git a/NADA-iOS-forRelease/Resouces/Extensions/UIViewController+Extension.swift b/NADA-iOS-forRelease/Resouces/Extensions/UIViewController+Extension.swift index 0795f341..10548a0d 100644 --- a/NADA-iOS-forRelease/Resouces/Extensions/UIViewController+Extension.swift +++ b/NADA-iOS-forRelease/Resouces/Extensions/UIViewController+Extension.swift @@ -61,4 +61,23 @@ extension UIViewController { self.present(alertViewController, animated: true, completion: completion) } + + func showToast(message: String, + font: UIFont) { + let toastLabel = UILabel(frame: CGRect(x: self.view.frame.size.width/2 - 85, + y: self.view.frame.size.height - 230, + width: 170, height: 35)) + toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6) + toastLabel.textColor = UIColor.white + toastLabel.font = font + toastLabel.textAlignment = .center + toastLabel.text = message + toastLabel.alpha = 0.9 + toastLabel.layer.cornerRadius = 10 + toastLabel.clipsToBounds = true + self.view.addSubview(toastLabel) + UIView.animate(withDuration: 1.0, delay: 0.1, + options: .curveEaseOut, animations: { toastLabel.alpha = 0.0 }, + completion: {_ in toastLabel.removeFromSuperview() }) + } } diff --git a/NADA-iOS-forRelease/Resouces/Storyboards/Group/QRScan.storyboard b/NADA-iOS-forRelease/Resouces/Storyboards/Group/QRScan.storyboard index 0e18fd7f..a7f54a7a 100644 --- a/NADA-iOS-forRelease/Resouces/Storyboards/Group/QRScan.storyboard +++ b/NADA-iOS-forRelease/Resouces/Storyboards/Group/QRScan.storyboard @@ -1,11 +1,10 @@ - + - + - @@ -17,17 +16,11 @@ - - + - - - - - diff --git a/NADA-iOS-forRelease/Sources/Cells/CreationCard/FrontCardCreationCollectionViewCell.swift b/NADA-iOS-forRelease/Sources/Cells/CreationCard/FrontCardCreationCollectionViewCell.swift index df77d9b7..40f007a1 100644 --- a/NADA-iOS-forRelease/Sources/Cells/CreationCard/FrontCardCreationCollectionViewCell.swift +++ b/NADA-iOS-forRelease/Sources/Cells/CreationCard/FrontCardCreationCollectionViewCell.swift @@ -20,7 +20,7 @@ class FrontCardCreationCollectionViewCell: UICollectionViewCell { private var optionalTextFieldList = [UITextField]() private var cardBackgroundImage: UIImage? private var defaultImageIndex: Int? - + public var presentingBirthBottomVCClosure: (() -> Void)? public var presentingMBTIBottomVCClosure: (() -> Void)? diff --git a/NADA-iOS-forRelease/Sources/ViewControllers/BottomSheet/SelectGroupBottomSheetViewController.swift b/NADA-iOS-forRelease/Sources/ViewControllers/BottomSheet/SelectGroupBottomSheetViewController.swift index 1fc098d1..c0d74040 100644 --- a/NADA-iOS-forRelease/Sources/ViewControllers/BottomSheet/SelectGroupBottomSheetViewController.swift +++ b/NADA-iOS-forRelease/Sources/ViewControllers/BottomSheet/SelectGroupBottomSheetViewController.swift @@ -79,19 +79,14 @@ extension SelectGroupBottomSheetViewController: UIPickerViewDelegate, UIPickerVi func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView { let label = (view as? UILabel) ?? UILabel() - label.textColor = .quaternary label.textAlignment = .center - label.font = UIFont(name: "SpoqaHanSansNeo-Regular", size: 16) if pickerView.selectedRow(inComponent: component) == row { - label.attributedText = NSAttributedString(string: groupList[row], attributes: [NSAttributedString.Key.font: UIFont(name: "SpoqaHanSansNeo-Bold", size: 16.0)!, NSAttributedString.Key.foregroundColor: UIColor.mainColorNadaMain]) - + label.attributedText = NSAttributedString(string: groupList[row], attributes: [NSAttributedString.Key.font: UIFont.textBold01, NSAttributedString.Key.foregroundColor: UIColor.mainColorNadaMain]) } else { - label.attributedText = NSAttributedString(string: groupList[row], attributes: [NSAttributedString.Key.font: UIFont(name: "SpoqaHanSansNeo-Regular", size: 16.0)!, NSAttributedString.Key.foregroundColor: UIColor.quaternary]) + label.attributedText = NSAttributedString(string: groupList[row], attributes: [NSAttributedString.Key.font: UIFont.textRegular03, NSAttributedString.Key.foregroundColor: UIColor.quaternary]) } - label.text = groupList[row] - return label } diff --git a/NADA-iOS-forRelease/Sources/ViewControllers/CardCreation/CardCreationPreviewViewController.swift b/NADA-iOS-forRelease/Sources/ViewControllers/CardCreation/CardCreationPreviewViewController.swift index b8f788ff..56addb29 100644 --- a/NADA-iOS-forRelease/Sources/ViewControllers/CardCreation/CardCreationPreviewViewController.swift +++ b/NADA-iOS-forRelease/Sources/ViewControllers/CardCreation/CardCreationPreviewViewController.swift @@ -35,7 +35,7 @@ class CardCreationPreviewViewController: UIViewController { guard let frontCardDataModel = frontCardDataModel, let backCardDataModel = backCardDataModel else { return } cardCreationRequest = CardCreationRequest(userID: "", frontCard: frontCardDataModel, backCard: backCardDataModel) guard let cardCreationRequest = cardCreationRequest else { return } - // TODO: - 갤러리 추가/이미지 코드 추가 + cardCreationWithAPI(request: cardCreationRequest, image: cardBackgroundImage ?? UIImage()) } @IBAction func touchBackButton(_ sender: Any) { diff --git a/NADA-iOS-forRelease/Sources/ViewControllers/Group/GroupViewController.swift b/NADA-iOS-forRelease/Sources/ViewControllers/Group/GroupViewController.swift index 0f191e1d..a5954aab 100644 --- a/NADA-iOS-forRelease/Sources/ViewControllers/Group/GroupViewController.swift +++ b/NADA-iOS-forRelease/Sources/ViewControllers/Group/GroupViewController.swift @@ -5,6 +5,7 @@ // Created by 민 on 2021/10/08. // +import Photos import UIKit class GroupViewController: UIViewController { @@ -20,9 +21,30 @@ class GroupViewController: UIViewController { } @IBAction func presentToAddWithQrView(_ sender: Any) { - guard let nextVC = UIStoryboard.init(name: Const.Storyboard.Name.qrScan, bundle: nil).instantiateViewController(withIdentifier: Const.ViewController.Identifier.qrScanViewController) as? QRScanViewController else { return } - nextVC.modalPresentationStyle = .overFullScreen - self.present(nextVC, animated: true, completion: nil) + switch AVCaptureDevice.authorizationStatus(for: .video) { + case .denied: + makeOKCancelAlert(title: "카메라 권한이 허용되어 있지 않아요.", + message: "QR코드 인식을 위해 카메라 권한이 필요합니다. 앱 설정으로 이동해 허용해 주세요.", + okAction: { _ in UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)}, + cancelAction: nil, + completion: nil) + case .authorized: + guard let nextVC = UIStoryboard.init(name: Const.Storyboard.Name.qrScan, bundle: nil).instantiateViewController(withIdentifier: Const.ViewController.Identifier.qrScanViewController) as? QRScanViewController else { return } + nextVC.modalPresentationStyle = .overFullScreen + self.present(nextVC, animated: true, completion: nil) + case .notDetermined: + AVCaptureDevice.requestAccess(for: .video) { granted in + if granted { + DispatchQueue.main.async { + guard let nextVC = UIStoryboard.init(name: Const.Storyboard.Name.qrScan, bundle: nil).instantiateViewController(withIdentifier: Const.ViewController.Identifier.qrScanViewController) as? QRScanViewController else { return } + nextVC.modalPresentationStyle = .overFullScreen + self.present(nextVC, animated: true, completion: nil) + } + } + } + default: + break + } } // 중간 그룹 이름들 나열된 뷰 diff --git a/NADA-iOS-forRelease/Sources/ViewControllers/Group/QRScanViewController.swift b/NADA-iOS-forRelease/Sources/ViewControllers/Group/QRScanViewController.swift index 567482d8..7b266044 100644 --- a/NADA-iOS-forRelease/Sources/ViewControllers/Group/QRScanViewController.swift +++ b/NADA-iOS-forRelease/Sources/ViewControllers/Group/QRScanViewController.swift @@ -6,13 +6,133 @@ // import UIKit +import AVFoundation class QRScanViewController: UIViewController { + // MARK: - Properties + private let captureSession = AVCaptureSession() + + // 네비게이션 바 + private let titleLabel: UILabel = { + let label = UILabel() + label.text = "QR스캔" + label.textColor = .background + label.font = UIFont.title01 + return label + }() + + private let dismissButton: UIButton = { + let button = UIButton() + button.setImage(UIImage(named: "iconQRClear"), for: .normal) + button.addTarget(self, action: #selector(dismissQRScanViewController), for: .touchUpInside) + return button + }() + override func viewDidLoad() { super.viewDidLoad() + basicSetting() + } + +} - // Do any additional setup after loading the view. +extension QRScanViewController { + @objc func dismissQRScanViewController() { + self.dismiss(animated: true, completion: nil) + } +} + +extension QRScanViewController { + + private func basicSetting() { + guard let captureDevice = AVCaptureDevice.default(for: AVMediaType.video) else { + fatalError("No video device found") + } + do { + let rectOfInterest = CGRect(x: 24, y: (UIScreen.main.bounds.height - 200) / 2, width: 327, height: 327) + + let input = try AVCaptureDeviceInput(device: captureDevice) + captureSession.addInput(input) + + let output = AVCaptureMetadataOutput() + captureSession.addOutput(output) + + output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) + output.metadataObjectTypes = [AVMetadataObject.ObjectType.qr] + + let rectConverted = setVideoLayer(rectOfInterest: rectOfInterest) + output.rectOfInterest = rectConverted + + setGuideLineView(rectOfInterest: rectOfInterest) + captureSession.startRunning() + } catch { + print("error") + } + } + + private func setVideoLayer(rectOfInterest: CGRect) -> CGRect { + let videoLayer = AVCaptureVideoPreviewLayer(session: captureSession) + videoLayer.frame = view.layer.bounds + videoLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill + view.layer.addSublayer(videoLayer) + + return videoLayer.metadataOutputRectConverted(fromLayerRect: rectOfInterest) + } + + private func setGuideLineView(rectOfInterest: CGRect) { + let guideImage = UIImageView() + guideImage.image = UIImage(named: "subtract") + guideImage.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(titleLabel) + view.addSubview(dismissButton) + view.addSubview(guideImage) + titleLabel.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + titleLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 68), + titleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24) + ]) + + dismissButton.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + dismissButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 68), + dismissButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24) + ]) + + NSLayoutConstraint.activate([ + guideImage.centerXAnchor.constraint(equalTo: view.centerXAnchor), + guideImage.centerYAnchor.constraint(equalTo: view.centerYAnchor), + guideImage.widthAnchor.constraint(equalToConstant: 327), + guideImage.heightAnchor.constraint(equalToConstant: 327) + ]) } +} + +extension QRScanViewController: AVCaptureMetadataOutputObjectsDelegate { + + func metadataOutput(_ captureOutput: AVCaptureMetadataOutput, + didOutput metadataObjects: [AVMetadataObject], + from connection: AVCaptureConnection) { + + if let metadataObject = metadataObjects.first { + guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject, let stringValue = readableObject.stringValue else { + return + } + + // ✅ qr코드가 가진 문자열이 URL 형태를 띈다면 출력.(아무런 qr코드나 찍는다고 출력시키면 안되니까 여기서 분기처리 가능. ) + if stringValue.hasPrefix("http://") { + print(stringValue) + + self.captureSession.stopRunning() + // TODO: 여기서 QR에 있는 ID값으로 명함검색 API통신 + let nextVC = CardResultBottomSheetViewController() + .setTitle("이채연") + .setHeight(574) + nextVC.modalPresentationStyle = .overFullScreen + self.present(nextVC, animated: false, completion: nil) + } else { + showToast(message: "유효하지 않은 QR입니다.", font: UIFont.button02) + } + } + } }