Implements #4693 - Alert users of Element on iOS11 deprecation.

This commit is contained in:
Stefan Ceriu
2021-08-24 14:58:12 +03:00
committed by Stefan Ceriu
parent 5c3f054a63
commit 95572d5e44
24 changed files with 823 additions and 26 deletions
@@ -0,0 +1,22 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
@objc protocol BannerPresentationProtocol {
func presentBannerView(_ bannerView: UIView, animated: Bool)
func dismissBannerView(animated: Bool)
}
@@ -0,0 +1,84 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
class HomeViewControllerWithBannerWrapperViewController: UIViewController, BannerPresentationProtocol {
@objc let homeViewController: HomeViewController
private var bannerContainerView: UIView!
private var stackView: UIStackView!
init(viewController: HomeViewController) {
self.homeViewController = viewController
super.init(nibName: nil, bundle: nil)
self.tabBarItem.tag = viewController.tabBarItem.tag
self.tabBarItem.image = viewController.tabBarItem.image
self.accessibilityLabel = viewController.accessibilityLabel
}
required init?(coder: NSCoder) {
fatalError("Not implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
stackView = UIStackView()
stackView.axis = .vertical
stackView.distribution = .fill
stackView.alignment = .fill
view.vc_addSubViewMatchingParent(stackView)
addChild(homeViewController)
stackView.addArrangedSubview(homeViewController.view)
homeViewController.didMove(toParent: self)
}
// MARK: - BannerPresentationProtocol
func presentBannerView(_ bannerView: UIView, animated: Bool) {
bannerView.alpha = 0.0
bannerView.isHidden = true
self.stackView.insertArrangedSubview(bannerView, at: 0)
self.stackView.layoutIfNeeded()
UIView.animate(withDuration: (animated ? 0.25 : 0.0)) {
bannerView.alpha = 1.0
bannerView.isHidden = false
self.stackView.layoutIfNeeded()
}
}
func dismissBannerView(animated: Bool) {
guard stackView.arrangedSubviews.count > 1, let bannerView = self.stackView.arrangedSubviews.first else {
return
}
UIView.animate(withDuration: (animated ? 0.25 : 0.0)) {
bannerView.alpha = 0.0
bannerView.isHidden = true
self.stackView.layoutIfNeeded()
} completion: { _ in
bannerView.removeFromSuperview()
}
}
}
@@ -0,0 +1,110 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import UIKit
import Reusable
protocol VersionCheckAlertViewControllerDelegate: AnyObject {
func alertViewControllerDidRequestDismissal(_ alertViewController: VersionCheckAlertViewController)
func alertViewControllerDidRequestAction(_ alertViewController: VersionCheckAlertViewController)
}
struct VersionCheckAlertViewControllerDetails {
let title: String
let subtitle: String
let actionButtonTitle: String
}
class VersionCheckAlertViewController: UIViewController {
@IBOutlet private var alertContainerView: UIView!
@IBOutlet private var titleLabel: UILabel!
@IBOutlet private var subtitleLabel: UILabel!
@IBOutlet private var dismissButton: UIButton!
@IBOutlet private var actionButton: UIButton!
private var themeService: ThemeService!
private var details: VersionCheckAlertViewControllerDetails?
weak var delegate: VersionCheckAlertViewControllerDelegate?
static func instantiate(themeService: ThemeService) -> VersionCheckAlertViewController {
let versionCheckAlertViewController = VersionCheckAlertViewController(nibName: nil, bundle: nil)
versionCheckAlertViewController.themeService = themeService
versionCheckAlertViewController.modalPresentationStyle = .overFullScreen
versionCheckAlertViewController.modalTransitionStyle = .crossDissolve
return versionCheckAlertViewController
}
override func viewDidLoad() {
super.viewDidLoad()
actionButton.layer.masksToBounds = true
actionButton.layer.cornerRadius = 6.0
configureWithDetails(details)
NotificationCenter.default.addObserver(self, selector: #selector(updateTheme), name: .themeServiceDidChangeTheme, object: nil)
updateTheme()
}
func configureWithDetails(_ details: VersionCheckAlertViewControllerDetails?) {
guard let details = details else {
return
}
guard self.isViewLoaded else {
self.details = details
return
}
titleLabel.text = details.title
actionButton.setTitle(details.actionButtonTitle, for: .normal)
let attributedSubtitle = NSMutableAttributedString(string: details.subtitle)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineHeightMultiple = 1.2
paragraphStyle.alignment = .center
attributedSubtitle.addAttribute(.paragraphStyle, value: paragraphStyle, range: .init(location: 0, length: attributedSubtitle.length))
subtitleLabel.attributedText = attributedSubtitle
}
// MARK: - Private
@IBAction private func onDismissButtonTap(_ sender: UIButton) {
delegate?.alertViewControllerDidRequestDismissal(self)
}
@IBAction private func onActionButtonTap(_ sender: UIButton) {
delegate?.alertViewControllerDidRequestAction(self)
}
@objc private func updateTheme() {
let theme = themeService.theme
alertContainerView.backgroundColor = theme.colors.background
titleLabel.textColor = theme.colors.primaryContent
subtitleLabel.textColor = theme.colors.secondaryContent
dismissButton.tintColor = theme.colors.secondaryContent
actionButton.vc_setBackgroundColor(theme.colors.accent, for: .normal)
}
}
@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="VersionCheckAlertViewController" customModule="Riot" customModuleProvider="target">
<connections>
<outlet property="actionButton" destination="EbY-m0-XSs" id="63P-Xf-QDA"/>
<outlet property="alertContainerView" destination="KIG-b9-Tyx" id="U06-A9-P9c"/>
<outlet property="dismissButton" destination="fGK-xG-RKK" id="udW-wA-Anp"/>
<outlet property="subtitleLabel" destination="zgc-27-11w" id="EEW-oJ-npn"/>
<outlet property="titleLabel" destination="KmG-fj-orS" id="Xcy-ek-zHo"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="680" height="614"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KIG-b9-Tyx">
<rect key="frame" x="42.5" y="186" width="595" height="242"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fGK-xG-RKK">
<rect key="frame" x="547" y="4" width="44" height="44"/>
<constraints>
<constraint firstAttribute="width" constant="44" id="8Pq-sX-5mB"/>
<constraint firstAttribute="height" constant="44" id="Wyp-3I-uEw"/>
</constraints>
<state key="normal" image="version_check_close_icon"/>
<connections>
<action selector="onDismissButtonTap:" destination="-1" eventType="touchUpInside" id="doW-WY-0Gv"/>
</connections>
</button>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="s18-lG-O4e">
<rect key="frame" x="16" y="52" width="563" height="174"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="Ter-fV-mb4">
<rect key="frame" x="0.0" y="0.0" width="563" height="114"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Were ending support for iOS 11" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KmG-fj-orS">
<rect key="frame" x="156.5" y="0.0" width="250.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
<color key="textColor" red="0.090196078431372548" green="0.098039215686274508" blue="0.10980392156862745" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zgc-27-11w">
<rect key="frame" x="0.0" y="32.5" width="563" height="81.5"/>
<string key="text">We've been working on enhancing Element for a faster and more polished experience. Unfortunately your current version of iOS is not compatible with some of those fixes and will no longer be supported. We're advising you to upgrade your operating system to use Element to its full potential.</string>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.45098039215686275" green="0.49019607843137253" blue="0.5490196078431373" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="EbY-m0-XSs">
<rect key="frame" x="200" y="134" width="163" height="40"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="15"/>
<inset key="contentEdgeInsets" minX="62" minY="11" maxX="62" maxY="11"/>
<state key="normal" title="Got it"/>
<connections>
<action selector="onActionButtonTap:" destination="-1" eventType="touchUpInside" id="sg4-JL-L3g"/>
</connections>
</button>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="600" id="EWq-BN-h4D"/>
<constraint firstAttribute="trailing" secondItem="s18-lG-O4e" secondAttribute="trailing" constant="16" id="IGg-Uc-Vj7"/>
<constraint firstAttribute="height" relation="lessThanOrEqual" constant="600" id="Kq2-HB-3xI"/>
<constraint firstItem="s18-lG-O4e" firstAttribute="top" secondItem="fGK-xG-RKK" secondAttribute="bottom" constant="4" id="SVY-JE-eRa"/>
<constraint firstItem="fGK-xG-RKK" firstAttribute="top" secondItem="KIG-b9-Tyx" secondAttribute="top" constant="4" id="aHW-7J-fAP"/>
<constraint firstItem="s18-lG-O4e" firstAttribute="leading" secondItem="KIG-b9-Tyx" secondAttribute="leading" constant="16" id="hUS-p8-LYF"/>
<constraint firstAttribute="trailing" secondItem="fGK-xG-RKK" secondAttribute="trailing" constant="4" id="qel-Uc-gCm"/>
<constraint firstAttribute="bottom" secondItem="s18-lG-O4e" secondAttribute="bottom" constant="16" id="x0D-6M-ENQ"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
<integer key="value" value="8"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" red="0.090196078431372548" green="0.098039215686274508" blue="0.10980392156862745" alpha="0.75" colorSpace="custom" customColorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="KIG-b9-Tyx" secondAttribute="bottom" constant="27" id="O2i-3j-Zdq"/>
<constraint firstItem="KIG-b9-Tyx" firstAttribute="centerY" secondItem="i5M-Pr-FkT" secondAttribute="centerY" id="gla-Ua-rd6"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="KIG-b9-Tyx" secondAttribute="trailing" constant="27" id="hZu-FV-h9a"/>
<constraint firstItem="KIG-b9-Tyx" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="rdh-sM-1Me"/>
<constraint firstItem="KIG-b9-Tyx" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="27" id="s7X-L5-bfF"/>
<constraint firstItem="KIG-b9-Tyx" firstAttribute="top" relation="greaterThanOrEqual" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="27" id="uyT-Zm-oWx"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="330.43478260869568" y="58.928571428571423"/>
</view>
</objects>
<resources>
<image name="version_check_close_icon" width="16" height="16"/>
</resources>
</document>
@@ -0,0 +1,74 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import UIKit
import Reusable
protocol VersionCheckBannerViewDelegate: AnyObject {
func bannerViewDidRequestDismissal(_ bannerView: VersionCheckBannerView)
func bannerViewDidRequestInteraction(_ bannerView: VersionCheckBannerView)
}
struct VersionCheckBannerViewDetails {
let title: String
let subtitle: String
}
class VersionCheckBannerView: UIView, NibLoadable, Themable {
@IBOutlet private var titleLabel: UILabel!
@IBOutlet private var subtitleLabel: UILabel!
@IBOutlet private var infoButton: UIButton!
@IBOutlet private var dismissButton: UIButton!
weak var delegate: VersionCheckBannerViewDelegate?
override func awakeFromNib() {
super.awakeFromNib()
let tapGestureRecognizer = UITapGestureRecognizer()
tapGestureRecognizer.addTarget(self, action: #selector(handleTapGesture))
self.addGestureRecognizer(tapGestureRecognizer)
}
func configureWithDetails(_ details: VersionCheckBannerViewDetails) {
titleLabel.text = details.title
subtitleLabel.text = details.subtitle
}
// MARK: - Themable
func update(theme: Theme) {
backgroundColor = theme.colors.background
titleLabel.textColor = theme.colors.primaryContent
subtitleLabel.textColor = theme.colors.secondaryContent
infoButton.tintColor = theme.colors.primaryContent
dismissButton.tintColor = theme.colors.secondaryContent
}
// MARK: - Private
@IBAction private func onDismissButtonTap(_ sender: UIButton) {
delegate?.bannerViewDidRequestDismissal(self)
}
@objc private func handleTapGesture(_ gestureRecognizer: UITapGestureRecognizer) {
delegate?.bannerViewDidRequestInteraction(self)
}
}
@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="VersionCheckBannerView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="479" height="150"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="top" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="5ts-Up-IFL">
<rect key="frame" x="12" y="16" width="419" height="118"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" verticalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aWS-bd-dO7">
<rect key="frame" x="0.0" y="0.0" width="45" height="24"/>
<state key="normal" image="version_check_info_icon"/>
</button>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="OJ5-KQ-ePa">
<rect key="frame" x="53" y="0.0" width="366" height="75.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Were ending support for iOS 11" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="XGd-6U-k3l">
<rect key="frame" x="0.0" y="0.0" width="366" height="20.5"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
<color key="textColor" red="0.090196078431372548" green="0.098039215686274508" blue="0.10980392156862745" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="btO-Jc-DmU">
<rect key="frame" x="0.0" y="28.5" width="366" height="47"/>
<string key="text">We will soon be ending support for Element on iOS 11. To continue using Element to its full potential, we advise you to upgrade your version of iOS.</string>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="0.090196078431372548" green="0.098039215686274508" blue="0.10980392156862745" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
</stackView>
<button opaque="NO" contentMode="scaleToFill" horizontalCompressionResistancePriority="751" verticalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qyW-5Q-Bkm">
<rect key="frame" x="431" y="4" width="44" height="44"/>
<constraints>
<constraint firstAttribute="width" constant="44" id="N0T-vY-YT7"/>
<constraint firstAttribute="height" constant="44" id="Rx3-dQ-K2O"/>
</constraints>
<state key="normal" image="version_check_close_icon"/>
<connections>
<action selector="onDismissButtonTap:" destination="iN0-l3-epB" eventType="touchUpInside" id="pDN-9q-Lr5"/>
</connections>
</button>
</subviews>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="qyW-5Q-Bkm" secondAttribute="trailing" constant="4" id="Psr-tv-GLd"/>
<constraint firstItem="qyW-5Q-Bkm" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="4" id="acO-Ae-IEB"/>
<constraint firstItem="5ts-Up-IFL" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="16" id="bRM-rK-xBC"/>
<constraint firstItem="5ts-Up-IFL" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="12" id="er6-CV-ezV"/>
<constraint firstItem="qyW-5Q-Bkm" firstAttribute="leading" secondItem="5ts-Up-IFL" secondAttribute="trailing" id="rYR-NR-y0G"/>
<constraint firstAttribute="bottom" secondItem="5ts-Up-IFL" secondAttribute="bottom" priority="100" constant="16" id="rjk-yN-Qxr"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="dismissButton" destination="qyW-5Q-Bkm" id="1XZ-Mv-9A5"/>
<outlet property="infoButton" destination="aWS-bd-dO7" id="Nk7-7P-PK5"/>
<outlet property="subtitleLabel" destination="btO-Jc-DmU" id="cLh-sg-vfz"/>
<outlet property="titleLabel" destination="XGd-6U-k3l" id="FTQ-fK-u4d"/>
</connections>
<point key="canvasLocation" x="277.536231884058" y="-150"/>
</view>
</objects>
<resources>
<image name="version_check_close_icon" width="16" height="16"/>
<image name="version_check_info_icon" width="24" height="24"/>
</resources>
</document>
@@ -0,0 +1,128 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
private let osVersionToBeDropped = 11
private let hasOSVersionBeenDropped = false
class VersionCheckCoordinator: VersionCheckBannerViewDelegate, VersionCheckAlertViewControllerDelegate {
private let rootViewController: UIViewController
private let bannerPresenter: BannerPresentationProtocol
private let themeService: ThemeService
@UserDefaultsBacked(key: "versionCheckCoordinatorNextDisplayDateTimeInterval")
private var nextDisplayDateTimeInterval: Double?
private var versionCheckBannerView: VersionCheckBannerView?
init(rootViewController: UIViewController, bannerPresenter: BannerPresentationProtocol, themeService: ThemeService) {
self.rootViewController = rootViewController
self.bannerPresenter = bannerPresenter
self.themeService = themeService
NotificationCenter.default.addObserver(self, selector: #selector(updateTheme), name: .themeServiceDidChangeTheme, object: nil)
}
func performVersionCheck() {
let majorOSVersion = ProcessInfo().operatingSystemVersion.majorVersion
guard majorOSVersion < osVersionToBeDropped else {
return
}
if let timeInterval = nextDisplayDateTimeInterval {
let nextDisplayDate = Date(timeIntervalSince1970: timeInterval)
if nextDisplayDate > Date() {
return
}
}
let versionCheckBannerView = VersionCheckBannerView.loadFromNib()
versionCheckBannerView.delegate = self
versionCheckBannerView.update(theme: themeService.theme)
if hasOSVersionBeenDropped {
versionCheckBannerView.configureWithDetails(VersionCheckBannerViewDetails(title: VectorL10n.versionCheckBannerTitleDeprecated(String(osVersionToBeDropped)),
subtitle: VectorL10n.versionCheckBannerSubtitleDeprecated(String(osVersionToBeDropped))))
} else {
versionCheckBannerView.configureWithDetails(VersionCheckBannerViewDetails(title: VectorL10n.versionCheckBannerTitleSupported(String(osVersionToBeDropped)),
subtitle: VectorL10n.versionCheckBannerSubtitleSupported(String(osVersionToBeDropped))))
}
bannerPresenter.presentBannerView(versionCheckBannerView, animated: true)
self.versionCheckBannerView = versionCheckBannerView
}
// MARK: - VersionDropBannerViewDelegate
func bannerViewDidRequestDismissal(_ bannerView: VersionCheckBannerView) {
dismissVersionCheckBanner()
}
func bannerViewDidRequestInteraction(_ bannerView: VersionCheckBannerView) {
let versionCheckAlertViewController = VersionCheckAlertViewController.instantiate(themeService: themeService)
versionCheckAlertViewController.delegate = self
if hasOSVersionBeenDropped {
versionCheckAlertViewController.configureWithDetails(VersionCheckAlertViewControllerDetails(title: VectorL10n.versionCheckModalTitleDeprecated(String(osVersionToBeDropped)),
subtitle: VectorL10n.versionCheckModalSubtitleDeprecated,
actionButtonTitle: VectorL10n.versionCheckModalActionTitleDeprecated))
} else {
versionCheckAlertViewController.configureWithDetails(VersionCheckAlertViewControllerDetails(title: VectorL10n.versionCheckModalTitleSupported(String(osVersionToBeDropped)),
subtitle: VectorL10n.versionCheckModalSubtitleSupported,
actionButtonTitle: VectorL10n.versionCheckModalActionTitleSupported))
}
rootViewController.present(versionCheckAlertViewController, animated: true) {
self.dismissVersionCheckBanner()
}
}
// MARK: - VersionCheckAlertViewControllerDelegate
func alertViewControllerDidRequestDismissal(_ alertViewController: VersionCheckAlertViewController) {
rootViewController.dismiss(animated: true, completion: nil)
}
func alertViewControllerDidRequestAction(_ alertViewController: VersionCheckAlertViewController) {
rootViewController.dismiss(animated: true, completion: nil)
guard hasOSVersionBeenDropped else {
return
}
if let url = URL(string: "https://support.apple.com/en-gb/guide/iphone/iph3e504502/ios") {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
// MARK: - Private
private func dismissVersionCheckBanner() {
bannerPresenter.dismissBannerView(animated: true)
let nextDisplayDate = Calendar.current.date(byAdding: .month, value: 1, to: Date())
nextDisplayDateTimeInterval = nextDisplayDate?.timeIntervalSince1970
}
@objc private func updateTheme() {
let theme = themeService.theme
versionCheckBannerView?.update(theme: theme)
}
}