mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-22 01:22:46 +02:00
Add call transfer module
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="dBQ-CG-VDL">
|
||||
<device id="retina6_5" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17505"/>
|
||||
<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>
|
||||
<!--Call Transfer Main View Controller-->
|
||||
<scene sceneID="EyC-m5-6uM">
|
||||
<objects>
|
||||
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="dBQ-CG-VDL" customClass="CallTransferMainViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ht4-fu-3rS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ivb-NU-kFo">
|
||||
<rect key="frame" x="0.0" y="44" width="414" height="56"/>
|
||||
<subviews>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="BQy-Hx-23Q">
|
||||
<rect key="frame" x="18" y="12.666666666666664" width="378" height="32"/>
|
||||
<segments>
|
||||
<segment title="Users"/>
|
||||
<segment title="Dial pad"/>
|
||||
</segments>
|
||||
<connections>
|
||||
<action selector="segmentedControlValueChanged:" destination="dBQ-CG-VDL" eventType="valueChanged" id="xas-5X-YIb"/>
|
||||
</connections>
|
||||
</segmentedControl>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="BQy-Hx-23Q" firstAttribute="centerY" secondItem="ivb-NU-kFo" secondAttribute="centerY" id="3bo-xx-XQO"/>
|
||||
<constraint firstItem="BQy-Hx-23Q" firstAttribute="leading" secondItem="ivb-NU-kFo" secondAttribute="leading" constant="18" id="4fL-rC-m02"/>
|
||||
<constraint firstAttribute="trailing" secondItem="BQy-Hx-23Q" secondAttribute="trailing" constant="18" id="O8K-YL-fBV"/>
|
||||
<constraint firstAttribute="height" constant="56" id="gVH-Xy-3uB"/>
|
||||
<constraint firstItem="BQy-Hx-23Q" firstAttribute="centerX" secondItem="ivb-NU-kFo" secondAttribute="centerX" id="uzE-ji-fqt"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="b0y-K0-cMv">
|
||||
<rect key="frame" x="0.0" y="100" width="414" height="698"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="mNr-eP-dbL">
|
||||
<rect key="frame" x="0.0" y="798" width="414" height="98"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="WjD-md-81g">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="64"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GUZ-FS-Td0">
|
||||
<rect key="frame" x="8" y="10" width="218" height="44"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="CL2-cJ-Hq0"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<inset key="contentEdgeInsets" minX="8" minY="0.0" maxX="8" maxY="0.0"/>
|
||||
<inset key="titleEdgeInsets" minX="8" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
<state key="normal" title="Consult first" image="selection_untick">
|
||||
<color key="titleColor" systemColor="labelColor"/>
|
||||
</state>
|
||||
<state key="selected" image="selection_tick"/>
|
||||
<connections>
|
||||
<action selector="consultButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="Cmf-Xv-er5"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GPr-un-yKK" customClass="RoundedButton" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="242" y="10" width="156" height="44"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="IIn-jW-9iZ"/>
|
||||
<constraint firstAttribute="width" constant="156" id="a8K-gK-zdi"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<state key="normal" title="Connect"/>
|
||||
<connections>
|
||||
<action selector="connectButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="JDN-12-LLC"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="GPr-un-yKK" firstAttribute="centerY" secondItem="WjD-md-81g" secondAttribute="centerY" id="GU0-T5-6wb"/>
|
||||
<constraint firstItem="GUZ-FS-Td0" firstAttribute="leading" secondItem="WjD-md-81g" secondAttribute="leading" constant="8" id="H5w-Lf-dIb"/>
|
||||
<constraint firstAttribute="height" constant="64" id="Ie3-WQ-ARI"/>
|
||||
<constraint firstAttribute="trailing" secondItem="GPr-un-yKK" secondAttribute="trailing" constant="16" id="XUO-J8-2LK"/>
|
||||
<constraint firstItem="GPr-un-yKK" firstAttribute="leading" secondItem="GUZ-FS-Td0" secondAttribute="trailing" constant="16" id="aKo-Ey-1cF"/>
|
||||
<constraint firstItem="GUZ-FS-Td0" firstAttribute="centerY" secondItem="WjD-md-81g" secondAttribute="centerY" id="fcx-xi-SWI"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="WjD-md-81g" secondAttribute="trailing" id="0Bj-es-XW6"/>
|
||||
<constraint firstItem="WjD-md-81g" firstAttribute="top" secondItem="mNr-eP-dbL" secondAttribute="top" id="Hfy-g6-fWh"/>
|
||||
<constraint firstItem="WjD-md-81g" firstAttribute="top" secondItem="mNr-eP-dbL" secondAttribute="top" id="Zgs-Dq-QcE"/>
|
||||
<constraint firstItem="WjD-md-81g" firstAttribute="leading" secondItem="mNr-eP-dbL" secondAttribute="leading" id="w1Q-xn-Pdr"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="6ex-OQ-2sZ"/>
|
||||
<color key="backgroundColor" red="0.94509803921568625" green="0.96078431372549022" blue="0.97254901960784312" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="ivb-NU-kFo" firstAttribute="trailing" secondItem="6ex-OQ-2sZ" secondAttribute="trailing" id="8VB-uR-ky0"/>
|
||||
<constraint firstItem="ivb-NU-kFo" firstAttribute="leading" secondItem="6ex-OQ-2sZ" secondAttribute="leading" id="A8z-qE-R6n"/>
|
||||
<constraint firstAttribute="trailing" secondItem="mNr-eP-dbL" secondAttribute="trailing" id="DUd-Km-Bwd"/>
|
||||
<constraint firstItem="mNr-eP-dbL" firstAttribute="top" secondItem="b0y-K0-cMv" secondAttribute="bottom" id="Eac-dV-Vn0"/>
|
||||
<constraint firstItem="6ex-OQ-2sZ" firstAttribute="trailing" secondItem="b0y-K0-cMv" secondAttribute="trailing" id="Qo1-yS-ctz"/>
|
||||
<constraint firstAttribute="bottom" secondItem="mNr-eP-dbL" secondAttribute="bottom" id="VTQ-2Y-tHP"/>
|
||||
<constraint firstItem="b0y-K0-cMv" firstAttribute="leading" secondItem="6ex-OQ-2sZ" secondAttribute="leading" id="b4o-2l-yIe"/>
|
||||
<constraint firstItem="b0y-K0-cMv" firstAttribute="top" secondItem="ivb-NU-kFo" secondAttribute="bottom" id="cKV-r0-vsE"/>
|
||||
<constraint firstItem="6ex-OQ-2sZ" firstAttribute="bottom" secondItem="WjD-md-81g" secondAttribute="bottom" id="e9A-aJ-Ziy"/>
|
||||
<constraint firstItem="mNr-eP-dbL" firstAttribute="leading" secondItem="Ht4-fu-3rS" secondAttribute="leading" id="qST-XX-Cds"/>
|
||||
<constraint firstItem="ivb-NU-kFo" firstAttribute="top" secondItem="6ex-OQ-2sZ" secondAttribute="top" id="sun-63-fyH"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="bottomBgView" destination="mNr-eP-dbL" id="1aq-Xb-xlJ"/>
|
||||
<outlet property="connectButton" destination="GPr-un-yKK" id="6Wy-xb-P7t"/>
|
||||
<outlet property="consultButton" destination="GUZ-FS-Td0" id="wXK-Ut-bJ5"/>
|
||||
<outlet property="containerView" destination="b0y-K0-cMv" id="GDc-7P-W2U"/>
|
||||
<outlet property="segmentedControl" destination="BQy-Hx-23Q" id="6Oe-r5-yNn"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="bLY-II-iJ3" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-1703.2" y="254.12293853073464"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="selection_tick" width="22" height="22"/>
|
||||
<image name="selection_untick" width="22" height="22"/>
|
||||
<systemColor name="labelColor">
|
||||
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -0,0 +1,216 @@
|
||||
// File created from simpleScreenTemplate
|
||||
// $ createSimpleScreen.sh CallTransfer2 CallTransferMain
|
||||
/*
|
||||
Copyright 2020 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
|
||||
|
||||
@objc protocol CallTransferMainViewControllerDelegate: class {
|
||||
func callTransferMainViewControllerDidComplete(_ viewController: CallTransferMainViewController,
|
||||
consult: Bool,
|
||||
contact: MXKContact?,
|
||||
phoneNumber: String?)
|
||||
func callTransferMainViewControllerDidCancel(_ viewController: CallTransferMainViewController)
|
||||
}
|
||||
|
||||
@objcMembers
|
||||
final class CallTransferMainViewController: UIViewController {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Outlets
|
||||
|
||||
@IBOutlet private weak var segmentedControl: UISegmentedControl! {
|
||||
didSet {
|
||||
segmentedControl.setTitle(VectorL10n.callTransferUsers, forSegmentAt: 0)
|
||||
segmentedControl.setTitle(VectorL10n.callTransferDialpad, forSegmentAt: 1)
|
||||
}
|
||||
}
|
||||
@IBOutlet private weak var containerView: UIView!
|
||||
@IBOutlet private weak var bottomBgView: UIView!
|
||||
@IBOutlet private weak var consultButton: UIButton!
|
||||
@IBOutlet private weak var connectButton: RoundedButton! {
|
||||
didSet {
|
||||
connectButton.isEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var selectedContact: MXKContact? {
|
||||
didSet {
|
||||
updateConnectButton()
|
||||
}
|
||||
}
|
||||
private var phoneNumber: String? {
|
||||
didSet {
|
||||
updateConnectButton()
|
||||
}
|
||||
}
|
||||
private var session: MXSession!
|
||||
private var theme: Theme!
|
||||
|
||||
private lazy var contactsVC: CallTransferSelectContactViewController = {
|
||||
let controller = CallTransferSelectContactViewController.instantiate(withSession: session)
|
||||
controller.delegate = self
|
||||
return controller
|
||||
}()
|
||||
|
||||
private lazy var dialpadVC: DialpadViewController = {
|
||||
let configuration = DialpadConfiguration(showsTitle: false,
|
||||
showsCloseButton: false,
|
||||
showsCallButton: false)
|
||||
let controller = DialpadViewController.instantiate(withConfiguration: configuration)
|
||||
controller.delegate = self
|
||||
return controller
|
||||
}()
|
||||
|
||||
// MARK: Public
|
||||
|
||||
weak var delegate: CallTransferMainViewControllerDelegate?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
class func instantiate(withSession session: MXSession) -> CallTransferMainViewController {
|
||||
let viewController = StoryboardScene.CallTransferMainViewController.initialScene.instantiate()
|
||||
viewController.session = session
|
||||
viewController.theme = ThemeService.shared().theme
|
||||
return viewController
|
||||
}
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
|
||||
self.title = VectorL10n.callTransferTitle
|
||||
self.vc_removeBackTitle()
|
||||
|
||||
self.setupViews()
|
||||
self.registerThemeServiceDidChangeThemeNotification()
|
||||
self.update(theme: self.theme)
|
||||
}
|
||||
|
||||
override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||
return self.theme.statusBarStyle
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func updateConnectButton() {
|
||||
if selectedContact != nil {
|
||||
connectButton.isEnabled = true
|
||||
} else if let phoneNumber = phoneNumber, !phoneNumber.isEmpty {
|
||||
connectButton.isEnabled = true
|
||||
} else {
|
||||
connectButton.isEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
private func setupViews() {
|
||||
let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in
|
||||
self?.cancelButtonAction()
|
||||
}
|
||||
self.navigationItem.leftBarButtonItem = cancelBarButtonItem
|
||||
|
||||
addChild(contactsVC)
|
||||
addChild(dialpadVC)
|
||||
|
||||
if let view = contentView(at: segmentedControl.selectedSegmentIndex) {
|
||||
containerView.vc_addSubViewMatchingParent(view)
|
||||
}
|
||||
}
|
||||
|
||||
private func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
|
||||
self.view.backgroundColor = theme.headerBackgroundColor
|
||||
|
||||
if let navigationBar = self.navigationController?.navigationBar {
|
||||
theme.applyStyle(onNavigationBar: navigationBar)
|
||||
}
|
||||
|
||||
self.bottomBgView.backgroundColor = theme.headerBackgroundColor
|
||||
self.consultButton.tintColor = theme.tintColor
|
||||
self.consultButton.setTitleColor(theme.textPrimaryColor, for: .normal)
|
||||
self.connectButton.update(theme: theme)
|
||||
}
|
||||
|
||||
private func registerThemeServiceDidChangeThemeNotification() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil)
|
||||
}
|
||||
|
||||
private func contentView(at index: Int) -> UIView? {
|
||||
switch index {
|
||||
case 0:
|
||||
return contactsVC.view
|
||||
case 1:
|
||||
return dialpadVC.view
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@objc private func themeDidChange() {
|
||||
self.update(theme: ThemeService.shared().theme)
|
||||
}
|
||||
|
||||
@IBAction private func segmentedControlValueChanged(_ sender: UISegmentedControl) {
|
||||
containerView.vc_removeAllSubviews()
|
||||
if let view = contentView(at: sender.selectedSegmentIndex) {
|
||||
containerView.vc_addSubViewMatchingParent(view)
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction private func consultButtonAction(_ sender: UIButton) {
|
||||
sender.isSelected = !sender.isSelected
|
||||
}
|
||||
|
||||
@IBAction private func connectButtonAction(_ sender: UIButton) {
|
||||
delegate?.callTransferMainViewControllerDidComplete(self,
|
||||
consult: consultButton.isSelected,
|
||||
contact: selectedContact,
|
||||
phoneNumber: phoneNumber)
|
||||
}
|
||||
|
||||
private func cancelButtonAction() {
|
||||
self.delegate?.callTransferMainViewControllerDidCancel(self)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - CallTransferSelectContactViewControllerDelegate
|
||||
|
||||
extension CallTransferMainViewController: CallTransferSelectContactViewControllerDelegate {
|
||||
|
||||
func callTransferSelectContactViewControllerDidSelectContact(_ viewController: CallTransferSelectContactViewController, contact: MXKContact?) {
|
||||
selectedContact = contact
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - DialpadViewControllerDelegate
|
||||
|
||||
extension CallTransferMainViewController: DialpadViewControllerDelegate {
|
||||
|
||||
func dialpadViewControllerDidTapDigit(_ viewController: DialpadViewController, digit: String) {
|
||||
phoneNumber = viewController.rawPhoneNumber
|
||||
}
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="dBQ-CG-VDL">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17505"/>
|
||||
<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>
|
||||
<!--Call Transfer Select Contact View Controller-->
|
||||
<scene sceneID="EyC-m5-6uM">
|
||||
<objects>
|
||||
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="dBQ-CG-VDL" customClass="CallTransferSelectContactViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ht4-fu-3rS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="Vo0-Wd-yGk">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="dBQ-CG-VDL" id="TjA-dM-d9K"/>
|
||||
<outlet property="delegate" destination="dBQ-CG-VDL" id="wkl-rO-hoU"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="6ex-OQ-2sZ"/>
|
||||
<color key="backgroundColor" red="0.94509803921568625" green="0.96078431372549022" blue="0.97254901960784312" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Vo0-Wd-yGk" firstAttribute="leading" secondItem="Ht4-fu-3rS" secondAttribute="leading" id="Bat-7v-Ygf"/>
|
||||
<constraint firstItem="Vo0-Wd-yGk" firstAttribute="top" secondItem="6ex-OQ-2sZ" secondAttribute="top" id="FcW-wS-bew"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Vo0-Wd-yGk" secondAttribute="bottom" id="XfZ-kM-EaY"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Vo0-Wd-yGk" secondAttribute="trailing" id="fu0-p8-Dxy"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="mainTableView" destination="Vo0-Wd-yGk" id="P63-bd-0rh"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="bLY-II-iJ3" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-1703" y="255"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
+287
@@ -0,0 +1,287 @@
|
||||
// File created from simpleScreenTemplate
|
||||
// $ createSimpleScreen.sh CallTransfer CallTransferSelectContact
|
||||
/*
|
||||
Copyright 2020 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 CallTransferSelectContactViewControllerDelegate: class {
|
||||
func callTransferSelectContactViewControllerDidSelectContact(_ viewController: CallTransferSelectContactViewController,
|
||||
contact: MXKContact?)
|
||||
}
|
||||
|
||||
final class CallTransferSelectContactViewController: UIViewController {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Outlets
|
||||
|
||||
@IBOutlet private weak var mainTableView: UITableView!
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var session: MXSession!
|
||||
private var theme: Theme!
|
||||
private var contactsDataSource: ContactsDataSource! {
|
||||
didSet {
|
||||
contactsDataSource.delegate = self
|
||||
}
|
||||
}
|
||||
private var selectedIndexPath: IndexPath?
|
||||
|
||||
private lazy var mainSearchBar: UISearchBar = {
|
||||
let searchBar = UISearchBar(frame: CGRect(origin: .zero, size: CGSize(width: mainTableView.frame.width, height: 44)))
|
||||
searchBar.delegate = self
|
||||
searchBar.placeholder = VectorL10n.searchDefaultPlaceholder
|
||||
searchBar.returnKeyType = .done
|
||||
return searchBar
|
||||
}()
|
||||
|
||||
private struct Row {
|
||||
var contact: MXKContact
|
||||
var accessoryType: UITableViewCell.AccessoryType = .checkmark
|
||||
}
|
||||
|
||||
private struct Section {
|
||||
var header: String?
|
||||
var rows: [Row]
|
||||
}
|
||||
|
||||
private var sections: [Section] = [] {
|
||||
didSet {
|
||||
mainTableView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Public
|
||||
|
||||
weak var delegate: CallTransferSelectContactViewControllerDelegate?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
class func instantiate(withSession session: MXSession) -> CallTransferSelectContactViewController {
|
||||
let viewController = StoryboardScene.CallTransferSelectContactViewController.initialScene.instantiate()
|
||||
viewController.session = session
|
||||
viewController.theme = ThemeService.shared().theme
|
||||
viewController.contactsDataSource = ContactsDataSource(matrixSession: session)
|
||||
return viewController
|
||||
}
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
|
||||
self.vc_removeBackTitle()
|
||||
|
||||
self.setupViews()
|
||||
self.registerThemeServiceDidChangeThemeNotification()
|
||||
self.update(theme: self.theme)
|
||||
|
||||
updateSections()
|
||||
}
|
||||
|
||||
override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||
return self.theme.statusBarStyle
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func updateSections() {
|
||||
var tmpSections: [Section] = []
|
||||
|
||||
for section in 0..<contactsDataSource.numberOfSections(in: mainTableView) {
|
||||
var rows: [Row] = []
|
||||
for row in 0..<contactsDataSource.tableView(mainTableView, numberOfRowsInSection: section) {
|
||||
let indexPath = IndexPath(row: row, section: section)
|
||||
let accessoryType: UITableViewCell.AccessoryType = indexPath == selectedIndexPath ? .checkmark : .none
|
||||
if let contact = contactsDataSource.contact(at: indexPath) {
|
||||
rows.append(Row(contact: contact,
|
||||
accessoryType: accessoryType))
|
||||
}
|
||||
}
|
||||
if !rows.isEmpty {
|
||||
tmpSections.append(Section(header: VectorL10n.callTransferContactsAll, rows: rows))
|
||||
}
|
||||
}
|
||||
|
||||
let recentsSection = Section(header: VectorL10n.callTransferContactsRecent, rows: [])
|
||||
tmpSections.insert(recentsSection, at: 0)
|
||||
|
||||
sections = tmpSections
|
||||
}
|
||||
|
||||
private func setupViews() {
|
||||
mainTableView.tableHeaderView = mainSearchBar
|
||||
|
||||
mainTableView.register(cellType: ContactTableViewCell.self)
|
||||
}
|
||||
|
||||
private func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
|
||||
self.view.backgroundColor = theme.headerBackgroundColor
|
||||
self.mainTableView.backgroundColor = theme.headerBackgroundColor
|
||||
|
||||
if let navigationBar = self.navigationController?.navigationBar {
|
||||
theme.applyStyle(onNavigationBar: navigationBar)
|
||||
}
|
||||
|
||||
theme.applyStyle(onSearchBar: mainSearchBar)
|
||||
|
||||
mainTableView.reloadData()
|
||||
}
|
||||
|
||||
private func registerThemeServiceDidChangeThemeNotification() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil)
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@objc private func themeDidChange() {
|
||||
self.update(theme: ThemeService.shared().theme)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDataSource
|
||||
|
||||
extension CallTransferSelectContactViewController: UITableViewDataSource {
|
||||
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return sections.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return sections[section].rows.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let row = sections[indexPath.section].rows[indexPath.row]
|
||||
|
||||
let cell: ContactTableViewCell = tableView.dequeueReusableCell(for: indexPath)
|
||||
|
||||
cell.render(row.contact)
|
||||
// replace presence with user id
|
||||
cell.contactInformationLabel.text = row.contact.matrixIdentifiers.first as? String
|
||||
|
||||
if row.accessoryType == .checkmark {
|
||||
cell.accessoryView = UIImageView(image: Asset.Images.checkmark.image)
|
||||
} else {
|
||||
cell.accessoryView = nil
|
||||
cell.accessoryType = row.accessoryType
|
||||
}
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDelegate
|
||||
|
||||
extension CallTransferSelectContactViewController: UITableViewDelegate {
|
||||
|
||||
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
||||
cell.backgroundColor = theme.backgroundColor
|
||||
cell.selectedBackgroundView = UIView()
|
||||
cell.selectedBackgroundView?.backgroundColor = theme.selectedBackgroundColor
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
return sections[section].header
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
|
||||
if selectedIndexPath == indexPath {
|
||||
selectedIndexPath = nil
|
||||
delegate?.callTransferSelectContactViewControllerDidSelectContact(self, contact: nil)
|
||||
} else {
|
||||
selectedIndexPath = indexPath
|
||||
let contact = sections[indexPath.section].rows[indexPath.row].contact
|
||||
delegate?.callTransferSelectContactViewControllerDidSelectContact(self, contact: contact)
|
||||
}
|
||||
|
||||
updateSections()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - UISearchBarDelegate
|
||||
|
||||
extension CallTransferSelectContactViewController {
|
||||
|
||||
override func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
|
||||
contactsDataSource.search(withPattern: searchText, forceReset: false)
|
||||
}
|
||||
|
||||
override func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
|
||||
if let contact = contactsDataSource.searchInputContact {
|
||||
delegate?.callTransferSelectContactViewControllerDidSelectContact(self, contact: contact)
|
||||
}
|
||||
|
||||
searchBar.resignFirstResponder()
|
||||
}
|
||||
|
||||
override func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
|
||||
searchBar.text = nil
|
||||
|
||||
contactsDataSource.search(withPattern: nil, forceReset: false)
|
||||
|
||||
searchBar.resignFirstResponder()
|
||||
}
|
||||
|
||||
override func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
|
||||
DispatchQueue.main.async {
|
||||
searchBar.setShowsCancelButton(true, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
override func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
|
||||
DispatchQueue.main.async {
|
||||
searchBar.setShowsCancelButton(false, animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - MXKDataSourceDelegate
|
||||
|
||||
extension CallTransferSelectContactViewController: MXKDataSourceDelegate {
|
||||
|
||||
func cellViewClass(for cellData: MXKCellData!) -> MXKCellRendering.Type! {
|
||||
return nil
|
||||
}
|
||||
|
||||
func cellReuseIdentifier(for cellData: MXKCellData!) -> String! {
|
||||
return nil
|
||||
}
|
||||
|
||||
func dataSource(_ dataSource: MXKDataSource!, didCellChange changes: Any!) {
|
||||
updateSections()
|
||||
}
|
||||
|
||||
func dataSource(_ dataSource: MXKDataSource!, didStateChange state: MXKDataSourceState) {
|
||||
updateSections()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ContactTableViewCell: Reusable {}
|
||||
Reference in New Issue
Block a user