Implement dialpad view controller

This commit is contained in:
ismailgulek
2021-01-13 21:51:47 +03:00
parent 313ff48feb
commit aa6f3e8e60
7 changed files with 853 additions and 155 deletions
@@ -1,14 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="dBQ-CG-VDL">
<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="16087"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17505"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="Stack View standard spacing" 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>
<!--Simple Screen Template View Controller-->
<!--Dialpad View Controller-->
<scene sceneID="EyC-m5-6uM">
<objects>
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="dBQ-CG-VDL" customClass="DialpadViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
@@ -16,127 +18,280 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jOh-c7-uod">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="c4q-B8-hPy">
<rect key="frame" x="0.0" y="0.0" width="375" height="427.5"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fNE-v3-2lx">
<rect key="frame" x="0.0" y="0.0" width="375" height="427.5"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="launch_screen_logo" translatesAutoresizingMaskIntoConstraints="NO" id="G57-ET-hEP">
<rect key="frame" x="163.5" y="40" width="48" height="46"/>
<constraints>
<constraint firstAttribute="width" constant="48" id="2M1-Gt-gVT"/>
<constraint firstAttribute="height" constant="46" id="PQ6-qU-yxc"/>
</constraints>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="30" translatesAutoresizingMaskIntoConstraints="NO" id="12d-Dc-Rlv">
<rect key="frame" x="57.5" y="121" width="260" height="86.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Screen Title" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1Nw-CZ-lKr">
<rect key="frame" x="0.0" y="0.0" width="260" height="20.5"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Some description to explain what this screen does." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5dj-7z-eH5">
<rect key="frame" x="0.0" y="50.5" width="260" height="36"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="50" translatesAutoresizingMaskIntoConstraints="NO" id="4Ll-vk-JLe">
<rect key="frame" x="0.0" y="357.5" width="375" height="50"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Wbk-EX-kTs">
<rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kgv-EZ-dF9">
<rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="WcJ-IL-5KV"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
<state key="normal" title="OK">
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="1" colorSpace="calibratedRGB"/>
</state>
<state key="disabled">
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="0.5" colorSpace="calibratedRGB"/>
</state>
<connections>
<action selector="validateButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="kpR-g5-ogv"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="kgv-EZ-dF9" firstAttribute="top" secondItem="Wbk-EX-kTs" secondAttribute="top" id="1mu-8N-etF"/>
<constraint firstAttribute="bottom" secondItem="kgv-EZ-dF9" secondAttribute="bottom" id="2ce-b1-aV5"/>
<constraint firstAttribute="trailing" secondItem="kgv-EZ-dF9" secondAttribute="trailing" id="OHz-zo-Uvl"/>
<constraint firstAttribute="width" priority="750" constant="500" id="eud-Ba-XSx"/>
<constraint firstItem="kgv-EZ-dF9" firstAttribute="leading" secondItem="Wbk-EX-kTs" secondAttribute="leading" id="gPb-HX-NWn"/>
</constraints>
</view>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" priority="750" constant="500" id="9am-iX-rzi"/>
<constraint firstItem="G57-ET-hEP" firstAttribute="centerX" secondItem="fNE-v3-2lx" secondAttribute="centerX" id="9nR-qN-2Um"/>
<constraint firstAttribute="trailing" secondItem="4Ll-vk-JLe" secondAttribute="trailing" id="CU4-Sr-hLT"/>
<constraint firstItem="4Ll-vk-JLe" firstAttribute="leading" secondItem="fNE-v3-2lx" secondAttribute="leading" id="FGu-8C-v1U"/>
<constraint firstItem="4Ll-vk-JLe" firstAttribute="top" secondItem="12d-Dc-Rlv" secondAttribute="bottom" constant="150" id="Hue-GK-ORf"/>
<constraint firstAttribute="bottom" secondItem="4Ll-vk-JLe" secondAttribute="bottom" constant="20" id="Vn1-zQ-G8t"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="12d-Dc-Rlv" secondAttribute="trailing" constant="20" id="aIO-gg-9cw"/>
<constraint firstItem="12d-Dc-Rlv" firstAttribute="top" secondItem="G57-ET-hEP" secondAttribute="bottom" constant="35" id="edf-PJ-o5x"/>
<constraint firstItem="12d-Dc-Rlv" firstAttribute="centerX" secondItem="fNE-v3-2lx" secondAttribute="centerX" id="ksz-nC-DeX"/>
<constraint firstItem="G57-ET-hEP" firstAttribute="top" secondItem="fNE-v3-2lx" secondAttribute="top" constant="40" id="pk2-Kp-dhS"/>
<constraint firstItem="12d-Dc-Rlv" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="fNE-v3-2lx" secondAttribute="leading" constant="20" id="pzO-68-d2O"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="fNE-v3-2lx" firstAttribute="top" secondItem="c4q-B8-hPy" secondAttribute="top" id="bHO-0I-Jjh"/>
<constraint firstItem="fNE-v3-2lx" firstAttribute="centerX" secondItem="c4q-B8-hPy" secondAttribute="centerX" id="fGs-s5-GHA"/>
<constraint firstItem="fNE-v3-2lx" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="c4q-B8-hPy" secondAttribute="leading" id="jpJ-bp-Vmz"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="fNE-v3-2lx" secondAttribute="trailing" id="juO-Zk-MPs"/>
<constraint firstAttribute="bottom" secondItem="fNE-v3-2lx" secondAttribute="bottom" id="sZa-ea-aZQ"/>
</constraints>
</view>
</subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalCompressionResistancePriority="751" text="Dial pad" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ObS-Bw-Z12">
<rect key="frame" x="16" y="16" width="71.5" height="24"/>
<fontDescription key="fontDescription" type="system" pointSize="20"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" multipleTouchEnabled="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" adjustsFontForContentSizeCategory="YES" minimumFontSize="24" translatesAutoresizingMaskIntoConstraints="NO" id="iWR-Bv-qzs">
<rect key="frame" x="16" y="90" width="343" height="41"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="c4q-B8-hPy" secondAttribute="bottom" id="KlD-dP-EYo"/>
<constraint firstItem="c4q-B8-hPy" firstAttribute="width" secondItem="jOh-c7-uod" secondAttribute="width" id="Tly-og-biF"/>
<constraint firstAttribute="trailing" secondItem="c4q-B8-hPy" secondAttribute="trailing" id="fNe-8B-X6c"/>
<constraint firstItem="c4q-B8-hPy" firstAttribute="leading" secondItem="jOh-c7-uod" secondAttribute="leading" id="h5p-NS-unN"/>
<constraint firstItem="c4q-B8-hPy" firstAttribute="top" secondItem="jOh-c7-uod" secondAttribute="top" id="zPm-BG-Pm8"/>
<constraint firstAttribute="height" constant="41" id="8wN-Le-Iww"/>
</constraints>
</scrollView>
<fontDescription key="fontDescription" type="boldSystem" pointSize="34"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="numberPad" returnKeyType="done" smartDashesType="no" smartInsertDeleteType="no" smartQuotesType="no"/>
</textField>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="iak-30-PMd">
<rect key="frame" x="0.0" y="146" width="375" height="1"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="CHU-Ka-X4d"/>
</constraints>
</view>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="3Bl-zP-6pR">
<rect key="frame" x="0.0" y="155" width="375" height="492"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" alignment="center" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="fnQ-jm-HT2">
<rect key="frame" x="0.0" y="0.0" width="375" height="492"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" spacing="32" translatesAutoresizingMaskIntoConstraints="NO" id="ruO-8N-EAb">
<rect key="frame" x="53.5" y="0.0" width="268" height="93.5"/>
<subviews>
<button opaque="NO" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Dum-9Z-dKh" customClass="DialpadButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="13" width="68" height="68"/>
<constraints>
<constraint firstAttribute="width" constant="68" id="Z0y-aw-8sf"/>
<constraint firstAttribute="height" constant="68" id="q1C-9k-MLf"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="28"/>
<state key="normal" title="1"/>
<connections>
<action selector="digitButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="MOx-7L-sps"/>
</connections>
</button>
<button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="TIL-aL-5ij" customClass="DialpadButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="100" y="13" width="68" height="68"/>
<constraints>
<constraint firstAttribute="width" constant="68" id="GyZ-oW-RI3"/>
<constraint firstAttribute="height" constant="68" id="RQc-r6-iwY"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="28"/>
<state key="normal" title="2"/>
<connections>
<action selector="digitButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="aJe-6Q-hie"/>
</connections>
</button>
<button opaque="NO" tag="3" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Yrk-zC-XL5" customClass="DialpadButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="200" y="13" width="68" height="68"/>
<constraints>
<constraint firstAttribute="height" constant="68" id="4uz-EY-slt"/>
<constraint firstAttribute="width" constant="68" id="tcJ-0w-5pB"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="28"/>
<state key="normal" title="3"/>
<connections>
<action selector="digitButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="P8g-0L-BGY"/>
</connections>
</button>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" spacing="32" translatesAutoresizingMaskIntoConstraints="NO" id="J6F-Bl-DOp">
<rect key="frame" x="53.5" y="99.5" width="268" height="93.5"/>
<subviews>
<button opaque="NO" tag="4" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="JfX-9z-x4y" customClass="DialpadButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="13" width="68" height="68"/>
<constraints>
<constraint firstAttribute="width" constant="68" id="HuW-Ng-AXr"/>
<constraint firstAttribute="height" constant="68" id="Wma-1J-joN"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="28"/>
<state key="normal" title="4"/>
<connections>
<action selector="digitButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="BLa-fl-IIk"/>
</connections>
</button>
<button opaque="NO" tag="5" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hI1-sM-NT5" customClass="DialpadButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="100" y="13" width="68" height="68"/>
<constraints>
<constraint firstAttribute="height" constant="68" id="UYB-Sq-cbi"/>
<constraint firstAttribute="width" constant="68" id="kLi-YK-Jr2"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="28"/>
<state key="normal" title="5"/>
<connections>
<action selector="digitButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="9YX-l4-p9g"/>
</connections>
</button>
<button opaque="NO" tag="6" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cMg-az-Zgx" customClass="DialpadButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="200" y="13" width="68" height="68"/>
<constraints>
<constraint firstAttribute="height" constant="68" id="NKt-Kb-snG"/>
<constraint firstAttribute="width" constant="68" id="OIm-Gk-qZf"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="28"/>
<state key="normal" title="6"/>
<connections>
<action selector="digitButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="cfm-6z-c5p"/>
</connections>
</button>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" spacing="32" translatesAutoresizingMaskIntoConstraints="NO" id="ctg-KC-yPp">
<rect key="frame" x="53.5" y="199" width="268" height="94"/>
<subviews>
<button opaque="NO" tag="7" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="EF6-7Y-DhC" customClass="DialpadButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="13" width="68" height="68"/>
<constraints>
<constraint firstAttribute="width" constant="68" id="pkn-IF-lwD"/>
<constraint firstAttribute="height" constant="68" id="qgq-Fm-ONP"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="28"/>
<state key="normal" title="7"/>
<connections>
<action selector="digitButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="Rjb-WC-1k3"/>
</connections>
</button>
<button opaque="NO" tag="8" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4Od-gu-C4x" customClass="DialpadButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="100" y="13" width="68" height="68"/>
<constraints>
<constraint firstAttribute="width" constant="68" id="2Xe-eX-quA"/>
<constraint firstAttribute="height" constant="68" id="qoK-7c-T0g"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="28"/>
<state key="normal" title="8"/>
<connections>
<action selector="digitButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="Y0O-jU-b32"/>
</connections>
</button>
<button opaque="NO" tag="9" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Rgd-Tt-xlI" customClass="DialpadButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="200" y="13" width="68" height="68"/>
<constraints>
<constraint firstAttribute="width" constant="68" id="QoU-xy-26k"/>
<constraint firstAttribute="height" constant="68" id="g7r-y7-K9s"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="28"/>
<state key="normal" title="9"/>
<connections>
<action selector="digitButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="CVD-7O-WtY"/>
</connections>
</button>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" spacing="32" translatesAutoresizingMaskIntoConstraints="NO" id="dvZ-XT-zLP">
<rect key="frame" x="53.5" y="299" width="268" height="93.5"/>
<subviews>
<button opaque="NO" tag="-99" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hh8-U6-dJT" customClass="DialpadButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="12.5" width="68" height="68"/>
<constraints>
<constraint firstAttribute="height" constant="68" id="4mU-dy-vEa"/>
<constraint firstAttribute="width" constant="68" id="xRx-S5-ATL"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="28"/>
<inset key="titleEdgeInsets" minX="0.0" minY="8" maxX="0.0" maxY="0.0"/>
<state key="normal" title="*"/>
<connections>
<action selector="digitButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="V0v-hJ-Kgx"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4Rc-ls-1wr" customClass="DialpadButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="100" y="12.5" width="68" height="68"/>
<constraints>
<constraint firstAttribute="height" constant="68" id="0WC-Ri-gpT"/>
<constraint firstAttribute="width" constant="68" id="AU3-fm-wmC"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="28"/>
<state key="normal" title="0"/>
<connections>
<action selector="digitButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="Irt-qu-feP"/>
</connections>
</button>
<button opaque="NO" tag="-1" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Izh-vM-Fao" customClass="DialpadButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="200" y="12.5" width="68" height="68"/>
<constraints>
<constraint firstAttribute="width" constant="68" id="4J4-8u-YKL"/>
<constraint firstAttribute="height" constant="68" id="b4D-z5-eN2"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="28"/>
<state key="normal" title="#"/>
<connections>
<action selector="digitButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="9ML-V5-T0y"/>
</connections>
</button>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" spacing="32" translatesAutoresizingMaskIntoConstraints="NO" id="xzj-PF-Bxu">
<rect key="frame" x="53.5" y="398.5" width="268" height="93.5"/>
<subviews>
<button opaque="NO" tag="-99" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SVW-fH-Ey6" customClass="DialpadActionButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="12.5" width="68" height="68"/>
<constraints>
<constraint firstAttribute="height" constant="68" id="L2l-Qz-R8A"/>
<constraint firstAttribute="width" constant="68" id="nEw-2X-e3a"/>
</constraints>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<inset key="contentEdgeInsets" minX="0.0" minY="0.0" maxX="4" maxY="0.0"/>
<state key="normal" image="call_dialpad_backspace_icon"/>
<connections>
<action selector="backspaceButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="3MX-35-8Jg"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="B17-BJ-SiW" customClass="DialpadActionButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="100" y="12.5" width="68" height="68"/>
<constraints>
<constraint firstAttribute="height" constant="68" id="Gdz-8i-Fag"/>
<constraint firstAttribute="width" constant="68" id="lZO-dC-UHo"/>
</constraints>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" image="call_dialpad_call_icon"/>
<connections>
<action selector="callButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="TOV-1D-XQj"/>
</connections>
</button>
<button opaque="NO" userInteractionEnabled="NO" tag="-1" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Xig-ln-gBC">
<rect key="frame" x="200" y="12.5" width="68" height="68"/>
<constraints>
<constraint firstAttribute="height" constant="68" id="WLJ-xL-89j"/>
<constraint firstAttribute="width" constant="68" id="afw-C4-e8i"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="28"/>
</button>
</subviews>
</stackView>
</subviews>
</stackView>
</subviews>
</stackView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6Yp-ue-lX3">
<rect key="frame" x="337" y="14" width="24" height="24"/>
<constraints>
<constraint firstAttribute="width" constant="24" id="4zP-zo-5wL"/>
<constraint firstAttribute="height" constant="24" id="KQs-Fl-rbE"/>
</constraints>
<inset key="contentEdgeInsets" minX="8" minY="8" maxX="8" maxY="8"/>
<state key="normal" backgroundImage="close_button"/>
<connections>
<action selector="closeButtonAction:" destination="dBQ-CG-VDL" eventType="touchUpInside" id="fL7-rx-hal"/>
</connections>
</button>
</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 firstAttribute="trailing" secondItem="jOh-c7-uod" secondAttribute="trailing" id="7K8-MG-xLT"/>
<constraint firstItem="6ex-OQ-2sZ" firstAttribute="bottom" secondItem="jOh-c7-uod" secondAttribute="bottom" id="DGP-MJ-g6l"/>
<constraint firstItem="jOh-c7-uod" firstAttribute="leading" secondItem="Ht4-fu-3rS" secondAttribute="leading" id="TGc-b5-uMu"/>
<constraint firstItem="6ex-OQ-2sZ" firstAttribute="leading" secondItem="jOh-c7-uod" secondAttribute="leading" id="Z7r-yd-J4e"/>
<constraint firstItem="jOh-c7-uod" firstAttribute="trailing" secondItem="6ex-OQ-2sZ" secondAttribute="trailing" id="jVN-Fr-MKN"/>
<constraint firstItem="jOh-c7-uod" firstAttribute="top" secondItem="6ex-OQ-2sZ" secondAttribute="top" id="s7K-jf-P1z"/>
<constraint firstItem="3Bl-zP-6pR" firstAttribute="top" secondItem="iak-30-PMd" secondAttribute="bottom" constant="8" id="0tN-Pw-128"/>
<constraint firstItem="6ex-OQ-2sZ" firstAttribute="trailing" secondItem="6Yp-ue-lX3" secondAttribute="trailing" constant="14" id="2Z1-Dz-fFi"/>
<constraint firstItem="ObS-Bw-Z12" firstAttribute="top" secondItem="6ex-OQ-2sZ" secondAttribute="top" constant="16" id="71T-Cl-4XN"/>
<constraint firstAttribute="trailing" secondItem="3Bl-zP-6pR" secondAttribute="trailing" id="7rH-Qx-lcG"/>
<constraint firstItem="ObS-Bw-Z12" firstAttribute="leading" secondItem="6ex-OQ-2sZ" secondAttribute="leading" constant="16" id="8eQ-vO-QYP"/>
<constraint firstItem="iak-30-PMd" firstAttribute="leading" secondItem="Ht4-fu-3rS" secondAttribute="leading" id="9Xl-gS-JmB"/>
<constraint firstItem="6Yp-ue-lX3" firstAttribute="top" secondItem="6ex-OQ-2sZ" secondAttribute="top" constant="14" id="F2X-j6-dpR"/>
<constraint firstItem="iWR-Bv-qzs" firstAttribute="leading" secondItem="6ex-OQ-2sZ" secondAttribute="leading" constant="16" id="Kya-4X-MrH"/>
<constraint firstItem="iak-30-PMd" firstAttribute="top" secondItem="iWR-Bv-qzs" secondAttribute="bottom" constant="15" id="OUn-gV-R17"/>
<constraint firstItem="6ex-OQ-2sZ" firstAttribute="bottom" secondItem="3Bl-zP-6pR" secondAttribute="bottom" constant="20" id="auB-aa-QHx"/>
<constraint firstItem="3Bl-zP-6pR" firstAttribute="leading" secondItem="6ex-OQ-2sZ" secondAttribute="leading" id="duP-WQ-TVi"/>
<constraint firstItem="6ex-OQ-2sZ" firstAttribute="trailing" secondItem="iWR-Bv-qzs" secondAttribute="trailing" constant="16" id="fb4-zh-ZDR"/>
<constraint firstAttribute="trailing" secondItem="iak-30-PMd" secondAttribute="trailing" id="gS0-ga-OGR"/>
<constraint firstItem="iWR-Bv-qzs" firstAttribute="top" secondItem="ObS-Bw-Z12" secondAttribute="bottom" priority="750" constant="50" id="nkS-49-CiR"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6ex-OQ-2sZ"/>
</view>
<connections>
<outlet property="informationLabel" destination="5dj-7z-eH5" id="y4w-i9-5hB"/>
<outlet property="logoImageView" destination="G57-ET-hEP" id="d3W-8B-JwX"/>
<outlet property="okButton" destination="kgv-EZ-dF9" id="do0-Ot-OKn"/>
<outlet property="okButtonBackgroundView" destination="Wbk-EX-kTs" id="2gv-gg-ROL"/>
<outlet property="titleLabel" destination="1Nw-CZ-lKr" id="zXP-Xt-Zl9"/>
<outlet property="backspaceButton" destination="SVW-fH-Ey6" id="s2W-oS-a90"/>
<outlet property="callButton" destination="B17-BJ-SiW" id="rmo-gK-pkv"/>
<outlet property="closeButton" destination="6Yp-ue-lX3" id="xc1-ue-iUo"/>
<outlet property="digitsStackView" destination="fnQ-jm-HT2" id="ltK-Bg-hwY"/>
<outlet property="lineView" destination="iak-30-PMd" id="T6L-kl-Dsy"/>
<outlet property="phoneNumberTextField" destination="iWR-Bv-qzs" id="ezn-FP-ihl"/>
<outlet property="titleLabel" destination="ObS-Bw-Z12" id="0ZH-xI-zhw"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="bLY-II-iJ3" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -145,6 +300,11 @@
</scene>
</scenes>
<resources>
<image name="launch_screen_logo" width="240" height="240"/>
<image name="call_dialpad_backspace_icon" width="32" height="24.5"/>
<image name="call_dialpad_call_icon" width="27" height="27"/>
<image name="close_button" width="16" height="16"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
@@ -17,27 +17,64 @@
*/
import UIKit
import libPhoneNumber_iOS
protocol DialpadViewControllerDelegate: class {
func dialpadViewControllerDidTapSetupAction(_ viewController: DialpadViewController)
func dialpadViewControllerDidCancel(_ viewController: DialpadViewController)
@objc protocol DialpadViewControllerDelegate: class {
func dialpadViewControllerDidTapCall(_ viewController: DialpadViewController, withPhoneNumber phoneNumber: String)
func dialpadViewControllerDidTapClose(_ viewController: DialpadViewController)
}
final class DialpadViewController: UIViewController {
// MARK: - Properties
@objcMembers
class DialpadViewController: UIViewController {
// MARK: Outlets
@IBOutlet private weak var logoImageView: UIImageView!
@IBOutlet private weak var closeButton: UIButton!
@IBOutlet private weak var titleLabel: UILabel!
@IBOutlet private weak var informationLabel: UILabel!
@IBOutlet private weak var okButtonBackgroundView: UIView!
@IBOutlet private weak var okButton: UIButton!
@IBOutlet private weak var phoneNumberTextField: UITextField! {
didSet {
phoneNumberTextField.text = nil
// avoid showing keyboard on text field
phoneNumberTextField.inputView = UIView()
phoneNumberTextField.inputAccessoryView = UIView()
}
}
@IBOutlet private weak var lineView: UIView!
@IBOutlet private weak var digitsStackView: UIStackView!
@IBOutlet private weak var backspaceButton: DialpadActionButton! {
didSet {
backspaceButton.type = .backspace
}
}
@IBOutlet private weak var callButton: DialpadActionButton! {
didSet {
callButton.type = .call
}
}
// MARK: Private
private enum Constants {
static let sizeOniPad: CGSize = CGSize(width: 375, height: 667)
}
private var wasCursorAtTheEnd: Bool = true
/// Phone number as formatted
private var phoneNumber: String = "" {
willSet {
wasCursorAtTheEnd = isCursorAtTheEnd()
} didSet {
phoneNumberTextField.text = phoneNumber
if wasCursorAtTheEnd {
moveCursorToTheEnd()
}
}
}
/// Phone number as non-formatted
private var rawPhoneNumber: String {
return phoneNumber.vc_removingAllWhitespaces()
}
private var theme: Theme!
// MARK: Public
@@ -59,10 +96,7 @@ final class DialpadViewController: UIViewController {
// Do any additional setup after loading the view.
self.title = "Template"
self.vc_removeBackTitle()
self.setupViews()
titleLabel.text = VectorL10n.dialpadTitle
self.registerThemeServiceDidChangeThemeNotification()
self.update(theme: self.theme)
}
@@ -73,38 +107,73 @@ final class DialpadViewController: UIViewController {
// MARK: - Private
private func setupViews() {
let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in
self?.cancelButtonAction()
private func isCursorAtTheEnd() -> Bool {
guard let selectedRange = phoneNumberTextField.selectedTextRange else {
return true
}
self.navigationItem.rightBarButtonItem = cancelBarButtonItem
// let logoImage = Asset.Images.*
// self.logoImageView.image = keybackupLogoImage
// self.titleLabel.text = VectorL10n.xxxxTitle
// self.informationLabel.text = VectorL10n.xxxxDescription
//
// self.okButton.setTitle(VectorL10n.xxxxAction, for: .normal)
if !selectedRange.isEmpty {
return false
}
let cursorEndPos = phoneNumberTextField.offset(from: phoneNumberTextField.beginningOfDocument, to: selectedRange.end)
return cursorEndPos == phoneNumber.count
}
private func moveCursorToTheEnd() {
guard let cursorPos = phoneNumberTextField.position(from: phoneNumberTextField.beginningOfDocument,
offset: phoneNumber.count) else { return }
phoneNumberTextField.selectedTextRange = phoneNumberTextField.textRange(from: cursorPos,
to: cursorPos)
}
private func reformatPhoneNumber() {
guard let phoneNumberUtil = NBPhoneNumberUtil.sharedInstance() else {
// no formatter
return
}
do {
// try formatting the number
if phoneNumber.hasPrefix("00") {
let range = phoneNumber.startIndex..<phoneNumber.index(phoneNumber.startIndex, offsetBy: 2)
phoneNumber.replaceSubrange(range, with: "+")
}
let nbPhoneNumber = try phoneNumberUtil.parse(rawPhoneNumber, defaultRegion: nil)
phoneNumber = try phoneNumberUtil.format(nbPhoneNumber, numberFormat: .INTERNATIONAL)
} catch {
// continue without formatting
}
}
private func update(theme: Theme) {
self.theme = theme
self.view.backgroundColor = theme.headerBackgroundColor
self.view.backgroundColor = theme.backgroundColor
if let navigationBar = self.navigationController?.navigationBar {
theme.applyStyle(onNavigationBar: navigationBar)
}
self.logoImageView.tintColor = theme.textPrimaryColor
titleLabel.textColor = theme.noticeSecondaryColor
phoneNumberTextField.textColor = theme.textPrimaryColor
lineView.backgroundColor = theme.lineBreakColor
closeButton.setBackgroundImage(Asset.Images.closeButton.image.vc_tintedImage(usingColor: theme.tabBarUnselectedItemTintColor), for: .normal)
self.titleLabel.textColor = theme.textPrimaryColor
self.informationLabel.textColor = theme.textPrimaryColor
self.okButtonBackgroundView.backgroundColor = theme.backgroundColor
theme.applyStyle(onButton: self.okButton)
updateThemesOfAllButtons(in: digitsStackView, with: theme)
}
private func updateThemesOfAllButtons(in view: UIView, with theme: Theme) {
if let button = view as? DialpadButton {
button.update(theme: theme)
} else {
for subview in view.subviews {
updateThemesOfAllButtons(in: subview, with: theme)
}
}
}
private func registerThemeServiceDidChangeThemeNotification() {
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil)
@@ -116,11 +185,90 @@ final class DialpadViewController: UIViewController {
self.update(theme: ThemeService.shared().theme)
}
@IBAction private func validateButtonAction(_ sender: Any) {
self.delegate?.dialpadViewControllerDidTapSetupAction(self)
@IBAction private func closeButtonAction(_ sender: UIButton) {
delegate?.dialpadViewControllerDidTapClose(self)
}
private func cancelButtonAction() {
self.delegate?.dialpadViewControllerDidCancel(self)
@IBAction private func digitButtonAction(_ sender: DialpadButton) {
let digit = sender.title(for: .normal) ?? ""
if let selectedRange = phoneNumberTextField.selectedTextRange {
if isCursorAtTheEnd() {
phoneNumber += digit
reformatPhoneNumber()
return
}
let cursorStartPos = phoneNumberTextField.offset(from: phoneNumberTextField.beginningOfDocument, to: selectedRange.start)
let cursorEndPos = phoneNumberTextField.offset(from: phoneNumberTextField.beginningOfDocument, to: selectedRange.end)
phoneNumber.replaceSubrange((phoneNumber.index(phoneNumber.startIndex, offsetBy: cursorStartPos))..<(phoneNumber.index(phoneNumber.startIndex, offsetBy: cursorEndPos)), with: digit)
guard let cursorPos = phoneNumberTextField.position(from: phoneNumberTextField.beginningOfDocument,
offset: cursorEndPos + digit.count) else { return }
reformatPhoneNumber()
phoneNumberTextField.selectedTextRange = phoneNumberTextField.textRange(from: cursorPos,
to: cursorPos)
} else {
phoneNumber += digit
reformatPhoneNumber()
}
}
@IBAction private func backspaceButtonAction(_ sender: DialpadActionButton) {
if phoneNumber.isEmpty {
return
}
if let selectedRange = phoneNumberTextField.selectedTextRange {
let cursorStartPos = phoneNumberTextField.offset(from: phoneNumberTextField.beginningOfDocument, to: selectedRange.start)
let cursorEndPos = phoneNumberTextField.offset(from: phoneNumberTextField.beginningOfDocument, to: selectedRange.end)
let rangePos: UITextPosition!
if selectedRange.isEmpty {
// just caret, remove one char from the cursor position
if cursorStartPos == 0 {
// already at the beginning of the text, no more text to remove here
return
}
phoneNumber.replaceSubrange((phoneNumber.index(phoneNumber.startIndex, offsetBy: cursorStartPos-1))..<(phoneNumber.index(phoneNumber.startIndex, offsetBy: cursorEndPos)), with: "")
rangePos = phoneNumberTextField.position(from: phoneNumberTextField.beginningOfDocument,
offset: cursorStartPos-1)
} else {
// really some text selected, remove selected range of text
phoneNumber.replaceSubrange((phoneNumber.index(phoneNumber.startIndex, offsetBy: cursorStartPos))..<(phoneNumber.index(phoneNumber.startIndex, offsetBy: cursorEndPos)), with: "")
rangePos = phoneNumberTextField.position(from: phoneNumberTextField.beginningOfDocument,
offset: cursorStartPos)
}
reformatPhoneNumber()
guard let cursorPos = rangePos else { return }
phoneNumberTextField.selectedTextRange = phoneNumberTextField.textRange(from: cursorPos,
to: cursorPos)
} else {
phoneNumber.removeLast()
reformatPhoneNumber()
}
}
@IBAction private func callButtonAction(_ sender: DialpadActionButton) {
delegate?.dialpadViewControllerDidTapCall(self, withPhoneNumber: rawPhoneNumber)
}
}
// MARK: - CustomSizedPresentable
extension DialpadViewController: CustomSizedPresentable {
func customSize(withParentContainerSize containerSize: CGSize) -> CGSize {
return Constants.sizeOniPad
}
}
@@ -0,0 +1,39 @@
//
// 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
/// Dialpad action button type
@objc enum DialpadActionButtonType: Int {
case backspace
case call
}
/// Action button class for Dialpad screen
class DialpadActionButton: DialpadButton {
var type: DialpadActionButtonType = .backspace
override func update(theme: Theme) {
switch type {
case .backspace:
backgroundColor = theme.warningColor
case .call:
backgroundColor = theme.tintColor
}
}
}
@@ -0,0 +1,56 @@
//
// 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
/// Digit button class for Dialpad screen
class DialpadButton: UIButton {
private enum Constants {
static let size: CGSize = CGSize(width: 68, height: 68)
}
init() {
super.init(frame: CGRect(origin: .zero, size: Constants.size))
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setup()
}
private func setup() {
clipsToBounds = true
layer.cornerRadius = Constants.size.width/2
}
}
// MARK: - Themable
extension DialpadButton: Themable {
func update(theme: Theme) {
setTitleColor(theme.textPrimaryColor, for: .normal)
backgroundColor = theme.headerBackgroundColor
}
}