Applied the "increase min version to iOS 13" changes

This commit is contained in:
Morgan Pretty 2022-07-01 13:33:00 +10:00
parent 8cf2a57fcc
commit cdb211b72a
34 changed files with 134 additions and 480 deletions

View File

@ -96,7 +96,6 @@
45F32C232057297A00A300D5 /* MediaPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F32C1D205718B000A300D5 /* MediaPageViewController.swift */; };
4C090A1B210FD9C7001FD7F9 /* HapticFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */; };
4C1885D2218F8E1C00B67051 /* PhotoGridViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1885D1218F8E1C00B67051 /* PhotoGridViewCell.swift */; };
4C21D5D6223A9DC500EF8A77 /* UIAlerts+iOS9.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C21D5D5223A9DC500EF8A77 /* UIAlerts+iOS9.m */; };
4C21D5D8223AC60F00EF8A77 /* PhotoCapture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C21D5D7223AC60F00EF8A77 /* PhotoCapture.swift */; };
4C4AE6A1224AF35700D4AF6F /* SendMediaNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4AE69F224AF21900D4AF6F /* SendMediaNavigationController.swift */; };
4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */; };
@ -367,7 +366,6 @@
C33FDDC5255A582000E217F9 /* OWSError.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0B255A581D00E217F9 /* OWSError.m */; };
C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC12255A581E00E217F9 /* TSConstants.h */; settings = {ATTRIBUTES = (Public, ); }; };
C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC16255A581E00E217F9 /* FunctionalUtil.h */; settings = {ATTRIBUTES = (Public, ); }; };
C33FDDD3255A582000E217F9 /* OWSQueues.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC19255A581F00E217F9 /* OWSQueues.h */; settings = {ATTRIBUTES = (Public, ); }; };
C33FDEF8255A656D00E217F9 /* Promise+Delaying.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D32553860900C340D1 /* Promise+Delaying.swift */; };
C3402FE52559036600EA6424 /* SessionUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C331FF1B2558F9D300070591 /* SessionUIKit.framework */; };
C3471ECB2555356A00297E91 /* MessageSender+Encryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3471ECA2555356A00297E91 /* MessageSender+Encryption.swift */; };
@ -1105,7 +1103,6 @@
4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticFeedback.swift; sourceTree = "<group>"; };
4C1885D1218F8E1C00B67051 /* PhotoGridViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoGridViewCell.swift; sourceTree = "<group>"; };
4C1D2337218B6BA000A0598F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
4C21D5D5223A9DC500EF8A77 /* UIAlerts+iOS9.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIAlerts+iOS9.m"; sourceTree = "<group>"; };
4C21D5D7223AC60F00EF8A77 /* PhotoCapture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoCapture.swift; sourceTree = "<group>"; };
4C4AE69F224AF21900D4AF6F /* SendMediaNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendMediaNavigationController.swift; sourceTree = "<group>"; };
4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DismissableTextField.swift; sourceTree = "<group>"; };
@ -1402,7 +1399,6 @@
C33FDC0B255A581D00E217F9 /* OWSError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSError.m; sourceTree = "<group>"; };
C33FDC12255A581E00E217F9 /* TSConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSConstants.h; sourceTree = "<group>"; };
C33FDC16255A581E00E217F9 /* FunctionalUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FunctionalUtil.h; sourceTree = "<group>"; };
C33FDC19255A581F00E217F9 /* OWSQueues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSQueues.h; sourceTree = "<group>"; };
C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBackgroundTask.m; sourceTree = "<group>"; };
C3471ECA2555356A00297E91 /* MessageSender+Encryption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageSender+Encryption.swift"; sourceTree = "<group>"; };
C3471F4B25553AB000297E91 /* MessageReceiver+Decryption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+Decryption.swift"; sourceTree = "<group>"; };
@ -2102,7 +2098,6 @@
34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */,
FD848B9728422F1A000E298B /* Date+Utilities.swift */,
FDD2506D283711D600198BDA /* DifferenceKit+Utilities.swift */,
4C21D5D5223A9DC500EF8A77 /* UIAlerts+iOS9.m */,
45C0DC1A1E68FE9000E04C47 /* UIApplication+OWS.swift */,
45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */,
EF764C331DB67CC5000D9A87 /* UIViewController+Permissions.h */,
@ -3223,7 +3218,6 @@
C33FDC0B255A581D00E217F9 /* OWSError.m */,
C33FDBA1255A581400E217F9 /* OWSOperation.h */,
C33FDB78255A581000E217F9 /* OWSOperation.m */,
C33FDC19255A581F00E217F9 /* OWSQueues.h */,
C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */,
C33FDA6F255A57FA00E217F9 /* ReachabilityManager.swift */,
C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */,
@ -3950,7 +3944,6 @@
C38EF249255B6D67007E1867 /* UIColor+OWS.h in Headers */,
C38EF3F5255B6DF7007E1867 /* OWSTextField.h in Headers */,
C38EF366255B6DCC007E1867 /* ScreenLockViewController.h in Headers */,
C33FDDD3255A582000E217F9 /* OWSQueues.h in Headers */,
C33FDDB3255A582000E217F9 /* OWSError.h in Headers */,
C38EF35E255B6DCC007E1867 /* OWSViewController.h in Headers */,
C38EF367255B6DCC007E1867 /* OWSTableViewController.h in Headers */,
@ -5377,7 +5370,6 @@
34A6C28021E503E700B5B12E /* OWSImagePickerController.swift in Sources */,
C31A6C5C247F2CF3001123EF /* CGRect+Utilities.swift in Sources */,
FD4B200E283492210034334B /* InsetLockableTableView.swift in Sources */,
4C21D5D6223A9DC500EF8A77 /* UIAlerts+iOS9.m in Sources */,
B8269D3325C7A8C600488AB4 /* InputViewButton.swift in Sources */,
B8269D3D25C7B34D00488AB4 /* InputTextView.swift in Sources */,
340FC8B6204DAC8D007AEB0F /* OWSQRCodeScanningViewController.m in Sources */,

View File

@ -121,6 +121,7 @@ final class ContextMenuVC: UIViewController {
let menuHeight = (CGFloat(actions.count) * ContextMenuVC.actionViewHeight)
let spacing = Values.smallSpacing
// FIXME: Need to update this when an appropriate replacement is added (see https://teng.pub/technical/2021/11/9/uiapplication-key-window-replacement)
let margin = max(UIApplication.shared.keyWindow!.safeAreaInsets.bottom, Values.mediumSpacing)
if frame.maxY + spacing + menuHeight > UIScreen.main.bounds.height - margin {

View File

@ -11,7 +11,6 @@ final class ContextMenuWindow : UIWindow {
initialize()
}
@available(iOS 13.0, *)
override init(windowScene: UIWindowScene) {
super.init(windowScene: windowScene)
initialize()

View File

@ -662,6 +662,7 @@ extension ConversationVC:
func handleItemLongPressed(_ cellViewModel: MessageViewModel) {
// Show the context menu if applicable
guard
// FIXME: Need to update this when an appropriate replacement is added (see https://teng.pub/technical/2021/11/9/uiapplication-key-window-replacement)
let keyWindow: UIWindow = UIApplication.shared.keyWindow,
let sectionIndex: Int = self.viewModel.interactionData
.firstIndex(where: { $0.model == .messages }),

View File

@ -241,17 +241,11 @@ final class ConversationVC: BaseVC, OWSConversationSettingsViewDelegate, Convers
for: .highlighted
)
result.layer.cornerRadius = (ConversationVC.messageRequestButtonHeight / 2)
result.layer.borderColor = {
if #available(iOS 13.0, *) {
return Colors.sessionHeading
.resolvedColor(
// Note: This is needed for '.cgColor' to support dark mode
with: UITraitCollection(userInterfaceStyle: isDarkMode ? .dark : .light)
).cgColor
}
return Colors.sessionHeading.cgColor
}()
result.layer.borderColor = Colors.sessionHeading
.resolvedColor(
// Note: This is needed for '.cgColor' to support dark mode
with: UITraitCollection(userInterfaceStyle: isDarkMode ? .dark : .light)
).cgColor
result.layer.borderWidth = 1
result.addTarget(self, action: #selector(acceptMessageRequest), for: .touchUpInside)
@ -272,17 +266,11 @@ final class ConversationVC: BaseVC, OWSConversationSettingsViewDelegate, Convers
for: .highlighted
)
result.layer.cornerRadius = (ConversationVC.messageRequestButtonHeight / 2)
result.layer.borderColor = {
if #available(iOS 13.0, *) {
return Colors.destructive
.resolvedColor(
// Note: This is needed for '.cgColor' to support dark mode
with: UITraitCollection(userInterfaceStyle: isDarkMode ? .dark : .light)
).cgColor
}
return Colors.destructive.cgColor
}()
result.layer.borderColor = Colors.destructive
.resolvedColor(
// Note: This is needed for '.cgColor' to support dark mode
with: UITraitCollection(userInterfaceStyle: isDarkMode ? .dark : .light)
).cgColor
result.layer.borderWidth = 1
result.addTarget(self, action: #selector(deleteMessageRequest), for: .touchUpInside)

View File

@ -141,17 +141,16 @@ final class InputViewButton : UIView {
}
}
// MARK: Delegate
protocol InputViewButtonDelegate : class {
// MARK: - Delegate
protocol InputViewButtonDelegate: AnyObject {
func handleInputViewButtonTapped(_ inputViewButton: InputViewButton)
func handleInputViewButtonLongPressBegan(_ inputViewButton: InputViewButton)
func handleInputViewButtonLongPressMoved(_ inputViewButton: InputViewButton, with touch: UITouch)
func handleInputViewButtonLongPressEnded(_ inputViewButton: InputViewButton, with touch: UITouch)
}
extension InputViewButtonDelegate {
extension InputViewButtonDelegate {
func handleInputViewButtonLongPressBegan(_ inputViewButton: InputViewButton) { }
func handleInputViewButtonLongPressMoved(_ inputViewButton: InputViewButton, with touch: UITouch) { }
func handleInputViewButtonLongPressEnded(_ inputViewButton: InputViewButton, with touch: UITouch) { }

View File

@ -78,12 +78,7 @@ final class NewDMVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControll
// Set up tab bar
view.addSubview(tabBar)
tabBar.pin(.leading, to: .leading, of: view)
let tabBarInset: CGFloat
if #available(iOS 13, *) {
tabBarInset = UIDevice.current.isIPad ? navigationBar.height() + 20 : navigationBar.height()
} else {
tabBarInset = 0
}
let tabBarInset: CGFloat = (UIDevice.current.isIPad ? navigationBar.height() + 20 : navigationBar.height())
tabBar.pin(.top, to: .top, of: view, withInset: tabBarInset)
view.pin(.trailing, to: .trailing, of: tabBar)
// Set up page VC constraints
@ -95,13 +90,7 @@ final class NewDMVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControll
view.pin(.bottom, to: .bottom, of: pageVCView)
let screen = UIScreen.main.bounds
pageVCView.set(.width, to: screen.width)
let height: CGFloat
if #available(iOS 13, *) {
height = navigationController!.view.bounds.height - navigationBar.height() - TabBar.snHeight
} else {
let statusBarHeight = UIApplication.shared.statusBarFrame.height
height = navigationController!.view.bounds.height - navigationBar.height() - TabBar.snHeight - statusBarHeight
}
let height: CGFloat = (navigationController!.view.bounds.height - navigationBar.height() - TabBar.snHeight)
pageVCView.set(.height, to: height)
enterPublicKeyVC.constrainHeight(to: height)
scanQRCodePlaceholderVC.constrainHeight(to: height)

View File

@ -4,7 +4,7 @@
import Foundation
protocol GifPickerLayoutDelegate: class {
protocol GifPickerLayoutDelegate: AnyObject {
func imageInfosForLayout() -> [GiphyImageInfo]
}

View File

@ -77,14 +77,6 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
let titleView = TitleView()
titleView.delegate = self
titleView.text = photoCollection.localizedTitle()
if #available(iOS 11, *) {
// do nothing
} else {
// must assign titleView frame manually on older iOS
titleView.frame = CGRect(origin: .zero, size: titleView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize))
}
navigationItem.titleView = titleView
self.titleView = titleView
@ -269,11 +261,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
// MARK:
var lastPageYOffset: CGFloat {
var yOffset = collectionView.contentSize.height - collectionView.bounds.height + collectionView.adjustedContentInset.bottom
if #available(iOS 11.0, *) {
yOffset += view.safeAreaInsets.bottom
}
return yOffset
return (collectionView.contentSize.height - collectionView.bounds.height + collectionView.adjustedContentInset.bottom + view.safeAreaInsets.bottom)
}
func scrollToBottom(animated: Bool) {
@ -344,10 +332,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
static let kInterItemSpacing: CGFloat = 2
private class func buildLayout() -> UICollectionViewFlowLayout {
let layout = UICollectionViewFlowLayout()
if #available(iOS 11, *) {
layout.sectionInsetReference = .fromSafeArea
}
layout.sectionInsetReference = .fromSafeArea
layout.minimumInteritemSpacing = kInterItemSpacing
layout.minimumLineSpacing = kInterItemSpacing
layout.sectionHeadersPinToVisibleBounds = true
@ -356,13 +341,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
}
func updateLayout() {
let containerWidth: CGFloat
if #available(iOS 11.0, *) {
containerWidth = self.view.safeAreaLayoutGuide.layoutFrame.size.width
} else {
containerWidth = self.view.frame.size.width
}
let containerWidth: CGFloat = self.view.safeAreaLayoutGuide.layoutFrame.size.width
let kItemsPerPortraitRow = 4
let screenWidth = min(UIScreen.main.bounds.width, UIScreen.main.bounds.height)
let approxItemWidth = screenWidth / CGFloat(kItemsPerPortraitRow)
@ -586,7 +565,7 @@ extension ImagePickerGridController: UIGestureRecognizerDelegate {
}
}
protocol TitleViewDelegate: class {
protocol TitleViewDelegate: AnyObject {
func titleViewWasTapped(_ titleView: TitleView)
}

View File

@ -894,20 +894,6 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
let landscapeHeaderText = String(format: landscapeHeaderFormat, name, formattedDate)
self.title = landscapeHeaderText
self.navigationItem.title = landscapeHeaderText
if #available(iOS 11, *) {
// Do nothing, on iOS11+, autolayout grows the stack view as necessary.
} else {
// Size the titleView to be large enough to fit the widest label,
// but no larger. If we go for a "full width" label, our title view
// will not be centered (since the left and right bar buttons have different widths)
portraitHeaderNameLabel.sizeToFit()
portraitHeaderDateLabel.sizeToFit()
let width = max(portraitHeaderNameLabel.frame.width, portraitHeaderDateLabel.frame.width)
let headerFrame: CGRect = CGRect(x: 0, y: 0, width: width, height: 44)
portraitHeaderView.frame = headerFrame
}
}
// MARK: - InteractivelyDismissableViewController

View File

@ -754,11 +754,7 @@ private class MediaGallerySectionHeader: UICollectionReusableView {
get {
// HACK: scrollbar incorrectly appears *behind* section headers
// in collection view on iOS11 =(
if #available(iOS 11, *) {
return AlwaysOnTopLayer.self
} else {
return super.layerClass
}
return AlwaysOnTopLayer.self
}
}

View File

@ -453,16 +453,10 @@ protocol ImageCaptureOutput: AnyObject {
class CaptureOutput {
let imageOutput: ImageCaptureOutput
let imageOutput: ImageCaptureOutput = PhotoCaptureOutputAdaptee()
let movieOutput: AVCaptureMovieFileOutput
init() {
if #available(iOS 10.0, *) {
imageOutput = PhotoCaptureOutputAdaptee()
} else {
imageOutput = StillImageCaptureOutput()
}
movieOutput = AVCaptureMovieFileOutput()
// disable movie fragment writing since it's not supported on mp4
// leaving it enabled causes all audio to be lost on videos longer
@ -531,7 +525,6 @@ class CaptureOutput {
}
}
@available(iOS 10.0, *)
class PhotoCaptureOutputAdaptee: NSObject, ImageCaptureOutput {
let photoOutput = AVCapturePhotoOutput()
@ -586,7 +579,6 @@ class PhotoCaptureOutputAdaptee: NSObject, ImageCaptureOutput {
self.completion = completion
}
@available(iOS 11.0, *)
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
var data = photo.fileDataRepresentation()!
// Call normalized here to fix the orientation

View File

@ -115,12 +115,7 @@ class PhotoCaptureViewController: OWSViewController {
init(imageName: String, block: @escaping () -> Void) {
self.button = OWSButton(imageName: imageName, tintColor: .ows_white, block: block)
if #available(iOS 10, *) {
button.autoPinToSquareAspectRatio()
} else {
button.sizeToFit()
}
button.autoPinToSquareAspectRatio()
button.layer.shadowOffset = CGSize.zero
button.layer.shadowOpacity = 0.35
button.layer.shadowRadius = 4
@ -600,20 +595,6 @@ class RecordingTimerView: UIView {
return icon
}()
// MARK: - Overrides //
override func sizeThatFits(_ size: CGSize) -> CGSize {
if #available(iOS 10, *) {
return super.sizeThatFits(size)
} else {
// iOS9 manual layout sizing required for items in the navigation bar
var baseSize = label.frame.size
baseSize.width = baseSize.width + stackViewSpacing + RecordingTimerView.iconWidth + layoutMargins.left + layoutMargins.right
baseSize.height = baseSize.height + layoutMargins.top + layoutMargins.bottom
return baseSize
}
}
// MARK: -
var recordingStartTime: TimeInterval?
@ -662,10 +643,5 @@ class RecordingTimerView: UIView {
Logger.verbose("recordingDuration: \(recordingDuration)")
let durationDate = Date(timeIntervalSinceReferenceDate: recordingDuration)
label.text = timeFormatter.string(from: durationDate)
if #available(iOS 10, *) {
// do nothing
} else {
label.sizeToFit()
}
}
}

View File

@ -6,7 +6,7 @@ import Foundation
import Photos
import PromiseKit
protocol PhotoCollectionPickerDelegate: class {
protocol PhotoCollectionPickerDelegate: AnyObject {
func photoCollectionPicker(_ photoCollectionPicker: PhotoCollectionPickerController, didPickCollection collection: PhotoCollection)
}

View File

@ -498,6 +498,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
// MARK: - App Mode
private func adapt(appMode: AppMode) {
// FIXME: Need to update this when an appropriate replacement is added (see https://teng.pub/technical/2021/11/9/uiapplication-key-window-replacement)
guard let window: UIWindow = UIApplication.shared.keyWindow else { return }
switch (appMode) {

View File

@ -71,13 +71,7 @@ final class QRCodeVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControl
view.pin(.bottom, to: .bottom, of: pageVCView)
let screen = UIScreen.main.bounds
pageVCView.set(.width, to: screen.width)
let height: CGFloat
if #available(iOS 13, *) {
height = navigationController!.view.bounds.height - navigationBar.height() - TabBar.snHeight
} else {
let statusBarHeight = UIApplication.shared.statusBarFrame.height
height = navigationController!.view.bounds.height - navigationBar.height() - TabBar.snHeight - statusBarHeight
}
let height: CGFloat = (navigationController!.view.bounds.height - navigationBar.height() - TabBar.snHeight)
pageVCView.set(.height, to: height)
viewMyQRCodeVC.constrainHeight(to: height)
scanQRCodePlaceholderVC.constrainHeight(to: height)

View File

@ -391,39 +391,31 @@ final class SettingsVC: BaseVC, AvatarViewHelperDelegate {
closeButton.isAccessibilityElement = true
navigationItem.leftBarButtonItem = closeButton
if #available(iOS 13, *) { // Pre iOS 13 the user can't switch actively but the app still responds to system changes
let appModeIcon: UIImage
if isSystemDefault {
appModeIcon = isDarkMode ? #imageLiteral(resourceName: "ic_theme_auto").withTintColor(.white) : #imageLiteral(resourceName: "ic_theme_auto").withTintColor(.black)
}
else {
appModeIcon = isDarkMode ? #imageLiteral(resourceName: "ic_dark_theme_on").withTintColor(.white) : #imageLiteral(resourceName: "ic_dark_theme_off").withTintColor(.black)
}
let appModeButton = UIButton()
appModeButton.setImage(appModeIcon, for: UIControl.State.normal)
appModeButton.tintColor = Colors.text
appModeButton.addTarget(self, action: #selector(switchAppMode), for: UIControl.Event.touchUpInside)
appModeButton.accessibilityLabel = "Switch app mode button"
let qrCodeIcon = isDarkMode ? #imageLiteral(resourceName: "QRCode").withTintColor(.white) : #imageLiteral(resourceName: "QRCode").withTintColor(.black)
let qrCodeButton = UIButton()
qrCodeButton.setImage(qrCodeIcon, for: UIControl.State.normal)
qrCodeButton.tintColor = Colors.text
qrCodeButton.addTarget(self, action: #selector(showQRCode), for: UIControl.Event.touchUpInside)
qrCodeButton.accessibilityLabel = "Show QR code button"
let stackView = UIStackView(arrangedSubviews: [ appModeButton, qrCodeButton ])
stackView.axis = .horizontal
stackView.spacing = Values.mediumSpacing
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: stackView)
let appModeIcon: UIImage
if isSystemDefault {
appModeIcon = isDarkMode ? #imageLiteral(resourceName: "ic_theme_auto").withTintColor(.white) : #imageLiteral(resourceName: "ic_theme_auto").withTintColor(.black)
}
else {
let qrCodeIcon = isDarkMode ? #imageLiteral(resourceName: "QRCode").asTintedImage(color: .white) : #imageLiteral(resourceName: "QRCode").asTintedImage(color: .black)
let qrCodeButton = UIBarButtonItem(image: qrCodeIcon, style: .plain, target: self, action: #selector(showQRCode))
qrCodeButton.tintColor = Colors.text
navigationItem.rightBarButtonItem = qrCodeButton
appModeIcon = isDarkMode ? #imageLiteral(resourceName: "ic_dark_theme_on").withTintColor(.white) : #imageLiteral(resourceName: "ic_dark_theme_off").withTintColor(.black)
}
let appModeButton = UIButton()
appModeButton.setImage(appModeIcon, for: UIControl.State.normal)
appModeButton.tintColor = Colors.text
appModeButton.addTarget(self, action: #selector(switchAppMode), for: UIControl.Event.touchUpInside)
appModeButton.accessibilityLabel = "Switch app mode button"
let qrCodeIcon = isDarkMode ? #imageLiteral(resourceName: "QRCode").withTintColor(.white) : #imageLiteral(resourceName: "QRCode").withTintColor(.black)
let qrCodeButton = UIButton()
qrCodeButton.setImage(qrCodeIcon, for: UIControl.State.normal)
qrCodeButton.tintColor = Colors.text
qrCodeButton.addTarget(self, action: #selector(showQRCode), for: UIControl.Event.touchUpInside)
qrCodeButton.accessibilityLabel = "Show QR code button"
let stackView = UIStackView(arrangedSubviews: [ appModeButton, qrCodeButton ])
stackView.axis = .horizontal
stackView.spacing = Values.mediumSpacing
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: stackView)
}
}

View File

@ -108,9 +108,8 @@ class BaseVC : UIViewController {
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
if #available(iOS 13.0, *) {
SNLog("Current trait collection: \(UITraitCollection.current), previous trait collection: \(previousTraitCollection)")
}
SNLog("Current trait collection: \(UITraitCollection.current), previous trait collection: \(previousTraitCollection)")
if LKAppModeUtilities.isSystemDefault {
NotificationCenter.default.post(name: .appModeChanged, object: nil)
}

View File

@ -2,7 +2,7 @@
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
public protocol CaptionContainerViewDelegate: class {
public protocol CaptionContainerViewDelegate: AnyObject {
func captionContainerViewDidUpdateText(_ captionContainerView: CaptionContainerView)
}

View File

@ -609,7 +609,7 @@ open class MarqueeLabel: UILabel, CAAnimationDelegate {
animationDuration = {
switch self.speed {
case .rate(let rate):
return CGFloat(fabs(self.awayOffset) / rate)
return CGFloat(abs(self.awayOffset) / rate)
case .duration(let duration):
return duration
}
@ -634,7 +634,7 @@ open class MarqueeLabel: UILabel, CAAnimationDelegate {
// Find when the lead label will be totally offscreen
let offsetDistance = awayOffset
let offscreenAmount = homeLabelFrame.size.width
let startFadeFraction = fabs(offscreenAmount / offsetDistance)
let startFadeFraction = abs(offscreenAmount / offsetDistance)
// Find when the animation will hit that point
let startFadeTimeFraction = timingFunctionForAnimationCurve(animationCurve).durationPercentageForPositionPercentage(startFadeFraction, duration: (animationDelay + animationDuration))
let startFadeTime = startFadeTimeFraction * animationDuration
@ -1764,14 +1764,14 @@ fileprivate extension CAMediaTimingFunction {
// Calculate f(t0)
f0 = YforCurveAt(t0, controlPoints: controlPoints) - y_0
// Check if this is close (enough)
if (fabs(f0) < epsilon) {
if (abs(f0) < epsilon) {
// Done!
return t0
}
// Else continue Newton's Method
df0 = derivativeCurveYValueAt(t0, controlPoints: controlPoints)
// Check if derivative is small or zero ( http://en.wikipedia.org/wiki/Newton's_method#Failure_analysis )
if (fabs(df0) < 1e-6) {
if (abs(df0) < 1e-6) {
break
}
// Else recalculate t1

View File

@ -9,28 +9,13 @@ protocol SelectionHapticFeedbackAdapter {
}
class SelectionHapticFeedback: SelectionHapticFeedbackAdapter {
let adapter: SelectionHapticFeedbackAdapter
init() {
if #available(iOS 10, *) {
adapter = ModernSelectionHapticFeedbackAdapter()
} else {
adapter = LegacySelectionHapticFeedbackAdapter()
}
}
let adapter: SelectionHapticFeedbackAdapter = ModernSelectionHapticFeedbackAdapter()
func selectionChanged() {
adapter.selectionChanged()
}
}
class LegacySelectionHapticFeedbackAdapter: NSObject, SelectionHapticFeedbackAdapter {
func selectionChanged() {
// do nothing
}
}
@available(iOS 10, *)
class ModernSelectionHapticFeedbackAdapter: NSObject, SelectionHapticFeedbackAdapter {
let selectionFeedbackGenerator: UISelectionFeedbackGenerator

View File

@ -2,32 +2,26 @@
@objc final class SNAppearance : NSObject {
@objc static func switchToSessionAppearance() {
if #available(iOS 13, *) {
UINavigationBar.appearance().barTintColor = Colors.navigationBarBackground
UINavigationBar.appearance().isTranslucent = false
UINavigationBar.appearance().tintColor = Colors.text
UIToolbar.appearance().barTintColor = Colors.navigationBarBackground
UIToolbar.appearance().isTranslucent = false
UIToolbar.appearance().tintColor = Colors.text
UISwitch.appearance().onTintColor = Colors.accent
UINavigationBar.appearance().titleTextAttributes = [ NSAttributedString.Key.foregroundColor : Colors.text ]
}
UINavigationBar.appearance().barTintColor = Colors.navigationBarBackground
UINavigationBar.appearance().isTranslucent = false
UINavigationBar.appearance().tintColor = Colors.text
UIToolbar.appearance().barTintColor = Colors.navigationBarBackground
UIToolbar.appearance().isTranslucent = false
UIToolbar.appearance().tintColor = Colors.text
UISwitch.appearance().onTintColor = Colors.accent
UINavigationBar.appearance().titleTextAttributes = [ NSAttributedString.Key.foregroundColor : Colors.text ]
}
@objc static func switchToImagePickerAppearance() {
if #available(iOS 13, *) {
UINavigationBar.appearance().barTintColor = .white
UINavigationBar.appearance().isTranslucent = false
UINavigationBar.appearance().tintColor = .black
UINavigationBar.appearance().titleTextAttributes = [ NSAttributedString.Key.foregroundColor : UIColor.black ]
}
UINavigationBar.appearance().barTintColor = .white
UINavigationBar.appearance().isTranslucent = false
UINavigationBar.appearance().tintColor = .black
UINavigationBar.appearance().titleTextAttributes = [ NSAttributedString.Key.foregroundColor : UIColor.black ]
}
@objc static func switchToDocumentPickerAppearance() {
if #available(iOS 13, *) {
let textColor: UIColor = isDarkMode ? .white : .black
UINavigationBar.appearance().tintColor = textColor
UINavigationBar.appearance().titleTextAttributes = [ NSAttributedString.Key.foregroundColor : textColor ]
}
let textColor: UIColor = isDarkMode ? .white : .black
UINavigationBar.appearance().tintColor = textColor
UINavigationBar.appearance().titleTextAttributes = [ NSAttributedString.Key.foregroundColor : textColor ]
}
}

View File

@ -1,85 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import <objc/runtime.h>
@implementation UIAlertController (iOS9)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// On iOS9, avoids an exception when presenting an alert controller.
//
// *** Assertion failure in -[UIAlertController supportedInterfaceOrientations], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.30.14/UIAlertController.m:542
// Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UIAlertController:supportedInterfaceOrientations was invoked recursively!'
//
// I'm not sure when this was introduced, or the exact root casue, but this quick workaround
// seems reasonable given the small size of our iOS9 userbase.
if (@available(iOS 10, *)) {
return;
}
Class class = [self class];
// supportedInterfaceOrientation
SEL originalOrientationSelector = @selector(supportedInterfaceOrientations);
SEL swizzledOrientationSelector = @selector(ows_iOS9Alerts_swizzle_supportedInterfaceOrientation);
Method originalOrientationMethod = class_getInstanceMethod(class, originalOrientationSelector);
Method swizzledOrientationMethod = class_getInstanceMethod(class, swizzledOrientationSelector);
BOOL didAddOrientationMethod = class_addMethod(class,
originalOrientationSelector,
method_getImplementation(swizzledOrientationMethod),
method_getTypeEncoding(swizzledOrientationMethod));
if (didAddOrientationMethod) {
class_replaceMethod(class,
swizzledOrientationSelector,
method_getImplementation(originalOrientationMethod),
method_getTypeEncoding(originalOrientationMethod));
} else {
method_exchangeImplementations(originalOrientationMethod, swizzledOrientationMethod);
}
// shouldAutorotate
SEL originalAutorotateSelector = @selector(shouldAutorotate);
SEL swizzledAutorotateSelector = @selector(ows_iOS9Alerts_swizzle_shouldAutorotate);
Method originalAutorotateMethod = class_getInstanceMethod(class, originalAutorotateSelector);
Method swizzledAutorotateMethod = class_getInstanceMethod(class, swizzledAutorotateSelector);
BOOL didAddAutorotateMethod = class_addMethod(class,
originalAutorotateSelector,
method_getImplementation(swizzledAutorotateMethod),
method_getTypeEncoding(swizzledAutorotateMethod));
if (didAddAutorotateMethod) {
class_replaceMethod(class,
swizzledAutorotateSelector,
method_getImplementation(originalAutorotateMethod),
method_getTypeEncoding(originalAutorotateMethod));
} else {
method_exchangeImplementations(originalAutorotateMethod, swizzledAutorotateMethod);
}
});
}
#pragma mark - Method Swizzling
- (UIInterfaceOrientationMask)ows_iOS9Alerts_swizzle_supportedInterfaceOrientation
{
OWSLogInfo(@"swizzled");
return UIInterfaceOrientationMaskAllButUpsideDown;
}
- (BOOL)ows_iOS9Alerts_swizzle_shouldAutorotate
{
OWSLogInfo(@"swizzled");
return NO;
}
@end

View File

@ -27,6 +27,6 @@ import UIKit
}
func openSystemSettings() {
openURL(URL(string: UIApplication.openSettingsURLString)!)
open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
}
}

View File

@ -14,22 +14,7 @@ NSString *const IsScreenBlockActiveDidChangeNotification = @"IsScreenBlockActive
const CGFloat OWSWindowManagerCallBannerHeight(void)
{
if (@available(iOS 11.4, *)) {
return CurrentAppContext().statusBarHeight + 20;
}
if (![UIDevice currentDevice].hasIPhoneXNotch) {
return CurrentAppContext().statusBarHeight + 20;
}
// Hardcode CallBanner height for iPhone X's on older iOS.
//
// As of iOS11.4 and iOS12, this no longer seems to be an issue, but previously statusBarHeight returned
// something like 20pts (IIRC), meaning our call banner did not extend sufficiently past the iPhone X notch.
//
// Before noticing that this behavior changed, I actually assumed that notch height was intentionally excluded from
// the statusBarHeight, and that this was not a bug, else I'd have taken better notes.
return 64;
return CurrentAppContext().statusBarHeight + 20;
}
// Behind everything, especially the root window.
@ -200,19 +185,7 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
- (UIWindow *)createMenuActionsWindowWithRoowWindow:(UIWindow *)rootWindow
{
UIWindow *window;
if (@available(iOS 11, *)) {
// On iOS11, setting the windowLevel is insufficient, so we override
// the `windowLevel` getter.
window = [[MessageActionsWindow alloc] initWithFrame:rootWindow.bounds];
} else {
// On iOS9, 10 overriding the `windowLevel` getter does not cause the
// window to be displayed above the keyboard, but setting the window
// level works.
window = [[UIWindow alloc] initWithFrame:rootWindow.bounds];
window.windowLevel = UIWindowLevel_MessageActions();
}
UIWindow *window = [[MessageActionsWindow alloc] initWithFrame:rootWindow.bounds];
window.hidden = YES;
window.backgroundColor = UIColor.clearColor;

View File

@ -23,12 +23,7 @@ public extension UISearchBar {
setImage(searchImage, for: .search, state: .normal)
let clearImage = #imageLiteral(resourceName: "searchbar_clear").withTint(Colors.searchBarPlaceholder)!
setImage(clearImage, for: .clear, state: .normal)
let searchTextField: UITextField
if #available(iOS 13, *) {
searchTextField = self.searchTextField
} else {
searchTextField = self.value(forKey: "_searchField") as! UITextField
}
let searchTextField: UITextField = self.searchTextField
searchTextField.backgroundColor = Colors.searchBarBackground // The search bar background color
searchTextField.textColor = Colors.text
searchTextField.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("Search", comment: ""), attributes: [ .foregroundColor : Colors.searchBarPlaceholder ])

View File

@ -34,11 +34,7 @@ public final class AppModeManager : NSObject {
let userDefaults = UserDefaults.standard
guard userDefaults.dictionaryRepresentation().keys.contains("appMode") else {
if #available(iOS 13.0, *) {
return UITraitCollection.current.userInterfaceStyle == .dark ? .dark : .light
}
return .light
return (UITraitCollection.current.userInterfaceStyle == .dark ? .dark : .light)
}
let mode = userDefaults.integer(forKey: "appMode")

View File

@ -174,8 +174,7 @@ import SessionMessagingKit
return .failure(error:defaultErrorDescription)
}
if #available(iOS 11.0, *) {
switch laError.code {
switch laError.code {
case .biometryNotAvailable:
Logger.error("local authentication error: biometryNotAvailable.")
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE",
@ -191,41 +190,41 @@ import SessionMessagingKit
default:
// Fall through to second switch
break
}
}
switch laError.code {
case .authenticationFailed:
Logger.error("local authentication error: authenticationFailed.")
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED",
comment: "Indicates that Touch ID/Face ID/Phone Passcode authentication failed."))
case .userCancel, .userFallback, .systemCancel, .appCancel:
Logger.info("local authentication cancelled.")
return .cancel
case .passcodeNotSet:
Logger.error("local authentication error: passcodeNotSet.")
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET",
comment: "Indicates that Touch ID/Face ID/Phone Passcode passcode is not set."))
case .touchIDNotAvailable:
Logger.error("local authentication error: touchIDNotAvailable.")
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE",
comment: "Indicates that Touch ID/Face ID/Phone Passcode are not available on this device."))
case .touchIDNotEnrolled:
Logger.error("local authentication error: touchIDNotEnrolled.")
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED",
comment: "Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device."))
case .touchIDLockout:
Logger.error("local authentication error: touchIDLockout.")
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT",
comment: "Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures."))
case .invalidContext:
owsFailDebug("context not valid.")
return .unexpectedFailure(error:defaultErrorDescription)
case .notInteractive:
owsFailDebug("context not interactive.")
return .unexpectedFailure(error:defaultErrorDescription)
case .authenticationFailed:
Logger.error("local authentication error: authenticationFailed.")
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED",
comment: "Indicates that Touch ID/Face ID/Phone Passcode authentication failed."))
case .userCancel, .userFallback, .systemCancel, .appCancel:
Logger.info("local authentication cancelled.")
return .cancel
case .passcodeNotSet:
Logger.error("local authentication error: passcodeNotSet.")
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET",
comment: "Indicates that Touch ID/Face ID/Phone Passcode passcode is not set."))
case .touchIDNotAvailable:
Logger.error("local authentication error: touchIDNotAvailable.")
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE",
comment: "Indicates that Touch ID/Face ID/Phone Passcode are not available on this device."))
case .touchIDNotEnrolled:
Logger.error("local authentication error: touchIDNotEnrolled.")
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED",
comment: "Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device."))
case .touchIDLockout:
Logger.error("local authentication error: touchIDLockout.")
return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT",
comment: "Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures."))
case .invalidContext:
owsFailDebug("context not valid.")
return .unexpectedFailure(error:defaultErrorDescription)
case .notInteractive:
owsFailDebug("context not interactive.")
return .unexpectedFailure(error:defaultErrorDescription)
}
}
return .failure(error:defaultErrorDescription)
}
@ -241,10 +240,7 @@ import SessionMessagingKit
// Never recycle biometric auth.
context.touchIDAuthenticationAllowableReuseDuration = TimeInterval(0)
if #available(iOS 11.0, *) {
assert(!context.interactionNotAllowed)
}
assert(!context.interactionNotAllowed)
return context
}

View File

@ -161,28 +161,16 @@ NS_ASSUME_NONNULL_BEGIN
OWSLogDebug(@"");
[UIView setAnimationsEnabled:NO];
if (@available(iOS 11.0, *)) {
if (!CurrentAppContext().isMainApp) {
self.additionalSafeAreaInsets = UIEdgeInsetsZero;
} else if (OWSWindowManager.sharedManager.hasCall) {
self.additionalSafeAreaInsets = UIEdgeInsetsMake(20, 0, 0, 0);
} else {
self.additionalSafeAreaInsets = UIEdgeInsetsZero;
}
// in iOS11 we have to ensure the navbar frame *in* layoutSubviews.
[navbar layoutSubviews];
if (!CurrentAppContext().isMainApp) {
self.additionalSafeAreaInsets = UIEdgeInsetsZero;
} else if (OWSWindowManager.sharedManager.hasCall) {
self.additionalSafeAreaInsets = UIEdgeInsetsMake(20, 0, 0, 0);
} else {
// in iOS9/10 we only need to size the navbar once
[navbar sizeToFit];
[navbar layoutIfNeeded];
// Since the navbar's frame was updated, we need to be sure our child VC's
// container view is updated.
[self.view setNeedsLayout];
[self.view layoutSubviews];
self.additionalSafeAreaInsets = UIEdgeInsetsZero;
}
[navbar layoutSubviews];
[UIView setAnimationsEnabled:YES];
}

View File

@ -110,11 +110,7 @@ const CGFloat kOWSTable_DefaultCellHeight = 45.f;
+ (void)configureCell:(UITableViewCell *)cell
{
cell.backgroundColor = LKColors.cellBackground;
if (@available(iOS 13, *)) {
cell.contentView.backgroundColor = UIColor.clearColor;
} else {
cell.contentView.backgroundColor = LKColors.cellBackground;
}
cell.contentView.backgroundColor = UIColor.clearColor;
cell.textLabel.font = [UIFont systemFontOfSize:LKValues.mediumFontSize];
cell.textLabel.textColor = LKColors.text;

View File

@ -114,28 +114,6 @@ public class OWSNavigationBar: UINavigationBar {
self.navBarLayoutDelegate?.navBarCallLayoutDidChange(navbar: self)
}
public override func sizeThatFits(_ size: CGSize) -> CGSize {
guard OWSWindowManager.shared().hasCall() else {
return super.sizeThatFits(size)
}
if #available(iOS 11, *) {
return super.sizeThatFits(size)
} else if #available(iOS 10, *) {
// iOS10
// sizeThatFits is repeatedly called to determine how much space to reserve for that navbar.
// That is, increasing this causes the child view controller to be pushed down.
// (as of iOS11, this is not used and instead we use additionalSafeAreaInsets)
return CGSize(width: fullWidth, height: navbarWithoutStatusHeight + statusBarHeight)
} else {
// iOS9
// sizeThatFits is repeatedly called to determine how much space to reserve for that navbar.
// That is, increasing this causes the child view controller to be pushed down.
// (as of iOS11, this is not used and instead we use additionalSafeAreaInsets)
return CGSize(width: fullWidth, height: navbarWithoutStatusHeight + callBannerHeight + 20)
}
}
public override func layoutSubviews() {
guard CurrentAppContext().isMainApp else {
super.layoutSubviews()

View File

@ -1,28 +0,0 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
#ifdef DEBUG
#define AssertOnDispatchQueue(queue) \
{ \
if (@available(iOS 10.0, *)) { \
dispatch_assert_queue(queue); \
} else { \
_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \
OWSAssertDebug(dispatch_get_current_queue() == queue); \
_Pragma("clang diagnostic pop") \
} \
}
#else
#define AssertOnDispatchQueue(queue)
#endif
NS_ASSUME_NONNULL_END

View File

@ -29,19 +29,13 @@ public extension UIColor {
let renderer: UIGraphicsImageRenderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { rendererContext in
if #available(iOS 13.0, *) {
rendererContext.cgContext
.setFillColor(
self.resolvedColor(
// Note: This is needed for '.cgColor' to support dark mode
with: UITraitCollection(userInterfaceStyle: isDarkMode ? .dark : .light)
).cgColor
)
}
else {
rendererContext.cgContext.setFillColor(self.cgColor)
}
rendererContext.cgContext
.setFillColor(
self.resolvedColor(
// Note: This is needed for '.cgColor' to support dark mode
with: UITraitCollection(userInterfaceStyle: isDarkMode ? .dark : .light)
).cgColor
)
rendererContext.cgContext.fill(bounds)
}
}

View File

@ -53,25 +53,13 @@ public extension UIView {
}
func renderAsImage(opaque: Bool, scale: CGFloat) -> UIImage? {
if #available(iOS 10, *) {
let format = UIGraphicsImageRendererFormat()
format.scale = scale
format.opaque = opaque
let renderer = UIGraphicsImageRenderer(bounds: self.bounds,
format: format)
return renderer.image { (context) in
self.layer.render(in: context.cgContext)
}
} else {
UIGraphicsBeginImageContextWithOptions(bounds.size, opaque, scale)
if let _ = UIGraphicsGetCurrentContext() {
drawHierarchy(in: bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
owsFailDebug("Could not create graphics context.")
return nil
let format = UIGraphicsImageRendererFormat()
format.scale = scale
format.opaque = opaque
let renderer = UIGraphicsImageRenderer(bounds: self.bounds,
format: format)
return renderer.image { (context) in
self.layer.render(in: context.cgContext)
}
}