/* * Copyright (c) 2010-2020 Belledonne Communications SARL. * * This file is part of linphone-iphone * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import Foundation import SnapKit import UIKit extension UIView { // Few constraints wrapper to abstract SnapKit functions @objc func removeConstraints() -> UIView { snp.removeConstraints() return self } func square(_ size:Int) -> UIView { snp.makeConstraints { (make) in make.width.equalTo(size) make.height.equalTo(size) } return self } func squareMax(_ size:Int) -> UIView { snp.makeConstraints { (make) in make.height.lessThanOrEqualTo(size).priority(.high) make.width.equalTo(snp.height).priority(.high) } return self } func makeHeightMatchWidth() -> UIView { snp.makeConstraints { (make) in make.height.equalTo(snp.width) } return self } func makeWidthMatchHeight() -> UIView { snp.makeConstraints { (make) in make.width.equalTo(snp.height) } return self } func size(w:CGFloat,h:CGFloat) -> UIView { snp.makeConstraints { (make) in make.width.equalTo(w) make.height.equalTo(h) } return self } func updateSize(w:CGFloat,h:CGFloat) -> UIView { snp.updateConstraints { (make) in make.width.equalTo(w) make.height.equalTo(h) } return self } func height(_ h:CGFloat) -> UIView { snp.makeConstraints { (make) in make.height.equalTo(h) } return self } func height(_ h:Int) -> UIView { return height(CGFloat(h)) } func width(_ h:CGFloat) -> UIView { snp.makeConstraints { (make) in make.width.equalTo(h) } return self } func updateWidth(_ h:CGFloat) -> UIView { snp.updateConstraints { (make) in make.width.equalTo(h) } return self } func width(_ h:Int) -> UIView { return width(CGFloat(h)) } func maxHeight(_ h:CGFloat) -> UIView { snp.makeConstraints { (make) in make.height.lessThanOrEqualTo(h) } return self } func maxWidth(_ h:CGFloat) -> UIView { snp.makeConstraints { (make) in make.width.lessThanOrEqualTo(h) } return self } func minWidth(_ h:CGFloat) -> UIView { snp.makeConstraints { (make) in make.width.greaterThanOrEqualTo(h) } return self } func matchParentSideBorders(insetedByDx:CGFloat = 0) -> UIView { snp.makeConstraints { (make) in make.left.equalToSuperview().offset(insetedByDx) make.right.equalToSuperview().offset(-insetedByDx) } return self } func matchBordersOf(view:UIView) -> UIView { snp.makeConstraints { (make) in make.left.right.equalTo(view) } return self } func matchLeftBordersOf(view:UIView) -> UIView { snp.makeConstraints { (make) in make.left.equalTo(view) } return self } @objc func matchParentDimmensions() -> UIView { snp.makeConstraints { (make) in make.left.right.top.bottom.equalToSuperview() } return self } func matchParentDimmensions(insetedByDx:CGFloat) -> UIView { snp.makeConstraints { (make) in make.left.top.equalToSuperview().offset(insetedByDx) make.right.bottom.equalToSuperview().offset(-insetedByDx) } return self } func matchParentDimmensions(insetedBy:UIEdgeInsets) -> UIView { snp.makeConstraints { (make) in make.left.equalToSuperview().offset(insetedBy.left) make.top.equalToSuperview().offset(insetedBy.top) make.right.equalToSuperview().offset(-insetedBy.right) make.bottom.equalToSuperview().offset(-insetedBy.bottom) } return self } func matchBordersWith(view:UIView, insetedByDx:CGFloat = 0) -> UIView { snp.makeConstraints { (make) in make.left.top.equalTo(view).offset(insetedByDx) make.right.bottom.equalTo(view).offset(-insetedByDx) } return self } func updateTopBorderWith(view:UIView, inset:CGFloat = 0) -> UIView { snp.updateConstraints { (make) in make.top.equalTo(view).offset(inset) } return self } func matchParentEdges() -> UIView { snp.makeConstraints { (make) in make.edges.equalToSuperview() } return self } func matchDimentionsOf(view:UIView) -> UIView { snp.makeConstraints { (make) in make.left.right.top.bottom.equalTo(view) } return self } func matchParentHeight() -> UIView { snp.makeConstraints { (make) in make.top.bottom.equalToSuperview() } return self } func addRightMargin(margin:CGFloat) -> UIView { snp.makeConstraints { (make) in make.rightMargin.equalTo(margin) } return self } func matchParentHeightDividedBy(_ divider : CGFloat) -> UIView { snp.makeConstraints { (make) in make.height.equalToSuperview().dividedBy(divider) } return self } func matchParentWidthDividedBy(_ divider : CGFloat) -> UIView { snp.makeConstraints { (make) in make.width.equalToSuperview().dividedBy(divider) } return self } func center() -> UIView { snp.makeConstraints { (make) in make.center.equalToSuperview() } return self } func alignParentTop(withMargin:CGFloat = 0.0) -> UIView { snp.makeConstraints { (make) in make.top.equalToSuperview().offset(withMargin) } return self } func alignParentTop(withMargin:Int ) -> UIView { return alignParentTop(withMargin:CGFloat(withMargin)) } func alignUnder(view:UIView, withMargin:CGFloat = 0.0) -> UIView { snp.makeConstraints { (make) in make.top.equalTo(view.snp.bottom).offset(withMargin) } return self } func alignUnder(view:UIView, withMargin:Int) -> UIView { return alignUnder(view: view,withMargin:CGFloat(withMargin)) } func matchRightOf(view:UIView, withMargin:CGFloat = 0) -> UIView { snp.makeConstraints { (make) in make.right.equalTo(view).offset(withMargin) } return self } func updateAlignUnder(view:UIView, withMargin:CGFloat = 0.0) -> UIView { snp.updateConstraints { (make) in make.top.equalTo(view.snp.bottom).offset(withMargin) } return self } func alignParentBottom(withMargin:CGFloat = 0.0) -> UIView { snp.makeConstraints { (make) in make.bottom.equalToSuperview().offset(-withMargin) } return self } func updateAlignParentBottom(withMargin:CGFloat = 0.0) -> UIView { snp.updateConstraints { (make) in make.bottom.equalToSuperview().offset(-withMargin) } return self } func alignParentBottom(withMargin:Int) -> UIView { return alignParentBottom(withMargin:CGFloat(withMargin)) } func updateAlignParentBottom(withMargin:Int) -> UIView { return updateAlignParentBottom(withMargin:CGFloat(withMargin)) } func alignAbove(view:UIView, withMargin:CGFloat = 0.0) -> UIView { snp.makeConstraints { (make) in make.bottom.equalTo(view.snp.top).offset(-withMargin) } return self } func alignAbove(view:UIView, withMargin:Int) -> UIView { return alignAbove(view: view,withMargin:CGFloat(withMargin)) } func alignBottomWith(otherView:UIView) -> UIView { snp.makeConstraints { (make) in make.bottom.equalTo(otherView) } return self } func marginLeft(_ m:CGFloat) -> UIView { snp.makeConstraints { (make) in make.left.equalToSuperview().offset(m) } return self } func alignParentLeft(withMargin:CGFloat = 0.0) -> UIView { snp.makeConstraints { (make) in make.left.equalToSuperview().offset(withMargin) } return self } func updateAlignParentLeft(withMargin:CGFloat = 0.0) -> UIView { snp.updateConstraints { (make) in make.left.equalToSuperview().offset(withMargin) } return self } func alignParentLeft(withMargin:Int) -> UIView { return alignParentLeft(withMargin:CGFloat(withMargin)) } func alignParentRight(withMargin:Int = 0) -> UIView { snp.makeConstraints { (make) in make.right.equalToSuperview().offset(-withMargin) } return self } func updateAlignParentRight(withMargin:CGFloat = 0) -> UIView { snp.updateConstraints { (make) in make.right.equalToSuperview().offset(-withMargin) } return self } func alignParentRight(withMargin:CGFloat) -> UIView { return alignParentRight(withMargin:Int(withMargin)) } func alignRightWith(_ view:UIView) -> UIView { snp.makeConstraints { (make) in make.right.equalTo(view.snp.right) } return self } func toRightOf(_ view:UIView, withLeftMargin:Int = 0) -> UIView { snp.makeConstraints { (make) in make.left.equalTo(view.snp.right).offset(withLeftMargin) } return self } func toRightOf(_ view:UIView, withLeftMargin:CGFloat) -> UIView { return toRightOf(view,withLeftMargin: Int(withLeftMargin)) } func alignHorizontalCenterWith(_ view:UIView) -> UIView { snp.makeConstraints { (make) in make.centerY.equalTo(view) } return self } func alignVerticalCenterWith(_ view:UIView) -> UIView { snp.makeConstraints { (make) in make.centerX.equalTo(view) } return self } func toLeftOf(_ view:UIView) -> UIView { snp.makeConstraints { (make) in make.right.equalTo(view.snp.left) } return self } func toLeftOf(_ view:UIView, withRightMargin:CGFloat) -> UIView { snp.makeConstraints { (make) in make.right.equalTo(view.snp.left).offset(-withRightMargin) } return self } func centerX(withDx:Int = 0) -> UIView { snp.makeConstraints { (make) in make.centerX.equalToSuperview().offset(withDx) } return self } func centerY(withDy:Int = 0) -> UIView { snp.makeConstraints { (make) in make.centerY.equalToSuperview().offset(withDy) } return self } func matchCenterXOf(view:UIView, withDx:Int = 0) -> UIView { snp.makeConstraints { (make) in make.centerX.equalTo(view).offset(withDx) } return self } func matchCenterYOf(view:UIView, withDy:Int = 0) -> UIView { snp.makeConstraints { (make) in make.centerY.equalTo(view).offset(withDy) } return self } func wrapContentY() -> UIView { subviews.first?.snp.makeConstraints({ make in make.top.equalToSuperview() }) subviews.last?.snp.makeConstraints({ make in make.bottom.equalToSuperview() }) return self } func wrapContentX() -> UIView { subviews.first?.snp.makeConstraints({ make in make.left.equalToSuperview() }) subviews.last?.snp.makeConstraints({ make in make.right.equalToSuperview() }) return self } func wrapContent(inset:UIEdgeInsets) -> UIView { subviews.first?.snp.makeConstraints({ make in make.left.equalToSuperview().offset(inset.left) }) subviews.last?.snp.makeConstraints({ make in make.right.equalToSuperview().offset(-inset.right) }) subviews.first?.snp.makeConstraints({ make in make.top.equalToSuperview().offset(inset.top) }) subviews.last?.snp.makeConstraints({ make in make.bottom.equalToSuperview().offset(-inset.bottom) }) return self } @objc func done() { // to avoid the unused variable warning } // Single click class TapGestureRecognizer: UITapGestureRecognizer { var action : (()->Void)? = nil } func onClick(action : @escaping ()->Void ){ let tap = TapGestureRecognizer(target: self , action: #selector(self.handleTap(_:))) tap.action = action tap.numberOfTapsRequired = 1 tap.cancelsTouchesInView = false self.addGestureRecognizer(tap) self.isUserInteractionEnabled = true } @objc func handleTap(_ sender: TapGestureRecognizer) { sender.action!() } // Long click class LongPressGestureRecognizer: UILongPressGestureRecognizer { var action : (()->Void)? = nil } func onLongClick(action : @escaping ()->Void ){ let tap = LongPressGestureRecognizer(target: self , action: #selector(self.handleLongClick(_:))) tap.action = action tap.cancelsTouchesInView = false self.addGestureRecognizer(tap) self.isUserInteractionEnabled = true } @objc func handleLongClick(_ sender: LongPressGestureRecognizer) { sender.action!() } func onLongClickOneClick(action : @escaping ()->Void ){ let tap = LongPressGestureRecognizer(target: self , action: #selector(self.handleLongClickOneClick(_:))) tap.action = action tap.cancelsTouchesInView = false self.addGestureRecognizer(tap) self.isUserInteractionEnabled = true } @objc func handleLongClickOneClick(_ sender: LongPressGestureRecognizer) { if (sender.state == .began){ sender.action!() } } func VIEW( _ desc: UICompositeViewDescription) -> T{ return PhoneMainView.instance().mainViewController.getCachedController(desc.name) as! T } // Theming func setFormInputBackground(readOnly:Bool) { if (readOnly) { backgroundColor = VoipTheme.voipFormDisabledFieldBackgroundColor.get() } else { layer.borderWidth = 1 layer.borderColor = VoipTheme.voipFormFieldBackgroundColor.get().cgColor } layer.cornerRadius = 3 clipsToBounds = true } @objc func toImage() -> UIImage? { UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0) guard let context = UIGraphicsGetCurrentContext() else { return nil } context.saveGState() layer.render(in: context) context.restoreGState() guard let image = UIGraphicsGetImageFromCurrentImageContext() else { return nil } UIGraphicsEndImageContext() return image } }