stanwood/Stanwood_Debugger_iOS

View on GitHub
Sources/Harlow/Modules/DataDetail/DataDetailViewController.swift

Summary

Maintainability
A
0 mins
Test Coverage
//
//  DataDetailViewController.swift
//
//  The MIT License (MIT)
//
//  Copyright (c) 2018 Stanwood GmbH (www.stanwood.io)
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//

import UIKit
import WebKit
import Loaf

class DataDetailViewController: UIViewController {
    
    var presenter: DataDetailPresenter!
    private var dataItem: NetworkData?
    private var scrollView: UIScrollView?
    private var imageView: UIImageView?
    private var imageViewFrame: CGRect = .zero
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configureView()
    }
    
    private func configureView() {
        view.backgroundColor = UIColor.white.withAlphaComponent(0.95)
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        presenter.viewDidLoad()
    }
    
    @objc func handleTap() {
        guard let imageView = imageView else { return }
        UIView.animate(withDuration: 0.5, delay: 0.0, options: .curveEaseInOut, animations: {
            imageView.frame = self.imageViewFrame
            self.scrollView?.zoomScale = 1.0
        }, completion: nil)
    }
    
    fileprivate func present(text: String, frame: CGRect) {
        let textView = UITextView(frame: frame)
        textView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.25)
        textView.addInnerShadow(onSide: .all)
        textView.isUserInteractionEnabled = true
        textView.isScrollEnabled = true
        textView.isEditable = false
        textView.isSelectable = false
        textView.text = text
        textView.textColor = UIColor.black.withAlphaComponent(0.9)
        textView.font = UIFont(name: "Menlo-Regular", size: 15)
        view.addSubview(textView)
        
        let copyButton = UIButton(frame: CGRect(x: textView.frame.width - 44, y: textView.frame.origin.y, width: 44, height: 44))
        let image = UIImage(named: "icon_copy", in: Bundle.debuggerBundle(), compatibleWith: nil)
        copyButton.setImage(image, for: .normal)
        copyButton.imageEdgeInsets = UIEdgeInsets(top: 5, left: 15, bottom: 15, right: 5)
        copyButton.addTarget(self, action: #selector(copyToClipboard(_:)), for: .touchUpInside)
        view.insertSubview(copyButton, aboveSubview: textView)
    }
    
    @objc func copyToClipboard(_ sender: UIButton) {
        guard let text = dataItem?.text, !text.isEmpty else {
            Loaf("No text to copy to clipboard", state: .success, sender: self).show()
            return
        }
        
        UIPasteboard.general.string = dataItem?.text
        Loaf("Copied text to clipboard", state: .success, sender: self).show()
    }
    
    fileprivate func present(htmlString: String, frame: CGRect) {
        let webView = WKWebView(frame: frame)
        view.addSubview(webView)
        webView.loadHTMLString(htmlString, baseURL: nil)
    }
    
    fileprivate func present(_ image: UIImage, frame: CGRect) {
        scrollView = UIScrollView(frame: frame)
        scrollView?.isUserInteractionEnabled = true
        scrollView?.zoomScale = 1.0
        scrollView?.minimumZoomScale = 1.0
        scrollView?.maximumZoomScale = 3.0
        
        if let scrollView = scrollView {
            view.addSubview(scrollView)
            
            let imageView = UIImageView(image: image)
            imageView.alpha = 0
            self.imageView = imageView
            imageView.isUserInteractionEnabled = true
            let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
            tap.numberOfTapsRequired = 2
            imageView.addGestureRecognizer(tap)
            
            scrollView.delegate = self
            scrollView.addSubview(imageView)
            
            UIView.animate(withDuration: 0.5, delay: 0.5, options: .curveEaseInOut, animations: {
                self.imageView?.alpha = 1
            }, completion:  { _ in
                self.imageViewFrame = imageView.frame
            })
        }
    }
}

extension DataDetailViewController: DataDetailViewable, UIScrollViewDelegate {
    
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return imageView
    }
    
    func show(_ networkData: NetworkData) {
        
        dataItem = networkData
        
        let heightOffset: CGFloat = navigationController?.navigationBar.frame.height ?? 0
        let statusBarOffset: CGFloat = UIApplication.shared.statusBarFrame.height
        let offset = heightOffset + statusBarOffset
        let frame = CGRect(x: 0, y: offset, width: view.frame.width, height: view.frame.height - offset)
        
        if let image = networkData.image {
            present(image, frame: frame)
        } else if networkData.isHTML {
            present(htmlString: networkData.text ?? "", frame: frame)
        } else if let text = networkData.text {
            present(text: text, frame: frame)
        }
    }

    var navigationBarTitle: String? {
        get { return title ?? navigationItem.title }
        set { title = newValue }
    }
}