781 lines
28 KiB
Swift
781 lines
28 KiB
Swift
import UIKit
|
|
import AVFoundation
|
|
import React
|
|
|
|
@objc(CameraView)
|
|
class CameraView: UIView, AVCaptureVideoDataOutputSampleBufferDelegate {
|
|
var captureSession: AVCaptureSession!
|
|
var videoOutput: AVCaptureVideoDataOutput?
|
|
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
|
|
var overlayImageView: UIImageView!
|
|
var titleLabel: UILabel!
|
|
var bottomLeftLabel: UILabel!
|
|
var cardData:NSArray!
|
|
var CARD_SCANNING_TYPE:Int!
|
|
var classData:NSDictionary?
|
|
var optionData:NSDictionary!
|
|
//var cardResult:NSDictionary!
|
|
var cardResult: [[String: Any]] = []
|
|
var correctAnswer:NSString! = ""
|
|
var scanCardButton1: UIButton!
|
|
var saveCardButton:UIButton!
|
|
var startScan:Bool = false
|
|
var attendanceTotalLabel: UILabel!
|
|
var attendanceTotalCount: UILabel!
|
|
var standardLabel: UILabel!
|
|
var standardName: UILabel!
|
|
|
|
private var timer: Timer?
|
|
private let timeLabel: UILabel = {
|
|
let label = UILabel()
|
|
//label.backgroundColor = UIColor.white.withAlphaComponent(0.7)
|
|
label.textColor = .white
|
|
label.textAlignment = .center
|
|
label.font = UIFont.systemFont(ofSize: 16, weight: .bold)
|
|
return label
|
|
}()
|
|
|
|
var answers = [
|
|
["is_correct": false, "option": "A"],
|
|
["is_correct": false, "option": "B"],
|
|
["is_correct": false, "option": "C"],
|
|
["is_correct": false, "option": "D"]
|
|
]
|
|
|
|
|
|
@objc var title: String? {
|
|
didSet {
|
|
titleLabel.text = title
|
|
}
|
|
}
|
|
|
|
|
|
@objc var type: NSNumber? {
|
|
didSet {
|
|
if let type = type {
|
|
|
|
CARD_SCANNING_TYPE = type.intValue
|
|
|
|
if (CARD_SCANNING_TYPE == 1){
|
|
createCorrectAnsLayout(context: self, scanCardButton:scanCardButton1)
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
@objc var cards: NSArray? {
|
|
didSet {
|
|
if let cards = cards {
|
|
|
|
cardData = cards
|
|
|
|
addCardsToTopRight(cards)
|
|
|
|
let cardResultCount = cardResult.count
|
|
let cardsCount = cards.count
|
|
|
|
attendanceTotalCount.text = "\(cardResultCount) / \(cardsCount)"
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
@objc var classes: NSDictionary? {
|
|
didSet {
|
|
if let classes = classes {
|
|
|
|
classData = classes
|
|
if let className = classes["class_name"] as? String {
|
|
standardName.text = className
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@objc var options: NSDictionary? {
|
|
didSet {
|
|
if let options = options {
|
|
|
|
optionData = options
|
|
|
|
if let standard_Label = options["standardLabel"] as? String {
|
|
standardLabel.text = standard_Label
|
|
}
|
|
|
|
if let attendance_label = options["attendanceLabel"] as? String {
|
|
attendanceTotalLabel.text = attendance_label
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@objc func setIntValue(_ val: NSNumber) {
|
|
|
|
}
|
|
|
|
@objc var onChange: RCTBubblingEventBlock?
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
setupCaptureSession()
|
|
setupOverlayImageView()
|
|
setupTitleLabel()
|
|
setupTimeLabel()
|
|
setupOrientationChangeObserver()
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
super.init(coder: coder)
|
|
setupCaptureSession()
|
|
setupOverlayImageView()
|
|
setupTitleLabel()
|
|
setupTimeLabel()
|
|
setupOrientationChangeObserver()
|
|
}
|
|
|
|
func setupOrientationChangeObserver() {
|
|
|
|
|
|
UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")
|
|
UIViewController.attemptRotationToDeviceOrientation()
|
|
|
|
// NotificationCenter.default.addObserver(self, selector: #selector(orientationChanged), name: UIDevice.orientationDidChangeNotification, object: nil)
|
|
}
|
|
|
|
|
|
@objc func orientationChanged() {
|
|
let orientation = UIDevice.current.orientation
|
|
switch orientation {
|
|
case .landscapeLeft, .landscapeRight:
|
|
adjustImageViewForLandscape()
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
func adjustImageViewForLandscape() {
|
|
overlayImageView.frame = self.bounds
|
|
overlayImageView.setNeedsLayout()
|
|
}
|
|
|
|
var isAuthorized: Bool {
|
|
get async {
|
|
let status = AVCaptureDevice.authorizationStatus(for: .video)
|
|
|
|
// Determine if the user previously authorized camera access.
|
|
var isAuthorized = status == .authorized
|
|
|
|
// If the system hasn't determined the user's authorization status,
|
|
// explicitly prompt them for approval.
|
|
if status == .notDetermined {
|
|
isAuthorized = await AVCaptureDevice.requestAccess(for: .video)
|
|
}
|
|
|
|
return isAuthorized
|
|
}
|
|
}
|
|
|
|
private func setupCaptureSession() {
|
|
captureSession = AVCaptureSession()
|
|
guard let captureSession = captureSession else { return }
|
|
|
|
guard let videoCaptureDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) else { return }
|
|
let videoInput: AVCaptureDeviceInput
|
|
|
|
do {
|
|
videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
|
|
} catch {
|
|
print("Error creating video input: \(error)")
|
|
return
|
|
}
|
|
|
|
if captureSession.canAddInput(videoInput) {
|
|
captureSession.addInput(videoInput)
|
|
} else {
|
|
print("Could not add video input to capture session")
|
|
return
|
|
}
|
|
|
|
videoOutput = AVCaptureVideoDataOutput()
|
|
guard let videoOutput = videoOutput else { return }
|
|
|
|
videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue"))
|
|
videoOutput.alwaysDiscardsLateVideoFrames = true
|
|
videoOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA]
|
|
|
|
if captureSession.canAddOutput(videoOutput) {
|
|
captureSession.addOutput(videoOutput)
|
|
} else {
|
|
print("Could not add video output to capture session")
|
|
return
|
|
}
|
|
|
|
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
|
|
guard let videoPreviewLayer = videoPreviewLayer else { return }
|
|
|
|
videoPreviewLayer.videoGravity = .resizeAspectFill
|
|
videoPreviewLayer.frame = self.layer.bounds
|
|
self.layer.addSublayer(videoPreviewLayer)
|
|
|
|
captureSession.startRunning()
|
|
}
|
|
|
|
override func layoutSubviews() {
|
|
super.layoutSubviews()
|
|
videoPreviewLayer?.frame = self.bounds
|
|
}
|
|
|
|
|
|
|
|
private func setupTimeLabel() {
|
|
timeLabel.frame = CGRect(x: 10, y: 10, width: 100, height: 30)
|
|
|
|
self.addSubview(timeLabel)
|
|
bringSubviewToFront(timeLabel)
|
|
timeLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
NSLayoutConstraint.activate([
|
|
timeLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 20),
|
|
timeLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20)
|
|
])
|
|
// Update the time every second
|
|
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
|
|
self?.updateTimeLabel()
|
|
}
|
|
}
|
|
|
|
private func updateTimeLabel() {
|
|
let formatter = DateFormatter()
|
|
formatter.dateFormat = "h:mm:ss a" // 12:11:11 PM format
|
|
let currentTime = formatter.string(from: Date())
|
|
timeLabel.text = currentTime
|
|
}
|
|
|
|
deinit {
|
|
captureSession.stopRunning()
|
|
timer?.invalidate()
|
|
}
|
|
|
|
private func setupTitleLabel() {
|
|
|
|
let attendanceLayout = createAttendanceLayout()
|
|
self.addSubview(attendanceLayout)
|
|
bringSubviewToFront(attendanceLayout)
|
|
|
|
let standardLayout = createStandardLayout(relativeTo: attendanceLayout)
|
|
self.addSubview(standardLayout)
|
|
bringSubviewToFront(standardLayout)
|
|
|
|
scanCardButton1 = UIButton(type: .system)
|
|
scanCardButton1.setTitleColor(.gray, for: .normal)
|
|
scanCardButton1.translatesAutoresizingMaskIntoConstraints = false
|
|
scanCardButton1.addTarget(self, action: #selector(scanCard), for: .touchUpInside)
|
|
self.addSubview(scanCardButton1)
|
|
bringSubviewToFront(scanCardButton1)
|
|
|
|
let buttonSize: CGFloat = 60
|
|
|
|
NSLayoutConstraint.activate([
|
|
scanCardButton1.widthAnchor.constraint(equalToConstant: buttonSize),
|
|
scanCardButton1.heightAnchor.constraint(equalToConstant: buttonSize),
|
|
scanCardButton1.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -10),
|
|
scanCardButton1.centerXAnchor.constraint(equalTo: self.centerXAnchor)
|
|
])
|
|
|
|
scanCardButton1.backgroundColor = .white
|
|
scanCardButton1.contentEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
|
|
|
|
let image = UIImage(systemName: "camera")?.withRenderingMode(.alwaysTemplate)
|
|
scanCardButton1.setImage(image, for: .normal)
|
|
scanCardButton1.tintColor = .gray
|
|
|
|
// Making the button round and setting border color to red
|
|
scanCardButton1.layer.cornerRadius = buttonSize / 2
|
|
scanCardButton1.layer.borderWidth = 3
|
|
scanCardButton1.layer.borderColor = UIColor.red.cgColor
|
|
scanCardButton1.imageEdgeInsets = UIEdgeInsets(top: -10, left: -10, bottom: -10, right: -10)
|
|
|
|
|
|
saveCardButton = UIButton(type: .system)
|
|
//saveCardButton.setTitle("Save", for: .normal)
|
|
saveCardButton.setTitleColor(.blue, for: .normal)
|
|
// Set the layout constraints
|
|
saveCardButton.translatesAutoresizingMaskIntoConstraints = false
|
|
saveCardButton.addTarget(self, action: #selector(saveCard), for: .touchUpInside)
|
|
self.addSubview(saveCardButton)
|
|
bringSubviewToFront(saveCardButton)
|
|
saveCardButton.frame = CGRect(x: 100, y: 100, width: 200, height: 50)
|
|
//saveCardButton.contentEdgeInsets = UIEdgeInsets(top: 40, left: 40, bottom: 40, right: 40)
|
|
|
|
|
|
let saveimage = UIImage(systemName: "doc")?.withRenderingMode(.alwaysTemplate)
|
|
saveCardButton.setImage(saveimage, for: .normal)
|
|
saveCardButton.tintColor = .gray
|
|
|
|
|
|
let savebuttonSize: CGFloat = 50
|
|
|
|
NSLayoutConstraint.activate([
|
|
saveCardButton.widthAnchor.constraint(equalToConstant: savebuttonSize),
|
|
saveCardButton.heightAnchor.constraint(equalToConstant: savebuttonSize),
|
|
saveCardButton.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -10),
|
|
saveCardButton.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20)
|
|
])
|
|
//
|
|
saveCardButton.backgroundColor = .white
|
|
saveCardButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
|
|
|
|
saveCardButton.layer.cornerRadius = savebuttonSize / 2
|
|
saveCardButton.layer.borderWidth = 2
|
|
saveCardButton.layer.borderColor = UIColor.red.cgColor
|
|
|
|
attendanceTotalCount = createLabel(withText: "0/6")
|
|
attendanceTotalLabel = createLabel(withText: "Instant Feedback")
|
|
standardName = createLabel(withText: "XII A")
|
|
standardLabel = createLabel(withText: "Standard")
|
|
|
|
// Create horizontal stack views for each row
|
|
let row1StackView = UIStackView(arrangedSubviews: [attendanceTotalCount, standardName])
|
|
row1StackView.axis = .horizontal
|
|
row1StackView.distribution = .fillEqually
|
|
row1StackView.spacing = 1
|
|
|
|
let row2StackView = UIStackView(arrangedSubviews: [attendanceTotalLabel, standardLabel])
|
|
row2StackView.axis = .horizontal
|
|
row2StackView.distribution = .fillEqually
|
|
row2StackView.spacing = 1
|
|
|
|
// Create a vertical stack view to hold the two rows
|
|
let mainStackView = UIStackView(arrangedSubviews: [row1StackView, row2StackView])
|
|
mainStackView.axis = .vertical
|
|
mainStackView.distribution = .fillEqually
|
|
mainStackView.spacing = 1
|
|
|
|
// Add the main stack view to the view
|
|
self.addSubview(mainStackView)
|
|
bringSubviewToFront(mainStackView)
|
|
mainStackView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
// Set constraints for the main stack view
|
|
NSLayoutConstraint.activate([
|
|
mainStackView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20),
|
|
mainStackView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -20),
|
|
mainStackView.widthAnchor.constraint(equalToConstant: 200), // Adjust as needed
|
|
mainStackView.heightAnchor.constraint(equalToConstant: 50) // Adjust as needed
|
|
])
|
|
|
|
|
|
|
|
}
|
|
@objc func scanCard() {
|
|
|
|
if (startScan) {
|
|
startScan = false;
|
|
scanCardButton1.setImage(UIImage(systemName: "camera"), for: .normal)
|
|
}else{
|
|
startScan = true;
|
|
scanCardButton1.setImage(UIImage(systemName: "pause.fill"), for: .normal)
|
|
}
|
|
|
|
}
|
|
|
|
@objc func saveCard() {
|
|
if(startScan){
|
|
if let onChange = onChange {
|
|
|
|
var dictionary: [String: Any] = [:]
|
|
if let classData = classData as? [String: Any],
|
|
let academicYear = classData["academic_year"] as? Int {
|
|
dictionary["academic_year"] = academicYear
|
|
|
|
} else {
|
|
print("Failed to extract academic year")
|
|
}
|
|
|
|
if let academic_year = classData?["academic_year"] as? String {
|
|
dictionary["academic_year"] = academic_year
|
|
}
|
|
if let class_id = classData?["class_id"] as? String {
|
|
dictionary["class_id"] = class_id
|
|
}
|
|
|
|
if let subject_id = classData?["subject_id"] as? String {
|
|
dictionary["subject_id"] = subject_id
|
|
}
|
|
|
|
dictionary["status"] = true
|
|
|
|
if (CARD_SCANNING_TYPE == 0) {
|
|
dictionary["attendance_details"] = cardResult
|
|
}
|
|
else if (CARD_SCANNING_TYPE == 1) {
|
|
|
|
if let name = classData?["name"] as? String {
|
|
dictionary["name"] = name
|
|
}
|
|
if let topics = classData?["topics"] as? String {
|
|
dictionary["topics"] = topics
|
|
}
|
|
|
|
if let subject_id = classData?["subject_id"] as? String {
|
|
dictionary["subject_id"] = subject_id
|
|
}
|
|
|
|
dictionary["correct_answer"] = correctAnswer
|
|
dictionary["answers"] = answers
|
|
|
|
dictionary["feedback_result"] = cardResult
|
|
}
|
|
else if (CARD_SCANNING_TYPE == 2) {
|
|
dictionary["quiz_result"] = cardResult
|
|
}
|
|
|
|
// onChange(["attendance_details": data, "academic_year": academicYear, "class_id": "35", "status": true, "subject_id": "5"])
|
|
if CARD_SCANNING_TYPE == 1 && (correctAnswer == nil || correctAnswer.length == 0){
|
|
showToast(message: "Please choose the correct answer.", font: .systemFont(ofSize: 12.0))
|
|
}else{
|
|
onChange(dictionary)
|
|
startScan = false;
|
|
scanCardButton1.setImage(UIImage(systemName: "camera"), for: .normal)
|
|
captureSession.stopRunning()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func showToast(message : String, font: UIFont) {
|
|
|
|
let toastLabel = UILabel(frame: CGRect(x: self.frame.size.width/2 - 75, y: self.frame.size.height-100, width: 200, height: 35))
|
|
toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6)
|
|
toastLabel.textColor = UIColor.white
|
|
toastLabel.font = font
|
|
toastLabel.textAlignment = .center;
|
|
toastLabel.text = message
|
|
toastLabel.alpha = 1.0
|
|
toastLabel.layer.cornerRadius = 10;
|
|
toastLabel.clipsToBounds = true
|
|
self.addSubview(toastLabel)
|
|
bringSubviewToFront(toastLabel)
|
|
|
|
UIView.animate(withDuration: 4.0, delay: 0.1, options: .curveEaseOut, animations: {
|
|
toastLabel.alpha = 0.0
|
|
}, completion: {(isCompleted) in
|
|
toastLabel.removeFromSuperview()
|
|
})
|
|
}
|
|
|
|
func createCorrectAnsLayout(context: UIView, scanCardButton: UIButton) -> UIView {
|
|
let correctAnsLayout = UIView()
|
|
correctAnsLayout.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
context.addSubview(correctAnsLayout)
|
|
NSLayoutConstraint.activate([
|
|
correctAnsLayout.bottomAnchor.constraint(equalTo: context.bottomAnchor, constant: -10),
|
|
correctAnsLayout.leadingAnchor.constraint(equalTo: scanCardButton.trailingAnchor, constant: 20),
|
|
correctAnsLayout.trailingAnchor.constraint(equalTo: saveCardButton.leadingAnchor, constant: -10)
|
|
])
|
|
|
|
|
|
let buttonTitles = ["A", "B", "C", "D"]
|
|
var previousButton: UIButton?
|
|
|
|
for (index, title) in buttonTitles.enumerated() {
|
|
let button = UIButton(type: .system)
|
|
button.setTitle(title, for: .normal)
|
|
button.backgroundColor = .gray
|
|
button.setTitleColor(.white, for: .normal)
|
|
button.titleLabel?.font = UIFont.systemFont(ofSize: 20) // Increase font size
|
|
button.layer.cornerRadius = 20 // Make the button rounded
|
|
button.layer.masksToBounds = true
|
|
button.translatesAutoresizingMaskIntoConstraints = false
|
|
button.tag = 1000 + index
|
|
button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
|
|
correctAnsLayout.addSubview(button)
|
|
|
|
NSLayoutConstraint.activate([
|
|
button.topAnchor.constraint(equalTo: correctAnsLayout.topAnchor),
|
|
button.bottomAnchor.constraint(equalTo: correctAnsLayout.bottomAnchor),
|
|
button.heightAnchor.constraint(equalToConstant: 40),
|
|
button.widthAnchor.constraint(equalToConstant: 40)
|
|
])
|
|
|
|
|
|
|
|
if let previousButton = previousButton {
|
|
NSLayoutConstraint.activate([
|
|
button.leadingAnchor.constraint(equalTo: previousButton.trailingAnchor, constant: 10),
|
|
button.widthAnchor.constraint(equalTo: previousButton.widthAnchor)
|
|
])
|
|
} else {
|
|
NSLayoutConstraint.activate([
|
|
button.leadingAnchor.constraint(equalTo: correctAnsLayout.leadingAnchor)
|
|
])
|
|
}
|
|
|
|
previousButton = button
|
|
}
|
|
|
|
return correctAnsLayout
|
|
}
|
|
|
|
@objc func buttonTapped(_ sender: UIButton) {
|
|
// Update the answers array
|
|
let tag = sender.tag - 1000
|
|
for index in 0..<answers.count {
|
|
answers[index]["is_correct"] = (index == tag)
|
|
}
|
|
|
|
let selectedOption = answers[tag]["option"] as! String
|
|
correctAnswer = selectedOption as NSString
|
|
|
|
|
|
// Update the button colors
|
|
for button in sender.superview!.subviews where button is UIButton {
|
|
(button as! UIButton).backgroundColor = .gray
|
|
}
|
|
sender.backgroundColor = .green
|
|
}
|
|
|
|
|
|
func addCardsToTopRight(_ CARD_LISTS: NSArray) {
|
|
|
|
let containerView = UIView()
|
|
containerView.translatesAutoresizingMaskIntoConstraints = false
|
|
self.addSubview(containerView)
|
|
bringSubviewToFront(containerView)
|
|
|
|
let tableLayout = createCardsDesignTableLayout(context: containerView)
|
|
containerView.addSubview(tableLayout)
|
|
|
|
NSLayoutConstraint.activate([
|
|
|
|
containerView.topAnchor.constraint(equalTo: self.topAnchor, constant: 20),
|
|
containerView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20),
|
|
tableLayout.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
|
|
tableLayout.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
|
|
tableLayout.topAnchor.constraint(equalTo: containerView.topAnchor),
|
|
tableLayout.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
|
|
])
|
|
|
|
var tableRow = UIStackView()
|
|
tableRow.axis = .horizontal
|
|
tableRow.spacing = 5
|
|
//tableRow.alignment = .leading
|
|
tableRow.alignment = .center // Centers the buttons vertically
|
|
tableRow.distribution = .equalSpacing // Ensures equal spacing between buttons
|
|
|
|
for (index, card) in CARD_LISTS.enumerated() {
|
|
guard let cardDict = card as? [String: Any] else { continue }
|
|
|
|
if index % 5 == 0 {
|
|
tableRow = UIStackView()
|
|
tableRow.axis = .horizontal
|
|
tableRow.spacing = 5
|
|
tableRow.alignment = .center // Centers the buttons vertically
|
|
tableRow.distribution = .equalSpacing // Ensures equal spacing between buttons
|
|
tableRow.translatesAutoresizingMaskIntoConstraints = false
|
|
tableLayout.addArrangedSubview(tableRow)
|
|
}
|
|
|
|
let cardButton = UIButton(type: .system)
|
|
|
|
if let cardId = cardDict["card_id"] as? Int {
|
|
cardButton.setTitle("\(cardId)", for: .normal)
|
|
cardButton.tag = cardId
|
|
} else if let cardId = cardDict["card_id"] as? String, let cardIdInt = Int(cardId) {
|
|
cardButton.setTitle(cardId, for: .normal)
|
|
cardButton.tag = cardIdInt
|
|
} else {
|
|
print("Could not cast card_id to Int for card: \(cardDict)")
|
|
}
|
|
|
|
cardButton.setTitleColor(.white, for: .normal)
|
|
cardButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 12)
|
|
cardButton.backgroundColor = UIColor.darkGray
|
|
cardButton.layer.cornerRadius = 15
|
|
|
|
tableRow.addArrangedSubview(cardButton)
|
|
NSLayoutConstraint.activate([
|
|
|
|
cardButton.heightAnchor.constraint(equalToConstant: 30),
|
|
cardButton.widthAnchor.constraint(equalToConstant: 30)
|
|
])
|
|
|
|
|
|
}
|
|
}
|
|
|
|
func createCardLabel(withText text: String) -> UILabel {
|
|
let label = UILabel()
|
|
label.text = text
|
|
label.textColor = .white
|
|
label.textAlignment = .center
|
|
label.font = UIFont(name: "OpenSans-Bold", size: 17)
|
|
label.minimumScaleFactor = 0.5
|
|
label.adjustsFontSizeToFitWidth = true
|
|
label.backgroundColor = .systemBlue
|
|
label.layer.cornerRadius = 10
|
|
label.layer.masksToBounds = true
|
|
label.translatesAutoresizingMaskIntoConstraints = false
|
|
label.heightAnchor.constraint(equalToConstant: 55).isActive = true
|
|
label.widthAnchor.constraint(equalToConstant: 55).isActive = true
|
|
return label
|
|
}
|
|
|
|
|
|
func createCardsDesignTableLayout(context: UIView) -> UIStackView {
|
|
let cardDesign = UIStackView()
|
|
cardDesign.axis = .vertical
|
|
cardDesign.spacing = 10
|
|
cardDesign.alignment = .leading
|
|
cardDesign.translatesAutoresizingMaskIntoConstraints = false
|
|
context.addSubview(cardDesign)
|
|
bringSubviewToFront(cardDesign)
|
|
|
|
return cardDesign
|
|
}
|
|
|
|
|
|
func createLabel(withText text: String) -> UILabel {
|
|
let label = UILabel()
|
|
label.text = text
|
|
label.textColor = .white
|
|
label.textAlignment = .center
|
|
label.font = UIFont.systemFont(ofSize: 11)
|
|
return label
|
|
}
|
|
|
|
|
|
func createAttendanceLayout() -> UIView {
|
|
let attendanceLayout = UIView()
|
|
attendanceLayout.translatesAutoresizingMaskIntoConstraints = false
|
|
attendanceLayout.backgroundColor = .red // Just for visibility, remove or set your color
|
|
attendanceLayout.accessibilityIdentifier = "attendance_layout_id"
|
|
return attendanceLayout
|
|
}
|
|
|
|
func createStandardLayout(relativeTo attendanceLayout: UIView) -> UIView {
|
|
let standardLayout = UIView()
|
|
standardLayout.translatesAutoresizingMaskIntoConstraints = false
|
|
standardLayout.backgroundColor = .blue // Just for visibility, remove or set your color
|
|
standardLayout.accessibilityIdentifier = "standard_layout_id"
|
|
return standardLayout
|
|
}
|
|
|
|
|
|
|
|
@objc var stringValue: String = "" {
|
|
didSet {
|
|
// Update the view with the new string value
|
|
}
|
|
}
|
|
|
|
func hasValue(cardlists: [Any], key: String, value: Int) -> Bool {
|
|
for cardD in cardData {
|
|
guard let cardDict = cardD as? [String: Any] else { continue }
|
|
if let cardIdString = cardDict[key] as? String, let cardIdInt = Int(cardIdString) {
|
|
if cardIdInt == value {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
private func storeCardResult(_ resultsArray : [[String: Any]]){
|
|
|
|
for marker in resultsArray {
|
|
let id = marker["card_id"] as! Int
|
|
let answer = marker["answer"] as! NSString
|
|
|
|
let cardExists = hasValue(cardlists: cardData as! [Any], key: "card_id", value: id)
|
|
if (cardExists) {
|
|
if (CARD_SCANNING_TYPE == 0) {
|
|
if let index = self.cardResult.firstIndex(where: { $0["card_id"] as! Int == id }) {
|
|
self.cardResult[index]["answer"] = answer
|
|
} else {
|
|
self.cardResult.append(["answer": answer, "attendance": 1, "card_id": id])
|
|
}
|
|
}else if(CARD_SCANNING_TYPE == 1){
|
|
if let index = self.cardResult.firstIndex(where: { $0["card_id"] as! Int == id }) {
|
|
self.cardResult[index]["answer"] = answer
|
|
} else {
|
|
self.cardResult.append(["answer": answer, "attendance": 1, "card_id": id])
|
|
}
|
|
}else if(CARD_SCANNING_TYPE == 2){
|
|
var serial = 0
|
|
if let serial_no = classData?["serial_no"] as? Int {
|
|
serial = serial_no
|
|
}
|
|
|
|
if let index = self.cardResult.firstIndex(where: { $0["card_id"] as! Int == id }) {
|
|
self.cardResult[index]["answer"] = answer
|
|
} else {
|
|
self.cardResult.append(["answer": answer, "serial_no": serial, "card_id": id])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
private func setupOverlayImageView() {
|
|
overlayImageView = UIImageView()
|
|
overlayImageView.translatesAutoresizingMaskIntoConstraints = false
|
|
self.addSubview(overlayImageView)
|
|
bringSubviewToFront(overlayImageView)
|
|
|
|
NSLayoutConstraint.activate([
|
|
overlayImageView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
|
|
overlayImageView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
|
|
overlayImageView.topAnchor.constraint(equalTo: self.topAnchor),
|
|
overlayImageView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
|
|
])
|
|
}
|
|
|
|
func updateOverlayImage(image: UIImage) {
|
|
overlayImageView.image = image
|
|
bringSubviewToFront(overlayImageView)
|
|
}
|
|
|
|
|
|
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
|
|
|
|
guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
|
|
let ciImage = CIImage(cvPixelBuffer: imageBuffer)
|
|
|
|
let context = CIContext()
|
|
guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else { return }
|
|
let uiImage = UIImage(cgImage: cgImage)
|
|
|
|
DispatchQueue.global(qos: .userInitiated).async {
|
|
|
|
let result = Wrapper.drawDetectedMarkers(on: uiImage, startScan: self.startScan, card_SCANNING_TYPE:Int32(self.CARD_SCANNING_TYPE)) as NSDictionary
|
|
|
|
let processedImage = result["image"] as! UIImage
|
|
let markerIds = result["markerIds"] as! [Int]
|
|
let resultsArray = result["resultsArray"] as! [[String: Any]]
|
|
|
|
DispatchQueue.main.async {
|
|
self.overlayImageView.image = processedImage
|
|
|
|
for markerId in markerIds {
|
|
if let cardButton = self.viewWithTag(markerId) as? UIButton {
|
|
cardButton.backgroundColor = .green
|
|
}
|
|
}
|
|
self.storeCardResult(resultsArray)
|
|
|
|
let cardResultCount = self.cardResult.count
|
|
let cardsCount = self.cardData.count
|
|
|
|
self.attendanceTotalCount.text = "\(cardResultCount) / \(cardsCount)"
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|