<commit_before>import AVFoundation
import ImageSource
import UIKit

enum SelectedPhotosBarState {
    case hidden
    case visible(SelectedPhotosBarData)
}

struct SelectedPhotosBarData { // TODO: make final class
    let lastPhoto: ImageSource?
    let penultimatePhoto: ImageSource?
    let countString: String
}

final class NewCameraView: UIView {
    
    // MARK: - Subviews
    var cameraOutputLayer: AVCaptureVideoPreviewLayer?
    private let closeButton = UIButton()
    private let photoLibraryButton = UIButton()
    private let captureButton = UIButton()
    private let flashButton = UIButton()
    private let toggleCameraButton = UIButton()
    private let hintLabel = UILabel()
    private let selectedPhotosBarView = SelectedPhotosBarView()
    private let flashView = UIView()
    private let snapshotView = UIImageView()
    private let photoView = UIImageView()
    
    // TODO: extract to separate view
    private let previewView = UIView()
    private let viewfinderBorderView = CameraViewfinderBorderView()
    
    // MARK: - Specs
    private let navigationBarHeight = CGFloat(52)
    private let captureButtonSize = CGFloat(64)
    
    // MARK: - Init
    init() {
        super.init(frame: .zero)
        
        backgroundColor = .white
        
        addSubview(previewView)
        addSubview(closeButton)
        addSubview(photoLibraryButton)
        addSubview(captureButton)
        addSubview(photoView)
        addSubview(flashButton)
        addSubview(toggleCameraButton)
        addSubview(hintLabel)
        addSubview(selectedPhotosBarView)
        addSubview(snapshotView)
        addSubview(flashView)
        
        photoView.backgroundColor = .lightGray
        photoView.contentMode = .scaleAspectFill
        photoView.layer.cornerRadius = 18.5
        photoView.clipsToBounds = true
        photoView.isUserInteractionEnabled = true
        photoView.addGestureRecognizer(UITapGestureRecognizer(
            target: self,
            action: #selector(onPhotoViewTap(_:))
        ))
        
        snapshotView.contentMode = .scaleAspectFill
        snapshotView.layer.cornerRadius = 10
        snapshotView.layer.masksToBounds = true
        snapshotView.isHidden = true
        
        flashView.backgroundColor = .white
        flashView.alpha = 0
        
        closeButton.addTarget(self, action: #selector(handleCloseButtonTap), for: .touchUpInside)
        
        captureButton.layer.cornerRadius = captureButtonSize / 2
        captureButton.layer.borderWidth = 6
        captureButton.addTarget(self, action: #selector(handleCaptureButtonTap), for: .touchUpInside)
        setCaptureButtonState(.enabled)
        
        previewView.layer.masksToBounds = true
        
        flashButton.addTarget(self, action: #selector(handleFlashButtonTap), for: .touchUpInside)
        
        toggleCameraButton.setImage(
            UIImage(named: "back_front_new", in: Resources.bundle, compatibleWith: nil),
            for: .normal
        )
        toggleCameraButton.addTarget(self, action: #selector(handleToggleCameraButtonTap), for: .touchUpInside)
        toggleCameraButton.sizeToFit()
        
        hintLabel.textColor = .gray
        hintLabel.textAlignment = .center
        hintLabel.numberOfLines = 0
        
        selectedPhotosBarView.isHidden = true
        
        previewView.addSubview(viewfinderBorderView)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // MARK: - NewCameraView
    var onCaptureButtonTap: (() -> ())?
    var onCloseButtonTap: (() -> ())?
    var onToggleCameraButtonTap: (() -> ())?
    var onFlashToggle: ((Bool) -> ())?
    
    var onDoneButtonTap: (() -> ())? {
        get { return selectedPhotosBarView.onButtonTap }
        set { selectedPhotosBarView.onButtonTap = newValue }
    }
    
    var onLastPhotoThumbnailTap: (() -> ())? {
        get { return selectedPhotosBarView.onLastPhotoThumbnailTap }
        set { selectedPhotosBarView.onLastPhotoThumbnailTap = newValue }
    }
    
    func setTheme(_ theme: NewCameraUITheme) {
        closeButton.setImage(theme.newCameraCloseIcon, for: .normal)
        
        flashButton.setImage(theme.newCameraFlashOffIcon, for: .normal)
        flashButton.setImage(theme.newCameraFlashOnIcon, for: .selected)
        
        hintLabel.font = theme.newCameraHintFont
        
        selectedPhotosBarView.setTheme(theme)
    }
    
    func setSelectedPhotosBarState(_ state: SelectedPhotosBarState, completion: @escaping () -> ()) {
        switch state {
        case .hidden:
            selectedPhotosBarView.isHidden = true
            completion()
        case .visible(let data):
            selectedPhotosBarView.isHidden = false
            selectedPhotosBarView.label.text = data.countString
            
            let dispatchGroup = DispatchGroup()
            
            dispatchGroup.enter()
            selectedPhotosBarView.lastPhotoThumbnailView.setImage(
                fromSource: data.lastPhoto,
                resultHandler: { result in
                    // TODO: fix possible but with leaving more times than entering
                    if !result.degraded {
                        dispatchGroup.leave()
                    }
                }
            )
            
            dispatchGroup.enter()
            selectedPhotosBarView.penultimatePhotoThumbnailView.setImage(
                fromSource: data.penultimatePhoto,
                resultHandler: { result in
                    // TODO: fix possible but with leaving more times than entering
                    if !result.degraded {
                        dispatchGroup.leave()
                    }
                }
            )<commit_msg>SEL-8362: Fix photo snapshot staying on screen after deleting the only photo<commit_after>import AVFoundation
import ImageSource
import UIKit

enum SelectedPhotosBarState {
    case hidden
    case visible(SelectedPhotosBarData)
}

struct SelectedPhotosBarData { // TODO: make final class
    let lastPhoto: ImageSource?
    let penultimatePhoto: ImageSource?
    let countString: String
}

final class NewCameraView: UIView {
    
    // MARK: - Subviews
    var cameraOutputLayer: AVCaptureVideoPreviewLayer?
    private let closeButton = UIButton()
    private let photoLibraryButton = UIButton()
    private let captureButton = UIButton()
    private let flashButton = UIButton()
    private let toggleCameraButton = UIButton()
    private let hintLabel = UILabel()
    private let selectedPhotosBarView = SelectedPhotosBarView()
    private let flashView = UIView()
    private let snapshotView = UIImageView()
    private let photoView = UIImageView()
    
    // TODO: extract to separate view
    private let previewView = UIView()
    private let viewfinderBorderView = CameraViewfinderBorderView()
    
    // MARK: - Specs
    private let navigationBarHeight = CGFloat(52)
    private let captureButtonSize = CGFloat(64)
    
    // MARK: - Init
    init() {
        super.init(frame: .zero)
        
        backgroundColor = .white
        
        addSubview(previewView)
        addSubview(closeButton)
        addSubview(photoLibraryButton)
        addSubview(captureButton)
        addSubview(photoView)
        addSubview(flashButton)
        addSubview(toggleCameraButton)
        addSubview(hintLabel)
        addSubview(selectedPhotosBarView)
        addSubview(snapshotView)
        addSubview(flashView)
        
        photoView.backgroundColor = .lightGray
        photoView.contentMode = .scaleAspectFill
        photoView.layer.cornerRadius = 18.5
        photoView.clipsToBounds = true
        photoView.isUserInteractionEnabled = true
        photoView.addGestureRecognizer(UITapGestureRecognizer(
            target: self,
            action: #selector(onPhotoViewTap(_:))
        ))
        
        snapshotView.contentMode = .scaleAspectFill
        snapshotView.layer.cornerRadius = 10
        snapshotView.layer.masksToBounds = true
        snapshotView.isHidden = true
        
        flashView.backgroundColor = .white
        flashView.alpha = 0
        
        closeButton.addTarget(self, action: #selector(handleCloseButtonTap), for: .touchUpInside)
        
        captureButton.layer.cornerRadius = captureButtonSize / 2
        captureButton.layer.borderWidth = 6
        captureButton.addTarget(self, action: #selector(handleCaptureButtonTap), for: .touchUpInside)
        setCaptureButtonState(.enabled)
        
        previewView.layer.masksToBounds = true
        
        flashButton.addTarget(self, action: #selector(handleFlashButtonTap), for: .touchUpInside)
        
        toggleCameraButton.setImage(
            UIImage(named: "back_front_new", in: Resources.bundle, compatibleWith: nil),
            for: .normal
        )
        toggleCameraButton.addTarget(self, action: #selector(handleToggleCameraButtonTap), for: .touchUpInside)
        toggleCameraButton.sizeToFit()
        
        hintLabel.textColor = .gray
        hintLabel.textAlignment = .center
        hintLabel.numberOfLines = 0
        
        selectedPhotosBarView.isHidden = true
        
        previewView.addSubview(viewfinderBorderView)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // MARK: - NewCameraView
    var onCaptureButtonTap: (() -> ())?
    var onCloseButtonTap: (() -> ())?
    var onToggleCameraButtonTap: (() -> ())?
    var onFlashToggle: ((Bool) -> ())?
    
    var onDoneButtonTap: (() -> ())? {
        get { return selectedPhotosBarView.onButtonTap }
        set { selectedPhotosBarView.onButtonTap = newValue }
    }
    
    var onLastPhotoThumbnailTap: (() -> ())? {
        get { return selectedPhotosBarView.onLastPhotoThumbnailTap }
        set { selectedPhotosBarView.onLastPhotoThumbnailTap = newValue }
    }
    
    func setTheme(_ theme: NewCameraUITheme) {
        closeButton.setImage(theme.newCameraCloseIcon, for: .normal)
        
        flashButton.setImage(theme.newCameraFlashOffIcon, for: .normal)
        flashButton.setImage(theme.newCameraFlashOnIcon, for: .selected)
        
        hintLabel.font = theme.newCameraHintFont
        
        selectedPhotosBarView.setTheme(theme)
    }
    
    func setSelectedPhotosBarState(_ state: SelectedPhotosBarState, completion: @escaping () -> ()) {
        switch state {
        case .hidden:
            selectedPhotosBarView.isHidden = true
            completion()
        case .visible(let data):
            selectedPhotosBarView.isHidden = false
            selectedPhotosBarView.label.text = data.countString
            
            let dispatchGroup = DispatchGroup()
            
            if let lastPhoto = data.lastPhoto {
                dispatchGroup.enter()
                selectedPhotosBarView.lastPhotoThumbnailView.setImage(
                    fromSource: lastPhoto,
                    resultHandler: { result in
                        // TODO: fix possible bug with leaving more times than entering
                        if !result.degraded {
                            dispatchGroup.leave()
                        }
                    }
                )
            }
            
            if let penultimatePhoto = data.penultimatePhoto {
                dispatchGroup.enter()
                selectedPhotosBarView.penultimatePhotoThumbnailView.setImage(
                    fromSource: penultimatePhoto,
                    resultHandler: { result in
                        // TODO: fix possible bug with leaving more times than entering
                        if !result.degraded {
                            dispatchGroup.leave()
                        }
                    }
                )
            }
{'fraction_non_alphanumeric': 0.076514704643128, 'fraction_numerical': 0.002528018875874273, 'mean_word_length': 2.1488458477049615, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2138144', 'n_tokens_mistral': 3217, 'n_tokens_neox': 3068, 'n_words': 631}