mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-21 17:12:45 +02:00
Update the Service Terms modal from the latest Figma.
Checkboxes have been removed from the individual policies. Reverse flow so that the service terms are show before the contacts access popup. Removes outOfContext from the modal as it will only be presented when requested. Fixes second presentation on swipe to dismiss of the modal.
This commit is contained in:
@@ -37,9 +37,9 @@ final class ServiceTermsModalScreenCoordinator: ServiceTermsModalScreenCoordinat
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(serviceTerms: MXServiceTerms, outOfContext: Bool = false) {
|
||||
init(serviceTerms: MXServiceTerms) {
|
||||
|
||||
let serviceTermsModalScreenViewModel = ServiceTermsModalScreenViewModel(serviceTerms: serviceTerms, outOfContext: outOfContext)
|
||||
let serviceTermsModalScreenViewModel = ServiceTermsModalScreenViewModel(serviceTerms: serviceTerms)
|
||||
let serviceTermsModalScreenViewController = ServiceTermsModalScreenViewController.instantiate(with: serviceTermsModalScreenViewModel)
|
||||
self.serviceTermsModalScreenViewModel = serviceTermsModalScreenViewModel
|
||||
self.serviceTermsModalScreenViewController = serviceTermsModalScreenViewController
|
||||
@@ -70,8 +70,4 @@ extension ServiceTermsModalScreenCoordinator: ServiceTermsModalScreenViewModelCo
|
||||
func serviceTermsModalScreenViewModelDidDecline(_ viewModel: ServiceTermsModalScreenViewModelType) {
|
||||
self.delegate?.serviceTermsModalScreenCoordinatorDidDecline(self)
|
||||
}
|
||||
|
||||
func serviceTermsModalScreenViewModelDidCancel(_ viewModel: ServiceTermsModalScreenViewModelType) {
|
||||
self.delegate?.serviceTermsModalScreenCoordinatorDidCancel(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ protocol ServiceTermsModalScreenCoordinatorDelegate: AnyObject {
|
||||
func serviceTermsModalScreenCoordinatorDidAccept(_ coordinator: ServiceTermsModalScreenCoordinatorType)
|
||||
func serviceTermsModalScreenCoordinator(_ coordinator: ServiceTermsModalScreenCoordinatorType, displayPolicy policy: MXLoginPolicyData)
|
||||
func serviceTermsModalScreenCoordinatorDidDecline(_ coordinator: ServiceTermsModalScreenCoordinatorType)
|
||||
func serviceTermsModalScreenCoordinatorDidCancel(_ coordinator: ServiceTermsModalScreenCoordinatorType)
|
||||
}
|
||||
|
||||
/// `ServiceTermsModalScreenCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow.
|
||||
|
||||
@@ -24,5 +24,4 @@ enum ServiceTermsModalScreenViewAction {
|
||||
case display(MXLoginPolicyData)
|
||||
case accept
|
||||
case decline
|
||||
case cancel
|
||||
}
|
||||
|
||||
+88
-39
@@ -1,12 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="V8j-Lb-PgC">
|
||||
<device id="retina6_1" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="V8j-Lb-PgC">
|
||||
<device id="retina5_9" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
@@ -15,48 +14,90 @@
|
||||
<objects>
|
||||
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="V8j-Lb-PgC" customClass="ServiceTermsModalScreenViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="EL9-GA-lwo">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9U2-KL-ZVA">
|
||||
<rect key="frame" x="0.0" y="44" width="414" height="852"/>
|
||||
<rect key="frame" x="0.0" y="44" width="375" height="768"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="e7g-um-WO4">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="852"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="768"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="voD-3Q-ryt">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="852"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="768"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="To continue you need to accept the Terms of this service." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bxI-mu-qng">
|
||||
<rect key="frame" x="20" y="20" width="374" height="100"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="100" id="1bP-8m-xrd"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="swq-xw-ItG">
|
||||
<rect key="frame" x="20" y="128" width="374" height="600"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</tableView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="dcx-ju-f0Q">
|
||||
<rect key="frame" x="20" y="736" width="374" height="96"/>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="gff-MZ-3bp">
|
||||
<rect key="frame" x="20" y="20" width="335" height="207"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DOt-5E-FjF">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="44"/>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="contacts_request_facepile" translatesAutoresizingMaskIntoConstraints="NO" id="XWa-N5-VF2">
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="46"/>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="To continue, accept the below terms and conditions" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bxI-mu-qng">
|
||||
<rect key="frame" x="0.0" y="46" width="335" height="100"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="d2a-Dw-Pu5"/>
|
||||
<constraint firstAttribute="height" constant="100" id="1bP-8m-xrd"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="This will allow someone to find you if they have your phone number or email saved in their phone contacts." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5fA-rc-XMP">
|
||||
<rect key="frame" x="0.0" y="146" width="335" height="61"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="insetGrouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="swq-xw-ItG">
|
||||
<rect key="frame" x="0.0" y="267" width="375" height="313"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="Service Terms Cell" textLabel="inf-zH-Iu8" style="IBUITableViewCellStyleDefault" id="krZ-0R-qfI">
|
||||
<rect key="frame" x="16" y="49" width="343" height="43.666667938232422"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="krZ-0R-qfI" id="I7f-2P-YXj">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="43.666667938232422"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="inf-zH-Iu8">
|
||||
<rect key="frame" x="16" y="0.0" width="311" height="43.666667938232422"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="0.0"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
</tableView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="dcx-ju-f0Q">
|
||||
<rect key="frame" x="20" y="588" width="335" height="146"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="This can be disabled anytime in settings." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qmt-nE-Lg7">
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="32"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="32" id="PCs-bC-vNT"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DOt-5E-FjF">
|
||||
<rect key="frame" x="0.0" y="44" width="335" height="45"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="45" id="d2a-Dw-Pu5"/>
|
||||
</constraints>
|
||||
<state key="normal" title="Accept"/>
|
||||
<connections>
|
||||
<action selector="acceptButtonAction:" destination="V8j-Lb-PgC" eventType="touchUpInside" id="uvI-tt-Nfj"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QHr-gh-dAD">
|
||||
<rect key="frame" x="0.0" y="52" width="374" height="44"/>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QHr-gh-dAD">
|
||||
<rect key="frame" x="0.0" y="101" width="335" height="45"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="y6d-Vg-5PP"/>
|
||||
<constraint firstAttribute="height" constant="45" id="y6d-Vg-5PP"/>
|
||||
</constraints>
|
||||
<state key="normal" title="Decline">
|
||||
<color key="titleColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -70,17 +111,16 @@
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="bxI-mu-qng" firstAttribute="leading" secondItem="voD-3Q-ryt" secondAttribute="leading" constant="20" symbolic="YES" id="1K2-u8-QsL"/>
|
||||
<constraint firstAttribute="trailing" secondItem="bxI-mu-qng" secondAttribute="trailing" constant="20" symbolic="YES" id="41D-TP-69f"/>
|
||||
<constraint firstItem="swq-xw-ItG" firstAttribute="top" secondItem="bxI-mu-qng" secondAttribute="bottom" constant="8" symbolic="YES" id="9Gg-Xb-o2W"/>
|
||||
<constraint firstItem="bxI-mu-qng" firstAttribute="top" secondItem="voD-3Q-ryt" secondAttribute="top" constant="20" symbolic="YES" id="W1m-x0-TyS"/>
|
||||
<constraint firstItem="gff-MZ-3bp" firstAttribute="top" secondItem="voD-3Q-ryt" secondAttribute="top" constant="20" symbolic="YES" id="RbQ-et-xoU"/>
|
||||
<constraint firstItem="dcx-ju-f0Q" firstAttribute="leading" secondItem="voD-3Q-ryt" secondAttribute="leading" constant="20" symbolic="YES" id="Wcx-d6-M14"/>
|
||||
<constraint firstAttribute="trailing" secondItem="swq-xw-ItG" secondAttribute="trailing" constant="20" symbolic="YES" id="Y5v-Gg-xkM"/>
|
||||
<constraint firstAttribute="bottom" secondItem="dcx-ju-f0Q" secondAttribute="bottom" constant="20" symbolic="YES" id="cpa-Lq-Mvs"/>
|
||||
<constraint firstAttribute="trailing" secondItem="swq-xw-ItG" secondAttribute="trailing" id="Y5v-Gg-xkM"/>
|
||||
<constraint firstAttribute="trailing" secondItem="dcx-ju-f0Q" secondAttribute="trailing" constant="20" symbolic="YES" id="eGO-kM-neh"/>
|
||||
<constraint firstAttribute="width" priority="750" constant="500" id="glD-Sz-73O"/>
|
||||
<constraint firstAttribute="trailing" secondItem="gff-MZ-3bp" secondAttribute="trailing" constant="20" symbolic="YES" id="iF6-Ga-3JK"/>
|
||||
<constraint firstItem="gff-MZ-3bp" firstAttribute="leading" secondItem="voD-3Q-ryt" secondAttribute="leading" constant="20" symbolic="YES" id="x7i-4D-XSX"/>
|
||||
<constraint firstItem="dcx-ju-f0Q" firstAttribute="top" secondItem="swq-xw-ItG" secondAttribute="bottom" constant="8" symbolic="YES" id="zYm-2k-kvi"/>
|
||||
<constraint firstItem="swq-xw-ItG" firstAttribute="leading" secondItem="voD-3Q-ryt" secondAttribute="leading" constant="20" symbolic="YES" id="ze1-Iw-v9U"/>
|
||||
<constraint firstItem="swq-xw-ItG" firstAttribute="leading" secondItem="voD-3Q-ryt" secondAttribute="leading" id="ze1-Iw-v9U"/>
|
||||
<constraint firstItem="swq-xw-ItG" firstAttribute="top" secondItem="gff-MZ-3bp" secondAttribute="bottom" constant="40" id="zfd-m4-7dW"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
@@ -104,21 +144,24 @@
|
||||
</constraints>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="bFg-jh-JZB"/>
|
||||
<color key="backgroundColor" red="0.94509803921568625" green="0.96078431372549022" blue="0.97254901960784312" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="9U2-KL-ZVA" secondAttribute="bottom" id="7Cb-nY-CsO"/>
|
||||
<constraint firstItem="9U2-KL-ZVA" firstAttribute="leading" secondItem="bFg-jh-JZB" secondAttribute="leading" id="GdQ-hK-muG"/>
|
||||
<constraint firstItem="bFg-jh-JZB" firstAttribute="bottom" secondItem="dcx-ju-f0Q" secondAttribute="bottom" id="gIp-7G-Joa"/>
|
||||
<constraint firstItem="bFg-jh-JZB" firstAttribute="trailing" secondItem="9U2-KL-ZVA" secondAttribute="trailing" id="sbD-ek-vGJ"/>
|
||||
<constraint firstItem="bFg-jh-JZB" firstAttribute="top" secondItem="9U2-KL-ZVA" secondAttribute="top" id="wTB-V6-IHV"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="bFg-jh-JZB"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="acceptButton" destination="DOt-5E-FjF" id="ktw-U4-efQ"/>
|
||||
<outlet property="declineButton" destination="QHr-gh-dAD" id="QOS-rE-4SP"/>
|
||||
<outlet property="messageLabel" destination="bxI-mu-qng" id="pbX-aZ-inC"/>
|
||||
<outlet property="descriptionLabel" destination="5fA-rc-XMP" id="OkU-OE-DgA"/>
|
||||
<outlet property="footerLabel" destination="Qmt-nE-Lg7" id="BOZ-Qy-Pxj"/>
|
||||
<outlet property="scrollView" destination="9U2-KL-ZVA" id="ojG-2y-X7b"/>
|
||||
<outlet property="tableView" destination="swq-xw-ItG" id="Fwb-Sc-bec"/>
|
||||
<outlet property="titleLabel" destination="bxI-mu-qng" id="pbX-aZ-inC"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="zK0-v6-7Wt" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
@@ -126,4 +169,10 @@
|
||||
<point key="canvasLocation" x="-3198" y="-647"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="contacts_request_facepile" width="110" height="46"/>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
+93
-126
@@ -22,13 +22,19 @@ final class ServiceTermsModalScreenViewController: UIViewController {
|
||||
|
||||
// MARK: - Constants
|
||||
|
||||
private enum Constants {
|
||||
static let cellReuseIdentifier = "Service Terms Cell"
|
||||
}
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Outlets
|
||||
|
||||
@IBOutlet private weak var scrollView: UIScrollView!
|
||||
|
||||
@IBOutlet private weak var messageLabel: UILabel!
|
||||
@IBOutlet private weak var titleLabel: UILabel!
|
||||
@IBOutlet private weak var descriptionLabel: UILabel!
|
||||
@IBOutlet private weak var footerLabel: UILabel!
|
||||
@IBOutlet private weak var tableView: UITableView!
|
||||
@IBOutlet private weak var acceptButton: UIButton!
|
||||
@IBOutlet private weak var declineButton: UIButton!
|
||||
@@ -42,9 +48,6 @@ final class ServiceTermsModalScreenViewController: UIViewController {
|
||||
|
||||
private var policies: [MXLoginPolicyData] = []
|
||||
|
||||
/// Policies checked by the end user
|
||||
private var checkedPolicies: Set<Int> = []
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
class func instantiate(with viewModel: ServiceTermsModalScreenViewModelType) -> ServiceTermsModalScreenViewController {
|
||||
@@ -60,8 +63,6 @@ final class ServiceTermsModalScreenViewController: UIViewController {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
|
||||
self.title = VectorL10n.serviceTermsModalTitle
|
||||
|
||||
self.setupViews()
|
||||
self.activityPresenter = ActivityIndicatorPresenter()
|
||||
@@ -84,19 +85,28 @@ final class ServiceTermsModalScreenViewController: UIViewController {
|
||||
private func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
|
||||
self.view.backgroundColor = theme.headerBackgroundColor
|
||||
view.backgroundColor = theme.headerBackgroundColor
|
||||
|
||||
if let navigationBar = self.navigationController?.navigationBar {
|
||||
if let navigationBar = navigationController?.navigationBar {
|
||||
theme.applyStyle(onNavigationBar: navigationBar)
|
||||
}
|
||||
|
||||
self.messageLabel.textColor = theme.textPrimaryColor
|
||||
titleLabel.font = theme.fonts.bodySB
|
||||
titleLabel.textColor = theme.colors.primaryContent
|
||||
|
||||
descriptionLabel.font = theme.fonts.body
|
||||
descriptionLabel.textColor = theme.colors.secondaryContent
|
||||
|
||||
footerLabel.font = theme.fonts.footnote.withSize(13)
|
||||
footerLabel.textColor = theme.colors.secondaryContent
|
||||
|
||||
self.acceptButton.backgroundColor = theme.backgroundColor
|
||||
theme.applyStyle(onButton: self.acceptButton)
|
||||
acceptButton.titleLabel?.font = theme.fonts.body
|
||||
acceptButton.setTitleColor(theme.colors.background, for: .normal)
|
||||
acceptButton.backgroundColor = theme.colors.accent
|
||||
|
||||
theme.applyStyle(onButton: self.declineButton)
|
||||
self.declineButton.setTitleColor(self.theme.warningColor, for: .normal)
|
||||
declineButton.titleLabel?.font = theme.fonts.body
|
||||
declineButton.setTitleColor(theme.warningColor, for: .normal)
|
||||
|
||||
self.refreshViews()
|
||||
}
|
||||
@@ -110,30 +120,24 @@ final class ServiceTermsModalScreenViewController: UIViewController {
|
||||
}
|
||||
|
||||
private func setupViews() {
|
||||
let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in
|
||||
self?.cancelButtonAction()
|
||||
}
|
||||
|
||||
self.navigationItem.rightBarButtonItem = cancelBarButtonItem
|
||||
|
||||
self.setupTableView()
|
||||
self.scrollView.keyboardDismissMode = .interactive
|
||||
|
||||
self.messageLabel.text = VectorL10n.serviceTermsModalMessage(self.viewModel.serviceUrl)
|
||||
self.titleLabel.text = VectorL10n.serviceTermsModalTitleMessage
|
||||
self.footerLabel.text = VectorL10n.serviceTermsModalFooter
|
||||
|
||||
self.acceptButton.setTitle(VectorL10n.serviceTermsModalAcceptButton, for: .normal)
|
||||
self.acceptButton.setTitle(VectorL10n.serviceTermsModalAcceptButton, for: .highlighted)
|
||||
self.refreshAcceptButton()
|
||||
self.acceptButton.layer.cornerRadius = 8
|
||||
|
||||
if self.viewModel.outOfContext
|
||||
&& self.viewModel.serviceType == MXServiceTypeIdentityService {
|
||||
self.title = VectorL10n.serviceTermsModalTitleIdentityServer
|
||||
self.messageLabel.text = VectorL10n.serviceTermsModalMessageIdentityServer(self.viewModel.serviceUrl)
|
||||
|
||||
self.declineButton.setTitle(VectorL10n.serviceTermsModalDeclineButton, for: .normal)
|
||||
self.declineButton.setTitle(VectorL10n.serviceTermsModalDeclineButton, for: .highlighted)
|
||||
self.declineButton.setTitle(VectorL10n.serviceTermsModalDeclineButton, for: .normal)
|
||||
self.declineButton.setTitle(VectorL10n.serviceTermsModalDeclineButton, for: .highlighted)
|
||||
|
||||
if self.viewModel.serviceType == MXServiceTypeIdentityService {
|
||||
self.descriptionLabel.text = VectorL10n.serviceTermsModalDescriptionIdentityServer
|
||||
} else {
|
||||
self.declineButton.isHidden = true
|
||||
self.descriptionLabel.text = VectorL10n.serviceTermsModalDescriptionIntegrationManager
|
||||
// TODO: Set a different image for the integration manager.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,13 +165,14 @@ final class ServiceTermsModalScreenViewController: UIViewController {
|
||||
|
||||
private func renderLoading() {
|
||||
self.activityPresenter.presentActivityIndicator(on: self.view, animated: true)
|
||||
self.acceptButton.isEnabled = false
|
||||
}
|
||||
|
||||
private func renderLoaded(policies: [MXLoginPolicyData], alreadyAcceptedPoliciesUrls: [String]) {
|
||||
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
|
||||
|
||||
self.policies = policies
|
||||
self.updateCheckedPolicies(with: alreadyAcceptedPoliciesUrls)
|
||||
self.acceptButton.isEnabled = true
|
||||
|
||||
self.refreshViews()
|
||||
}
|
||||
@@ -187,21 +192,6 @@ final class ServiceTermsModalScreenViewController: UIViewController {
|
||||
|
||||
private func refreshViews() {
|
||||
self.tableView.reloadData()
|
||||
self.refreshAcceptButton()
|
||||
}
|
||||
|
||||
private func refreshAcceptButton() {
|
||||
// Enable the button only if the user has accepted all policies
|
||||
self.acceptButton.isEnabled = (self.policies.count == self.checkedPolicies.count)
|
||||
}
|
||||
|
||||
// Pre-check policies already accepted by the user
|
||||
private func updateCheckedPolicies(with acceptedPoliciesUrls: [String]) {
|
||||
for url in acceptedPoliciesUrls {
|
||||
if let policyIndex = self.policies.firstIndex(where: { $0.url == url }) {
|
||||
checkedPolicies.insert(policyIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -214,37 +204,6 @@ final class ServiceTermsModalScreenViewController: UIViewController {
|
||||
@IBAction private func declineButtonAction(_ sender: Any) {
|
||||
self.viewModel.process(viewAction: .decline)
|
||||
}
|
||||
|
||||
private func cancelButtonAction() {
|
||||
self.viewModel.process(viewAction: .cancel)
|
||||
}
|
||||
|
||||
@objc private func didTapCheckbox(sender: UITapGestureRecognizer) {
|
||||
|
||||
guard let policyIndex = sender.view?.tag else {
|
||||
return
|
||||
}
|
||||
|
||||
let isCheckBoxSelected: Bool
|
||||
|
||||
if self.checkedPolicies.contains(policyIndex) {
|
||||
self.checkedPolicies.remove(policyIndex)
|
||||
isCheckBoxSelected = false
|
||||
} else {
|
||||
checkedPolicies.insert(policyIndex)
|
||||
isCheckBoxSelected = true
|
||||
}
|
||||
|
||||
if let checkBoxImageView = sender.view as? UIImageView {
|
||||
if isCheckBoxSelected {
|
||||
checkBoxImageView.accessibilityTraits.insert(.selected)
|
||||
} else {
|
||||
checkBoxImageView.accessibilityTraits.remove(.selected)
|
||||
}
|
||||
}
|
||||
|
||||
self.refreshViews()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -259,72 +218,80 @@ extension ServiceTermsModalScreenViewController: ServiceTermsModalScreenViewMode
|
||||
// MARK: - UITableViewDataSource
|
||||
|
||||
extension ServiceTermsModalScreenViewController: UITableViewDataSource {
|
||||
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
// The first section contains the server's URL. Then use individual
|
||||
// sections for each policy so the cells aren't grouped together.
|
||||
return 1 + policies.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return self.policies.count
|
||||
return 1
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
// The first section has header text. Modify the rest to reduce cell spacing.
|
||||
return section == 0 ? 20 : 8
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
return section == 0 ? "Identity Server Terms" : nil
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
|
||||
// Reduce the height between sections to only be the header height value.
|
||||
return CGFloat.leastNormalMagnitude
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCellWithCheckBoxAndLabel.defaultReuseIdentifier(), for: indexPath) as? TableViewCellWithCheckBoxAndLabel else {
|
||||
fatalError("\(String(describing: TableViewCellWithCheckBoxAndLabel.self)) should be registered")
|
||||
if indexPath.section == 0 {
|
||||
return identityServerURLCell(forRowAt: indexPath)
|
||||
} else {
|
||||
return policyCell(forRowAt: indexPath)
|
||||
}
|
||||
|
||||
let policy = policies[indexPath.row]
|
||||
let checked = checkedPolicies.contains(indexPath.row)
|
||||
|
||||
cell.label.attributedText = self.cellLabel(for: policy)
|
||||
cell.label.font = .systemFont(ofSize: 15)
|
||||
cell.isEnabled = checked
|
||||
cell.vc_setAccessoryDisclosureIndicator(withTheme: self.theme)
|
||||
cell.backgroundColor = self.theme.backgroundColor
|
||||
|
||||
if let checkBox = cell.checkBox, checkBox.gestureRecognizers?.isEmpty ?? true {
|
||||
let gesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapCheckbox))
|
||||
gesture.numberOfTapsRequired = 1
|
||||
gesture.numberOfTouchesRequired = 1
|
||||
|
||||
checkBox.isUserInteractionEnabled = true
|
||||
checkBox.tag = indexPath.row
|
||||
checkBox.addGestureRecognizer(gesture)
|
||||
|
||||
checkBox.isAccessibilityElement = true
|
||||
checkBox.accessibilityTraits = .button
|
||||
checkBox.accessibilityLabel = VectorL10n.accessibilityCheckboxLabel
|
||||
checkBox.accessibilityHint = VectorL10n.serviceTermsModalPolicyCheckboxAccessibilityHint(policy.name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO: Handle this in the integration manager too
|
||||
private func identityServerURLCell(forRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: Constants.cellReuseIdentifier, for: indexPath)
|
||||
|
||||
cell.textLabel?.text = viewModel.serviceUrl
|
||||
cell.textLabel?.font = theme.fonts.callout
|
||||
cell.textLabel?.textColor = theme.colors.secondaryContent
|
||||
cell.accessoryView = nil
|
||||
cell.backgroundColor = .clear
|
||||
cell.selectionStyle = .none
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
private func policyCell(forRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: Constants.cellReuseIdentifier, for: indexPath)
|
||||
|
||||
let policyIndex = indexPath.section - 1
|
||||
|
||||
func cellLabel(for policy: MXLoginPolicyData) -> NSAttributedString {
|
||||
let policy = policies[policyIndex]
|
||||
|
||||
// TableViewCellWithCheckBoxAndLabel does not have a detailTextLabel
|
||||
// Do it by hand
|
||||
cell.textLabel?.text = policy.name
|
||||
cell.textLabel?.textColor = theme.colors.primaryContent
|
||||
cell.textLabel?.font = theme.fonts.body
|
||||
cell.vc_setAccessoryDisclosureIndicator(withTheme: self.theme)
|
||||
cell.accessoryView?.tintColor = theme.colors.quarterlyContent
|
||||
cell.backgroundColor = theme.colors.background
|
||||
cell.selectionStyle = .default
|
||||
|
||||
var labelDetail: String = ""
|
||||
switch self.viewModel.serviceType {
|
||||
case MXServiceTypeIdentityService:
|
||||
labelDetail = VectorL10n.serviceTermsModalDescriptionForIdentityServer1
|
||||
+ "\n"
|
||||
+ VectorL10n.serviceTermsModalDescriptionForIdentityServer2
|
||||
case MXServiceTypeIntegrationManager:
|
||||
labelDetail = VectorL10n.serviceTermsModalDescriptionForIntegrationManager
|
||||
default: break
|
||||
}
|
||||
|
||||
let label = NSMutableAttributedString(string: policy.name,
|
||||
attributes: [.foregroundColor: theme.textPrimaryColor])
|
||||
label.append(NSAttributedString(string: "\n"))
|
||||
label.append(NSAttributedString(string: labelDetail,
|
||||
attributes: [.foregroundColor: theme.textSecondaryColor]))
|
||||
return label
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
extension ServiceTermsModalScreenViewController: UITableViewDelegate {
|
||||
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
|
||||
return indexPath.section > 0 ? indexPath : nil
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let policy = policies[indexPath.row]
|
||||
self.viewModel.process(viewAction: .display(policy))
|
||||
let policy = policies[indexPath.section - 1]
|
||||
viewModel.process(viewAction: .display(policy))
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import Foundation
|
||||
final class ServiceTermsModalScreenViewModel: ServiceTermsModalScreenViewModelType {
|
||||
|
||||
// MARK: - Properties
|
||||
let outOfContext: Bool
|
||||
|
||||
// MARK: Private
|
||||
|
||||
@@ -43,9 +42,8 @@ final class ServiceTermsModalScreenViewModel: ServiceTermsModalScreenViewModelTy
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(serviceTerms: MXServiceTerms, outOfContext: Bool) {
|
||||
init(serviceTerms: MXServiceTerms) {
|
||||
self.serviceTerms = serviceTerms
|
||||
self.outOfContext = outOfContext
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
@@ -60,8 +58,6 @@ final class ServiceTermsModalScreenViewModel: ServiceTermsModalScreenViewModelTy
|
||||
self.acceptTerms()
|
||||
case .decline:
|
||||
self.coordinatorDelegate?.serviceTermsModalScreenViewModelDidDecline(self)
|
||||
case .cancel:
|
||||
self.coordinatorDelegate?.serviceTermsModalScreenViewModelDidCancel(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,8 +97,10 @@ final class ServiceTermsModalScreenViewModel: ServiceTermsModalScreenViewModelTy
|
||||
self.update(viewState: .accepted)
|
||||
|
||||
// Send a notification to update the identity service immediately.
|
||||
let userInfo = [MXIdentityServiceNotificationIdentityServerKey: self.serviceTerms.baseUrl]
|
||||
NotificationCenter.default.post(name: .MXIdentityServiceTermsAccepted, object: nil, userInfo: userInfo)
|
||||
if self.serviceTerms.serviceType == MXServiceTypeIdentityService {
|
||||
let userInfo = [MXIdentityServiceNotificationIdentityServerKey: self.serviceTerms.baseUrl]
|
||||
NotificationCenter.default.post(name: .MXIdentityServiceTermsAccepted, object: nil, userInfo: userInfo)
|
||||
}
|
||||
|
||||
// Notify the delegate.
|
||||
self.coordinatorDelegate?.serviceTermsModalScreenViewModelDidAccept(self)
|
||||
|
||||
@@ -26,7 +26,6 @@ protocol ServiceTermsModalScreenViewModelCoordinatorDelegate: AnyObject {
|
||||
func serviceTermsModalScreenViewModel(_ coordinator: ServiceTermsModalScreenViewModelType, displayPolicy policy: MXLoginPolicyData)
|
||||
func serviceTermsModalScreenViewModelDidAccept(_ viewModel: ServiceTermsModalScreenViewModelType)
|
||||
func serviceTermsModalScreenViewModelDidDecline(_ viewModel: ServiceTermsModalScreenViewModelType)
|
||||
func serviceTermsModalScreenViewModelDidCancel(_ viewModel: ServiceTermsModalScreenViewModelType)
|
||||
}
|
||||
|
||||
/// Protocol describing the view model used by `ServiceTermsModalScreenViewController`
|
||||
@@ -34,9 +33,6 @@ protocol ServiceTermsModalScreenViewModelType {
|
||||
|
||||
var serviceUrl: String { get }
|
||||
var serviceType: MXServiceType { get }
|
||||
/// If true, terms are displayed out of a context of a flow (like a background 3pids lookup)
|
||||
/// In this case, the wording needs to provide more information about the intent
|
||||
var outOfContext: Bool { get }
|
||||
var policies: [MXLoginPolicyData]? { get set }
|
||||
var alreadyAcceptedPoliciesUrls: [String] { get set }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user