implement CallUITests classes (TestCases, TestPlans, Methods, Accessibility Identifiers)
|
|
@ -1,26 +1,55 @@
|
||||||
variables:
|
variables:
|
||||||
archive_scheme: linphone
|
workspace: linphone.xcworkspace
|
||||||
archive_path: linphone.xcarchive
|
scheme: linphone
|
||||||
export_path: linphone-adhoc-ipa
|
destination: name=iPhone 13 Pro
|
||||||
export_options_plist: linphone-adhoc.plist
|
testResult_path: derivedData/Logs/Test
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- Build
|
||||||
|
- UITests
|
||||||
|
|
||||||
job-ios:
|
before_script:
|
||||||
|
- pod install
|
||||||
|
- pwd
|
||||||
|
- sed 's/fileprivate let tableView =/public let tableView =/g' ./Pods/DropDown/DropDown/src/DropDown.swift > tmp.swift && mv -f tmp.swift ./Pods/DropDown/DropDown/src/DropDown.swift
|
||||||
|
|
||||||
stage: build
|
Compile & Build:
|
||||||
tags: [ "macmini-m1-xcode13" ]
|
stage: Build
|
||||||
|
tags: ["macmini-m1-xcode13"]
|
||||||
script:
|
before_script:
|
||||||
- pod install --repo-update
|
- pod install --repo-update
|
||||||
- pwd
|
- pwd
|
||||||
- sed 's/fileprivate let tableView =/public let tableView =/g' ./Pods/DropDown/DropDown/src/DropDown.swift > tmp.swift && mv -f tmp.swift ./Pods/DropDown/DropDown/src/DropDown.swift
|
- sed 's/fileprivate let tableView =/public let tableView =/g' ./Pods/DropDown/DropDown/src/DropDown.swift > tmp.swift && mv -f tmp.swift ./Pods/DropDown/DropDown/src/DropDown.swift
|
||||||
- xcodebuild archive -scheme $archive_scheme -archivePath ./$archive_path -configuration Release -workspace ./linphone.xcworkspace -UseModernBuildSystem=YES -destination 'generic/platform=iOS'
|
- xcrun simctl shutdown "$destination" && xcrun simctl erase "$destination"
|
||||||
- xcodebuild -exportArchive -archivePath ./$archive_path -exportPath ./$export_path -exportOptionsPlist ./$export_options_plist -allowProvisioningUpdates -UseModernBuildSystem=YES -destination 'generic/platform=iOS'
|
script:
|
||||||
|
- xcodebuild -workspace $workspace -scheme $scheme -UseModernBuildSystem=YES -destination "$destination" -derivedDataPath derivedData
|
||||||
|
after_script: []
|
||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- $archive_path
|
- derivedData/Build
|
||||||
- $export_path
|
|
||||||
when: always
|
when: always
|
||||||
expire_in: 1 week
|
expire_in: 2 hour
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
after_script:
|
||||||
|
- ${TRAINER_EXE} -p $testResult_path/*.xcresult -o $testResult_path/
|
||||||
|
- ${XCPARSE_EXE} attachments $testResult_path/*.xcresult results --uti public.image
|
||||||
|
- mv $testResult_path/*.xcresult results && mv derivedData/logs.txt results
|
||||||
|
|
||||||
|
Call Views:
|
||||||
|
stage: UITests
|
||||||
|
tags: ["macmini-m1-xcode13"]
|
||||||
|
dependencies: ["Compile & Build"]
|
||||||
|
script:
|
||||||
|
- xcodebuild test -workspace $workspace -scheme $scheme -sdk iphonesimulator -destination "$destination" -UseModernBuildSystem=YES -testPlan Default -derivedDataPath derivedData | tee derivedData/logs.txt
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- results/*
|
||||||
|
when: always
|
||||||
|
reports:
|
||||||
|
junit:
|
||||||
|
- $testResult_path/*.xml
|
||||||
|
expire_in: 4 week
|
||||||
|
|
|
||||||
5
CallUITests-Info.plist
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict/>
|
||||||
|
</plist>
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@
|
||||||
<button opaque="NO" tag="130" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bes-x4-C4l" userLabel="maybeLaterButton" customClass="UIRoundBorderedButton">
|
<button opaque="NO" tag="130" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bes-x4-C4l" userLabel="maybeLaterButton" customClass="UIRoundBorderedButton">
|
||||||
<rect key="frame" x="38" y="312" width="299" height="40"/>
|
<rect key="frame" x="38" y="312" width="299" height="40"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Finish configuration">
|
<accessibility key="accessibilityConfiguration" identifier="assistant_link_view_later" label="Finish configuration">
|
||||||
<bool key="isElement" value="YES"/>
|
<bool key="isElement" value="YES"/>
|
||||||
</accessibility>
|
</accessibility>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||||
|
|
@ -171,6 +171,7 @@
|
||||||
</button>
|
</button>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="assistant_link_view"/>
|
||||||
</view>
|
</view>
|
||||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2Nl-QG-fTA" userLabel="activateSMSView">
|
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2Nl-QG-fTA" userLabel="activateSMSView">
|
||||||
<rect key="frame" x="0.0" y="66" width="375" height="535"/>
|
<rect key="frame" x="0.0" y="66" width="375" height="535"/>
|
||||||
|
|
@ -244,7 +245,8 @@
|
||||||
<gestureRecognizers/>
|
<gestureRecognizers/>
|
||||||
</view>
|
</view>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="assistant_link_view"/>
|
||||||
</view>
|
</view>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="1" green="1" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="1" green="1" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@
|
||||||
<subviews>
|
<subviews>
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="tZu-nz-jXM" userLabel="acceptButton">
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="tZu-nz-jXM" userLabel="acceptButton">
|
||||||
<rect key="frame" x="20" y="2" width="54" height="54"/>
|
<rect key="frame" x="20" y="2" width="54" height="54"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="assistant_view_accept"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="54" id="4WQ-mk-JlN"/>
|
<constraint firstAttribute="width" constant="54" id="4WQ-mk-JlN"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
|
@ -121,7 +122,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="wordWrap" translatesAutoresizingMaskIntoConstraints="NO" id="38" userLabel="linphoneLoginButton" customClass="UIRoundBorderedButton">
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="wordWrap" translatesAutoresizingMaskIntoConstraints="NO" id="38" userLabel="linphoneLoginButton" customClass="UIRoundBorderedButton">
|
||||||
<rect key="frame" x="40" y="227" width="299" height="40"/>
|
<rect key="frame" x="40" y="227" width="299" height="40"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Use Linphone account">
|
<accessibility key="accessibilityConfiguration" identifier="assistant_view_linphone_login" label="Use Linphone account">
|
||||||
<bool key="isElement" value="NO"/>
|
<bool key="isElement" value="NO"/>
|
||||||
</accessibility>
|
</accessibility>
|
||||||
<constraints>
|
<constraints>
|
||||||
|
|
@ -143,7 +144,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="wordWrap" translatesAutoresizingMaskIntoConstraints="NO" id="39" userLabel="loginButton" customClass="UIRoundBorderedButton">
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="wordWrap" translatesAutoresizingMaskIntoConstraints="NO" id="39" userLabel="loginButton" customClass="UIRoundBorderedButton">
|
||||||
<rect key="frame" x="40" y="301" width="299" height="40"/>
|
<rect key="frame" x="40" y="301" width="299" height="40"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Use SIP account">
|
<accessibility key="accessibilityConfiguration" identifier="assistant_view_sip_login" label="Use SIP account">
|
||||||
<bool key="isElement" value="YES"/>
|
<bool key="isElement" value="YES"/>
|
||||||
</accessibility>
|
</accessibility>
|
||||||
<constraints>
|
<constraints>
|
||||||
|
|
@ -187,6 +188,7 @@
|
||||||
</button>
|
</button>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="assistant_view"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="38" firstAttribute="leading" secondItem="39" secondAttribute="leading" id="23x-IR-Mtg"/>
|
<constraint firstItem="38" firstAttribute="leading" secondItem="39" secondAttribute="leading" id="23x-IR-Mtg"/>
|
||||||
<constraint firstItem="plw-Mp-teD" firstAttribute="top" secondItem="Yci-5h-O4o" secondAttribute="bottom" id="94M-05-soq"/>
|
<constraint firstItem="plw-Mp-teD" firstAttribute="top" secondItem="Yci-5h-O4o" secondAttribute="bottom" id="94M-05-soq"/>
|
||||||
|
|
@ -880,7 +882,7 @@ Once it is done, come back here and click on the button.</string>
|
||||||
<textField opaque="NO" clipsSubviews="YES" tag="100" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" adjustsFontSizeToFit="NO" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="YRW-ex-VZy" userLabel="usernameField" customClass="UIAssistantTextField">
|
<textField opaque="NO" clipsSubviews="YES" tag="100" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" adjustsFontSizeToFit="NO" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="YRW-ex-VZy" userLabel="usernameField" customClass="UIAssistantTextField">
|
||||||
<rect key="frame" x="38" y="20" width="299" height="30"/>
|
<rect key="frame" x="38" y="20" width="299" height="30"/>
|
||||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Username"/>
|
<accessibility key="accessibilityConfiguration" identifier="assistant_linphone_login_view_username_field" label="Username"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="30" id="QcL-i5-g1D"/>
|
<constraint firstAttribute="height" constant="30" id="QcL-i5-g1D"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
|
@ -913,7 +915,7 @@ Once it is done, come back here and click on the button.</string>
|
||||||
<textField opaque="NO" clipsSubviews="YES" tag="101" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" adjustsFontSizeToFit="NO" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="ap4-xh-CVK" userLabel="passwordField" customClass="UIAssistantTextField">
|
<textField opaque="NO" clipsSubviews="YES" tag="101" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" adjustsFontSizeToFit="NO" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="ap4-xh-CVK" userLabel="passwordField" customClass="UIAssistantTextField">
|
||||||
<rect key="frame" x="38" y="93" width="299" height="30"/>
|
<rect key="frame" x="38" y="93" width="299" height="30"/>
|
||||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Password"/>
|
<accessibility key="accessibilityConfiguration" identifier="assistant_linphone_login_view_password_field" label="Password"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="30" id="BWP-n1-3OS"/>
|
<constraint firstAttribute="height" constant="30" id="BWP-n1-3OS"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
|
@ -966,6 +968,7 @@ Once it is done, come back here and click on the button.</string>
|
||||||
</view>
|
</view>
|
||||||
<switch opaque="NO" tag="181" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="TXA-w5-uUE" userLabel="useUsernameSwitch">
|
<switch opaque="NO" tag="181" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="TXA-w5-uUE" userLabel="useUsernameSwitch">
|
||||||
<rect key="frame" x="43" y="272" width="51" height="31"/>
|
<rect key="frame" x="43" y="272" width="51" height="31"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="assistant_linphone_login_view_username_switch"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="31" id="koR-bG-wd3"/>
|
<constraint firstAttribute="height" constant="31" id="koR-bG-wd3"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
|
@ -975,7 +978,7 @@ Once it is done, come back here and click on the button.</string>
|
||||||
</switch>
|
</switch>
|
||||||
<button opaque="NO" tag="130" contentMode="scaleToFill" misplaced="YES" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eIr-bh-JLB" userLabel="linphoneLoginButton" customClass="UIRoundBorderedButton">
|
<button opaque="NO" tag="130" contentMode="scaleToFill" misplaced="YES" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eIr-bh-JLB" userLabel="linphoneLoginButton" customClass="UIRoundBorderedButton">
|
||||||
<rect key="frame" x="31" y="345" width="299" height="40"/>
|
<rect key="frame" x="31" y="345" width="299" height="40"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Login">
|
<accessibility key="accessibilityConfiguration" identifier="assistant_linphone_login_view_login" label="Login">
|
||||||
<bool key="isElement" value="YES"/>
|
<bool key="isElement" value="YES"/>
|
||||||
</accessibility>
|
</accessibility>
|
||||||
<constraints>
|
<constraints>
|
||||||
|
|
@ -1009,6 +1012,7 @@ Once it is done, come back here and click on the button.</string>
|
||||||
</label>
|
</label>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="assistant_linphone_login_view"/>
|
||||||
<gestureRecognizers/>
|
<gestureRecognizers/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="ZDs-1W-ZXo" firstAttribute="leading" secondItem="ZFh-2U-bBK" secondAttribute="trailing" constant="-7" id="0fB-qP-gK5"/>
|
<constraint firstItem="ZDs-1W-ZXo" firstAttribute="leading" secondItem="ZFh-2U-bBK" secondAttribute="trailing" constant="-7" id="0fB-qP-gK5"/>
|
||||||
|
|
@ -1089,7 +1093,7 @@ Once it is done, come back here and click on the button.</string>
|
||||||
<textField opaque="NO" clipsSubviews="YES" tag="100" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" adjustsFontSizeToFit="NO" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="FJ1-Xt-g7g" userLabel="usernameField" customClass="UIAssistantTextField">
|
<textField opaque="NO" clipsSubviews="YES" tag="100" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" adjustsFontSizeToFit="NO" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="FJ1-Xt-g7g" userLabel="usernameField" customClass="UIAssistantTextField">
|
||||||
<rect key="frame" x="38" y="153" width="298" height="30"/>
|
<rect key="frame" x="38" y="153" width="298" height="30"/>
|
||||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Username"/>
|
<accessibility key="accessibilityConfiguration" identifier="assistant_login_view_username_field" label="Username"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="30" id="Xxt-U5-krh"/>
|
<constraint firstAttribute="height" constant="30" id="Xxt-U5-krh"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
|
@ -1122,7 +1126,7 @@ Once it is done, come back here and click on the button.</string>
|
||||||
<textField opaque="NO" clipsSubviews="YES" tag="101" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" adjustsFontSizeToFit="NO" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="zEa-Dj-QiH" userLabel="passwordField" customClass="UIAssistantTextField">
|
<textField opaque="NO" clipsSubviews="YES" tag="101" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" adjustsFontSizeToFit="NO" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="zEa-Dj-QiH" userLabel="passwordField" customClass="UIAssistantTextField">
|
||||||
<rect key="frame" x="38" y="227" width="298" height="30"/>
|
<rect key="frame" x="38" y="227" width="298" height="30"/>
|
||||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Password"/>
|
<accessibility key="accessibilityConfiguration" identifier="assistant_login_view_password_field" label="Password"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="30" id="ywR-ZJ-1YN"/>
|
<constraint firstAttribute="height" constant="30" id="ywR-ZJ-1YN"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
|
@ -1155,7 +1159,7 @@ Once it is done, come back here and click on the button.</string>
|
||||||
<textField opaque="NO" clipsSubviews="YES" tag="104" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" adjustsFontSizeToFit="NO" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="5kh-Wo-SMY" userLabel="domainField" customClass="UIAssistantTextField">
|
<textField opaque="NO" clipsSubviews="YES" tag="104" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" adjustsFontSizeToFit="NO" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="5kh-Wo-SMY" userLabel="domainField" customClass="UIAssistantTextField">
|
||||||
<rect key="frame" x="38" y="301" width="298" height="30"/>
|
<rect key="frame" x="38" y="301" width="298" height="30"/>
|
||||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Domain"/>
|
<accessibility key="accessibilityConfiguration" identifier="assistant_login_view_domain_field" label="Domain"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="30" id="Evx-tD-kkq"/>
|
<constraint firstAttribute="height" constant="30" id="Evx-tD-kkq"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
|
@ -1231,7 +1235,7 @@ Once it is done, come back here and click on the button.</string>
|
||||||
</label>
|
</label>
|
||||||
<button opaque="NO" tag="130" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2Ch-Ji-vjA" userLabel="loginButton" customClass="UIRoundBorderedButton">
|
<button opaque="NO" tag="130" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2Ch-Ji-vjA" userLabel="loginButton" customClass="UIRoundBorderedButton">
|
||||||
<rect key="frame" x="38" y="516" width="298" height="40"/>
|
<rect key="frame" x="38" y="516" width="298" height="40"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Login">
|
<accessibility key="accessibilityConfiguration" identifier="assistant_login_view_login" label="Login">
|
||||||
<bool key="isElement" value="YES"/>
|
<bool key="isElement" value="YES"/>
|
||||||
</accessibility>
|
</accessibility>
|
||||||
<constraints>
|
<constraints>
|
||||||
|
|
@ -1251,6 +1255,7 @@ Once it is done, come back here and click on the button.</string>
|
||||||
</button>
|
</button>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="assistant_login_view"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="tAv-f7-kDI" firstAttribute="leading" secondItem="56" secondAttribute="leading" constant="38" id="1fc-cF-x8o"/>
|
<constraint firstItem="tAv-f7-kDI" firstAttribute="leading" secondItem="56" secondAttribute="leading" constant="38" id="1fc-cF-x8o"/>
|
||||||
<constraint firstItem="UJ1-kb-e8g" firstAttribute="leading" secondItem="XPq-fy-KZS" secondAttribute="leading" id="2Qq-A9-qTY"/>
|
<constraint firstItem="UJ1-kb-e8g" firstAttribute="leading" secondItem="XPq-fy-KZS" secondAttribute="leading" id="2Qq-A9-qTY"/>
|
||||||
|
|
@ -1614,6 +1619,7 @@ To enable it in a commercial project, please contact us.</string>
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8Uk-jk-U5R">
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8Uk-jk-U5R">
|
||||||
<rect key="frame" x="110" y="259" width="155" height="31"/>
|
<rect key="frame" x="110" y="259" width="155" height="31"/>
|
||||||
<color key="backgroundColor" red="0.9497097135" green="0.27055108550000001" blue="0.030769694600000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.9497097135" green="0.27055108550000001" blue="0.030769694600000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="assistant_login_warning_view_skip"/>
|
||||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
<state key="normal" title="Button"/>
|
<state key="normal" title="Button"/>
|
||||||
<buttonConfiguration key="configuration" style="plain" title="I understand"/>
|
<buttonConfiguration key="configuration" style="plain" title="I understand"/>
|
||||||
|
|
@ -1623,6 +1629,7 @@ To enable it in a commercial project, please contact us.</string>
|
||||||
</button>
|
</button>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="assistant_login_warning_view"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="gol-XQ-ghT" firstAttribute="top" secondItem="gPg-U6-Op5" secondAttribute="bottom" constant="20" id="BHO-FK-4Y0"/>
|
<constraint firstItem="gol-XQ-ghT" firstAttribute="top" secondItem="gPg-U6-Op5" secondAttribute="bottom" constant="20" id="BHO-FK-4Y0"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="gol-XQ-ghT" secondAttribute="trailing" constant="50" id="Cfx-sn-2oz"/>
|
<constraint firstAttribute="trailing" secondItem="gol-XQ-ghT" secondAttribute="trailing" constant="50" id="Cfx-sn-2oz"/>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
@ -96,6 +96,7 @@
|
||||||
<button hidden="YES" opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Fac-hy-za4" userLabel="backToCallButton" customClass="UIBackToCallButton">
|
<button hidden="YES" opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Fac-hy-za4" userLabel="backToCallButton" customClass="UIBackToCallButton">
|
||||||
<rect key="frame" x="165" y="0.0" width="83" height="66"/>
|
<rect key="frame" x="165" y="0.0" width="83" height="66"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="back_to_call"/>
|
||||||
<state key="normal" image="call_back_default.png">
|
<state key="normal" image="call_back_default.png">
|
||||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</state>
|
</state>
|
||||||
|
|
@ -194,6 +195,7 @@
|
||||||
<gestureRecognizers/>
|
<gestureRecognizers/>
|
||||||
</view>
|
</view>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="chats_list_view"/>
|
||||||
</view>
|
</view>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="1" green="1" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="1" green="1" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
|
@ -217,7 +219,7 @@
|
||||||
<image name="call_back_disabled.png" width="61.599998474121094" height="44"/>
|
<image name="call_back_disabled.png" width="61.599998474121094" height="44"/>
|
||||||
<image name="cancel_edit_default.png" width="47.200000762939453" height="47.200000762939453"/>
|
<image name="cancel_edit_default.png" width="47.200000762939453" height="47.200000762939453"/>
|
||||||
<image name="cancel_edit_disabled.png" width="47.200000762939453" height="47.200000762939453"/>
|
<image name="cancel_edit_disabled.png" width="47.200000762939453" height="47.200000762939453"/>
|
||||||
<image name="cancel_forward.png" width="80" height="80"/>
|
<image name="cancel_forward.png" width="29" height="29"/>
|
||||||
<image name="chat_add_default.png" width="50.400001525878906" height="44.799999237060547"/>
|
<image name="chat_add_default.png" width="50.400001525878906" height="44.799999237060547"/>
|
||||||
<image name="chat_add_group.png" width="64" height="42.400001525878906"/>
|
<image name="chat_add_group.png" width="64" height="42.400001525878906"/>
|
||||||
<image name="color_E.png" width="2" height="2"/>
|
<image name="color_E.png" width="2" height="2"/>
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@
|
||||||
<rect key="frame" x="31" y="0.0" width="426" height="66"/>
|
<rect key="frame" x="31" y="0.0" width="426" height="66"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Enter an address"/>
|
<accessibility key="accessibilityConfiguration" identifier="adress_field" label="Enter an address"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="33"/>
|
<fontDescription key="fontDescription" type="system" pointSize="33"/>
|
||||||
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="alphabet" returnKeyType="join"/>
|
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="alphabet" returnKeyType="join"/>
|
||||||
<connections>
|
<connections>
|
||||||
|
|
@ -248,7 +248,7 @@
|
||||||
<button hidden="YES" opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="183" userLabel="backButton">
|
<button hidden="YES" opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="183" userLabel="backButton">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="180" height="66"/>
|
<rect key="frame" x="0.0" y="0.0" width="180" height="66"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Back"/>
|
<accessibility key="accessibilityConfiguration" identifier="back_to_call" label="Back"/>
|
||||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||||
<state key="normal" image="call_alt_back_default.png" backgroundImage="color_F.png">
|
<state key="normal" image="call_alt_back_default.png" backgroundImage="color_F.png">
|
||||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
|
@ -262,7 +262,7 @@
|
||||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="222" userLabel="addContactButton">
|
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="222" userLabel="addContactButton">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="180" height="66"/>
|
<rect key="frame" x="0.0" y="0.0" width="180" height="66"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Add to contact"/>
|
<accessibility key="accessibilityConfiguration" identifier="dialer_view_group_call" label="Add to contact"/>
|
||||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||||
<state key="normal" image="contact_add_default.png" backgroundImage="color_F.png">
|
<state key="normal" image="contact_add_default.png" backgroundImage="color_F.png">
|
||||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
|
@ -292,6 +292,7 @@
|
||||||
</view>
|
</view>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="dialer_view"/>
|
||||||
</view>
|
</view>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="1" green="1" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="1" green="1" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||||
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
|
|
@ -144,7 +145,7 @@
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
</scrollView>
|
</scrollView>
|
||||||
<view hidden="YES" clearsContextBeforeDrawing="NO" tag="16" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="31" userLabel="waitView">
|
<view hidden="YES" clearsContextBeforeDrawing="NO" tag="16" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="31" userLabel="waitView">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||||
|
|
@ -166,7 +167,7 @@
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" tag="1" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="i7c-YH-msu" customClass="TPKeyboardAvoidingScrollView">
|
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" tag="1" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="i7c-YH-msu" customClass="TPKeyboardAvoidingScrollView">
|
||||||
<rect key="frame" x="0.0" y="260.5" width="667" height="375"/>
|
<rect key="frame" x="0.0" y="261" width="667" height="375"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<imageView userInteractionEnabled="NO" tag="2" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="linphone_logo.png" translatesAutoresizingMaskIntoConstraints="NO" id="eAY-9z-N0l" userLabel="logoImage">
|
<imageView userInteractionEnabled="NO" tag="2" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="linphone_logo.png" translatesAutoresizingMaskIntoConstraints="NO" id="eAY-9z-N0l" userLabel="logoImage">
|
||||||
|
|
@ -192,7 +193,7 @@
|
||||||
<size key="shadowOffset" width="-1" height="-1"/>
|
<size key="shadowOffset" width="-1" height="-1"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" tag="5" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="USERNAME" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qbs-8f-pLW" userLabel="usernameLabel">
|
<label opaque="NO" userInteractionEnabled="NO" tag="5" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="USERNAME" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qbs-8f-pLW" userLabel="usernameLabel">
|
||||||
<rect key="frame" x="158" y="105" width="350" height="20"/>
|
<rect key="frame" x="158" y="104" width="350" height="20"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||||
<color key="textColor" red="0.42667588591575623" green="0.4266631007194519" blue="0.42667034268379211" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" red="0.42667588591575623" green="0.4266631007194519" blue="0.42667034268379211" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
|
@ -212,14 +213,14 @@
|
||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" tag="7" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Invalid username" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="Bgv-t3-ZGF" userLabel="usernameErrorLabel">
|
<label opaque="NO" userInteractionEnabled="NO" tag="7" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Invalid username" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="Bgv-t3-ZGF" userLabel="usernameErrorLabel">
|
||||||
<rect key="frame" x="158" y="146" width="350" height="15"/>
|
<rect key="frame" x="158" y="145" width="350" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="9"/>
|
<fontDescription key="fontDescription" type="system" pointSize="9"/>
|
||||||
<color key="textColor" red="0.98594832420349121" green="0.0" blue="0.026950567960739136" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" red="0.98594832420349121" green="0.0" blue="0.026950567960739136" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" tag="8" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="DOMAIN" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1GT-Pk-UQT" userLabel="domainLabel">
|
<label opaque="NO" userInteractionEnabled="NO" tag="8" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="DOMAIN" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1GT-Pk-UQT" userLabel="domainLabel">
|
||||||
<rect key="frame" x="158" y="182" width="350" height="14"/>
|
<rect key="frame" x="158" y="181" width="350" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||||
<color key="textColor" red="0.42667588591575623" green="0.4266631007194519" blue="0.42667034268379211" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" red="0.42667588591575623" green="0.4266631007194519" blue="0.42667034268379211" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
|
@ -239,21 +240,21 @@
|
||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" tag="10" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Invalid domain" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="Q6W-CO-Qyo" userLabel="domainErrorLabel">
|
<label opaque="NO" userInteractionEnabled="NO" tag="10" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Invalid domain" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="Q6W-CO-Qyo" userLabel="domainErrorLabel">
|
||||||
<rect key="frame" x="158" y="223" width="350" height="15"/>
|
<rect key="frame" x="158" y="222" width="350" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="9"/>
|
<fontDescription key="fontDescription" type="system" pointSize="9"/>
|
||||||
<color key="textColor" red="0.98594832420349121" green="0.0" blue="0.026950567960739136" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" red="0.98594832420349121" green="0.0" blue="0.026950567960739136" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" tag="11" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="PASSWORD" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3ie-wD-Jq5" userLabel="passwordLabel">
|
<label opaque="NO" userInteractionEnabled="NO" tag="11" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="PASSWORD" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3ie-wD-Jq5" userLabel="passwordLabel">
|
||||||
<rect key="frame" x="158" y="259" width="350" height="14"/>
|
<rect key="frame" x="158" y="258" width="350" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||||
<color key="textColor" red="0.42667588591575623" green="0.4266631007194519" blue="0.42667034268379211" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" red="0.42667588591575623" green="0.4266631007194519" blue="0.42667034268379211" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<textField opaque="NO" clipsSubviews="YES" tag="12" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" adjustsFontSizeToFit="NO" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="iFV-rZ-JMe" userLabel="passwordField" customClass="UIAssistantTextField">
|
<textField opaque="NO" clipsSubviews="YES" tag="12" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" adjustsFontSizeToFit="NO" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="iFV-rZ-JMe" userLabel="passwordField" customClass="UIAssistantTextField">
|
||||||
<rect key="frame" x="158" y="277" width="350" height="25"/>
|
<rect key="frame" x="158" y="276" width="350" height="25"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||||
<color key="backgroundColor" red="0.85415387153625488" green="0.85412830114364624" blue="0.85414278507232666" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.85415387153625488" green="0.85412830114364624" blue="0.85414278507232666" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Password"/>
|
<accessibility key="accessibilityConfiguration" label="Password"/>
|
||||||
|
|
@ -266,14 +267,14 @@
|
||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" tag="13" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Invalid password" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="sac-b3-hPk" userLabel="passwordErrorLabel">
|
<label opaque="NO" userInteractionEnabled="NO" tag="13" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Invalid password" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="sac-b3-hPk" userLabel="passwordErrorLabel">
|
||||||
<rect key="frame" x="158" y="300" width="350" height="15"/>
|
<rect key="frame" x="158" y="299" width="350" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="9"/>
|
<fontDescription key="fontDescription" type="system" pointSize="9"/>
|
||||||
<color key="textColor" red="0.98594832420349121" green="0.0" blue="0.026950567960739136" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" red="0.98594832420349121" green="0.0" blue="0.026950567960739136" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<button opaque="NO" tag="14" contentMode="scaleToFill" fixedFrame="YES" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0lR-zp-xF9" userLabel="downloadButton" customClass="UIRoundBorderedButton">
|
<button opaque="NO" tag="14" contentMode="scaleToFill" fixedFrame="YES" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0lR-zp-xF9" userLabel="downloadButton" customClass="UIRoundBorderedButton">
|
||||||
<rect key="frame" x="158" y="328" width="350" height="39"/>
|
<rect key="frame" x="158" y="327" width="350" height="39"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
<color key="backgroundColor" red="0.20521381497383118" green="0.20520767569541931" blue="0.20521116256713867" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.20521381497383118" green="0.20520767569541931" blue="0.20521116256713867" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Fetch and apply">
|
<accessibility key="accessibilityConfiguration" label="Fetch and apply">
|
||||||
|
|
@ -293,7 +294,7 @@
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<activityIndicatorView opaque="NO" clearsContextBeforeDrawing="NO" userInteractionEnabled="NO" tag="17" contentMode="scaleToFill" fixedFrame="YES" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="U6u-rm-UlH" userLabel="activityIndicator">
|
<activityIndicatorView opaque="NO" clearsContextBeforeDrawing="NO" userInteractionEnabled="NO" tag="17" contentMode="scaleToFill" fixedFrame="YES" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="U6u-rm-UlH" userLabel="activityIndicator">
|
||||||
<rect key="frame" x="188.5" y="426.5" width="37" height="37"/>
|
<rect key="frame" x="189" y="426" width="37" height="37"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
</activityIndicatorView>
|
</activityIndicatorView>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
|
@ -301,10 +302,14 @@
|
||||||
</view>
|
</view>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<point key="canvasLocation" x="830" y="78"/>
|
||||||
</view>
|
</view>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="linphone_logo.png" width="41.599998474121094" height="42.400001525878906"/>
|
<image name="linphone_logo.png" width="41.599998474121094" height="42.400001525878906"/>
|
||||||
|
<systemColor name="systemBackgroundColor">
|
||||||
|
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
</systemColor>
|
||||||
</resources>
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||||
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
|
|
@ -26,7 +27,7 @@
|
||||||
<view tag="1" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="avX-6g-QDq" userLabel="background">
|
<view tag="1" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="avX-6g-QDq" userLabel="background">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="559"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="559"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
</view>
|
</view>
|
||||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6sv-JD-j8Z" userLabel="statusBarBG">
|
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6sv-JD-j8Z" userLabel="statusBarBG">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="35"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="35"/>
|
||||||
|
|
@ -43,6 +44,12 @@
|
||||||
<viewController nibName="UICompositeView" wantsFullScreenLayout="YES" id="208" userLabel="mainViewController" customClass="UICompositeView">
|
<viewController nibName="UICompositeView" wantsFullScreenLayout="YES" id="208" userLabel="mainViewController" customClass="UICompositeView">
|
||||||
<extendedEdge key="edgesForExtendedLayout"/>
|
<extendedEdge key="edgesForExtendedLayout"/>
|
||||||
<nil key="simulatedStatusBarMetrics"/>
|
<nil key="simulatedStatusBarMetrics"/>
|
||||||
|
<point key="canvasLocation" x="135" y="88"/>
|
||||||
</viewController>
|
</viewController>
|
||||||
</objects>
|
</objects>
|
||||||
|
<resources>
|
||||||
|
<systemColor name="systemBackgroundColor">
|
||||||
|
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
</systemColor>
|
||||||
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
<button opaque="NO" tag="6" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="gTj-vM-UtG" userLabel="backButton" customClass="UIInterfaceStyleButton">
|
<button opaque="NO" tag="6" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="gTj-vM-UtG" userLabel="backButton" customClass="UIInterfaceStyleButton">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="91" height="66"/>
|
<rect key="frame" x="0.0" y="0.0" width="91" height="66"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Back"/>
|
<accessibility key="accessibilityConfiguration" identifier="settings_view_back" label="Back"/>
|
||||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||||
<state key="normal" image="back_default.png">
|
<state key="normal" image="back_default.png">
|
||||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
|
@ -58,7 +58,8 @@
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||||
</view>
|
</view>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="settings_view"/>
|
||||||
</view>
|
</view>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="1" green="1" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="1" green="1" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||||
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
|
|
@ -49,6 +50,7 @@
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="John Doe" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="19" translatesAutoresizingMaskIntoConstraints="NO" id="XbU-2B-u1b" userLabel="nameLabel">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="John Doe" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="19" translatesAutoresizingMaskIntoConstraints="NO" id="XbU-2B-u1b" userLabel="nameLabel">
|
||||||
<rect key="frame" x="76" y="15" width="224" height="31"/>
|
<rect key="frame" x="76" y="15" width="224" height="31"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="name_label"/>
|
||||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="25"/>
|
<fontDescription key="fontDescription" type="boldSystem" pointSize="25"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
|
|
@ -56,6 +58,7 @@
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="john.doe@sip.linphone.org" lineBreakMode="middleTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="V8A-tK-4iV" userLabel="addressLabel">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="john.doe@sip.linphone.org" lineBreakMode="middleTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="V8A-tK-4iV" userLabel="addressLabel">
|
||||||
<rect key="frame" x="76" y="54" width="208" height="38"/>
|
<rect key="frame" x="76" y="54" width="208" height="38"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="side_menu_view_sip_adress"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" red="0.98766469955444336" green="0.27512490749359131" blue="0.029739789664745331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" red="0.98766469955444336" green="0.27512490749359131" blue="0.029739789664745331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
|
|
@ -72,7 +75,7 @@
|
||||||
</connections>
|
</connections>
|
||||||
</imageView>
|
</imageView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
||||||
<gestureRecognizers/>
|
<gestureRecognizers/>
|
||||||
<connections>
|
<connections>
|
||||||
<outletCollection property="gestureRecognizers" destination="1kD-az-BAx" appends="YES" id="OGc-fj-HQy"/>
|
<outletCollection property="gestureRecognizers" destination="1kD-az-BAx" appends="YES" id="OGc-fj-HQy"/>
|
||||||
|
|
@ -81,7 +84,7 @@
|
||||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" bounces="NO" style="plain" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="Ttt-1k-jAm">
|
<tableView clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" bounces="NO" style="plain" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="Ttt-1k-jAm">
|
||||||
<rect key="frame" x="0.0" y="100" width="300" height="754"/>
|
<rect key="frame" x="0.0" y="100" width="300" height="754"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="dataSource" destination="Yyh-z6-IGO" id="ytx-b8-NGX"/>
|
<outlet property="dataSource" destination="Yyh-z6-IGO" id="ytx-b8-NGX"/>
|
||||||
<outlet property="delegate" destination="Yyh-z6-IGO" id="c1j-vG-TbB"/>
|
<outlet property="delegate" destination="Yyh-z6-IGO" id="c1j-vG-TbB"/>
|
||||||
|
|
@ -124,5 +127,11 @@
|
||||||
<resources>
|
<resources>
|
||||||
<image name="avatar.png" width="414.39999389648438" height="414.39999389648438"/>
|
<image name="avatar.png" width="414.39999389648438" height="414.39999389648438"/>
|
||||||
<image name="led_connected.png" width="19.200000762939453" height="19.200000762939453"/>
|
<image name="led_connected.png" width="19.200000762939453" height="19.200000762939453"/>
|
||||||
|
<systemColor name="secondarySystemBackgroundColor">
|
||||||
|
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
</systemColor>
|
||||||
|
<systemColor name="systemBackgroundColor">
|
||||||
|
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
</systemColor>
|
||||||
</resources>
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
|
|
|
||||||
|
|
@ -277,6 +277,7 @@
|
||||||
[PhoneMainView.instance changeCurrentView:ConferenceWaitingRoomFragment.compositeViewDescription];
|
[PhoneMainView.instance changeCurrentView:ConferenceWaitingRoomFragment.compositeViewDescription];
|
||||||
} else {
|
} else {
|
||||||
const LinphoneAddress *addr = linphone_call_log_get_remote_address(callLog);
|
const LinphoneAddress *addr = linphone_call_log_get_remote_address(callLog);
|
||||||
|
[tableView deselectRowAtIndexPath:indexPath animated:NO];
|
||||||
[LinphoneManager.instance call:addr];
|
[LinphoneManager.instance call:addr];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
startedInBackground = FALSE;
|
startedInBackground = FALSE;
|
||||||
}
|
}
|
||||||
_onlyPortrait = FALSE;
|
_onlyPortrait = FALSE;
|
||||||
return self;
|
return self;
|
||||||
[[UIApplication sharedApplication] setDelegate:self];
|
[[UIApplication sharedApplication] setDelegate:self];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -407,7 +407,6 @@
|
||||||
{
|
{
|
||||||
|
|
||||||
[self setBool:[lm lpConfigBoolForKey:@"use_device_ringtone"] forKey:@"use_device_ringtone"];
|
[self setBool:[lm lpConfigBoolForKey:@"use_device_ringtone"] forKey:@"use_device_ringtone"];
|
||||||
[self setBool:linphone_core_is_record_aware_enabled(LC) forKey:@"record_aware"];
|
|
||||||
|
|
||||||
[self setBool:linphone_core_get_use_info_for_dtmf(LC) forKey:@"sipinfo_dtmf_preference"];
|
[self setBool:linphone_core_get_use_info_for_dtmf(LC) forKey:@"sipinfo_dtmf_preference"];
|
||||||
[self setBool:linphone_core_get_use_rfc2833_for_dtmf(LC) forKey:@"rfc_dtmf_preference"];
|
[self setBool:linphone_core_get_use_rfc2833_for_dtmf(LC) forKey:@"rfc_dtmf_preference"];
|
||||||
|
|
@ -490,6 +489,7 @@
|
||||||
[self setInteger:linphone_core_get_upload_bandwidth(LC) forKey:@"upload_bandwidth_preference"];
|
[self setInteger:linphone_core_get_upload_bandwidth(LC) forKey:@"upload_bandwidth_preference"];
|
||||||
[self setInteger:linphone_core_get_download_bandwidth(LC) forKey:@"download_bandwidth_preference"];
|
[self setInteger:linphone_core_get_download_bandwidth(LC) forKey:@"download_bandwidth_preference"];
|
||||||
[self setBool:linphone_core_adaptive_rate_control_enabled(LC) forKey:@"adaptive_rate_control_preference"];
|
[self setBool:linphone_core_adaptive_rate_control_enabled(LC) forKey:@"adaptive_rate_control_preference"];
|
||||||
|
[self setObject:[lm lpConfigStringForKey:@"dns_server_ip"] forKey:@"dns_server_preference"];
|
||||||
}
|
}
|
||||||
|
|
||||||
// tunnel section
|
// tunnel section
|
||||||
|
|
@ -934,8 +934,6 @@
|
||||||
[lm lpConfigSetBool:[self boolForKey:@"use_device_ringtone"] forKey:@"use_device_ringtone"];
|
[lm lpConfigSetBool:[self boolForKey:@"use_device_ringtone"] forKey:@"use_device_ringtone"];
|
||||||
[ProviderDelegate resetSharedProviderConfiguration];
|
[ProviderDelegate resetSharedProviderConfiguration];
|
||||||
|
|
||||||
linphone_core_set_record_aware_enabled(LC, [self boolForKey:@"record_aware"]);
|
|
||||||
|
|
||||||
linphone_core_set_use_info_for_dtmf(LC, [self boolForKey:@"sipinfo_dtmf_preference"]);
|
linphone_core_set_use_info_for_dtmf(LC, [self boolForKey:@"sipinfo_dtmf_preference"]);
|
||||||
linphone_core_set_inc_timeout(LC, [self integerForKey:@"incoming_call_timeout_preference"]);
|
linphone_core_set_inc_timeout(LC, [self integerForKey:@"incoming_call_timeout_preference"]);
|
||||||
linphone_core_set_in_call_timeout(LC, [self integerForKey:@"in_call_timeout_preference"]);
|
linphone_core_set_in_call_timeout(LC, [self integerForKey:@"in_call_timeout_preference"]);
|
||||||
|
|
@ -1033,6 +1031,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
linphone_core_enable_adaptive_rate_control(LC, [self boolForKey:@"adaptive_rate_control_preference"]);
|
linphone_core_enable_adaptive_rate_control(LC, [self boolForKey:@"adaptive_rate_control_preference"]);
|
||||||
|
|
||||||
|
if ([self stringForKey:@"dns_server_preference"] != [lm lpConfigStringForKey:@"dns_server_ip"]) {
|
||||||
|
[lm lpConfigSetString:[self stringForKey:@"dns_server_preference"] forKey:@"dns_server_ip"];
|
||||||
|
[lm setDnsServer];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// tunnel section
|
// tunnel section
|
||||||
if (linphone_core_tunnel_available()) {
|
if (linphone_core_tunnel_available()) {
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,8 @@ typedef struct _LinphoneManagerSounds {
|
||||||
|
|
||||||
- (void)setupGSMInteraction;
|
- (void)setupGSMInteraction;
|
||||||
- (BOOL)isCTCallCenterExist;
|
- (BOOL)isCTCallCenterExist;
|
||||||
- (void) checkLocalNetworkPermission;
|
- (void)checkLocalNetworkPermission;
|
||||||
|
- (void)setDnsServer;
|
||||||
|
|
||||||
|
|
||||||
@property (readonly) BOOL isTesting;
|
@property (readonly) BOOL isTesting;
|
||||||
|
|
@ -214,5 +215,6 @@ typedef struct _LinphoneManagerSounds {
|
||||||
@property(strong, nonatomic) OrderedDictionary *linphoneManagerAddressBookMap;
|
@property(strong, nonatomic) OrderedDictionary *linphoneManagerAddressBookMap;
|
||||||
@property (nonatomic, assign) BOOL contactsUpdated;
|
@property (nonatomic, assign) BOOL contactsUpdated;
|
||||||
@property UIImage *avatar;
|
@property UIImage *avatar;
|
||||||
|
@property NSString *customCoreDNS;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
||||||
|
|
@ -1118,6 +1118,14 @@ static void linphone_iphone_is_composing_received(LinphoneCore *lc, LinphoneChat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setDnsServer {
|
||||||
|
NSString *dns_server_ip = [self lpConfigStringForKey:@"dns_server_ip"];
|
||||||
|
if ([dns_server_ip isEqualToString:@""]) {dns_server_ip = NULL;}
|
||||||
|
bctbx_list_t *dns_server_list = dns_server_ip?bctbx_list_new((void *)[dns_server_ip UTF8String]):NULL;
|
||||||
|
linphone_core_set_dns_servers_app(LC, dns_server_list);
|
||||||
|
bctbx_list_free(dns_server_list);
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
// scheduling loop
|
// scheduling loop
|
||||||
|
|
@ -1247,6 +1255,8 @@ static BOOL libStarted = FALSE;
|
||||||
// go directly to bg mode
|
// go directly to bg mode
|
||||||
[self enterBackgroundMode];
|
[self enterBackgroundMode];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreatorStatus status, const char *resp) {
|
void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreatorStatus status, const char *resp) {
|
||||||
|
|
@ -1436,6 +1446,8 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat
|
||||||
|
|
||||||
linphone_core_reload_ms_plugins(theLinphoneCore, NULL);
|
linphone_core_reload_ms_plugins(theLinphoneCore, NULL);
|
||||||
[self migrationAllPost];
|
[self migrationAllPost];
|
||||||
|
|
||||||
|
linphone_core_enable_record_aware(theLinphoneCore, true); //force record aware enable
|
||||||
|
|
||||||
/* Use the rootca from framework, which is already set*/
|
/* Use the rootca from framework, which is already set*/
|
||||||
//linphone_core_set_root_ca(theLinphoneCore, [LinphoneManager bundleFile:@"rootca.pem"].UTF8String);
|
//linphone_core_set_root_ca(theLinphoneCore, [LinphoneManager bundleFile:@"rootca.pem"].UTF8String);
|
||||||
|
|
@ -1453,6 +1465,7 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat
|
||||||
|
|
||||||
/*call iterate once immediately in order to initiate background connections with sip server or remote provisioning
|
/*call iterate once immediately in order to initiate background connections with sip server or remote provisioning
|
||||||
* grab, if any */
|
* grab, if any */
|
||||||
|
[self setDnsServer]; //configure DNS if custom DNS server is set
|
||||||
[self iterate];
|
[self iterate];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1686,6 +1699,9 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
|
||||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo
|
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo
|
||||||
completionHandler:^(BOOL granted){
|
completionHandler:^(BOOL granted){
|
||||||
}];
|
}];
|
||||||
|
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio
|
||||||
|
completionHandler:^(BOOL granted){
|
||||||
|
}];
|
||||||
|
|
||||||
/*start the video preview in case we are in the main view*/
|
/*start the video preview in case we are in the main view*/
|
||||||
if (linphone_core_video_display_enabled(theLinphoneCore) && [self lpConfigBoolForKey:@"preview_preference"]) {
|
if (linphone_core_video_display_enabled(theLinphoneCore) && [self lpConfigBoolForKey:@"preview_preference"]) {
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@
|
||||||
<button opaque="NO" tag="6" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="27" userLabel="callSecurityButton">
|
<button opaque="NO" tag="6" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="27" userLabel="callSecurityButton">
|
||||||
<rect key="frame" x="332" y="0.0" width="24" height="42"/>
|
<rect key="frame" x="332" y="0.0" width="24" height="42"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
<accessibility key="accessibilityConfiguration">
|
<accessibility key="accessibilityConfiguration" identifier="status_bar_incall_security">
|
||||||
<bool key="isElement" value="NO"/>
|
<bool key="isElement" value="YES"/>
|
||||||
</accessibility>
|
</accessibility>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||||
<state key="normal" image="security_ok.png">
|
<state key="normal" image="security_ok.png">
|
||||||
|
|
@ -52,6 +52,7 @@
|
||||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SKk-s0-5HE" userLabel="callQualityButton">
|
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SKk-s0-5HE" userLabel="callQualityButton">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="42" height="42"/>
|
<rect key="frame" x="0.0" y="0.0" width="42" height="42"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="status_bar_incall_quality"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||||
<state key="normal" image="call_quality_indicator_4.png">
|
<state key="normal" image="call_quality_indicator_4.png">
|
||||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
|
@ -61,6 +62,7 @@
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="status_bar_incall_security"/>
|
||||||
</view>
|
</view>
|
||||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lfO-I4-PXi" userLabel="outcallView">
|
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lfO-I4-PXi" userLabel="outcallView">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="360" height="42"/>
|
<rect key="frame" x="0.0" y="0.0" width="360" height="42"/>
|
||||||
|
|
@ -69,7 +71,9 @@
|
||||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yg7-rx-XVv" userLabel="sideMenuButton">
|
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yg7-rx-XVv" userLabel="sideMenuButton">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="42" height="42"/>
|
<rect key="frame" x="0.0" y="0.0" width="42" height="42"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Side menu button"/>
|
<accessibility key="accessibilityConfiguration" identifier="side_menu_button" label="Side menu button">
|
||||||
|
<accessibilityTraits key="traits" button="YES"/>
|
||||||
|
</accessibility>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||||
<state key="normal" image="menu.png">
|
<state key="normal" image="menu.png">
|
||||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
|
@ -93,7 +97,7 @@
|
||||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Mhg-P6-RfU" userLabel="registrationState" customClass="UIIconButton">
|
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Mhg-P6-RfU" userLabel="registrationState" customClass="UIIconButton">
|
||||||
<rect key="frame" x="46" y="0.0" width="194" height="42"/>
|
<rect key="frame" x="46" y="0.0" width="194" height="42"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="Registration state"/>
|
<accessibility key="accessibilityConfiguration" identifier="status_bar_registration_state" label="Registration state"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||||
<inset key="titleEdgeInsets" minX="6" minY="0.0" maxX="0.0" maxY="0.0"/>
|
<inset key="titleEdgeInsets" minX="6" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||||
<state key="normal" title="Registered" image="led_disconnected.png">
|
<state key="normal" title="Registered" image="led_disconnected.png">
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<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"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
|
|
@ -28,13 +29,15 @@
|
||||||
<view autoresizesSubviews="NO" tag="5" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="UhA-h1-Cu8" userLabel="detailsView">
|
<view autoresizesSubviews="NO" tag="5" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="UhA-h1-Cu8" userLabel="detailsView">
|
||||||
<rect key="frame" x="187" y="42" width="187" height="559"/>
|
<rect key="frame" x="187" y="42" width="187" height="559"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="details_view"/>
|
||||||
<gestureRecognizers/>
|
<gestureRecognizers/>
|
||||||
</view>
|
</view>
|
||||||
<view autoresizesSubviews="NO" tag="1" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="15" userLabel="mainView">
|
<view autoresizesSubviews="NO" tag="1" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="15" userLabel="mainView">
|
||||||
<rect key="frame" x="0.0" y="42" width="188" height="559"/>
|
<rect key="frame" x="0.0" y="42" width="188" height="559"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="main_view"/>
|
||||||
<gestureRecognizers/>
|
<gestureRecognizers/>
|
||||||
<connections>
|
<connections>
|
||||||
<outletCollection property="gestureRecognizers" destination="40" appends="YES" id="41"/>
|
<outletCollection property="gestureRecognizers" destination="40" appends="YES" id="41"/>
|
||||||
|
|
@ -43,21 +46,24 @@
|
||||||
<view autoresizesSubviews="NO" tag="3" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="16" userLabel="tabBar">
|
<view autoresizesSubviews="NO" tag="3" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="16" userLabel="tabBar">
|
||||||
<rect key="frame" x="0.0" y="601" width="375" height="66"/>
|
<rect key="frame" x="0.0" y="601" width="375" height="66"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="tab_bar"/>
|
||||||
</view>
|
</view>
|
||||||
<view clearsContextBeforeDrawing="NO" tag="4" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="26" userLabel="sideMenuView">
|
<view clearsContextBeforeDrawing="NO" tag="4" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="26" userLabel="sideMenuView">
|
||||||
<rect key="frame" x="-375" y="42" width="375" height="625"/>
|
<rect key="frame" x="-375" y="42" width="375" height="625"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="side_menu_view"/>
|
||||||
</view>
|
</view>
|
||||||
<view autoresizesSubviews="NO" tag="2" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="14" userLabel="statusBar">
|
<view autoresizesSubviews="NO" tag="2" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="14" userLabel="statusBar">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="42"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="42"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
|
<accessibility key="accessibilityConfiguration" identifier="status_bar"/>
|
||||||
</view>
|
</view>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
<viewLayoutGuide key="safeArea" id="JWS-o5-QR7"/>
|
||||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
<nil key="simulatedStatusBarMetrics"/>
|
<nil key="simulatedStatusBarMetrics"/>
|
||||||
<viewLayoutGuide key="safeArea" id="JWS-o5-QR7"/>
|
|
||||||
<point key="canvasLocation" x="-139.85507246376812" y="-17.075892857142858"/>
|
<point key="canvasLocation" x="-139.85507246376812" y="-17.075892857142858"/>
|
||||||
</view>
|
</view>
|
||||||
<view contentMode="scaleToFill" id="20" userLabel="Landscape View">
|
<view contentMode="scaleToFill" id="20" userLabel="Landscape View">
|
||||||
|
|
@ -70,7 +76,7 @@
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</view>
|
</view>
|
||||||
<view autoresizesSubviews="NO" tag="1" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="23" userLabel="mainView">
|
<view autoresizesSubviews="NO" tag="1" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="23" userLabel="mainView">
|
||||||
<rect key="frame" x="90" y="42" width="142.5" height="625"/>
|
<rect key="frame" x="90" y="42" width="143" height="625"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -89,9 +95,9 @@
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</view>
|
</view>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
<viewLayoutGuide key="safeArea" id="M2K-Ww-Tkq"/>
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="simulatedStatusBarMetrics"/>
|
<nil key="simulatedStatusBarMetrics"/>
|
||||||
<viewLayoutGuide key="safeArea" id="M2K-Ww-Tkq"/>
|
|
||||||
<point key="canvasLocation" x="655.79710144927537" y="-71.316964285714278"/>
|
<point key="canvasLocation" x="655.79710144927537" y="-71.316964285714278"/>
|
||||||
</view>
|
</view>
|
||||||
<swipeGestureRecognizer direction="right" id="40">
|
<swipeGestureRecognizer direction="right" id="40">
|
||||||
|
|
@ -101,4 +107,9 @@
|
||||||
</connections>
|
</connections>
|
||||||
</swipeGestureRecognizer>
|
</swipeGestureRecognizer>
|
||||||
</objects>
|
</objects>
|
||||||
|
<resources>
|
||||||
|
<systemColor name="systemBackgroundColor">
|
||||||
|
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
</systemColor>
|
||||||
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
|
|
|
||||||
|
|
@ -405,11 +405,13 @@
|
||||||
[ControlsViewModelBridge toggleStatsVisibility];
|
[ControlsViewModelBridge toggleStatsVisibility];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (IBAction)onSideMenuClick:(id)sender {
|
- (IBAction)onSideMenuClick:(id)sender {
|
||||||
UICompositeView *cvc = PhoneMainView.instance.mainViewController;
|
UICompositeView *cvc = PhoneMainView.instance.mainViewController;
|
||||||
[cvc hideSideMenu:(cvc.sideMenuView.frame.origin.x == 0)];
|
[cvc hideSideMenu:(cvc.sideMenuView.frame.origin.x == 0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (IBAction)onRegistrationStateClick:(id)sender {
|
- (IBAction)onRegistrationStateClick:(id)sender {
|
||||||
if (linphone_core_get_default_account(LC)) {
|
if (linphone_core_get_default_account(LC)) {
|
||||||
linphone_core_refresh_registers(LC);
|
linphone_core_refresh_registers(LC);
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,7 @@ static RootViewManager *rootViewManagerInstance = nil;
|
||||||
volumeView.userInteractionEnabled = false;
|
volumeView.userInteractionEnabled = false;
|
||||||
|
|
||||||
[self.view addSubview:mainViewController.view];
|
[self.view addSubview:mainViewController.view];
|
||||||
|
self.view.accessibilityIdentifier = @"phone_view";
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewWillAppear:(BOOL)animated {
|
- (void)viewWillAppear:(BOOL)animated {
|
||||||
|
|
@ -720,6 +721,9 @@ static RootViewManager *rootViewManagerInstance = nil;
|
||||||
|
|
||||||
[errView addAction:defaultAction];
|
[errView addAction:defaultAction];
|
||||||
[self presentViewController:errView animated:YES completion:nil];
|
[self presentViewController:errView animated:YES completion:nil];
|
||||||
|
errView.view.accessibilityIdentifier = @"call_failed_error_view";
|
||||||
|
errView.view.subviews.firstObject.accessibilityIdentifier = @"call_failed_error_view";
|
||||||
|
errView.actions.firstObject.accessibilityIdentifier = @"call_failed_error_view_action";
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addInhibitedEvent:(id)event {
|
- (void)addInhibitedEvent:(id)event {
|
||||||
|
|
|
||||||
|
|
@ -625,16 +625,7 @@ import AVFoundation
|
||||||
Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: outgoing call started connecting with uuid \(uuid!) and callId \(callId!)")
|
Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: outgoing call started connecting with uuid \(uuid!) and callId \(callId!)")
|
||||||
CallManager.instance().providerDelegate.reportOutgoingCallStartedConnecting(uuid: uuid!)
|
CallManager.instance().providerDelegate.reportOutgoingCallStartedConnecting(uuid: uuid!)
|
||||||
} else {
|
} else {
|
||||||
if CallManager.instance().isConferenceCall(call: call) {
|
CallManager.instance().referedToCall = callId
|
||||||
let uuid = UUID()
|
|
||||||
let callInfo = CallInfo.newOutgoingCallInfo(addr: call.remoteAddress!, isSas: call.params?.mediaEncryption == .ZRTP, displayName: VoipTexts.conference_default_title, isVideo: call.params?.videoEnabled == true, isConference:true)
|
|
||||||
CallManager.instance().providerDelegate.callInfos.updateValue(callInfo, forKey: uuid)
|
|
||||||
CallManager.instance().providerDelegate.uuids.updateValue(uuid, forKey: "")
|
|
||||||
CallManager.instance().providerDelegate.reportOutgoingCallStartedConnecting(uuid: uuid)
|
|
||||||
Core.get().activateAudioSession(actived: true)
|
|
||||||
} else {
|
|
||||||
CallManager.instance().referedToCall = callId
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,8 @@ import IQKeyboardManager
|
||||||
},
|
},
|
||||||
nextActionEnableCondition: ConferenceSchedulingViewModel.shared.continueEnabled,
|
nextActionEnableCondition: ConferenceSchedulingViewModel.shared.continueEnabled,
|
||||||
title:VoipTexts.conference_group_call_title)
|
title:VoipTexts.conference_group_call_title)
|
||||||
|
view.accessibilityIdentifier = "start_group_call_view"
|
||||||
|
|
||||||
let subjectLabel = StyledLabel(VoipTheme.conference_scheduling_font, VoipTexts.conference_schedule_subject_title)
|
let subjectLabel = StyledLabel(VoipTheme.conference_scheduling_font, VoipTexts.conference_schedule_subject_title)
|
||||||
subjectLabel.addIndicatorIcon(iconName: "voip_mandatory")
|
subjectLabel.addIndicatorIcon(iconName: "voip_mandatory")
|
||||||
contentView.addSubview(subjectLabel)
|
contentView.addSubview(subjectLabel)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
extension UIColor {
|
extension UIColor {
|
||||||
public convenience init(hex: String) {
|
public convenience init(hex: String) {
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,8 @@ import UIKit
|
||||||
|
|
||||||
// Added in iOS
|
// Added in iOS
|
||||||
static let camera_required_for_video = NSLocalizedString("Camera use is not Authorized for &appName;. This permission is required to activate Video.",comment:"").replacingOccurrences(of: "&appName;", with: appName)
|
static let camera_required_for_video = NSLocalizedString("Camera use is not Authorized for &appName;. This permission is required to activate Video.",comment:"").replacingOccurrences(of: "&appName;", with: appName)
|
||||||
|
static let microphone_non_authorized_warning = NSLocalizedString("Warning : Microphone access is not Authorized for &appName;. To enable access, tap Settings and turn on Microphone, this will end your call",comment:"").replacingOccurrences(of: "&appName;", with: appName)
|
||||||
|
static let system_app_settings = NSLocalizedString("SETTINGS",comment:"")
|
||||||
static let conference_edit_error = NSLocalizedString("Unable to edit conference this time, date is invalid",comment:"")
|
static let conference_edit_error = NSLocalizedString("Unable to edit conference this time, date is invalid",comment:"")
|
||||||
static let ok = NSLocalizedString("ok",comment:"")
|
static let ok = NSLocalizedString("ok",comment:"")
|
||||||
static let conference_info_confirm_removal_delete = NSLocalizedString("DELETE",comment:"")
|
static let conference_info_confirm_removal_delete = NSLocalizedString("DELETE",comment:"")
|
||||||
|
|
|
||||||
|
|
@ -229,17 +229,24 @@ class ControlsViewModel {
|
||||||
|
|
||||||
func toggleMuteMicrophone() {
|
func toggleMuteMicrophone() {
|
||||||
if (!micAuthorized()) {
|
if (!micAuthorized()) {
|
||||||
AVAudioSession.sharedInstance().requestRecordPermission { granted in
|
askMicrophoneAccess()
|
||||||
if granted {
|
|
||||||
self.core.micEnabled = !self.core.micEnabled
|
|
||||||
self.updateMicState()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
core.micEnabled = !core.micEnabled
|
core.micEnabled = !core.micEnabled
|
||||||
updateMicState()
|
updateMicState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var microphoneAsking = false
|
||||||
|
func askMicrophoneAccess() {
|
||||||
|
microphoneAsking = true
|
||||||
|
let settings = ButtonAttributes(text:VoipTexts.system_app_settings, action: {
|
||||||
|
self.microphoneAsking = false
|
||||||
|
try! self.core.terminateAllCalls()
|
||||||
|
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
|
||||||
|
}, isDestructive:false)
|
||||||
|
let cancel = ButtonAttributes(text:VoipTexts.cancel, action: {self.microphoneAsking = false}, isDestructive:true)
|
||||||
|
VoipDialog(message:VoipTexts.microphone_non_authorized_warning, givenButtons: [cancel,settings]).show()
|
||||||
|
}
|
||||||
|
|
||||||
func forceEarpieceAudioRoute() {
|
func forceEarpieceAudioRoute() {
|
||||||
if (AudioRouteUtils.isHeadsetAudioRouteAvailable()) {
|
if (AudioRouteUtils.isHeadsetAudioRouteAvailable()) {
|
||||||
Log.i("[Call Controls] Headset found, route audio to it instead of earpiece")
|
Log.i("[Call Controls] Headset found, route audio to it instead of earpiece")
|
||||||
|
|
@ -271,15 +278,12 @@ class ControlsViewModel {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@objc class ControlsViewModelBridge: NSObject {
|
@objc class ControlsViewModelBridge: NSObject {
|
||||||
@objc static func showParticipants() {
|
@objc static func showParticipants() {
|
||||||
ControlsViewModel.shared.goToConferenceParticipantsListEvent.value = true
|
ControlsViewModel.shared.goToConferenceParticipantsListEvent.value = true
|
||||||
}
|
}
|
||||||
@objc static func toggleStatsVisibility() -> Void {
|
@objc static func toggleStatsVisibility() {
|
||||||
if (ControlsViewModel.shared.callStatsVisible.value == true) {
|
ControlsViewModel.shared.callStatsVisible.value = !(ControlsViewModel.shared.callStatsVisible.value ?? false)
|
||||||
ControlsViewModel.shared.callStatsVisible.value = false
|
|
||||||
} else {
|
|
||||||
ControlsViewModel.shared.callStatsVisible.value = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ import linphonesw
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
view.backgroundColor = VoipTheme.voipBackgroundColor.get()
|
view.backgroundColor = VoipTheme.voipBackgroundColor.get()
|
||||||
|
view.accessibilityIdentifier = "active_call_view"
|
||||||
|
|
||||||
// Hangup
|
// Hangup
|
||||||
let hangup = CallControlButton(width: 65, imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_terminate, onClickAction: {
|
let hangup = CallControlButton(width: 65, imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_terminate, onClickAction: {
|
||||||
|
|
@ -67,6 +68,8 @@ import linphonesw
|
||||||
})
|
})
|
||||||
view.addSubview(hangup)
|
view.addSubview(hangup)
|
||||||
hangup.alignParentLeft(withMargin:SharedLayoutConstants.margin_call_view_side_controls_buttons).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done()
|
hangup.alignParentLeft(withMargin:SharedLayoutConstants.margin_call_view_side_controls_buttons).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done()
|
||||||
|
hangup.accessibilityIdentifier = "active_call_view_hangup"
|
||||||
|
hangup.accessibilityLabel = "Hangup"
|
||||||
|
|
||||||
|
|
||||||
// Controls
|
// Controls
|
||||||
|
|
@ -119,9 +122,9 @@ import linphonesw
|
||||||
callPausedByRemoteView?.isHidden = true
|
callPausedByRemoteView?.isHidden = true
|
||||||
|
|
||||||
// Paused by local (Call)
|
// Paused by local (Call)
|
||||||
callPausedByLocalView = PausedCallOrConferenceView(iconName: "voip_conference_play_big",titleText: VoipTexts.call_locally_paused_title,subTitleText: VoipTexts.call_locally_paused_subtitle, onClickAction: {
|
callPausedByLocalView = PausedCallOrConferenceView(iconName: "voip_conference_play_big",titleText: VoipTexts.call_locally_paused_title,subTitleText: VoipTexts.call_locally_paused_subtitle, onClickAction: {
|
||||||
CallsViewModel.shared.currentCallData.value??.togglePause()
|
CallsViewModel.shared.currentCallData.value??.togglePause()
|
||||||
})
|
})
|
||||||
view.addSubview(callPausedByLocalView!)
|
view.addSubview(callPausedByLocalView!)
|
||||||
callPausedByLocalView?.matchParentSideBorders().matchParentHeight().alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).done()
|
callPausedByLocalView?.matchParentSideBorders().matchParentHeight().alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).done()
|
||||||
callPausedByLocalView?.isHidden = true
|
callPausedByLocalView?.isHidden = true
|
||||||
|
|
@ -222,6 +225,7 @@ import linphonesw
|
||||||
shadingMask.isHidden = true
|
shadingMask.isHidden = true
|
||||||
self.view.addSubview(shadingMask)
|
self.view.addSubview(shadingMask)
|
||||||
shadingMask.matchParentDimmensions().done()
|
shadingMask.matchParentDimmensions().done()
|
||||||
|
shadingMask.accessibilityIdentifier = "active_call_view_shading_mask"
|
||||||
|
|
||||||
// Extra Buttons
|
// Extra Buttons
|
||||||
let showextraButtons = CallControlButton(imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_more, onClickAction: {
|
let showextraButtons = CallControlButton(imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_more, onClickAction: {
|
||||||
|
|
@ -230,7 +234,9 @@ import linphonesw
|
||||||
})
|
})
|
||||||
view.addSubview(showextraButtons)
|
view.addSubview(showextraButtons)
|
||||||
showextraButtons.alignParentRight(withMargin:SharedLayoutConstants.margin_call_view_side_controls_buttons).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done()
|
showextraButtons.alignParentRight(withMargin:SharedLayoutConstants.margin_call_view_side_controls_buttons).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done()
|
||||||
|
showextraButtons.accessibilityIdentifier = "active_call_view_extra_buttons"
|
||||||
|
showextraButtons.accessibilityLabel = "More actions"
|
||||||
|
|
||||||
let boucingCounter = BouncingCounter(inButton:showextraButtons)
|
let boucingCounter = BouncingCounter(inButton:showextraButtons)
|
||||||
view.addSubview(boucingCounter)
|
view.addSubview(boucingCounter)
|
||||||
boucingCounter.dataSource = CallsViewModel.shared.chatAndCallsCount
|
boucingCounter.dataSource = CallsViewModel.shared.chatAndCallsCount
|
||||||
|
|
@ -255,11 +261,10 @@ import linphonesw
|
||||||
self.numpadView = NumpadView(superView: self.view,callData: CallsViewModel.shared.currentCallData.value!!,marginTop:self.currentCallView?.centerSection.frame.origin.y ?? 0.0, above:self.controlsView, onDismissAction: {
|
self.numpadView = NumpadView(superView: self.view,callData: CallsViewModel.shared.currentCallData.value!!,marginTop:self.currentCallView?.centerSection.frame.origin.y ?? 0.0, above:self.controlsView, onDismissAction: {
|
||||||
ControlsViewModel.shared.numpadVisible.value = false
|
ControlsViewModel.shared.numpadVisible.value = false
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
self.numpadView?.removeFromSuperview()
|
self.numpadView?.removeFromSuperview()
|
||||||
self.shadingMask.isHidden = true
|
self.shadingMask.isHidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call stats
|
// Call stats
|
||||||
|
|
@ -270,18 +275,21 @@ import linphonesw
|
||||||
self.currentCallStatsVew = CallStatsView(superView: self.view,callData: CallsViewModel.shared.currentCallData.value!!,marginTop:self.currentCallView?.centerSection.frame.origin.y ?? 0.0, above:self.controlsView, onDismissAction: {
|
self.currentCallStatsVew = CallStatsView(superView: self.view,callData: CallsViewModel.shared.currentCallData.value!!,marginTop:self.currentCallView?.centerSection.frame.origin.y ?? 0.0, above:self.controlsView, onDismissAction: {
|
||||||
ControlsViewModel.shared.callStatsVisible.value = false
|
ControlsViewModel.shared.callStatsVisible.value = false
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
self.currentCallStatsVew?.removeFromSuperview()
|
self.currentCallStatsVew?.removeFromSuperview()
|
||||||
self.shadingMask.isHidden = true
|
self.shadingMask.isHidden = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Video activation dialog request
|
// Video and Microphone activation dialog request
|
||||||
CallsViewModel.shared.callUpdateEvent.observe { (call) in
|
CallsViewModel.shared.callUpdateEvent.observe { (call) in
|
||||||
let core = Core.get()
|
let core = Core.get()
|
||||||
if (call?.state == .StreamsRunning) {
|
if (call?.state == .StreamsRunning) {
|
||||||
self.videoAcceptDialog?.removeFromSuperview()
|
self.videoAcceptDialog?.removeFromSuperview()
|
||||||
self.videoAcceptDialog = nil
|
self.videoAcceptDialog = nil
|
||||||
|
if (!ControlsViewModel.shared.micAuthorized() && !ControlsViewModel.shared.microphoneAsking) {
|
||||||
|
ControlsViewModel.shared.askMicrophoneAccess()
|
||||||
|
}
|
||||||
} else if (call?.state == .UpdatedByRemote) {
|
} else if (call?.state == .UpdatedByRemote) {
|
||||||
if (core.videoCaptureEnabled || core.videoDisplayEnabled) {
|
if (core.videoCaptureEnabled || core.videoDisplayEnabled) {
|
||||||
if (call?.currentParams?.videoEnabled != call?.remoteParams?.videoEnabled) {
|
if (call?.currentParams?.videoEnabled != call?.remoteParams?.videoEnabled) {
|
||||||
|
|
@ -351,8 +359,8 @@ import linphonesw
|
||||||
participantsListView?.removeFromSuperview()
|
participantsListView?.removeFromSuperview()
|
||||||
participantsListView = nil
|
participantsListView = nil
|
||||||
|
|
||||||
ControlsViewModel.shared.numpadVisible.value = false
|
ControlsViewModel.shared.numpadVisible.value = false
|
||||||
ControlsViewModel.shared.callStatsVisible.value = false
|
ControlsViewModel.shared.callStatsVisible.value = false
|
||||||
ControlsViewModel.shared.fullScreenMode.value = false
|
ControlsViewModel.shared.fullScreenMode.value = false
|
||||||
super.viewWillDisappear(animated)
|
super.viewWillDisappear(animated)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,13 +43,17 @@ import linphonesw
|
||||||
})
|
})
|
||||||
view.addSubview(accept)
|
view.addSubview(accept)
|
||||||
accept.centerX(withDx: buttons_distance_from_center_x).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done()
|
accept.centerX(withDx: buttons_distance_from_center_x).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done()
|
||||||
|
accept.accessibilityIdentifier = "I_call_view_accept"
|
||||||
|
accept.accessibilityLabel = "Accept"
|
||||||
|
|
||||||
// Decline
|
// Decline
|
||||||
let decline = CallControlButton(width: CallControlButton.hungup_width, imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_terminate, onClickAction: {
|
let decline = CallControlButton(width: CallControlButton.hungup_width, imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_terminate, onClickAction: {
|
||||||
self.callData.map { CallManager.instance().terminateCall(call: $0.call.getCobject)}
|
self.callData.map { CallManager.instance().terminateCall(call: $0.call.getCobject)}
|
||||||
})
|
})
|
||||||
view.addSubview(decline)
|
view.addSubview(decline)
|
||||||
decline.centerX(withDx: -buttons_distance_from_center_x).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done()
|
decline.centerX(withDx: -buttons_distance_from_center_x).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done()
|
||||||
|
decline.accessibilityIdentifier = "I_call_view_decline"
|
||||||
|
decline.accessibilityLabel = "Decline"
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc override func setCall(call:OpaquePointer) {
|
@objc override func setCall(call:OpaquePointer) {
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ import linphonesw
|
||||||
})
|
})
|
||||||
view.addSubview(cancelCall)
|
view.addSubview(cancelCall)
|
||||||
cancelCall.alignParentLeft(withMargin:SharedLayoutConstants.margin_call_view_side_controls_buttons).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done()
|
cancelCall.alignParentLeft(withMargin:SharedLayoutConstants.margin_call_view_side_controls_buttons).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done()
|
||||||
|
cancelCall.accessibilityIdentifier = "O_call_view_cancel"
|
||||||
|
cancelCall.accessibilityLabel = "Cancel"
|
||||||
|
|
||||||
// Controls
|
// Controls
|
||||||
let controlsView = ControlsView(showVideo: false, controlsViewModel: ControlsViewModel.shared)
|
let controlsView = ControlsView(showVideo: false, controlsViewModel: ControlsViewModel.shared)
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ class ActiveCallView: UIView { // = currentCall
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
callData?.isRemotelyRecorded.readCurrentAndObserve { (remotelyRecorded) in
|
callData?.isRemotelyRecorded.readCurrentAndObserve { (remotelyRecorded) in
|
||||||
self.centerSection.removeConstraints().matchParentSideBorders().alignUnder(view:remotelyRecorded == true ? self.remotelyRecordedIndicator : self.upperSection ,withMargin: ActiveCallView.center_view_margin_top).alignParentBottom().done()
|
self.centerSection.removeConstraints().matchParentSideBorders().alignUnder(view:remotelyRecorded == true ? self.remotelyRecordedIndicator : self.upperSection ,withMargin: ActiveCallView.center_view_margin_top).alignParentBottom().done()
|
||||||
self.setNeedsLayout()
|
self.setNeedsLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,6 +117,7 @@ class ActiveCallView: UIView { // = currentCall
|
||||||
|
|
||||||
displayNameDurationSipAddress.addSubview(duration)
|
displayNameDurationSipAddress.addSubview(duration)
|
||||||
duration.toRightOf(displayNameTop).alignParentRight().done()
|
duration.toRightOf(displayNameTop).alignParentRight().done()
|
||||||
|
duration.accessibilityIdentifier = "active_call_upper_section_duration"
|
||||||
|
|
||||||
displayNameDurationSipAddress.addSubview(sipAddress)
|
displayNameDurationSipAddress.addSubview(sipAddress)
|
||||||
sipAddress.matchParentSideBorders().alignUnder(view: displayNameTop,withMargin:sip_address_margin_top).done()
|
sipAddress.matchParentSideBorders().alignUnder(view: displayNameTop,withMargin:sip_address_margin_top).done()
|
||||||
|
|
@ -138,6 +139,8 @@ class ActiveCallView: UIView { // = currentCall
|
||||||
})
|
})
|
||||||
recordCallButtons.append(recordCall)
|
recordCallButtons.append(recordCall)
|
||||||
recordPauseView.addArrangedSubview(recordCall)
|
recordPauseView.addArrangedSubview(recordCall)
|
||||||
|
recordCall.accessibilityIdentifier = "active_call_upper_section_record"
|
||||||
|
recordCall.accessibilityLabel = "Record Call"
|
||||||
|
|
||||||
// Pause (with video)
|
// Pause (with video)
|
||||||
var pauseCall = CallControlButton(width: record_pause_button_size, height: record_pause_button_size, imageInset:record_pause_button_inset, buttonTheme: VoipTheme.call_pause, onClickAction: {
|
var pauseCall = CallControlButton(width: record_pause_button_size, height: record_pause_button_size, imageInset:record_pause_button_inset, buttonTheme: VoipTheme.call_pause, onClickAction: {
|
||||||
|
|
@ -146,6 +149,8 @@ class ActiveCallView: UIView { // = currentCall
|
||||||
pauseCallButtons.append(pauseCall)
|
pauseCallButtons.append(pauseCall)
|
||||||
recordPauseView.addArrangedSubview(pauseCall)
|
recordPauseView.addArrangedSubview(pauseCall)
|
||||||
upperSection.addArrangedSubview(recordPauseView)
|
upperSection.addArrangedSubview(recordPauseView)
|
||||||
|
pauseCall.accessibilityIdentifier = "active_call_upper_section_pause"
|
||||||
|
pauseCall.accessibilityLabel = "Pause Call"
|
||||||
|
|
||||||
|
|
||||||
stack.addArrangedSubview(upperSection)
|
stack.addArrangedSubview(upperSection)
|
||||||
|
|
@ -153,12 +158,13 @@ class ActiveCallView: UIView { // = currentCall
|
||||||
|
|
||||||
|
|
||||||
stack.addArrangedSubview(remotelyRecordedIndicator)
|
stack.addArrangedSubview(remotelyRecordedIndicator)
|
||||||
remotelyRecordedIndicator.matchParentSideBorders().height(CGFloat(ActiveCallView.remote_recording_height)).done()
|
remotelyRecordedIndicator.matchParentSideBorders().height(CGFloat(ActiveCallView.remote_recording_height)).done()
|
||||||
|
|
||||||
// Center Section : Avatar + video + record/pause buttons + videos
|
// Center Section : Avatar + video + record/pause buttons + videos
|
||||||
centerSection.layer.cornerRadius = ActiveCallView.center_view_corner_radius
|
centerSection.layer.cornerRadius = ActiveCallView.center_view_corner_radius
|
||||||
centerSection.clipsToBounds = true
|
centerSection.clipsToBounds = true
|
||||||
centerSection.backgroundColor = VoipTheme.voipParticipantBackgroundColor.get()
|
centerSection.backgroundColor = VoipTheme.voipParticipantBackgroundColor.get()
|
||||||
|
//centerSection.removeConstraints().matchParentSideBorders().alignUnder(view: remotelyRecordedIndicator, withMargin: ActiveCallView.center_view_margin_top).alignParentBottom().done()
|
||||||
|
|
||||||
// Record (w/o video)
|
// Record (w/o video)
|
||||||
recordCall = CallControlButton(width: record_pause_button_size, height: record_pause_button_size, imageInset:record_pause_button_inset, buttonTheme: VoipTheme.call_record, onClickAction: {
|
recordCall = CallControlButton(width: record_pause_button_size, height: record_pause_button_size, imageInset:record_pause_button_inset, buttonTheme: VoipTheme.call_record, onClickAction: {
|
||||||
|
|
@ -167,6 +173,8 @@ class ActiveCallView: UIView { // = currentCall
|
||||||
recordCallButtons.append(recordCall)
|
recordCallButtons.append(recordCall)
|
||||||
centerSection.addSubview(recordCall)
|
centerSection.addSubview(recordCall)
|
||||||
recordCall.alignParentLeft(withMargin:record_pause_button_margin).alignParentTop(withMargin:record_pause_button_margin).done()
|
recordCall.alignParentLeft(withMargin:record_pause_button_margin).alignParentTop(withMargin:record_pause_button_margin).done()
|
||||||
|
recordCall.accessibilityIdentifier = "active_call_center_section_record"
|
||||||
|
recordCall.accessibilityLabel = "Record Call"
|
||||||
|
|
||||||
// Pause (w/o video)
|
// Pause (w/o video)
|
||||||
pauseCall = CallControlButton(width: record_pause_button_size, height: record_pause_button_size, imageInset:record_pause_button_inset, buttonTheme: VoipTheme.call_pause, onClickAction: {
|
pauseCall = CallControlButton(width: record_pause_button_size, height: record_pause_button_size, imageInset:record_pause_button_inset, buttonTheme: VoipTheme.call_pause, onClickAction: {
|
||||||
|
|
@ -175,9 +183,12 @@ class ActiveCallView: UIView { // = currentCall
|
||||||
pauseCallButtons.append(pauseCall)
|
pauseCallButtons.append(pauseCall)
|
||||||
centerSection.addSubview(pauseCall)
|
centerSection.addSubview(pauseCall)
|
||||||
pauseCall.alignParentRight(withMargin:record_pause_button_margin).alignParentTop(withMargin:record_pause_button_margin).done()
|
pauseCall.alignParentRight(withMargin:record_pause_button_margin).alignParentTop(withMargin:record_pause_button_margin).done()
|
||||||
|
pauseCall.accessibilityIdentifier = "active_call_center_section_pause"
|
||||||
|
pauseCall.accessibilityLabel = "Pause Call"
|
||||||
|
|
||||||
// Avatar
|
// Avatar
|
||||||
centerSection.addSubview(avatar)
|
centerSection.addSubview(avatar)
|
||||||
|
avatar.square(Avatar.diameter_for_call_views).center().done()
|
||||||
|
|
||||||
// Remote Video Display
|
// Remote Video Display
|
||||||
centerSection.addSubview(remoteVideo)
|
centerSection.addSubview(remoteVideo)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import linphonesw
|
import linphonesw
|
||||||
|
|
||||||
@objc class CallStatsView: UIView {
|
|
||||||
|
@objc class CallStatsView: UIView{
|
||||||
|
|
||||||
// Layout constants
|
// Layout constants
|
||||||
let side_margins = 10.0
|
let side_margins = 10.0
|
||||||
|
|
@ -34,38 +35,44 @@ import linphonesw
|
||||||
layer.cornerRadius = corner_radius
|
layer.cornerRadius = corner_radius
|
||||||
clipsToBounds = true
|
clipsToBounds = true
|
||||||
superView.addSubview(self)
|
superView.addSubview(self)
|
||||||
matchParentSideBorders(insetedByDx: side_margins).alignParentTop(withMargin: marginTop).alignAbove(view: above,withMargin: SharedLayoutConstants.buttons_bottom_margin).done()
|
matchParentSideBorders(insetedByDx: side_margins).alignParentTop(withMargin: marginTop).alignParentBottom().done()
|
||||||
|
accessibilityIdentifier = "call_stats_view"
|
||||||
|
accessibilityViewIsModal = true
|
||||||
|
|
||||||
callData.callState.observe { state in
|
callData.callState.observe { state in
|
||||||
if (state == Call.State.End) {
|
if (state == Call.State.End) {
|
||||||
onDismissAction()
|
onDismissAction()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hide call stats button
|
||||||
let hide = CallControlButton(buttonTheme: VoipTheme.voip_cancel_light, onClickAction: {
|
let hide = CallControlButton(buttonTheme: VoipTheme.voip_cancel_light, onClickAction: {
|
||||||
onDismissAction()
|
onDismissAction()
|
||||||
})
|
})
|
||||||
addSubview(hide)
|
addSubview(hide)
|
||||||
hide.alignParentRight(withMargin: side_margins).alignParentTop(withMargin: side_margins).done()
|
hide.alignParentRight(withMargin: side_margins).alignParentTop(withMargin: side_margins).done()
|
||||||
|
hide.accessibilityIdentifier = "call_stats_view_hide"
|
||||||
|
hide.accessibilityLabel = "Hide"
|
||||||
|
|
||||||
|
// Audio Stats Title
|
||||||
let model = CallStatisticsData(call: callData.call)
|
let model = CallStatisticsData(call: callData.call)
|
||||||
let audioTitle = StyledLabel(VoipTheme.call_stats_font_title,NSLocalizedString("Audio", comment: ""))
|
let audioTitle = StyledLabel(VoipTheme.call_stats_font_title,NSLocalizedString("Audio", comment: ""))
|
||||||
addSubview(audioTitle)
|
addSubview(audioTitle)
|
||||||
audioTitle.matchParentSideBorders().alignParentTop(withMargin: margin_top).done()
|
audioTitle.matchParentSideBorders().alignParentTop(withMargin: margin_top).done()
|
||||||
|
|
||||||
|
// Audio Stats Corp
|
||||||
let audioStats = StyledLabel(VoipTheme.call_stats_font)
|
let audioStats = StyledLabel(VoipTheme.call_stats_font)
|
||||||
|
|
||||||
audioStats.numberOfLines = 0
|
audioStats.numberOfLines = 0
|
||||||
addSubview(audioStats)
|
addSubview(audioStats)
|
||||||
audioStats.matchParentSideBorders().alignUnder(view: audioTitle).done()
|
audioStats.matchParentSideBorders().alignUnder(view: audioTitle).done()
|
||||||
|
|
||||||
|
// Video Stats Title
|
||||||
let videoTitle = StyledLabel(VoipTheme.call_stats_font_title,NSLocalizedString("Video", comment: ""))
|
let videoTitle = StyledLabel(VoipTheme.call_stats_font_title,NSLocalizedString("Video", comment: ""))
|
||||||
addSubview(videoTitle)
|
addSubview(videoTitle)
|
||||||
videoTitle.alignUnder(view: audioStats, withMargin:audio_video_margin).matchParentSideBorders().done()
|
videoTitle.alignUnder(view: audioStats, withMargin:audio_video_margin).matchParentSideBorders().done()
|
||||||
|
|
||||||
|
// Video Stats Corp
|
||||||
let videoStats = StyledLabel(VoipTheme.call_stats_font)
|
let videoStats = StyledLabel(VoipTheme.call_stats_font)
|
||||||
|
|
||||||
videoStats.numberOfLines = 0
|
videoStats.numberOfLines = 0
|
||||||
addSubview(videoStats)
|
addSubview(videoStats)
|
||||||
videoStats.matchParentSideBorders().alignUnder(view: videoTitle).done()
|
videoStats.matchParentSideBorders().alignUnder(view: videoTitle).done()
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import linphonesw
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
super.init(title: VoipTexts.call_action_calls_list)
|
super.init(title: VoipTexts.call_action_calls_list)
|
||||||
|
accessibilityIdentifier = "calls_list_view"
|
||||||
|
|
||||||
// New Call
|
// New Call
|
||||||
let newCall = CallControlButton(width: buttons_size,height: buttons_size, imageInset:UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10), buttonTheme: VoipTheme.call_add, onClickAction: {
|
let newCall = CallControlButton(width: buttons_size,height: buttons_size, imageInset:UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10), buttonTheme: VoipTheme.call_add, onClickAction: {
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ class ControlsView: UIStackView {
|
||||||
controlsViewModel.isMuteMicrophoneEnabled.readCurrentAndObserve { (enabled) in
|
controlsViewModel.isMuteMicrophoneEnabled.readCurrentAndObserve { (enabled) in
|
||||||
mute.isEnabled = enabled == true
|
mute.isEnabled = enabled == true
|
||||||
}
|
}
|
||||||
|
mute.accessibilityIdentifier = "call_control_view_mute"
|
||||||
|
mute.accessibilityLabel = "Mute"
|
||||||
|
|
||||||
// Speaker
|
// Speaker
|
||||||
let speaker = CallControlButton(buttonTheme: VoipTheme.call_speaker, onClickAction: {
|
let speaker = CallControlButton(buttonTheme: VoipTheme.call_speaker, onClickAction: {
|
||||||
|
|
@ -52,6 +54,8 @@ class ControlsView: UIStackView {
|
||||||
controlsViewModel.isSpeakerSelected.readCurrentAndObserve { (selected) in
|
controlsViewModel.isSpeakerSelected.readCurrentAndObserve { (selected) in
|
||||||
speaker.isSelected = selected == true
|
speaker.isSelected = selected == true
|
||||||
}
|
}
|
||||||
|
speaker.accessibilityIdentifier = "call_control_view_speaker"
|
||||||
|
speaker.accessibilityLabel = "Speaker"
|
||||||
|
|
||||||
// Audio routes
|
// Audio routes
|
||||||
let routes = CallControlButton(buttonTheme: VoipTheme.call_audio_route, onClickAction: {
|
let routes = CallControlButton(buttonTheme: VoipTheme.call_audio_route, onClickAction: {
|
||||||
|
|
@ -93,6 +97,8 @@ class ControlsView: UIStackView {
|
||||||
controlsViewModel.isVideoUpdateInProgress.readCurrentAndObserve { (updateInProgress) in
|
controlsViewModel.isVideoUpdateInProgress.readCurrentAndObserve { (updateInProgress) in
|
||||||
video.isEnabled = updateInProgress != true && controlsViewModel.isVideoAvailable.value == true
|
video.isEnabled = updateInProgress != true && controlsViewModel.isVideoAvailable.value == true
|
||||||
}
|
}
|
||||||
|
video.accessibilityIdentifier = "call_control_view_video"
|
||||||
|
video.accessibilityLabel = "Video"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ class DismissableView: UIView {
|
||||||
})
|
})
|
||||||
headerView.addSubview(dismiss!)
|
headerView.addSubview(dismiss!)
|
||||||
dismiss?.alignParentRight(withMargin: dismiss_right_margin).centerY().done()
|
dismiss?.alignParentRight(withMargin: dismiss_right_margin).centerY().done()
|
||||||
|
dismiss?.accessibilityIdentifier = "dismissable_view_close"
|
||||||
|
|
||||||
let title = StyledLabel(VoipTheme.calls_list_header_font,title)
|
let title = StyledLabel(VoipTheme.calls_list_header_font,title)
|
||||||
headerView.addSubview(title)
|
headerView.addSubview(title)
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,8 @@ import linphonesw
|
||||||
|
|
||||||
var callData: CallData? = nil {
|
var callData: CallData? = nil {
|
||||||
didSet {
|
didSet {
|
||||||
duration.call = callData?.call.dir == .Incoming ? callData?.call : nil
|
//duration.call = callData?.call.dir == .Incoming ? callData?.call : nil
|
||||||
|
duration.call = callData?.call
|
||||||
callData?.call.remoteAddress.map {
|
callData?.call.remoteAddress.map {
|
||||||
avatar.fillFromAddress(address: $0)
|
avatar.fillFromAddress(address: $0)
|
||||||
displayName.text = $0.addressBookEnhancedDisplayName()
|
displayName.text = $0.addressBookEnhancedDisplayName()
|
||||||
|
|
@ -56,9 +57,11 @@ import linphonesw
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
view.backgroundColor = VoipTheme.voipBackgroundColor.get()
|
view.backgroundColor = VoipTheme.voipBackgroundColor.get()
|
||||||
|
view.accessibilityIdentifier = "IO_call_view"
|
||||||
|
|
||||||
view.addSubview(spinner)
|
view.addSubview(spinner)
|
||||||
spinner.square(IncomingOutgoingCommonView.spinner_size).matchParentSideBorders().alignParentTop(withMargin:IncomingOutgoingCommonView.spinner_margin_top + UIDevice.notchHeight()).done()
|
spinner.square(IncomingOutgoingCommonView.spinner_size).matchParentSideBorders().alignParentTop(withMargin:IncomingOutgoingCommonView.spinner_margin_top + UIDevice.notchHeight()).done()
|
||||||
|
spinner.accessibilityIdentifier = "IO_call_view_spinner"
|
||||||
|
|
||||||
let callType = StyledLabel(VoipTheme.call_header_title,forCallType)
|
let callType = StyledLabel(VoipTheme.call_header_title,forCallType)
|
||||||
view.addSubview(callType)
|
view.addSubview(callType)
|
||||||
|
|
@ -66,16 +69,19 @@ import linphonesw
|
||||||
|
|
||||||
self.view.addSubview(duration)
|
self.view.addSubview(duration)
|
||||||
duration.matchParentSideBorders().alignUnder(view:callType,withMargin:IncomingOutgoingCommonView.duration_margin_top).done()
|
duration.matchParentSideBorders().alignUnder(view:callType,withMargin:IncomingOutgoingCommonView.duration_margin_top).done()
|
||||||
|
duration.accessibilityIdentifier = "IO_call_view_duration"
|
||||||
|
|
||||||
// Center : Avatar + Display name + SIP Address
|
// Center : Avatar + Display name + SIP Address
|
||||||
let centerSection = UIView()
|
let centerSection = UIView()
|
||||||
centerSection.addSubview(avatar)
|
centerSection.addSubview(avatar)
|
||||||
|
avatar.square(Avatar.diameter_for_call_views).center().done()
|
||||||
centerSection.addSubview(displayName)
|
centerSection.addSubview(displayName)
|
||||||
displayName.height(IncomingOutgoingCommonView.display_name_height).matchParentSideBorders().alignUnder(view:avatar,withMargin:IncomingOutgoingCommonView.display_name_margin_top).done()
|
displayName.height(IncomingOutgoingCommonView.display_name_height).matchParentSideBorders().alignUnder(view:avatar,withMargin:IncomingOutgoingCommonView.display_name_margin_top).done()
|
||||||
centerSection.addSubview(sipAddress)
|
centerSection.addSubview(sipAddress)
|
||||||
sipAddress.height(IncomingOutgoingCommonView.sip_address_height).matchParentSideBorders().alignUnder(view:displayName,withMargin:IncomingOutgoingCommonView.sip_address_margin_top).done()
|
sipAddress.height(IncomingOutgoingCommonView.sip_address_height).matchParentSideBorders().alignUnder(view:displayName,withMargin:IncomingOutgoingCommonView.sip_address_margin_top).done()
|
||||||
self.view.addSubview(centerSection)
|
self.view.addSubview(centerSection)
|
||||||
centerSection.matchParentSideBorders().center().done()
|
centerSection.matchParentDimmensions().center().done()
|
||||||
|
|
||||||
|
|
||||||
layoutRotatableElements()
|
layoutRotatableElements()
|
||||||
}
|
}
|
||||||
|
|
@ -101,6 +107,7 @@ import linphonesw
|
||||||
|
|
||||||
override func viewWillDisappear(_ animated: Bool) {
|
override func viewWillDisappear(_ animated: Bool) {
|
||||||
spinner.stopRotation()
|
spinner.stopRotation()
|
||||||
|
duration.call = nil
|
||||||
super.viewWillDisappear(animated)
|
super.viewWillDisappear(animated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,9 @@ import linphonesw
|
||||||
layer.cornerRadius = corner_radius
|
layer.cornerRadius = corner_radius
|
||||||
clipsToBounds = true
|
clipsToBounds = true
|
||||||
superView.addSubview(self)
|
superView.addSubview(self)
|
||||||
matchParentSideBorders(insetedByDx: side_margins).alignParentTop(withMargin: marginTop).alignAbove(view: above,withMargin: SharedLayoutConstants.buttons_bottom_margin).done()
|
matchParentSideBorders(insetedByDx: side_margins).alignParentTop(withMargin: marginTop).alignParentBottom().done()
|
||||||
|
accessibilityIdentifier = "call_numpad_view"
|
||||||
|
accessibilityViewIsModal = true
|
||||||
|
|
||||||
callData.callState.observe { state in
|
callData.callState.observe { state in
|
||||||
if (state == Call.State.End) {
|
if (state == Call.State.End) {
|
||||||
|
|
@ -56,6 +58,8 @@ import linphonesw
|
||||||
})
|
})
|
||||||
addSubview(hide)
|
addSubview(hide)
|
||||||
hide.alignParentRight(withMargin: side_margins).alignParentTop(withMargin: side_margins).done()
|
hide.alignParentRight(withMargin: side_margins).alignParentTop(withMargin: side_margins).done()
|
||||||
|
hide.accessibilityIdentifier = "call_numpad_view_hide"
|
||||||
|
hide.accessibilityLabel = "Hide"
|
||||||
|
|
||||||
// DTMF History :
|
// DTMF History :
|
||||||
|
|
||||||
|
|
@ -65,6 +69,7 @@ import linphonesw
|
||||||
callData.enteredDTMF.readCurrentAndObserve { (dtmfs) in
|
callData.enteredDTMF.readCurrentAndObserve { (dtmfs) in
|
||||||
eneteredDtmf.text = dtmfs
|
eneteredDtmf.text = dtmfs
|
||||||
}
|
}
|
||||||
|
eneteredDtmf.accessibilityIdentifier = "call_numpad_view_text_field"
|
||||||
|
|
||||||
// Digit buttons
|
// Digit buttons
|
||||||
|
|
||||||
|
|
@ -86,6 +91,7 @@ import linphonesw
|
||||||
callData.sendDTMF(dtmf: "\(subkey)")
|
callData.sendDTMF(dtmf: "\(subkey)")
|
||||||
})
|
})
|
||||||
newRow.addArrangedSubview(digit)
|
newRow.addArrangedSubview(digit)
|
||||||
|
digit.accessibilityIdentifier = "call_numpad_view_digit_\(subkey)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@ class PausedCallOrConferenceView: UIView {
|
||||||
var icon : UIImageView? = nil
|
var icon : UIImageView? = nil
|
||||||
let title = StyledLabel(VoipTheme.call_or_conference_title)
|
let title = StyledLabel(VoipTheme.call_or_conference_title)
|
||||||
let subtitle = StyledLabel(VoipTheme.call_or_conference_subtitle)
|
let subtitle = StyledLabel(VoipTheme.call_or_conference_subtitle)
|
||||||
|
|
||||||
var onClickAction : (()->Void)? = nil
|
var onClickAction : (()->Void)? = nil
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
super.init(coder: coder)
|
super.init(coder: coder)
|
||||||
|
|
@ -44,6 +44,8 @@ class PausedCallOrConferenceView: UIView {
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
|
|
||||||
backgroundColor = VoipTheme.voip_translucent_popup_background
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
accessibilityIdentifier = "paused_call_view"
|
||||||
|
accessibilityViewIsModal = true
|
||||||
|
|
||||||
let centeredView = UIView()
|
let centeredView = UIView()
|
||||||
icon = UIImageView(image: UIImage(named:iconName)?.withPadding(padding: icon_padding))
|
icon = UIImageView(image: UIImage(named:iconName)?.withPadding(padding: icon_padding))
|
||||||
|
|
@ -53,7 +55,8 @@ class PausedCallOrConferenceView: UIView {
|
||||||
icon!.contentMode = .scaleAspectFit
|
icon!.contentMode = .scaleAspectFit
|
||||||
centeredView.addSubview(icon!)
|
centeredView.addSubview(icon!)
|
||||||
icon!.square(icon_size).centerX().done()
|
icon!.square(icon_size).centerX().done()
|
||||||
|
icon?.accessibilityIdentifier = "paused_call_view_icon"
|
||||||
|
|
||||||
title.numberOfLines = 0
|
title.numberOfLines = 0
|
||||||
centeredView.addSubview(title)
|
centeredView.addSubview(title)
|
||||||
title.alignUnder(view:icon!, withMargin:title_margin_top).matchParentSideBorders().done()
|
title.alignUnder(view:icon!, withMargin:title_margin_top).matchParentSideBorders().done()
|
||||||
|
|
@ -66,6 +69,11 @@ class PausedCallOrConferenceView: UIView {
|
||||||
|
|
||||||
self.addSubview(centeredView)
|
self.addSubview(centeredView)
|
||||||
centeredView.center().matchParentSideBorders().wrapContentY().done()
|
centeredView.center().matchParentSideBorders().wrapContentY().done()
|
||||||
|
|
||||||
|
self.onClickAction = onClickAction
|
||||||
|
icon!.onClick {
|
||||||
|
self.onClickAction?()
|
||||||
|
}
|
||||||
|
|
||||||
self.onClickAction = onClickAction
|
self.onClickAction = onClickAction
|
||||||
icon!.onClick {
|
icon!.onClick {
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ class RemotelyRecordingView: UIView {
|
||||||
addSubview(icon)
|
addSubview(icon)
|
||||||
icon.square(height).toLeftOf(label).done()
|
icon.square(height).toLeftOf(label).done()
|
||||||
|
|
||||||
isHidden = true
|
isHidden = true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,10 @@ class VoipExtraButtonsView: UIStackView {
|
||||||
axis = .vertical
|
axis = .vertical
|
||||||
distribution = .fillEqually
|
distribution = .fillEqually
|
||||||
alignment = .center
|
alignment = .center
|
||||||
|
|
||||||
layer.cornerRadius = corner_radius
|
layer.cornerRadius = corner_radius
|
||||||
clipsToBounds = true
|
clipsToBounds = true
|
||||||
|
accessibilityIdentifier = "active_call_extra_buttons_view"
|
||||||
|
accessibilityViewIsModal = true
|
||||||
|
|
||||||
let background = UIView()
|
let background = UIView()
|
||||||
background.backgroundColor = VoipTheme.voipExtraButtonsBackgroundColor.get()
|
background.backgroundColor = VoipTheme.voipExtraButtonsBackgroundColor.get()
|
||||||
|
|
@ -60,19 +61,22 @@ class VoipExtraButtonsView: UIStackView {
|
||||||
|
|
||||||
// First row
|
// First row
|
||||||
let numpad = VoipExtraButton(text: VoipTexts.call_action_numpad, buttonTheme: VoipTheme.call_action("voip_call_numpad"),onClickAction: {
|
let numpad = VoipExtraButton(text: VoipTexts.call_action_numpad, buttonTheme: VoipTheme.call_action("voip_call_numpad"),onClickAction: {
|
||||||
ControlsViewModel.shared.numpadVisible.value = true
|
ControlsViewModel.shared.numpadVisible.value = true
|
||||||
})
|
})
|
||||||
row1.addArrangedSubview(numpad)
|
row1.addArrangedSubview(numpad)
|
||||||
|
numpad.accessibilityIdentifier = "active_call_extra_buttons_numpad"
|
||||||
|
|
||||||
let stats = VoipExtraButton(text: VoipTexts.call_action_statistics, buttonTheme: VoipTheme.call_action("voip_call_stats"),onClickAction: {
|
let stats = VoipExtraButton(text: VoipTexts.call_action_statistics, buttonTheme: VoipTheme.call_action("voip_call_stats"),onClickAction: {
|
||||||
ControlsViewModel.shared.callStatsVisible.value = true
|
ControlsViewModel.shared.callStatsVisible.value = true
|
||||||
})
|
})
|
||||||
row1.addArrangedSubview(stats)
|
row1.addArrangedSubview(stats)
|
||||||
|
stats.accessibilityIdentifier = "active_call_extra_buttons_stats"
|
||||||
|
|
||||||
let chats = VoipExtraButton(text: VoipTexts.call_action_chat, buttonTheme: VoipTheme.call_action("voip_call_chat"),withbBoucinCounterDataSource:CallsViewModel.shared.currentCallUnreadChatMessageCount, onClickAction: {
|
let chats = VoipExtraButton(text: VoipTexts.call_action_chat, buttonTheme: VoipTheme.call_action("voip_call_chat"),withbBoucinCounterDataSource:CallsViewModel.shared.currentCallUnreadChatMessageCount, onClickAction: {
|
||||||
ControlsViewModel.shared.goToChatEvent.notifyAllObservers(with: true)
|
ControlsViewModel.shared.goToChatEvent.notifyAllObservers(with: true)
|
||||||
})
|
})
|
||||||
row1.addArrangedSubview(chats)
|
row1.addArrangedSubview(chats)
|
||||||
|
chats.accessibilityIdentifier = "active_call_extra_buttons_chats"
|
||||||
|
|
||||||
addArrangedSubview(row1)
|
addArrangedSubview(row1)
|
||||||
row1.matchParentSideBorders().done()
|
row1.matchParentSideBorders().done()
|
||||||
|
|
@ -91,12 +95,13 @@ class VoipExtraButtonsView: UIStackView {
|
||||||
PhoneMainView.instance().changeCurrentView(view.compositeViewDescription())
|
PhoneMainView.instance().changeCurrentView(view.compositeViewDescription())
|
||||||
})
|
})
|
||||||
row2.addArrangedSubview(transfer)
|
row2.addArrangedSubview(transfer)
|
||||||
|
transfer.accessibilityIdentifier = "active_call_extra_buttons_transfer"
|
||||||
|
|
||||||
let participants = VoipExtraButton(text: VoipTexts.call_action_participants_list, buttonTheme: VoipTheme.call_action("voip_call_participants"),onClickAction: {
|
let participants = VoipExtraButton(text: VoipTexts.call_action_participants_list, buttonTheme: VoipTheme.call_action("voip_call_participants"),onClickAction: {
|
||||||
ControlsViewModel.shared.goToConferenceParticipantsListEvent.notifyAllObservers(with: true)
|
ControlsViewModel.shared.goToConferenceParticipantsListEvent.notifyAllObservers(with: true)
|
||||||
})
|
})
|
||||||
row2.addArrangedSubview(participants)
|
row2.addArrangedSubview(participants)
|
||||||
|
participants.accessibilityIdentifier = "active_call_extra_buttons_participants"
|
||||||
|
|
||||||
let addcall = VoipExtraButton(text: VoipTexts.call_action_add_call, buttonTheme: VoipTheme.call_action("voip_call_add"),onClickAction: {
|
let addcall = VoipExtraButton(text: VoipTexts.call_action_add_call, buttonTheme: VoipTheme.call_action("voip_call_add"),onClickAction: {
|
||||||
let view: DialerView = self.VIEW(DialerView.compositeViewDescription());
|
let view: DialerView = self.VIEW(DialerView.compositeViewDescription());
|
||||||
|
|
@ -105,17 +110,19 @@ class VoipExtraButtonsView: UIStackView {
|
||||||
PhoneMainView.instance().changeCurrentView(view.compositeViewDescription())
|
PhoneMainView.instance().changeCurrentView(view.compositeViewDescription())
|
||||||
})
|
})
|
||||||
row2.addArrangedSubview(addcall)
|
row2.addArrangedSubview(addcall)
|
||||||
|
addcall.accessibilityIdentifier = "active_call_extra_buttons_add_call"
|
||||||
|
|
||||||
let layoutselect = VoipExtraButton(text: VoipTexts.call_action_change_conf_layout, buttonTheme: VoipTheme.call_action("voip_conference_mosaic"),onClickAction: {
|
let layoutselect = VoipExtraButton(text: VoipTexts.call_action_change_conf_layout, buttonTheme: VoipTheme.call_action("voip_conference_mosaic"),onClickAction: {
|
||||||
ControlsViewModel.shared.goToConferenceLayoutSettings.notifyAllObservers(with: true)
|
ControlsViewModel.shared.goToConferenceLayoutSettings.notifyAllObservers(with: true)
|
||||||
})
|
})
|
||||||
row2.addArrangedSubview(layoutselect)
|
row2.addArrangedSubview(layoutselect)
|
||||||
|
layoutselect.accessibilityIdentifier = "active_call_extra_buttons_layout_select"
|
||||||
|
|
||||||
let calls = VoipExtraButton(text: VoipTexts.call_action_calls_list, buttonTheme: VoipTheme.call_action("voip_calls_list"), withbBoucinCounterDataSource: CallsViewModel.shared.inactiveCallsCount, onClickAction: {
|
let calls = VoipExtraButton(text: VoipTexts.call_action_calls_list, buttonTheme: VoipTheme.call_action("voip_calls_list"), withbBoucinCounterDataSource: CallsViewModel.shared.inactiveCallsCount, onClickAction: {
|
||||||
ControlsViewModel.shared.goToCallsListEvent.notifyAllObservers(with: true)
|
ControlsViewModel.shared.goToCallsListEvent.notifyAllObservers(with: true)
|
||||||
})
|
})
|
||||||
row2.addArrangedSubview(calls)
|
row2.addArrangedSubview(calls)
|
||||||
|
calls.accessibilityIdentifier = "active_call_extra_buttons_calls"
|
||||||
|
|
||||||
addArrangedSubview(row2)
|
addArrangedSubview(row2)
|
||||||
row2.matchParentSideBorders().done()
|
row2.matchParentSideBorders().done()
|
||||||
|
|
|
||||||
134
Classes/Swift/Voip/VoipDialog_BACKUP_1064.swift
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
<<<<<<< HEAD
|
||||||
|
let title_margin_sides = 10.0
|
||||||
|
=======
|
||||||
|
let title_side_margin = 10
|
||||||
|
>>>>>>> 4b91fc131 (all)
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
<<<<<<< HEAD
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: title_margin_sides).done()
|
||||||
|
=======
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: CGFloat(title_side_margin)).done()
|
||||||
|
>>>>>>> 4b91fc131 (all)
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
134
Classes/Swift/Voip/VoipDialog_BACKUP_1156.swift
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
<<<<<<< HEAD
|
||||||
|
let title_margin_sides = 10.0
|
||||||
|
=======
|
||||||
|
let title_side_margin = 10
|
||||||
|
>>>>>>> 4b91fc131 (all)
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
<<<<<<< HEAD
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: title_margin_sides).done()
|
||||||
|
=======
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: CGFloat(title_side_margin)).done()
|
||||||
|
>>>>>>> 4b91fc131 (all)
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
134
Classes/Swift/Voip/VoipDialog_BACKUP_884.swift
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
<<<<<<< HEAD
|
||||||
|
let title_margin_sides = 10.0
|
||||||
|
=======
|
||||||
|
let title_side_margin = 10
|
||||||
|
>>>>>>> 4b91fc131 (all)
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
<<<<<<< HEAD
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: title_margin_sides).done()
|
||||||
|
=======
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: CGFloat(title_side_margin)).done()
|
||||||
|
>>>>>>> 4b91fc131 (all)
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
134
Classes/Swift/Voip/VoipDialog_BACKUP_973.swift
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
<<<<<<< HEAD
|
||||||
|
let title_margin_sides = 10.0
|
||||||
|
=======
|
||||||
|
let title_side_margin = 10
|
||||||
|
>>>>>>> 4b91fc131 (all)
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
<<<<<<< HEAD
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: title_margin_sides).done()
|
||||||
|
=======
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: CGFloat(title_side_margin)).done()
|
||||||
|
>>>>>>> 4b91fc131 (all)
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
126
Classes/Swift/Voip/VoipDialog_BASE_1064.swift
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders().done()
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
126
Classes/Swift/Voip/VoipDialog_BASE_1156.swift
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders().done()
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
126
Classes/Swift/Voip/VoipDialog_BASE_884.swift
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders().done()
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
126
Classes/Swift/Voip/VoipDialog_BASE_973.swift
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders().done()
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
126
Classes/Swift/Voip/VoipDialog_LOCAL_1064.swift
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
let title_margin_sides = 10.0
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: title_margin_sides).done()
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
126
Classes/Swift/Voip/VoipDialog_LOCAL_1156.swift
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
let title_margin_sides = 10.0
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: title_margin_sides).done()
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
126
Classes/Swift/Voip/VoipDialog_LOCAL_884.swift
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
let title_margin_sides = 10.0
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: title_margin_sides).done()
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
126
Classes/Swift/Voip/VoipDialog_LOCAL_973.swift
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
let title_margin_sides = 10.0
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: title_margin_sides).done()
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
127
Classes/Swift/Voip/VoipDialog_REMOTE_1064.swift
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
let title_side_margin = 10
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: CGFloat(title_side_margin)).done()
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
127
Classes/Swift/Voip/VoipDialog_REMOTE_1156.swift
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
let title_side_margin = 10
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: CGFloat(title_side_margin)).done()
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
127
Classes/Swift/Voip/VoipDialog_REMOTE_884.swift
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
let title_side_margin = 10
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: CGFloat(title_side_margin)).done()
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
127
Classes/Swift/Voip/VoipDialog_REMOTE_973.swift
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VoipDialog : UIView{
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
let center_corner_radius = 7.0
|
||||||
|
let title_margin_top = 20
|
||||||
|
let title_side_margin = 10
|
||||||
|
let button_margin = 20.0
|
||||||
|
let button_width = 135.0
|
||||||
|
let button_height = 40.0
|
||||||
|
let button_radius = 3.0
|
||||||
|
let button_spacing = 15.0
|
||||||
|
|
||||||
|
let center_view_sides_margin = 13.0
|
||||||
|
|
||||||
|
|
||||||
|
let title = StyledLabel(VoipTheme.basic_popup_title)
|
||||||
|
|
||||||
|
init(message:String, givenButtons:[ButtonAttributes]? = nil) {
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
backgroundColor = VoipTheme.voip_translucent_popup_background
|
||||||
|
|
||||||
|
let centerView = UIView()
|
||||||
|
centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8)
|
||||||
|
centerView.layer.cornerRadius = center_corner_radius
|
||||||
|
centerView.clipsToBounds = true
|
||||||
|
addSubview(centerView)
|
||||||
|
|
||||||
|
title.numberOfLines = 0
|
||||||
|
centerView.addSubview(title)
|
||||||
|
title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders(insetedByDx: CGFloat(title_side_margin)).done()
|
||||||
|
title.text = message
|
||||||
|
|
||||||
|
let buttonsView = UIStackView()
|
||||||
|
buttonsView.axis = .horizontal
|
||||||
|
buttonsView.spacing = button_spacing
|
||||||
|
|
||||||
|
var buttons = givenButtons
|
||||||
|
|
||||||
|
if (buttons == nil) { // assuming info popup, just putting an ok button
|
||||||
|
let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false)
|
||||||
|
buttons = [ok]
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons?.forEach {
|
||||||
|
let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background)
|
||||||
|
b.setTitle($0.text, for: .normal)
|
||||||
|
b.layer.cornerRadius = button_radius
|
||||||
|
b.clipsToBounds = true
|
||||||
|
buttonsView.addArrangedSubview(b)
|
||||||
|
b.applyTitleStyle(VoipTheme.form_button_bold)
|
||||||
|
let action = $0.action
|
||||||
|
b.onClick {
|
||||||
|
self.removeFromSuperview()
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
b.size(w: button_width,h: button_height).done()
|
||||||
|
}
|
||||||
|
centerView.addSubview(buttonsView)
|
||||||
|
buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func show() {
|
||||||
|
VoipDialog.rootVC()?.view.addSubview(self)
|
||||||
|
matchParentDimmensions().done()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func rootVC() -> UIViewController? {
|
||||||
|
return PhoneMainView.instance().mainViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var toastQueue: [String] = []
|
||||||
|
|
||||||
|
static func toast(message:String, timeout:CGFloat = 1.5) {
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
toastQueue.append(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
|
||||||
|
rootVC()?.present(alert, animated: true)
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeout) {
|
||||||
|
alert.dismiss(animated: true)
|
||||||
|
if (toastQueue.count > 0) {
|
||||||
|
let message = toastQueue.first
|
||||||
|
toastQueue.remove(at: 0)
|
||||||
|
self.toast(message: message!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonAttributes {
|
||||||
|
let text:String
|
||||||
|
let action: (()->Void)
|
||||||
|
let isDestructive: Bool
|
||||||
|
}
|
||||||
|
|
@ -42,6 +42,8 @@ class Avatar : UIImageView {
|
||||||
self.backgroundColor = color.get()
|
self.backgroundColor = color.get()
|
||||||
addSubview(initialsLabel)
|
addSubview(initialsLabel)
|
||||||
_ = initialsLabel.matchParentSideBorders().matchParentHeight()
|
_ = initialsLabel.matchParentSideBorders().matchParentHeight()
|
||||||
|
accessibilityLabel = "Avatar"
|
||||||
|
isAccessibilityElement = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ class StyledValuePicker: UIView {
|
||||||
|
|
||||||
onClick {
|
onClick {
|
||||||
self.dropDown.anchorView = self.superview
|
self.dropDown.anchorView = self.superview
|
||||||
self.dropDown.tableView.scrollToRow(at: IndexPath(row: liveIndex.value!, section: 0), at: .top, animated: true) // Change visibility to public instead of fileprivate in DropDown.swift
|
/*self.dropDown.tableView.scrollToRow(at: IndexPath(row: liveIndex.value!, section: 0), at: .top, animated: true) // Change visibility to public instead of fileprivate in DropDown.swift*/
|
||||||
self.dropDown.show()
|
self.dropDown.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,19 +25,16 @@ class CallTimer : StyledLabel {
|
||||||
let min_width = 50.0
|
let min_width = 50.0
|
||||||
|
|
||||||
let formatter = DateComponentsFormatter()
|
let formatter = DateComponentsFormatter()
|
||||||
|
var startDate = Date()
|
||||||
var call:Call? = nil {
|
var call:Call? = nil {
|
||||||
didSet {
|
didSet {
|
||||||
if (self.call != nil) {
|
self.format()
|
||||||
self.format()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var conference:Conference? = nil {
|
var conference:Conference? = nil {
|
||||||
didSet {
|
didSet {
|
||||||
if (self.conference != nil) {
|
self.format()
|
||||||
self.format()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,28 +48,24 @@ class CallTimer : StyledLabel {
|
||||||
formatter.unitsStyle = .positional
|
formatter.unitsStyle = .positional
|
||||||
formatter.allowedUnits = [.minute, .second ]
|
formatter.allowedUnits = [.minute, .second ]
|
||||||
formatter.zeroFormattingBehavior = [ .pad ]
|
formatter.zeroFormattingBehavior = [ .pad ]
|
||||||
let startDate = Date()
|
|
||||||
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
|
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
|
||||||
|
var elapsedTime: TimeInterval = 0
|
||||||
if (self.call != nil || self.conference != nil) {
|
if (self.call != nil || self.conference != nil) {
|
||||||
self.format()
|
elapsedTime = Date().timeIntervalSince(self.startDate)
|
||||||
} else {
|
}
|
||||||
let elapsedTime = Date().timeIntervalSince(startDate)
|
self.formatter.string(from: elapsedTime).map {
|
||||||
self.formatter.string(from: elapsedTime).map {
|
self.text = $0.hasPrefix("0:") ? "0" + $0 : $0
|
||||||
self.text = $0.hasPrefix("0:") ? "0" + $0 : $0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
minWidth(min_width).done()
|
minWidth(min_width).done()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func format() {
|
func format() {
|
||||||
guard let duration = self.call != nil ? self.call!.duration : self.conference != nil ? self.conference!.duration: nil else {
|
guard let duration = self.call != nil ? self.call!.duration : self.conference != nil ? self.conference!.duration: nil else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
formatter.string(from: TimeInterval(duration)).map {
|
startDate = Date().advanced(by: -TimeInterval(duration))
|
||||||
self.text = $0.hasPrefix("0:") ? "0" + $0 : $0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
9
Podfile
|
|
@ -51,6 +51,15 @@ target 'msgNotificationContent' do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
target 'CallUITests' do
|
||||||
|
# Uncomment the next line if you're using Swift or would like to use dynamic frameworks
|
||||||
|
use_frameworks!
|
||||||
|
|
||||||
|
# Pods for CallUITests
|
||||||
|
all_pods
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
post_install do |installer|
|
post_install do |installer|
|
||||||
system("sed 's/fileprivate let tableView =/public let tableView =/g' ./Pods/DropDown/DropDown/src/DropDown.swift > tmp.swift && mv -f tmp.swift ./Pods/DropDown/DropDown/src/DropDown.swift")
|
system("sed 's/fileprivate let tableView =/public let tableView =/g' ./Pods/DropDown/DropDown/src/DropDown.swift > tmp.swift && mv -f tmp.swift ./Pods/DropDown/DropDown/src/DropDown.swift")
|
||||||
# Get the version of linphone-sdk
|
# Get the version of linphone-sdk
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 277 B After Width: | Height: | Size: 4.7 KiB |
|
|
@ -14,16 +14,6 @@
|
||||||
<key>DefaultValue</key>
|
<key>DefaultValue</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
<dict>
|
|
||||||
<key>Type</key>
|
|
||||||
<string>PSToggleSwitchSpecifier</string>
|
|
||||||
<key>Title</key>
|
|
||||||
<string>Notify and get notified when call is recorded</string>
|
|
||||||
<key>Key</key>
|
|
||||||
<string>record_aware</string>
|
|
||||||
<key>DefaultValue</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
<dict>
|
||||||
<key>Type</key>
|
<key>Type</key>
|
||||||
<string>PSToggleSwitchSpecifier</string>
|
<string>PSToggleSwitchSpecifier</string>
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,22 @@
|
||||||
<key>Type</key>
|
<key>Type</key>
|
||||||
<string>PSGroupSpecifier</string>
|
<string>PSGroupSpecifier</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>Key</key>
|
||||||
|
<string>dns_server_preference</string>
|
||||||
|
<key>Title</key>
|
||||||
|
<string>DNS Server</string>
|
||||||
|
<key>Type</key>
|
||||||
|
<string>PSTextFieldSpecifier</string>
|
||||||
|
<key>AutocapitalizationType</key>
|
||||||
|
<string>None</string>
|
||||||
|
<key>AutocorrectionType</key>
|
||||||
|
<string>No</string>
|
||||||
|
<key>DefaultValue</key>
|
||||||
|
<string></string>
|
||||||
|
<key>IASKTextAlignment</key>
|
||||||
|
<string>IASKUITextAlignmentRight</string>
|
||||||
|
</dict>
|
||||||
<dict>
|
<dict>
|
||||||
<key>Key</key>
|
<key>Key</key>
|
||||||
<string>adaptive_rate_control_group</string>
|
<string>adaptive_rate_control_group</string>
|
||||||
|
|
|
||||||
96
UITests/CallUITests/ActiveCallUITests.swift
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class ActiveCallUITests: XCTestCase {
|
||||||
|
var methods: ActiveCallViewUITestsMethods!
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
continueAfterFailure = true
|
||||||
|
UITestsUtils.testAppSetup()
|
||||||
|
methods = ActiveCallViewUITestsMethods() //to reload accounts infos if testAppSetup change them
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func testViewDisplay() throws {
|
||||||
|
methods.startActiveCall()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testOpenCallStats() throws {
|
||||||
|
methods.startActiveCall()
|
||||||
|
methods.openCallStatsFromStatusBar()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCloseCallStats() throws {
|
||||||
|
methods.startActiveCall()
|
||||||
|
methods.openCallStatsFromStatusBar()
|
||||||
|
methods.closeCallStatsFromStatusBar()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCallRecord() throws {
|
||||||
|
methods.startActiveCall()
|
||||||
|
methods.startCallRecord()
|
||||||
|
methods.stopCallRecord()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testRemoteCallRecord() throws {
|
||||||
|
methods.startActiveCall()
|
||||||
|
methods.startCallRecord(remote: true)
|
||||||
|
methods.stopCallRecord(remote: true)
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPauseCall() throws {
|
||||||
|
methods.startActiveCall()
|
||||||
|
methods.pauseActiveCall()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testResumeCall() throws {
|
||||||
|
methods.startActiveCall()
|
||||||
|
methods.pauseActiveCall()
|
||||||
|
methods.resumeActiveCall()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testRemotePauseCall() throws {
|
||||||
|
methods.startActiveCall()
|
||||||
|
methods.pauseRemoteCall()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testRemoteResumeCall() throws {
|
||||||
|
methods.startActiveCall()
|
||||||
|
methods.pauseRemoteCall()
|
||||||
|
methods.resumeRemoteCall()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testToggleControls() throws {
|
||||||
|
methods.startActiveCall()
|
||||||
|
methods.toggleCallControls(buttonTag: "speaker", parentView: methods.app.activeCallView)
|
||||||
|
methods.toggleCallControls(buttonTag: "mute",parentView: methods.app.activeCallView)
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testOpenExtraMenu() throws {
|
||||||
|
methods.startActiveCall()
|
||||||
|
methods.openExtraButtonMenu()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCloseExtraMenu() throws {
|
||||||
|
methods.startActiveCall()
|
||||||
|
methods.openExtraButtonMenu()
|
||||||
|
methods.closeExtraButtonMenu()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testHangup() throws {
|
||||||
|
methods.startActiveCall()
|
||||||
|
methods.hangupActiveCall()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
53
UITests/CallUITests/ExtraMenuUITests.swift
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class ExtraMenuUITests: XCTestCase {
|
||||||
|
var methods: ExtraMenuActiveCallActionsUITestsMethods!
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
continueAfterFailure = true
|
||||||
|
UITestsUtils.testAppSetup()
|
||||||
|
methods = ExtraMenuActiveCallActionsUITestsMethods() //to reload accounts infos if testAppSetup change them
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func testViewDisplay() throws {
|
||||||
|
methods.displayExtraMenuButtonView()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testOpenCallStats() throws {
|
||||||
|
methods.displayExtraMenuButtonView()
|
||||||
|
methods.openCallStatsFromExtraMenuButtonView()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCloseCallStats() throws {
|
||||||
|
methods.displayExtraMenuButtonView()
|
||||||
|
methods.openCallStatsFromExtraMenuButtonView()
|
||||||
|
methods.closeCallStatsFromItself()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testOpenCallNumpad() throws {
|
||||||
|
methods.displayExtraMenuButtonView()
|
||||||
|
methods.openCallNumpad()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCloseCallNumpad() throws {
|
||||||
|
methods.displayExtraMenuButtonView()
|
||||||
|
methods.openCallNumpad()
|
||||||
|
methods.closeCallNumpad()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testNumpadtyping() {
|
||||||
|
methods.displayExtraMenuButtonView()
|
||||||
|
methods.openCallNumpad()
|
||||||
|
methods.composeNumpadNumbers()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//to complete with other buttons
|
||||||
|
}
|
||||||
36
UITests/CallUITests/IncomingCallUITests.swift
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class IncomingCallUITests: XCTestCase {
|
||||||
|
var methods: IncomingOutgoingCallViewUITestsMethods!
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
continueAfterFailure = true
|
||||||
|
UITestsUtils.testAppSetup()
|
||||||
|
methods = IncomingOutgoingCallViewUITestsMethods() //to reload accounts infos if testAppSetup changes them
|
||||||
|
}
|
||||||
|
|
||||||
|
func testViewDisplay() throws {
|
||||||
|
methods.startIncomingCall()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testNoAnswer() throws {
|
||||||
|
methods.startIncomingCall()
|
||||||
|
methods.noAnswerIncomingCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testDecline() throws {
|
||||||
|
methods.startIncomingCall()
|
||||||
|
methods.declineIncomingCall()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccept() throws {
|
||||||
|
methods.startIncomingCall()
|
||||||
|
methods.acceptIncomingCall()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
39
UITests/CallUITests/OutgoingCallUITests.swift
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class OutgoingCallUITests: XCTestCase {
|
||||||
|
var methods: IncomingOutgoingCallViewUITestsMethods!
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
continueAfterFailure = true
|
||||||
|
UITestsUtils.testAppSetup()
|
||||||
|
methods = IncomingOutgoingCallViewUITestsMethods() //to reload accounts infos if testAppSetup change them
|
||||||
|
}
|
||||||
|
|
||||||
|
func testViewDisplay() throws {
|
||||||
|
methods.startOutgoingCall()
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testNoAnswer() throws {
|
||||||
|
methods.startOutgoingCall()
|
||||||
|
methods.noAnswerOutgoingCall()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func testToggleMute() throws {
|
||||||
|
methods.startOutgoingCall()
|
||||||
|
methods.toggleCallControls(buttonTag: "mute", parentView: methods.app.callView)
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testToggleSpeaker() throws {
|
||||||
|
methods.startOutgoingCall()
|
||||||
|
methods.toggleCallControls(buttonTag: "speaker", parentView: methods.app.callView)
|
||||||
|
methods.endCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCancel() throws {
|
||||||
|
methods.startOutgoingCall()
|
||||||
|
methods.cancelOutgoingCall()
|
||||||
|
}
|
||||||
|
}
|
||||||
120
UITests/Methods/ActiveCallViewUITestsMethods.swift
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class ActiveCallViewUITestsMethods : IncomingOutgoingCallViewUITestsMethods {
|
||||||
|
|
||||||
|
func startActiveCall() {
|
||||||
|
XCTContext.runActivity(named: "Start Active Call") { _ in
|
||||||
|
startIncomingCall()
|
||||||
|
acceptIncomingCall()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func openCallStatsFromStatusBar() {
|
||||||
|
XCTContext.runActivity(named: "Display Call Stats From Status Bar") { _ in
|
||||||
|
app.representationWithElements.makeBackup(named: "call_stats_closed")
|
||||||
|
app.statusBar.buttons["status_bar_incall_quality"].tap()
|
||||||
|
|
||||||
|
//app.callStatsView.representation.reMake()
|
||||||
|
app.representationWithElements.otherElement = app.callStatsView
|
||||||
|
app.representationWithElements.withElementVariations(mainView: ["shadow"], statusBar: ["call_view"], tabBar: []).check()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeCallStatsFromStatusBar() {
|
||||||
|
XCTContext.runActivity(named: "Hide Call Stats From Status Bar") { _ in
|
||||||
|
app.statusBar.buttons["status_bar_incall_quality"].tap()
|
||||||
|
app.representationWithElements.reloadBackup(named: "call_stats_closed").check()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func startCallRecord(remote: Bool = false) {
|
||||||
|
XCTContext.runActivity(named: "Start \(remote ? "Remote" : "") Call Record") { _ in
|
||||||
|
app.representationWithElements.makeBackup(named: "record_end")
|
||||||
|
if (!remote) {
|
||||||
|
app.activeCallView.buttons["active_call_center_section_record"].tap()
|
||||||
|
//app.activeCallView.representation.withVariations(named: ["record"]).reMake()
|
||||||
|
app.representationWithElements.updateElementVariations(mainView: ["record"], statusBar: [], tabBar: []).check()
|
||||||
|
} else {
|
||||||
|
ghostAccount.startRecording()
|
||||||
|
//app.activeCallView.representation.withVariations(named: ["remote_record"]).reMake()
|
||||||
|
app.representationWithElements.updateElementVariations(mainView: ["remote_record"], statusBar: [], tabBar: []).check()
|
||||||
|
}
|
||||||
|
ghostAccount.waitForRecordingState(recording: true, onRemote: !remote, timeout: 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func stopCallRecord(remote: Bool = false) {
|
||||||
|
XCTContext.runActivity(named: "Stop \(remote ? "Remote" : "") Call Record") { _ in
|
||||||
|
if (!remote) {
|
||||||
|
app.activeCallView.buttons["active_call_center_section_record"].tap()
|
||||||
|
} else {
|
||||||
|
ghostAccount.mCore.currentCall?.stopRecording()
|
||||||
|
}
|
||||||
|
ghostAccount.waitForRecordingState(recording: false, onRemote: !remote, timeout: 5)
|
||||||
|
app.representationWithElements.reloadBackup(named: "record_end").check()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pauseActiveCall() {
|
||||||
|
XCTContext.runActivity(named: "Pause Active Call") { _ in
|
||||||
|
app.representationWithElements.makeBackup(named: "pause_end")
|
||||||
|
app.activeCallView.buttons["active_call_center_section_pause"].tap()
|
||||||
|
//app.activeCallView.representation.withVariations(named: ["pause"]).reMake()
|
||||||
|
app.representationWithElements.updateElementVariations(mainView: ["pause_shadow","pause"], statusBar: [], tabBar: []).check()
|
||||||
|
ghostAccount.waitForCallState(callState: .PausedByRemote, timeout: 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resumeActiveCall() {
|
||||||
|
XCTContext.runActivity(named: "Resume Active Call") { _ in
|
||||||
|
app.activeCallView.images["paused_call_view_icon"].tap()
|
||||||
|
app.representationWithElements.reloadBackup(named: "pause_end").check()
|
||||||
|
ghostAccount.waitForCallState(callState: .StreamsRunning, timeout: 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pauseRemoteCall() {
|
||||||
|
XCTContext.runActivity(named: "Pause Remote Call") { _ in
|
||||||
|
app.representationWithElements.makeBackup(named: "pause_end")
|
||||||
|
ghostAccount.pauseCall()
|
||||||
|
ghostAccount.waitForCallState(callState: .Paused, timeout: 5)
|
||||||
|
//app.activeCallView.representation.withVariations(named: ["remote_pause"]).reMake()
|
||||||
|
app.representationWithElements.updateElementVariations(mainView: ["pause_shadow","remote_pause"], statusBar: [], tabBar: []).check()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resumeRemoteCall() {
|
||||||
|
XCTContext.runActivity(named: "Resume Remote Call") { _ in
|
||||||
|
ghostAccount.resumeCall()
|
||||||
|
ghostAccount.waitForCallState(callState: .StreamsRunning, timeout: 5)
|
||||||
|
app.representationWithElements.reloadBackup(named: "pause_end").check()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func openExtraButtonMenu() {
|
||||||
|
XCTContext.runActivity(named: "Open Extra Menu Button") { _ in
|
||||||
|
app.representationWithElements.makeBackup(named: "extra_menu_closed")
|
||||||
|
app.activeCallView.buttons["active_call_view_extra_buttons"].tap()
|
||||||
|
//app.activeCallView.representation.withVariations(named: ["extra_menu"]).reMake()
|
||||||
|
app.representationWithElements.updateElementVariations(mainView: ["shadow","extra_menu"], statusBar: [], tabBar: []).check()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeExtraButtonMenu() {
|
||||||
|
XCTContext.runActivity(named: "Check Extra Menu View Integrity") { _ in
|
||||||
|
app.activeCallView.otherElements["active_call_view_shading_mask"].tap()
|
||||||
|
app.representationWithElements.reloadBackup(named: "extra_menu_closed").check()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func hangupActiveCall() {
|
||||||
|
XCTContext.runActivity(named: "Hangup Active Call") { _ in
|
||||||
|
app.activeCallView.buttons["active_call_view_hangup"].tap()
|
||||||
|
app.representationWithElements.reloadBackup(named: "call_end").check()
|
||||||
|
ghostAccount.waitForCallState(callState: .Released, timeout: 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
24
UITests/Methods/ConferenceCallViewUITestsMethods.swift
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
//
|
||||||
|
// ConferenceCallViewUITestsMethods.swift
|
||||||
|
// ConferenceUITests
|
||||||
|
//
|
||||||
|
// Created by Quentin Monnier on 05/08/2022.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
import linphonesw
|
||||||
|
|
||||||
|
class ConferrenceCallViewUITestsMethods {
|
||||||
|
|
||||||
|
let app: XCUIApplication
|
||||||
|
let appAccountAuthInfo = UITestsCoreManager.instance.appAccountAuthInfo!
|
||||||
|
let ghostAccounts = UITestsCoreManager.instance.ghostAccounts
|
||||||
|
|
||||||
|
init(app: XCUIApplication) {
|
||||||
|
self.app = app
|
||||||
|
}
|
||||||
|
|
||||||
|
func startOutgoingConference() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class ExtraMenuActiveCallActionsUITestsMethods : ActiveCallViewUITestsMethods {
|
||||||
|
|
||||||
|
func displayExtraMenuButtonView() {
|
||||||
|
startActiveCall()
|
||||||
|
openExtraButtonMenu()
|
||||||
|
}
|
||||||
|
|
||||||
|
func openCallStatsFromExtraMenuButtonView() {
|
||||||
|
app.extraMenuView.buttons["active_call_extra_buttons_stats"].tap()
|
||||||
|
|
||||||
|
app.representationWithElements.otherElement = app.callStatsView
|
||||||
|
app.representationWithElements.withElementVariations(mainView: ["shadow"], statusBar: ["call_view"], tabBar: []).check()
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeCallStatsFromItself() {
|
||||||
|
app.callStatsView.buttons["call_stats_view_hide"].tap()
|
||||||
|
|
||||||
|
app.representationWithElements.reloadBackup(named: "extra_menu_closed").check()
|
||||||
|
}
|
||||||
|
|
||||||
|
func openCallNumpad() {
|
||||||
|
app.extraMenuView.buttons["active_call_extra_buttons_numpad"].tap()
|
||||||
|
|
||||||
|
//app.numpadCallView.representation.reMake()
|
||||||
|
app.representationWithElements.otherElement = app.numpadCallView
|
||||||
|
app.representationWithElements.withElementVariations(mainView: ["shadow"], statusBar: ["call_view"], tabBar: []).check()
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeCallNumpad() {
|
||||||
|
app.numpadCallView.buttons["call_numpad_view_hide"].tap()
|
||||||
|
|
||||||
|
app.representationWithElements.reloadBackup(named: "extra_menu_closed").check()
|
||||||
|
}
|
||||||
|
|
||||||
|
func composeNumpadNumbers() {
|
||||||
|
|
||||||
|
let textField = app.staticTexts["call_numpad_view_text_field"]
|
||||||
|
var digitsLabel = ["1","2","3","4","5","6","7","8","9","*","0","#"]
|
||||||
|
digitsLabel += digitsLabel
|
||||||
|
digitsLabel.shuffle()
|
||||||
|
for label in digitsLabel {
|
||||||
|
app.numpadCallView.buttons["call_numpad_view_digit_\(label)"].tap()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
XCTAssertEqual(textField.label, digitsLabel.joined(), "Text Field value differs from the sequence typed (is equal to \"\(textField.label)\")")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func openView(buttonTag: String, view: View) {
|
||||||
|
let button = app.extraMenuView.buttons["active_call_extra_buttons_\(buttonTag)"].tap()
|
||||||
|
//button.tap(action: .displayView, on: view)
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeView(contextView: View) {
|
||||||
|
let hide = UIObject(identifier: "\(contextView.rawValue)_hide", type: .button, contextView: contextView)
|
||||||
|
//hide.tap(action: .hideView, on: contextView)
|
||||||
|
}
|
||||||
|
|
||||||
|
func backToCall(contextView: View) {
|
||||||
|
let button = UIObject(identifier: "back_to_call", type: .button, contextView: contextView)
|
||||||
|
//button.tap(action: .displayView, on: .ActiveCallView)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkNumpadView() {
|
||||||
|
|
||||||
|
UIObject(identifier: "call_numpad_view_hide", type: .button, contextView: .NumpadView)
|
||||||
|
let textField = UIObject(identifier: "call_numpad_view_text_field", type: .staticText, contextView: .NumpadView).element
|
||||||
|
|
||||||
|
var digitsLabel = ["1","2","3","4","5","6","7","8","9","*","0","#"]
|
||||||
|
digitsLabel += digitsLabel
|
||||||
|
digitsLabel.shuffle()
|
||||||
|
for label in digitsLabel {
|
||||||
|
UIObject(identifier: "call_numpad_view_digit_\(label)", type: .button, contextView: .NumpadView).element.tap()
|
||||||
|
}
|
||||||
|
|
||||||
|
XCTAssertEqual(textField.label, digitsLabel.joined(), "Text Field value differs from the sequence typed (is equal to \"\(textField.label)\")")
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeCallsList() {
|
||||||
|
let hide = UIObject(identifier: "dismissable_view_close", type: .button, contextView: .CallsListView)
|
||||||
|
//hide.tap(action: .hideView, on: .CallsListView)
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
133
UITests/Methods/IncomingOutgoingCallViewUITestsMethods.swift
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
import XCTest
|
||||||
|
import linphonesw
|
||||||
|
|
||||||
|
class IncomingOutgoingCallViewUITestsMethods {
|
||||||
|
|
||||||
|
let app = XCUIApplication()
|
||||||
|
let manager = UITestsCoreManager.instance
|
||||||
|
let appAccountAuthInfo: AuthInfo = UITestsCoreManager.instance.appAccountAuthInfo!
|
||||||
|
let ghostAccount: UITestsRegisteredLinphoneCore = UITestsCoreManager.instance.ghostAccounts[0]
|
||||||
|
|
||||||
|
func startIncomingCall() {
|
||||||
|
XCTContext.runActivity(named: "Start Incoming Call") { _ in
|
||||||
|
if (ghostAccount.callState != .Released) {ghostAccount.terminateCall()}
|
||||||
|
app.representationWithElements.makeBackup(named: "call_end")
|
||||||
|
|
||||||
|
ghostAccount.startCall(adress: manager.createAdress(authInfo: appAccountAuthInfo))
|
||||||
|
ghostAccount.waitForCallState(callState: .OutgoingRinging, timeout: 5)
|
||||||
|
|
||||||
|
_ = app.callView.waitForExistence(timeout: 5)
|
||||||
|
checkCallTime(element: app.callView.staticTexts["IO_call_view_duration"])
|
||||||
|
app.callView.images["IO_call_view_spinner"].representation.isAnimated(timeInterval: 0.5)
|
||||||
|
|
||||||
|
//app.callView.representation.reMake()
|
||||||
|
//app.statusBar.representation.withVariations(named: ["call_view"]).reMake()
|
||||||
|
app.representationWithElements.mainView = app.callView
|
||||||
|
app.representationWithElements.withElementVariations(mainView: [], statusBar: ["call_view"], tabBar: []).check()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func startOutgoingCall() {
|
||||||
|
XCTContext.runActivity(named: "Start Outgoing Call") { _ in
|
||||||
|
if (ghostAccount.callState != .Released) {ghostAccount.terminateCall()}
|
||||||
|
if (!app.dialerView.exists) { app.launch()}
|
||||||
|
app.representationWithElements.makeBackup(named: "call_end")
|
||||||
|
|
||||||
|
app.dialerView.textFields["adress_field"].fillTextField(ghostAccount.mAuthInfo.username)
|
||||||
|
checkCallTime(element: app.callView.staticTexts["IO_call_view_duration"])
|
||||||
|
|
||||||
|
//app.callView.representation.withVariations(named: ["outgoing"]).reMake()
|
||||||
|
//app.statusBar.representation.withVariations(named: ["call_view"]).reMake()
|
||||||
|
app.representationWithElements.mainView = app.callView
|
||||||
|
app.representationWithElements.withElementVariations(mainView: ["outgoing"], statusBar: ["call_view"], tabBar: []).check()
|
||||||
|
|
||||||
|
ghostAccount.waitForCallState(callState: .IncomingReceived, timeout: 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func endCall() {
|
||||||
|
XCTContext.runActivity(named: "End Call (from remote)") { _ in
|
||||||
|
if (ghostAccount.callState == .Released) {return}
|
||||||
|
|
||||||
|
ghostAccount.terminateCall()
|
||||||
|
ghostAccount.waitForCallState(callState: .Released, timeout: 5)
|
||||||
|
|
||||||
|
app.representationWithElements.reloadBackup(named: "call_end").check()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//expected format : "mm:ss"
|
||||||
|
func checkCallTime(element: XCUIElement) {
|
||||||
|
XCTContext.runActivity(named: "Check call time increment") { _ in
|
||||||
|
let timerArray: [Int] = (0..<3).map{_ in
|
||||||
|
sleep(1)
|
||||||
|
return Int(element.label.split(separator: ":").last ?? "") ?? 0
|
||||||
|
}
|
||||||
|
XCTAssert(Set(timerArray).count >= 2, "Call Time is not correctly incremented, less than 2 differents values are displayed in 3 seconds")
|
||||||
|
XCTAssert(timerArray == timerArray.sorted(), "Call Time is not correctly incremented, it is not increasing")
|
||||||
|
XCTAssert(timerArray.first! <= 3, "Call Time is not correctly initialized, it is more than 3 right after the start (found: \(timerArray.first!))")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func toggleCallControls(buttonTag: String, parentView: XCUIElement) {
|
||||||
|
XCTContext.runActivity(named: "Toggle call control Button : \"\(buttonTag)\"") { _ in
|
||||||
|
app.representationWithElements.makeBackup(named: buttonTag)
|
||||||
|
parentView.buttons["call_control_view_\(buttonTag)"].tap()
|
||||||
|
app.representationWithElements.updateElementVariations(mainView: [buttonTag], statusBar: [], tabBar: []).check()
|
||||||
|
|
||||||
|
parentView.buttons["call_control_view_\(buttonTag)"].tap()
|
||||||
|
app.representationWithElements.reloadBackup(named: buttonTag).check()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func noAnswerIncomingCall() {
|
||||||
|
XCTContext.runActivity(named: "Let Incoming Call Ring Until Stop") { _ in
|
||||||
|
XCTAssert(app.callView.waitForExistence(timeout: 5), "call already abort after less than 10 seconds ringing")
|
||||||
|
XCTAssert(app.callView.waitForNonExistence(timeout: 30), "call still not abort after 30 seconds ringing")
|
||||||
|
ghostAccount.waitForCallState(callState: .Released, timeout: 5)
|
||||||
|
app.representationWithElements.reloadBackup(named: "call_end").check()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func noAnswerOutgoingCall() {
|
||||||
|
XCTContext.runActivity(named: "Check Outgoing Call Failed Popup Integrity And Close") { context in
|
||||||
|
XCTAssert(app.callView.waitForExistence(timeout: 5), "call already abort after less than 10 seconds ringing")
|
||||||
|
XCTAssert(app.callView.waitForNonExistence(timeout: 30), "call still not abort after 30 seconds ringing")
|
||||||
|
ghostAccount.waitForCallState(callState: .Released, timeout: 5)
|
||||||
|
app.callFailedView.representation.check()
|
||||||
|
app.callFailedView.buttons["call_failed_error_view_action"].tap()
|
||||||
|
app.representationWithElements.reloadBackup(named: "call_end").check()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func cancelOutgoingCall() {
|
||||||
|
XCTContext.runActivity(named: "Cancel Outgoing Call") { _ in
|
||||||
|
app.callView.buttons["O_call_view_cancel"].tap()
|
||||||
|
app.representationWithElements.reloadBackup(named: "call_end").check()
|
||||||
|
ghostAccount.waitForCallState(callState: .Released, timeout: 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func declineIncomingCall() {
|
||||||
|
XCTContext.runActivity(named: "Decline Incoming Call") { _ in
|
||||||
|
app.callView.buttons["I_call_view_decline"].tap()
|
||||||
|
app.representationWithElements.reloadBackup(named: "call_end").check()
|
||||||
|
ghostAccount.waitForCallState(callState: .Released, timeout: 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func acceptIncomingCall() {
|
||||||
|
XCTContext.runActivity(named: "Accept Incoming Call") { _ in
|
||||||
|
app.callView.buttons["I_call_view_accept"].tap()
|
||||||
|
checkCallTime(element: app.activeCallView.staticTexts["active_call_upper_section_duration"])
|
||||||
|
app.representationWithElements.mainView = app.activeCallView
|
||||||
|
//app.activeCallView.representation.reMake()
|
||||||
|
app.representationWithElements.check()
|
||||||
|
ghostAccount.waitForCallState(callState: .StreamsRunning, timeout: 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
380
UITests/Methods/UITestsCoreManager.swift
Normal file
|
|
@ -0,0 +1,380 @@
|
||||||
|
import XCTest
|
||||||
|
import linphonesw
|
||||||
|
|
||||||
|
|
||||||
|
class UITestsCoreManager {
|
||||||
|
|
||||||
|
private var mCore: Core!
|
||||||
|
private var coreVersion: String = Core.getVersion
|
||||||
|
|
||||||
|
private var mAccountCreator: AccountCreator!
|
||||||
|
|
||||||
|
var appAccountAuthInfo: AuthInfo!
|
||||||
|
var ghostAccounts: UITestsGhostAccounts!
|
||||||
|
let dnsServer = "51.255.123.121"
|
||||||
|
|
||||||
|
static let instance = UITestsCoreManager()
|
||||||
|
|
||||||
|
|
||||||
|
init() {
|
||||||
|
LoggingService.Instance.logLevel = LogLevel.Debug
|
||||||
|
Core.enableLogCollection(state: .Enabled)
|
||||||
|
|
||||||
|
//Config account creator for flexiapi
|
||||||
|
let config: Config! = try! Factory.Instance.createConfig(path: "\(Factory.Instance.getConfigDir(context: nil))/linphonerc")
|
||||||
|
config.setInt(section: "account_creator", key: "backend", value: AccountCreatorBackend.FlexiAPI.rawValue)
|
||||||
|
config.setString(section: "account_creator", key: "url", value: "http://subscribe.example.org/flexiapi/api/")
|
||||||
|
try! mCore = Factory.Instance.createCoreWithConfig(config: config, systemContext: nil)
|
||||||
|
mCore.dnsServersApp = [dnsServer]
|
||||||
|
mAccountCreator = try! mCore.createAccountCreator(xmlrpcUrl: nil)
|
||||||
|
|
||||||
|
try? mCore.start()
|
||||||
|
|
||||||
|
ghostAccounts = UITestsGhostAccounts(coreCreationFunction: newRegisteredLinphoneCore)
|
||||||
|
|
||||||
|
appAccountAuthInfo = mCore.authInfoList.isEmpty ? createAccount() : mCore.authInfoList[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
mCore.stop()
|
||||||
|
mCore = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRegisteredLinphoneCore() -> UITestsRegisteredLinphoneCore {
|
||||||
|
let authInfo = mCore.authInfoList.indices.contains(ghostAccounts.count+1) ? mCore.authInfoList[ghostAccounts.count+1] : createAccount()
|
||||||
|
return UITestsRegisteredLinphoneCore(authInfo: authInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createAccount() -> AuthInfo {
|
||||||
|
XCTContext.runActivity(named: "Create new account") { _ in
|
||||||
|
mAccountCreator.username = "uitester_\(String(Int(Date().timeIntervalSince1970*1000)).suffix(5))"
|
||||||
|
mAccountCreator.password = String((0..<15).map{ _ in mAccountCreator!.username.randomElement()! })
|
||||||
|
mAccountCreator.domain = "sip.example.org"
|
||||||
|
mAccountCreator.email = "\(mAccountCreator!.username)@\(mAccountCreator!.domain)"
|
||||||
|
mAccountCreator.transport = TransportType.Tcp
|
||||||
|
_ = try! mAccountCreator.createAccount()
|
||||||
|
waitForAccountCreationStatus(status: .RequestOk, timeout: 5)
|
||||||
|
|
||||||
|
let authInfo = try! Factory.Instance.createAuthInfo(username: mAccountCreator.username, userid: "", passwd: mAccountCreator.password, ha1: "", realm: "", domain: mAccountCreator.domain)
|
||||||
|
mCore.addAuthInfo(info: authInfo)
|
||||||
|
XCTContext.runActivity(named: "username : \(mAccountCreator.username)\npassword : \(mAccountCreator.password)\ndomain : \(mAccountCreator.domain)") { _ in}
|
||||||
|
return authInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func accountsReset() {
|
||||||
|
XCTContext.runActivity(named: "Clear all accounts") { _ in
|
||||||
|
mCore.clearAllAuthInfo()
|
||||||
|
ghostAccounts.reset()
|
||||||
|
appAccountAuthInfo = createAccount()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createAdress(authInfo: AuthInfo) -> Address {
|
||||||
|
return try! Factory.Instance.createAddress(addr: "sip:\(authInfo.username)@\(authInfo.domain)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForAccountCreationStatus(status: AccountCreator.Status, timeout: Double) {
|
||||||
|
let expectation = XCTestExpectation(description: "account status is successfully : \(status)")
|
||||||
|
XCTContext.runActivity(named: "Waiting for account status : \(status)") { _ in
|
||||||
|
let accountCreatorDelegate = AccountCreatorDelegateStub(onCreateAccount: { (creator: AccountCreator, status: AccountCreator.Status, response: String) in
|
||||||
|
if (status == status) {
|
||||||
|
expectation.fulfill()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.mAccountCreator?.addDelegate(delegate: accountCreatorDelegate)
|
||||||
|
let result = XCTWaiter().wait(for: [expectation], timeout: timeout)
|
||||||
|
self.mAccountCreator?.removeDelegate(delegate: accountCreatorDelegate)
|
||||||
|
XCTAssert(result == .completed, "\"\(status)\" account status still not verified after \(timeout) seconds")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class UITestsGhostAccounts {
|
||||||
|
|
||||||
|
private var mCores = [UITestsRegisteredLinphoneCore]() {
|
||||||
|
didSet {
|
||||||
|
count = mCores.count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private(set) var count: Int!
|
||||||
|
|
||||||
|
private let newCore: (()->UITestsRegisteredLinphoneCore)!
|
||||||
|
|
||||||
|
init(coreCreationFunction: @escaping ()->UITestsRegisteredLinphoneCore) {
|
||||||
|
count = mCores.count
|
||||||
|
newCore = coreCreationFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
func reset() {
|
||||||
|
mCores = []
|
||||||
|
}
|
||||||
|
|
||||||
|
subscript (index: Int) -> UITestsRegisteredLinphoneCore {
|
||||||
|
while (index >= mCores.count) {
|
||||||
|
mCores.append(newCore())
|
||||||
|
}
|
||||||
|
return mCores[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class UITestsRegisteredLinphoneCore {
|
||||||
|
|
||||||
|
var mCore: Core!
|
||||||
|
var coreVersion: String = Core.getVersion
|
||||||
|
var description: String
|
||||||
|
|
||||||
|
private let manager = UITestsCoreManager.instance
|
||||||
|
|
||||||
|
private(set) var mCoreDelegate : CoreDelegate!
|
||||||
|
private(set) var mAccount: Account!
|
||||||
|
private(set) var mAuthInfo: AuthInfo!
|
||||||
|
|
||||||
|
private(set) var callState : Call.State = .Released
|
||||||
|
private(set) var registrationState : RegistrationState = .Cleared
|
||||||
|
|
||||||
|
init(authInfo: AuthInfo) {
|
||||||
|
|
||||||
|
description = "Ghost Account (\(authInfo.username))"
|
||||||
|
LoggingService.Instance.logLevel = LogLevel.Debug
|
||||||
|
Core.enableLogCollection(state: .Enabled)
|
||||||
|
|
||||||
|
try! mCore = Factory.Instance.createCore(configPath: "", factoryConfigPath: "", systemContext: nil)
|
||||||
|
mCore.dnsServers = [manager.dnsServer]
|
||||||
|
|
||||||
|
mCore.videoCaptureEnabled = true
|
||||||
|
mCore.videoDisplayEnabled = true
|
||||||
|
mCore.recordAwareEnabled = true
|
||||||
|
mCore.videoActivationPolicy!.automaticallyAccept = true
|
||||||
|
|
||||||
|
mCoreDelegate = CoreDelegateStub(onCallStateChanged: { (core: Core, call: Call, state: Call.State, message: String) in
|
||||||
|
self.callState = state
|
||||||
|
NSLog("\(call.params?.account?.params?.identityAddress) current call state is \(self.callState)\n")
|
||||||
|
|
||||||
|
}, onAccountRegistrationStateChanged: { (core: Core, account: Account, state: RegistrationState, message: String) in
|
||||||
|
self.registrationState = state
|
||||||
|
NSLog("New registration state is \(state) for user id \(account.params?.identityAddress)\n")
|
||||||
|
})
|
||||||
|
mCore.addDelegate(delegate: mCoreDelegate)
|
||||||
|
|
||||||
|
mCore.playFile = "sounds/hello8000.wav"
|
||||||
|
mCore.useFiles = true
|
||||||
|
|
||||||
|
try? mCore.start()
|
||||||
|
|
||||||
|
mAuthInfo = authInfo
|
||||||
|
login(transport: TransportType.Tcp)
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
mCore.stop()
|
||||||
|
mCore = nil
|
||||||
|
mCoreDelegate = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func login(transport: TransportType) {
|
||||||
|
XCTContext.runActivity(named: "\(description) : Login") { _ in
|
||||||
|
do {
|
||||||
|
let accountParams = try mCore.createAccountParams()
|
||||||
|
let identity = manager.createAdress(authInfo: mAuthInfo)
|
||||||
|
try accountParams.setIdentityaddress(newValue: identity)
|
||||||
|
let address = try Factory.Instance.createAddress(addr: String("sip:" + mAuthInfo.domain))
|
||||||
|
try address.setTransport(newValue: transport)
|
||||||
|
try accountParams.setServeraddress(newValue: address)
|
||||||
|
accountParams.registerEnabled = true
|
||||||
|
let account = try mCore.createAccount(params: accountParams)
|
||||||
|
mCore.addAuthInfo(info: mAuthInfo)
|
||||||
|
try mCore.addAccount(account: account)
|
||||||
|
mAccount = account
|
||||||
|
mCore.defaultAccount = mAccount
|
||||||
|
waitForRegistrationState(registrationState: .Ok, timeout: 5)
|
||||||
|
|
||||||
|
} catch { NSLog(error.localizedDescription) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func makeRecordFilePath() -> String{
|
||||||
|
var filePath = "recording_"
|
||||||
|
let now = Date()
|
||||||
|
let dateFormat = DateFormatter()
|
||||||
|
dateFormat.dateFormat = "E-d-MMM-yyyy-HH-mm-ss"
|
||||||
|
let date = dateFormat.string(from: now)
|
||||||
|
filePath = filePath.appending("\(date).mkv")
|
||||||
|
|
||||||
|
let paths = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)
|
||||||
|
let writablePath = paths[0]
|
||||||
|
return writablePath.appending("/\(filePath)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func startCall(adress: Address) {
|
||||||
|
XCTContext.runActivity(named: "\(description) : Start calling \(adress.username)") { _ in
|
||||||
|
do {
|
||||||
|
let params = try mCore.createCallParams(call: nil)
|
||||||
|
params.mediaEncryption = MediaEncryption.None
|
||||||
|
params.recordFile = makeRecordFilePath()
|
||||||
|
let _ = mCore.inviteAddressWithParams(addr: adress, params: params)
|
||||||
|
} catch { NSLog(error.localizedDescription) }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func terminateCall() {
|
||||||
|
XCTContext.runActivity(named: "\(description) : End call") { _ in
|
||||||
|
do {
|
||||||
|
if (mCore.callsNb == 0) { return }
|
||||||
|
let coreCall = (mCore.currentCall != nil) ? mCore.currentCall : mCore.calls[0]
|
||||||
|
if let call = coreCall {
|
||||||
|
try call.terminate()
|
||||||
|
}
|
||||||
|
} catch { NSLog(error.localizedDescription) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func acceptCall() {
|
||||||
|
XCTContext.runActivity(named: "\(description) : Accept call from \(mAuthInfo.username)") { _ in
|
||||||
|
// IMPORTANT : Make sure you allowed the use of the microphone (see key "Privacy - Microphone usage description" in Info.plist) !
|
||||||
|
do {
|
||||||
|
// if we wanted, we could create a CallParams object
|
||||||
|
// and answer using this object to make changes to the call configuration
|
||||||
|
// (see OutgoingCall tutorial)
|
||||||
|
try mCore.currentCall?.accept()
|
||||||
|
} catch { NSLog(error.localizedDescription) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toggleMicrophone() {
|
||||||
|
// The following toggles the microphone, disabling completely / enabling the sound capture
|
||||||
|
// from the device microphone
|
||||||
|
mCore.micEnabled = !mCore.micEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
func toggleSpeaker() {
|
||||||
|
// Get the currently used audio device
|
||||||
|
let currentAudioDevice = mCore.currentCall?.outputAudioDevice
|
||||||
|
let speakerEnabled = currentAudioDevice?.type == AudioDeviceType.Speaker
|
||||||
|
|
||||||
|
let test = currentAudioDevice?.deviceName
|
||||||
|
// We can get a list of all available audio devices using
|
||||||
|
// Note that on tablets for example, there may be no Earpiece device
|
||||||
|
for audioDevice in mCore.audioDevices {
|
||||||
|
|
||||||
|
// For IOS, the Speaker is an exception, Linphone cannot differentiate Input and Output.
|
||||||
|
// This means that the default output device, the earpiece, is paired with the default phone microphone.
|
||||||
|
// Setting the output audio device to the microphone will redirect the sound to the earpiece.
|
||||||
|
if (speakerEnabled && audioDevice.type == AudioDeviceType.Microphone) {
|
||||||
|
mCore.currentCall?.outputAudioDevice = audioDevice
|
||||||
|
return
|
||||||
|
} else if (!speakerEnabled && audioDevice.type == AudioDeviceType.Speaker) {
|
||||||
|
mCore.currentCall?.outputAudioDevice = audioDevice
|
||||||
|
return
|
||||||
|
}
|
||||||
|
/* If we wanted to route the audio to a bluetooth headset
|
||||||
|
else if (audioDevice.type == AudioDevice.Type.Bluetooth) {
|
||||||
|
core.currentCall?.outputAudioDevice = audioDevice
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toggleVideo() {
|
||||||
|
do {
|
||||||
|
if (mCore.callsNb == 0) { return }
|
||||||
|
let coreCall = (mCore.currentCall != nil) ? mCore.currentCall : mCore.calls[0]
|
||||||
|
if let call = coreCall {
|
||||||
|
let params = try mCore.createCallParams(call: call)
|
||||||
|
params.videoEnabled = !(call.currentParams!.videoEnabled)
|
||||||
|
try call.update(params: params)
|
||||||
|
}
|
||||||
|
} catch { NSLog(error.localizedDescription) }
|
||||||
|
}
|
||||||
|
|
||||||
|
func toggleCamera() {
|
||||||
|
do {
|
||||||
|
let currentDevice = mCore.videoDevice
|
||||||
|
for camera in mCore.videoDevicesList {
|
||||||
|
if (camera != currentDevice && camera != "StaticImage: Static picture") {
|
||||||
|
try mCore.setVideodevice(newValue: camera)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch { NSLog(error.localizedDescription) }
|
||||||
|
}
|
||||||
|
|
||||||
|
func pauseCall() {
|
||||||
|
do {
|
||||||
|
if (mCore.callsNb == 0) { return }
|
||||||
|
let coreCall = (mCore.currentCall != nil) ? mCore.currentCall : mCore.calls[0]
|
||||||
|
try coreCall!.pause()
|
||||||
|
} catch { NSLog(error.localizedDescription) }
|
||||||
|
}
|
||||||
|
|
||||||
|
func resumeCall() {
|
||||||
|
do {
|
||||||
|
if (mCore.callsNb == 0) { return }
|
||||||
|
let coreCall = (mCore.currentCall != nil) ? mCore.currentCall : mCore.calls[0]
|
||||||
|
try coreCall!.resume()
|
||||||
|
} catch { NSLog(error.localizedDescription) }
|
||||||
|
}
|
||||||
|
|
||||||
|
func startRecording() {
|
||||||
|
mCore.currentCall?.startRecording()
|
||||||
|
}
|
||||||
|
|
||||||
|
func stopRecording() {
|
||||||
|
mCore.currentCall?.stopRecording()
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForRegistrationState(registrationState: RegistrationState, timeout: TimeInterval) {
|
||||||
|
let expectation = XCTestExpectation(description: "registration state is successfully : \(registrationState)")
|
||||||
|
XCTContext.runActivity(named: "Waiting for registration state : \(registrationState)") { _ in
|
||||||
|
if (registrationState == self.registrationState) { return}
|
||||||
|
let registeredDelegate = AccountDelegateStub(onRegistrationStateChanged: { (account: Account, state: RegistrationState, message: String) in
|
||||||
|
if (registrationState == state) {
|
||||||
|
expectation.fulfill()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.mCore.defaultAccount!.addDelegate(delegate: registeredDelegate)
|
||||||
|
let result = XCTWaiter().wait(for: [expectation], timeout: timeout)
|
||||||
|
self.mCore.defaultAccount!.removeDelegate(delegate: registeredDelegate)
|
||||||
|
XCTAssert(result == .completed, "\"\(registrationState)\" registration state still not verified after \(timeout) seconds")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForCallState(callState: Call.State, timeout: TimeInterval) {
|
||||||
|
let expectation = XCTestExpectation(description: "call state is successfully : \(callState)")
|
||||||
|
XCTContext.runActivity(named: "Waiting for call state : \(callState)") { _ in
|
||||||
|
if (callState == self.callState) { return}
|
||||||
|
let callStateDelegate = CoreDelegateStub(onCallStateChanged: { (lc: Core, call: Call, state: Call.State, message: String) in
|
||||||
|
if (callState == state) {
|
||||||
|
expectation.fulfill()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.mCore.addDelegate(delegate: callStateDelegate)
|
||||||
|
let result = XCTWaiter().wait(for: [expectation], timeout: timeout)
|
||||||
|
self.mCore.removeDelegate(delegate: callStateDelegate)
|
||||||
|
XCTAssert(result == .completed, "\"\(callState)\" call state still not verified after \(timeout) seconds")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForRecordingState(recording: Bool, onRemote: Bool = false, timeout: TimeInterval) {
|
||||||
|
XCTContext.runActivity(named: "Waiting for call recording state : \(recording)") { _ in
|
||||||
|
var result = XCTWaiter.Result.timedOut
|
||||||
|
for _ in 0...Int(timeout) {
|
||||||
|
if (!onRemote && recording == mCore.currentCall?.params?.isRecording) {
|
||||||
|
result = .completed
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (onRemote && recording == mCore.currentCall?.remoteParams?.isRecording) {
|
||||||
|
result = .completed
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_ = XCTWaiter().wait(for: [XCTestExpectation()], timeout: 1)
|
||||||
|
}
|
||||||
|
let remoteText = onRemote ? "remote" : ""
|
||||||
|
XCTAssert(result == .completed, "\(remoteText) call recording is still not \(recording) after \(timeout) seconds")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
778
UITests/Methods/UITestsScreenshots.swift
Normal file
|
|
@ -0,0 +1,778 @@
|
||||||
|
import SwiftUI
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
extension XCUIElement {
|
||||||
|
private static var _representation = [String:UITestsScreenshots]()
|
||||||
|
|
||||||
|
// hack to add variable in extensions
|
||||||
|
var representation: UITestsScreenshots {
|
||||||
|
get {
|
||||||
|
let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self))
|
||||||
|
if (XCUIElement._representation[tmpAddress] == nil) {
|
||||||
|
XCUIElement._representation[tmpAddress] = UITestsScreenshots(element: self)
|
||||||
|
}
|
||||||
|
return XCUIElement._representation[tmpAddress]!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension XCUIApplication {
|
||||||
|
private static var _representationWithElement = UITestsAppRepresentation()
|
||||||
|
|
||||||
|
var representationWithElements: UITestsAppRepresentation {
|
||||||
|
get {
|
||||||
|
return XCUIApplication._representationWithElement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UITestsAppRepresentation : UITestsScreenshots {
|
||||||
|
|
||||||
|
var mainView: XCUIElement
|
||||||
|
var otherElement: XCUIElement?
|
||||||
|
private let statusBar: XCUIElement
|
||||||
|
private let tabBar: XCUIElement
|
||||||
|
private let app = XCUIApplication()
|
||||||
|
|
||||||
|
private(set) var allVariations = [[String](),[String](),[String](),[String]()]
|
||||||
|
|
||||||
|
private static var backup: [String:(XCUIElement,XCUIElement?,[[String]])] = [:]
|
||||||
|
|
||||||
|
private var elementsDescription = ""
|
||||||
|
override var description: String {
|
||||||
|
get {
|
||||||
|
let description = super.description + " (definition = " + elementsDescription + ")"
|
||||||
|
elementsDescription = ""
|
||||||
|
return description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.mainView = app.dialerView
|
||||||
|
self.statusBar = app.statusBar
|
||||||
|
self.tabBar = app.tabBar
|
||||||
|
super.init(element: app)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withElementVariations(mainView: [String], statusBar: [String], tabBar: [String], other: [String] = []) -> UITestsAppRepresentation {
|
||||||
|
allVariations = [mainView, statusBar, tabBar, other]
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateElementVariations(mainView: [String], statusBar: [String], tabBar: [String], other: [String] = []) -> UITestsAppRepresentation {
|
||||||
|
allVariations[0] += mainView
|
||||||
|
allVariations[1] += statusBar
|
||||||
|
allVariations[2] += tabBar
|
||||||
|
allVariations[3] += other
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
override func convertForComparaison(screenshot: UIImage) -> UIImage {
|
||||||
|
let elements = getElements()
|
||||||
|
if (svgManager.rects["mask"] == nil) {_=svgManager.parse()}
|
||||||
|
_=elements.map{
|
||||||
|
if ($0 != nil) {
|
||||||
|
if ($0!.representation.svgManager.rects["mask"] == nil) {_=$0!.representation.svgManager.parse()}
|
||||||
|
svgManager.rects["mask"]! += $0!.representation.svgManager.rects["mask"]!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.convertForComparaison(screenshot: screenshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func getReference() -> UIImage? {
|
||||||
|
UIGraphicsBeginImageContextWithOptions(UITestsScreenshots.screenSize, false, 1)
|
||||||
|
guard (super.getReference()?.draw(at: CGPoint(x: 0, y: 0)) != nil) else {return nil}
|
||||||
|
let elements = getElements()
|
||||||
|
for i in 0..<elements.count {
|
||||||
|
if (elements[i] != nil) {
|
||||||
|
elements[i]!.representation.withVariations(named: allVariations[i]).getReference()?.draw(at: CGPoint(x: 0, y: 0))
|
||||||
|
elementsDescription += elements[i]!.representation.description + " + "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let reference = UIGraphicsGetImageFromCurrentImageContext()!
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
return reference
|
||||||
|
}
|
||||||
|
|
||||||
|
func getElements() -> [XCUIElement?]{
|
||||||
|
return [mainView,statusBar,tabBar,otherElement].map {($0 != nil && self.element.frame.contains($0!.frame)) ? $0! : nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeBackup(named: String) {
|
||||||
|
UITestsAppRepresentation.backup[named] = (mainView,otherElement,allVariations)
|
||||||
|
}
|
||||||
|
|
||||||
|
func reloadBackup(named: String) -> UITestsAppRepresentation {
|
||||||
|
if let backup = UITestsAppRepresentation.backup[named] {
|
||||||
|
mainView = backup.0
|
||||||
|
allVariations = backup.2
|
||||||
|
otherElement = backup.1
|
||||||
|
UITestsAppRepresentation.backup.removeValue(forKey: named)
|
||||||
|
} else {
|
||||||
|
XCTFail("unable to find an app representation backup named \"\(named)\"")
|
||||||
|
}
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class UITestsScreenshots {
|
||||||
|
|
||||||
|
static let screenshotDelay: TimeInterval = 0.5
|
||||||
|
static let pixelTreshold: Int = 3
|
||||||
|
static let colorTreshold: Int = 3
|
||||||
|
static let screenSize: CGSize = {
|
||||||
|
var size = XCUIApplication().frame.size
|
||||||
|
let scaleFactor = 3.0
|
||||||
|
size.width.scale(by: scaleFactor)
|
||||||
|
size.height.scale(by: scaleFactor)
|
||||||
|
return size
|
||||||
|
}()
|
||||||
|
static let defaultPath: String = {
|
||||||
|
let path = #filePath
|
||||||
|
return String(path.prefix(path.distance(from: path.startIndex, to: path.range(of: "UITests")!.lowerBound) + "UITests/".count)) + "Screenshots/"
|
||||||
|
}()
|
||||||
|
internal var description: String {
|
||||||
|
get {
|
||||||
|
return viewName + (variations.isEmpty ? "" : "||\(variations.joined(separator: ","))")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private(set) var debugHistory: String = ""
|
||||||
|
|
||||||
|
internal let element: XCUIElement
|
||||||
|
private var _svgManager: SVGManager?
|
||||||
|
internal var svgManager: SVGManager {
|
||||||
|
get{
|
||||||
|
if (_svgManager == nil) {_svgManager = SVGManager(path: "\(UITestsScreenshots.defaultPath + viewName).svg")}
|
||||||
|
return _svgManager!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal var _viewName: String?
|
||||||
|
var viewName: String {
|
||||||
|
get {
|
||||||
|
if (_viewName == nil) {
|
||||||
|
_viewName = element.identifier
|
||||||
|
if (_viewName!.isEmpty) {_viewName = element.label} //for elements wich don't have identifier
|
||||||
|
debugHistory = "UITestsScreenshots : \(_viewName!) : "
|
||||||
|
}
|
||||||
|
return _viewName!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private(set) var variations = [String]()
|
||||||
|
|
||||||
|
init(element: XCUIElement) {
|
||||||
|
self.element = element
|
||||||
|
}
|
||||||
|
|
||||||
|
// public functions
|
||||||
|
|
||||||
|
func withVariations(named: [String]) -> UITestsScreenshots {
|
||||||
|
variations = named
|
||||||
|
debugHistory += " with varitions named \"\(named.joined(separator: "\", \""))\" -> "
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
func make(after time: TimeInterval = screenshotDelay) {
|
||||||
|
XCTContext.runActivity(named: "Make \"\(viewName)\" reference screenshot") { context in
|
||||||
|
debugHistory += "make reference -> "
|
||||||
|
guard checkVariationNonDefinition(), referenceExist(expectedValue: false), var screenshot = takeScreenshot(after: time) else {return}
|
||||||
|
saveImage(image: screenshot, path: getPath(name: viewName))
|
||||||
|
svgManager.createFile(referenceName: viewName, referenceArea: getElementArea(), svgSize: UITestsScreenshots.screenSize)
|
||||||
|
screenshot = UITestsScreenshots.imageInScreenAcrea(image: screenshot, area: getElementArea())
|
||||||
|
let preview = UITestsScreenshots.createPreview(title: "Reference", image: screenshot)
|
||||||
|
context.add(UITestsScreenshots.createAttachement(image: preview, name: description))
|
||||||
|
debugHistory += "done."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func reMake(after time: TimeInterval = screenshotDelay) {
|
||||||
|
XCTContext.runActivity(named: "Remake \"\(viewName)\" reference screenshot") { context in
|
||||||
|
debugHistory += "re make reference -> "
|
||||||
|
guard referenceImagesExist(names: [viewName]+variations, expectedValue: true), var screenshot = takeScreenshot(after: time) else {return}
|
||||||
|
_ = (variations.isEmpty ? [viewName] : variations).map{
|
||||||
|
saveImage(image: screenshot, path: getPath(name: $0))
|
||||||
|
_ = svgManager.updateImage(name: $0, area: getElementArea())
|
||||||
|
}
|
||||||
|
screenshot = UITestsScreenshots.imageInScreenAcrea(image: screenshot, area: getElementArea())
|
||||||
|
let preview = UITestsScreenshots.createPreview(title: "Reference", image: screenshot)
|
||||||
|
context.add(UITestsScreenshots.createAttachement(image: preview, name: description))
|
||||||
|
debugHistory += "done."
|
||||||
|
XCTFail("\"\(#function)\" is a temporary function, you can't succeed a test with it\nafter remaking a reference you have to use \"check()\" if you want to compare")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(after time: TimeInterval = screenshotDelay) {
|
||||||
|
XCTContext.runActivity(named: "Check \"\(viewName)\" screenshot with his reference") { context in
|
||||||
|
debugHistory += "compare screenshot to reference -> "
|
||||||
|
guard var screenshot = takeScreenshot(after: time), let reference = getReference() else {return}
|
||||||
|
screenshot = convertForComparaison(screenshot: screenshot)
|
||||||
|
guard let variances = UITestsScreenshots.getVarianceAreas(reference, screenshot) else {return}
|
||||||
|
if (!variances.areas.isEmpty) {
|
||||||
|
let errorMsg = "variances found with the reference view in \(variances.areas.count) areas."
|
||||||
|
debugHistory += errorMsg
|
||||||
|
XCTFail(errorMsg)
|
||||||
|
} else {
|
||||||
|
debugHistory += "done."
|
||||||
|
}
|
||||||
|
let preview = UITestsScreenshots.comparativePreview(reference: reference, screenshot: screenshot, difference: variances.image, areas: variances.areas)
|
||||||
|
context.add(UITestsScreenshots.createAttachement(image: preview, name: description))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addNewVariation(named name: String, after time: TimeInterval = screenshotDelay) {
|
||||||
|
XCTContext.runActivity(named: "Add \"\(viewName)\" reference screenshot new varation named \(name)") { context in
|
||||||
|
debugHistory += "add variances to a new variation named \(name) -> "
|
||||||
|
guard referenceImagesExist(names: [name], expectedValue: false), let screenshot = takeScreenshot(after: time), let reference = getReference() else {return}
|
||||||
|
guard let variances = UITestsScreenshots.getVarianceAreas(reference, convertForComparaison(screenshot: screenshot)) else {return}
|
||||||
|
guard !variances.areas.isEmpty else {
|
||||||
|
XCTFail(debugHistory + "error! : no variances found with the reference view")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
saveImage(image: screenshot, path: getPath(name: name))
|
||||||
|
_ = svgManager.addVariation(referenceName: viewName, name: name, area: getElementArea(), rects: variances.areas)
|
||||||
|
let preview = UITestsScreenshots.variationPreview(reference: reference, areas: variances.areas)
|
||||||
|
context.add(UITestsScreenshots.createAttachement(image: preview, name: description))
|
||||||
|
debugHistory += "done."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addNewFilterVariation(named name: String, color: UIColor, areas: [CGRect]) {
|
||||||
|
XCTContext.runActivity(named: "Add \"\(viewName)\" reference screenshot new filter varation named \(name)") { context in
|
||||||
|
let size = UITestsScreenshots.screenSize
|
||||||
|
UIGraphicsBeginImageContextWithOptions(size, false, 1)
|
||||||
|
color.setFill()
|
||||||
|
UIRectFillUsingBlendMode(CGRect(x: 0, y: 0, width: size.width, height: size.height), .normal)
|
||||||
|
let image = UIGraphicsGetImageFromCurrentImageContext()!
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
saveImage(image: image, path: getPath(name: name))
|
||||||
|
_ = svgManager.addVariation(referenceName: viewName, name: name, area: getElementArea(), rects: areas)
|
||||||
|
context.add(UITestsScreenshots.createAttachement(image: image, name: description))
|
||||||
|
debugHistory += "done."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addToMask(after time: TimeInterval = screenshotDelay) {
|
||||||
|
XCTContext.runActivity(named: "Add new areas to \"\(viewName)\" mask") { context in
|
||||||
|
debugHistory += "add variances to mask -> "
|
||||||
|
guard let screenshot = takeScreenshot(after: time), let reference = getReference() else {return}
|
||||||
|
guard let variances = UITestsScreenshots.getVarianceAreas(reference, convertForComparaison(screenshot: screenshot)) else {return}
|
||||||
|
guard !variances.areas.isEmpty else {
|
||||||
|
XCTFail(debugHistory + "error! : no variances found with the reference view")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = svgManager.addToMask(rects: variances.areas)
|
||||||
|
let preview = UITestsScreenshots.variationPreview(reference: reference, areas: variances.areas)
|
||||||
|
context.add(UITestsScreenshots.createAttachement(image: preview, name: description))
|
||||||
|
debugHistory += "done."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAnimated(timeInterval: TimeInterval) {
|
||||||
|
XCTContext.runActivity(named: "Check \"\(viewName)\" animation") { context in
|
||||||
|
debugHistory += "check if element is animated -> "
|
||||||
|
if (takeScreenshot(after: UITestsScreenshots.screenshotDelay)?.pngData() == takeScreenshot(after: timeInterval)?.pngData()) {
|
||||||
|
XCTFail("no animation detected for \"\(viewName)\"")
|
||||||
|
}
|
||||||
|
debugHistory += "done."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func takeScreenshot(after time: TimeInterval) -> UIImage? {
|
||||||
|
XCTContext.runActivity(named: "take screenshot") { context in
|
||||||
|
debugHistory += "take screenshot -> "
|
||||||
|
_=XCTWaiter.wait(for: [XCTestExpectation()], timeout: time)
|
||||||
|
return UIImage(data: element.screenshot().pngRepresentation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getReference() -> UIImage? {
|
||||||
|
debugHistory += "get reference -> "
|
||||||
|
guard svgManager.parse(withVariations: variations), referenceImagesExist(names: [viewName]+variations, expectedValue: true) == true else {return nil}
|
||||||
|
let filePaths = [getPath(name: viewName)]+variations.map{getPath(name: $0)}
|
||||||
|
let imagesName = [viewName] + variations.map{viewName+"_"+$0}
|
||||||
|
var images = [UIImage]()
|
||||||
|
for i in 0...imagesName.count-1 {
|
||||||
|
let image = getImage(path: filePaths[i])!
|
||||||
|
let area = svgManager.images[imagesName[i]]!.area
|
||||||
|
var clip = [CGRect]()
|
||||||
|
if (i>0) {clip = svgManager.rects[variations[i-1]]!}
|
||||||
|
images.append(UITestsScreenshots.imageInScreenAcrea(image: image, area: area, clip: clip))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
UIGraphicsBeginImageContextWithOptions(UITestsScreenshots.screenSize, false, 1)
|
||||||
|
_ = images.map{$0.draw(at: CGPoint(x: 0,y: 0))}
|
||||||
|
let reference = UIGraphicsGetImageFromCurrentImageContext()!
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
return imageWithMask(image: reference, mask: svgManager.rects["mask"]!)
|
||||||
|
}
|
||||||
|
|
||||||
|
//create attachement to return when calling public functions
|
||||||
|
|
||||||
|
static func createAttachement(image: UIImage, name: String, lifetime: XCTAttachment.Lifetime = .deleteOnSuccess) -> XCTAttachment {
|
||||||
|
let attachment = XCTAttachment(image: image)
|
||||||
|
attachment.lifetime = lifetime
|
||||||
|
attachment.name = name
|
||||||
|
return attachment
|
||||||
|
}
|
||||||
|
|
||||||
|
//image operations to prepare comparison
|
||||||
|
|
||||||
|
static func imageInScreenAcrea(image: UIImage, area: CGRect, clip: [CGRect] = []) -> UIImage {
|
||||||
|
UIGraphicsBeginImageContextWithOptions(UITestsScreenshots.screenSize, false, 1)
|
||||||
|
if (!clip.isEmpty) {UIGraphicsGetCurrentContext()!.clip(to: clip)}
|
||||||
|
image.draw(at: CGPoint(x: area.minX, y: area.minY))
|
||||||
|
let screenImage = UIGraphicsGetImageFromCurrentImageContext()!
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
return screenImage
|
||||||
|
}
|
||||||
|
|
||||||
|
static func setBackground(image: UIImage, color: UIColor) -> UIImage {
|
||||||
|
let size = UITestsScreenshots.screenSize
|
||||||
|
UIGraphicsBeginImageContextWithOptions(size, false, 1)
|
||||||
|
color.setFill()
|
||||||
|
UIRectFill(CGRect(x: 0, y: 0, width: size.width, height: size.height))
|
||||||
|
image.draw(at: CGPoint(x: 0,y: 0))
|
||||||
|
let newImage = UIGraphicsGetImageFromCurrentImageContext()!
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
return newImage
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func imageWithMask(image: UIImage, mask: [CGRect]) -> UIImage {
|
||||||
|
UIGraphicsBeginImageContextWithOptions(UITestsScreenshots.screenSize, false, 1)
|
||||||
|
image.draw(at: CGPoint(x: 0, y: 0))
|
||||||
|
_ = mask.map{UIRectFill($0)}
|
||||||
|
let maskedImage = UIGraphicsGetImageFromCurrentImageContext()!
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
return maskedImage
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertForComparaison(screenshot: UIImage) -> UIImage {
|
||||||
|
var area = getElementArea()
|
||||||
|
if (svgManager.rects["mask"] == nil) {_=svgManager.parse()}
|
||||||
|
var image = UITestsScreenshots.imageInScreenAcrea(image: screenshot, area: area)
|
||||||
|
image = imageWithMask(image: image, mask: svgManager.rects["mask"]!)
|
||||||
|
return image
|
||||||
|
}
|
||||||
|
|
||||||
|
func getElementArea() -> CGRect {
|
||||||
|
XCTContext.runActivity(named: "get element coordinates") { _ in
|
||||||
|
let area = element.frame
|
||||||
|
let rect = CGRect(x: area.minX*3, y: area.minY*3, width: area.width*3, height: area.height*3)
|
||||||
|
return rect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//comparison functions
|
||||||
|
static func getVarianceAreas(_ image1: UIImage, _ image2: UIImage) -> (image: UIImage, areas: [CGRect])? {
|
||||||
|
|
||||||
|
let margin: CGFloat = 20
|
||||||
|
let replacementColor: UInt8 = 255
|
||||||
|
var areas = [CGRect]()
|
||||||
|
|
||||||
|
//compare images
|
||||||
|
UIGraphicsBeginImageContextWithOptions(image1.size, false, 1)
|
||||||
|
setBackground(image: image1, color: UIColor.black).draw(at: CGPoint(x: 0, y: 0))
|
||||||
|
setBackground(image: image2, color: UIColor.black).draw(at: CGPoint(x: 0, y: 0), blendMode: .difference, alpha: 1)
|
||||||
|
let image = UIGraphicsGetImageFromCurrentImageContext()!
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
|
||||||
|
//findRects
|
||||||
|
let exeptMsg = "error! : unexpected error during image conversion for comparison"
|
||||||
|
guard let inputCGImage = image.cgImage else {
|
||||||
|
XCTFail(exeptMsg)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let colorSpace = CGColorSpaceCreateDeviceGray()
|
||||||
|
let width = inputCGImage.width
|
||||||
|
let height = inputCGImage.height
|
||||||
|
let bytesPerPixel = 1
|
||||||
|
let bitsPerComponent = 8
|
||||||
|
let bytesPerRow = bytesPerPixel * width
|
||||||
|
let bitmapInfo = CGImageAlphaInfo.none.rawValue
|
||||||
|
|
||||||
|
guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else {
|
||||||
|
XCTFail(exeptMsg)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
context.draw(inputCGImage, in: CGRect(x: 0, y: 0, width: width, height: height))
|
||||||
|
|
||||||
|
guard let buffer = context.data else {
|
||||||
|
XCTFail(exeptMsg)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let pixelBuffer = buffer.bindMemory(to: UInt8.self, capacity: width * height)
|
||||||
|
|
||||||
|
var rects: [Int:[CGRect]] = [:]
|
||||||
|
|
||||||
|
for row in 0 ..< Int(height) {
|
||||||
|
for column in 0 ..< Int(width) {
|
||||||
|
let offset = row * width + column
|
||||||
|
if (pixelBuffer[offset] > UInt8(colorTreshold)) {
|
||||||
|
pixelBuffer[offset] = replacementColor
|
||||||
|
let point = CGPoint(x: column, y: row)
|
||||||
|
|
||||||
|
var rect = CGRect(x: point.x, y: point.y, width: 1, height: 1)
|
||||||
|
for i in 0...1 {
|
||||||
|
if let prevRects = rects[row-i] {
|
||||||
|
for j in 0..<prevRects.count {
|
||||||
|
if (rect.insetBy(dx: -1, dy: -1).intersects(prevRects[j])) {
|
||||||
|
rect = prevRects[j].union(rect)
|
||||||
|
rects[row-i]!.remove(at: j)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rects[row] == nil) {rects[row] = []}
|
||||||
|
rects[row]!.append(rect)
|
||||||
|
if (rect.width >= CGFloat(pixelTreshold) && rect.height >= CGFloat(pixelTreshold)) {
|
||||||
|
areas.append(rect)
|
||||||
|
}
|
||||||
|
mergeCloseAreas(&areas, withMargin: margin)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let diff = UIImage(cgImage: (CGContext(data: pixelBuffer, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo)?.makeImage())!)
|
||||||
|
return (diff,areas)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func mergeCloseAreas(_ areas: inout [CGRect], withMargin margin: CGFloat) {
|
||||||
|
guard (areas.count >= 1) else {return}
|
||||||
|
let areaSize = areas.count
|
||||||
|
for i in 1...areaSize {
|
||||||
|
if (i != 1 && areas.last!.intersects(areas[areaSize-i].insetBy(dx: -margin, dy: -margin))) {
|
||||||
|
areas[areas.count-1] = areas.last!.union(areas[areaSize-i])
|
||||||
|
areas.remove(at: areaSize-i)
|
||||||
|
mergeCloseAreas(&areas, withMargin: margin)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//preview functions
|
||||||
|
|
||||||
|
static func comparativePreview(reference: UIImage, screenshot: UIImage, difference: UIImage, areas: [CGRect]) -> UIImage {
|
||||||
|
let realPreview = createPreview(title: "Real", image: screenshot, areas: areas, strokeColor: UIColor.red)
|
||||||
|
let refPreview = createPreview(title: "Reference", image: reference, areas: areas, strokeColor: UIColor.red)
|
||||||
|
let difPreview = createPreview(title: "Difference", image: difference)
|
||||||
|
return createPreviewTable(images: refPreview,realPreview,difPreview)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func variationPreview(reference: UIImage, areas: [CGRect]) -> UIImage {
|
||||||
|
let variationPreview = createPreview(title: "Reference", image: reference, areas: areas, fillColor: UIColor.blue.withAlphaComponent(0.3),strokeColor: UIColor.blue)
|
||||||
|
return variationPreview
|
||||||
|
}
|
||||||
|
|
||||||
|
static func createPreviewTable(images: UIImage...) -> UIImage {
|
||||||
|
let sideMargin: CGFloat = 6
|
||||||
|
let imageSize = images.first!.size
|
||||||
|
let globalSize = CGSize(width: (imageSize.width+sideMargin)*CGFloat(images.count), height: imageSize.height+sideMargin)
|
||||||
|
UIGraphicsBeginImageContextWithOptions(globalSize, false, 1)
|
||||||
|
|
||||||
|
for i in 0...images.count-1 {
|
||||||
|
images[i].draw(at: CGPoint(x: CGFloat(i)*(imageSize.width+sideMargin), y: sideMargin))
|
||||||
|
}
|
||||||
|
|
||||||
|
let tableImage = UIGraphicsGetImageFromCurrentImageContext()!
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
return tableImage
|
||||||
|
}
|
||||||
|
|
||||||
|
static func createPreview(title: String, image: UIImage, areas: [CGRect] = [], fillColor: UIColor? = nil, strokeColor: UIColor? = nil) -> UIImage {
|
||||||
|
let lineWidth: CGFloat = 3
|
||||||
|
let bottomMargin = image.size.height*0.05
|
||||||
|
let allSize = CGSize(width: image.size.width + lineWidth*2, height: image.size.height + bottomMargin + lineWidth*2)
|
||||||
|
|
||||||
|
UIGraphicsBeginImageContextWithOptions(allSize, false, 1)
|
||||||
|
|
||||||
|
//image
|
||||||
|
image.draw(at: CGPoint(x: lineWidth, y: lineWidth), blendMode: .normal, alpha: 1)
|
||||||
|
|
||||||
|
//rects
|
||||||
|
UIGraphicsGetCurrentContext()?.setLineWidth(lineWidth)
|
||||||
|
for area in areas {
|
||||||
|
let newArea = area.offsetBy(dx: lineWidth, dy: lineWidth)
|
||||||
|
if (fillColor != nil) {
|
||||||
|
fillColor?.setFill()
|
||||||
|
UIRectFillUsingBlendMode(newArea,.normal)
|
||||||
|
}
|
||||||
|
if (strokeColor != nil) {
|
||||||
|
strokeColor?.setStroke()
|
||||||
|
UIRectFrameUsingBlendMode(newArea.insetBy(dx: -3, dy: -3),.normal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//title
|
||||||
|
let textFont = UIFont(name: "Helvetica Bold", size: bottomMargin/2) ?? UIFont()
|
||||||
|
let textStyle=NSMutableParagraphStyle()
|
||||||
|
textStyle.alignment=NSTextAlignment.center
|
||||||
|
let textColor = UIColor.black
|
||||||
|
let textAttributes = [NSAttributedString.Key.font: textFont, NSAttributedString.Key.paragraphStyle: textStyle, NSAttributedString.Key.foregroundColor: textColor] as [NSAttributedString.Key : Any]
|
||||||
|
let text_h = textFont.lineHeight
|
||||||
|
let text_y = allSize.height-bottomMargin + (bottomMargin-text_h)/2
|
||||||
|
let text_rect = CGRect(x: 0, y: text_y, width: allSize.width, height: bottomMargin)
|
||||||
|
title.draw(in: text_rect, withAttributes: textAttributes)
|
||||||
|
|
||||||
|
let preview = UIGraphicsGetImageFromCurrentImageContext()!
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
return preview
|
||||||
|
}
|
||||||
|
|
||||||
|
//util functions
|
||||||
|
|
||||||
|
private func referenceExist(expectedValue: Bool) -> Bool {
|
||||||
|
guard (FileManager.default.fileExists(atPath: svgManager.path) == expectedValue) else {
|
||||||
|
XCTFail(debugHistory + "error! : \(svgManager.path+(expectedValue ? " does not" : " already")) exist")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private func referenceImagesExist(names: [String], expectedValue: Bool) -> Bool {
|
||||||
|
guard svgManager.parse() else {return false}
|
||||||
|
for name in names {
|
||||||
|
let realName = viewName + (name != viewName ? "_"+name : "")
|
||||||
|
if ((svgManager.images[realName] == nil) == expectedValue) {
|
||||||
|
XCTFail(debugHistory + "error! : \(realName) image \(expectedValue ? "does not" : "already") exist")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private func checkVariationNonDefinition(caller: String = #function) -> Bool {
|
||||||
|
guard variations.isEmpty else {
|
||||||
|
XCTFail(debugHistory + "error : \"\(caller)\" function works only for views, not for views variations")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
//disk operation functions
|
||||||
|
|
||||||
|
private func getPath(name: String) -> String{
|
||||||
|
return "\(UITestsScreenshots.defaultPath)images/\(viewName+((name != viewName) ? "_"+name : "")).png"
|
||||||
|
}
|
||||||
|
|
||||||
|
private func saveImage(image: UIImage, path: String) {
|
||||||
|
guard let data = image.pngData() else {
|
||||||
|
XCTFail("error != unable to save image at \(path)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
try data.write(to: URL(fileURLWithPath: path))
|
||||||
|
} catch {
|
||||||
|
NSLog(error.localizedDescription)
|
||||||
|
XCTFail(debugHistory + "error != unable to save image at \(path)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getImage(path: String) -> UIImage? {
|
||||||
|
guard let image = UIImage(contentsOfFile: path) else {
|
||||||
|
XCTFail(debugHistory + "error != unable to get image at \(path)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return image
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class SVGManager : NSObject {
|
||||||
|
var path: String
|
||||||
|
var parentPath: String
|
||||||
|
var rects: [String : [CGRect]] = [:]
|
||||||
|
var images: [String : (area: CGRect, line: Int)] = [:]
|
||||||
|
private var parser: XMLParser?
|
||||||
|
private var current: String?
|
||||||
|
|
||||||
|
private var defaultMask = [CGRect(x: 376, y: 2492, width: 418, height: 16)]
|
||||||
|
|
||||||
|
private var referenceStart: Int?
|
||||||
|
private var maskStart: Int?
|
||||||
|
private var clipPathStart: Int?
|
||||||
|
private var variationsStart: Int?
|
||||||
|
private var selectedVariationStarts: [String : Int]?
|
||||||
|
|
||||||
|
init(path: String) {
|
||||||
|
self.path = path
|
||||||
|
let index = path.lastIndex(of: "/")
|
||||||
|
self.parentPath = (index != nil) ? String(path.prefix(path.distance(from: path.startIndex, to: index!)+1)) : ""
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func svgRect(_ rect: CGRect, lock: Bool) -> String {
|
||||||
|
return "<rect x=\"\(rect.minX)\" y=\"\(rect.minY)\" width=\"\(rect.width)\" height=\"\(rect.height)\"\(lock ? " sodipodi:insensitive=\"true\"":"")/>"
|
||||||
|
}
|
||||||
|
|
||||||
|
func svgImage(name: String, area: CGRect, lock: Bool) -> String {
|
||||||
|
return "<image id=\"\(name)\" x=\"\(area.minX)\" y=\"\(area.minY)\" width=\"\(area.width)\" height=\"\(area.height)\" preserveAspectRatio=\"none\" xlink:href=\"images/\(name).png\"\(lock ? " sodipodi:insensitive=\"true\"":"")/>"
|
||||||
|
}
|
||||||
|
|
||||||
|
func createFile(referenceName name: String, referenceArea area: CGRect, svgSize: CGSize) {
|
||||||
|
let width = svgSize.width
|
||||||
|
let height = svgSize.height
|
||||||
|
var content = [String]()
|
||||||
|
content.append("<svg width=\"\(width)\" height=\"\(height)\" version=\"1.1\" viewBox=\"0 0 \(width) \(height)\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\">")
|
||||||
|
content.append("<g id=\"reference\" sodipodi:insensitive=\"true\">")
|
||||||
|
content.append(" \(svgImage(name: name, area: area, lock: true))")
|
||||||
|
content.append("</g>")
|
||||||
|
content.append("<defs>\n <clipPath id=\"clipPath\"/>\n</defs>")
|
||||||
|
content.append("<g id=\"variations\" clip-path=\"url(#clipPath)\"/>")
|
||||||
|
content.append("<g id=\"mask\" opacity=\"0.4\" fill=\"#000\" stroke=\"none\">")
|
||||||
|
_ = defaultMask.map{content.append(" \(svgRect($0, lock: true))")}
|
||||||
|
content.append("</g>")
|
||||||
|
content.append("</svg>")
|
||||||
|
let svg = content.joined(separator: "\n")
|
||||||
|
try! svg.write(toFile: path, atomically: true, encoding: String.Encoding.utf8)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateImage(name: String, area: CGRect) -> Bool {
|
||||||
|
guard parse(), images[name] != nil else {return false}
|
||||||
|
|
||||||
|
var svgData = try! String(contentsOf: URL(fileURLWithPath: path)).split(separator: "\n")
|
||||||
|
var lineIndex = images[name]!.line-1
|
||||||
|
var line = svgData[lineIndex]
|
||||||
|
while line.firstIndex(of: "<") == nil {
|
||||||
|
svgData.remove(at: lineIndex)
|
||||||
|
lineIndex += -1
|
||||||
|
line = svgData[lineIndex]
|
||||||
|
}
|
||||||
|
svgData[lineIndex] = line.prefix(line.distance(from: line.startIndex, to: line.firstIndex(of: "<")!)) + Substring(svgImage(name: name, area: area, lock: true))
|
||||||
|
try! String(svgData.joined(separator: "\n")).write(toFile: path, atomically: true, encoding: String.Encoding.utf8)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func addToMask(rects: [CGRect]) -> Bool {
|
||||||
|
guard parse() else {return false}
|
||||||
|
var content = ""
|
||||||
|
for rect in rects {
|
||||||
|
content += "\(svgRect(rect, lock: false))\n"
|
||||||
|
}
|
||||||
|
svgInsert(content, at: maskStart!)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func addVariation(referenceName: String, name: String, area: CGRect, rects: [CGRect]) -> Bool {
|
||||||
|
guard parse() else {return false}
|
||||||
|
|
||||||
|
var content = "<g id=\"\(name)\" display=\"none\" fill=\"none\" stroke=\"#00f\" stroke-width=\"3\">\n"
|
||||||
|
content += " \(svgImage(name: "\(referenceName)_\(name)", area: area, lock: true))\n"
|
||||||
|
for rect in rects {
|
||||||
|
content += " \(svgRect(rect, lock: false))\n"
|
||||||
|
}
|
||||||
|
content += "</g>\n"
|
||||||
|
svgInsert(content, at: variationsStart!)
|
||||||
|
|
||||||
|
content = "<use xlink:href=\"#\(name)\"/>"
|
||||||
|
svgInsert(content, at: clipPathStart!, parentElement: "clipPath")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
//if some variations are delete with a svg editor like Inkscape, this variations are copied in the clipPath wich break some functionalities.
|
||||||
|
//this function is called at eeach parse to clean the clipPath if needed.
|
||||||
|
func removeClipPathAnomalies() {
|
||||||
|
guard (clipPathStart ?? 0 < (variationsStart ?? 0 )-2) else {return}
|
||||||
|
var svgData = try! String(contentsOf: URL(fileURLWithPath: path)).split(separator: "\n")
|
||||||
|
var index = clipPathStart!
|
||||||
|
var use = false
|
||||||
|
var line = svgData[index]
|
||||||
|
while !line.contains("</clipPath>") && !line.contains("</defs>") {
|
||||||
|
if (use == true) {
|
||||||
|
if (line.contains("/>")) {use = false}
|
||||||
|
} else {
|
||||||
|
if (line.range(of: "<use") != nil) {use = true}
|
||||||
|
else {
|
||||||
|
svgData.remove(at: index)
|
||||||
|
index += -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index += 1
|
||||||
|
line = svgData[index]
|
||||||
|
}
|
||||||
|
try! String(svgData.joined(separator: "\n")).write(toFile: path, atomically: true, encoding: String.Encoding.utf8)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parse(withVariations headers: [String] = []) -> Bool {
|
||||||
|
rects["mask"] = []
|
||||||
|
_ = headers.map{rects[$0] = []}
|
||||||
|
parser = XMLParser(contentsOf: URL(fileURLWithPath: path))
|
||||||
|
guard (parser != nil) else {return false}
|
||||||
|
parser!.delegate = self
|
||||||
|
parser!.parse()
|
||||||
|
removeClipPathAnomalies()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func svgInsert(_ content: String, at index: Int, parentElement: String = "g") {
|
||||||
|
var svgData = try! String(contentsOf: URL(fileURLWithPath: path)).split(separator: "\n")
|
||||||
|
let line = svgData[index-1]
|
||||||
|
let prefix = line.prefix(line.distance(from: line.startIndex, to: line.firstIndex(of: "<") ?? line.startIndex))
|
||||||
|
if (line.suffix(2) == "/>") {
|
||||||
|
svgData[index-1] = line.prefix(line.count-2)+">"
|
||||||
|
svgData.insert(prefix+"</\(parentElement)>", at: index)
|
||||||
|
}
|
||||||
|
svgData.insert(prefix+Substring(" "+content), at: index)
|
||||||
|
|
||||||
|
try! String(svgData.joined(separator: "\n")).write(toFile: path, atomically: true, encoding: String.Encoding.utf8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SVGManager : XMLParserDelegate {
|
||||||
|
|
||||||
|
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
|
||||||
|
|
||||||
|
if (elementName == "g") {
|
||||||
|
if (rects[attributeDict["id"] ?? ""] != nil) {
|
||||||
|
current = attributeDict["id"]
|
||||||
|
}
|
||||||
|
if (attributeDict["id"] == "reference") {
|
||||||
|
referenceStart = parser.lineNumber
|
||||||
|
} else if (attributeDict["id"] == "mask") {
|
||||||
|
maskStart = parser.lineNumber
|
||||||
|
} else if (attributeDict["id"] == "variations") {
|
||||||
|
variationsStart = parser.lineNumber
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementName == "clipPath" && attributeDict["id"] == "clipPath") {
|
||||||
|
clipPathStart = parser.lineNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementName == "rect" && current != nil) {
|
||||||
|
if current != nil { rects[current!]?.append(getRect(attributes: attributeDict))}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementName == "image") {
|
||||||
|
guard var imageName = attributeDict["xlink:href"] else {return}
|
||||||
|
guard FileManager.default.fileExists(atPath: imageName) || FileManager.default.fileExists(atPath: parentPath+imageName) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
imageName = String(imageName.suffix(imageName.distance(from: imageName.lastIndex(of: "/") ?? imageName.startIndex, to: imageName.endIndex)-1))
|
||||||
|
imageName = String(imageName.prefix(imageName.distance(from: imageName.startIndex, to: imageName.lastIndex(of: ".") ?? imageName.endIndex)))
|
||||||
|
images[imageName] = (getRect(attributes: attributeDict),parser.lineNumber)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
|
||||||
|
if (elementName == "g") {
|
||||||
|
current = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getRect(attributes: [String:String]) -> CGRect {
|
||||||
|
var values = [Int]()
|
||||||
|
for header in ["x","y","width","height"] {
|
||||||
|
if let val = NumberFormatter().number(from: attributes[header] ?? "0") {
|
||||||
|
values.append(Int(truncating: val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CGRect(x: values[0], y: values[1], width: values[2], height: values[3])
|
||||||
|
}
|
||||||
|
}
|
||||||
204
UITests/Methods/UITestsUtils.swift
Normal file
|
|
@ -0,0 +1,204 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
//
|
||||||
|
// Definition of some main views usually used in tests.
|
||||||
|
//
|
||||||
|
// Real utility in order to have more explicit test failed reports when child elements
|
||||||
|
// are defined with them. When an element will be not find, the error message will specify
|
||||||
|
// if it was because of the element non-display or its parent view non-display.
|
||||||
|
//
|
||||||
|
// It Allow to really simplify the screenshot comparison too.
|
||||||
|
//
|
||||||
|
|
||||||
|
extension XCUIApplication {
|
||||||
|
|
||||||
|
private static let _phoneView = XCUIApplication().descendants(matching: .other)["phone_view"]
|
||||||
|
private static let _mainView = _phoneView.otherElements["main_view"]
|
||||||
|
|
||||||
|
var phoneView: XCUIElement {get{return XCUIApplication._phoneView}}
|
||||||
|
|
||||||
|
//SubViews
|
||||||
|
private static let _callStatsView = _activeCallView.otherElements["call_stats_view"]
|
||||||
|
private static let _extraMenuView = _activeCallView.otherElements["active_call_extra_buttons_view"]
|
||||||
|
private static let _numpadCallView = _activeCallView.otherElements["call_numpad_view"]
|
||||||
|
private static let _pauseCallView = _activeCallView.otherElements["paused_call_view"]
|
||||||
|
|
||||||
|
var callStatsView: XCUIElement {get{return XCUIApplication._callStatsView}}
|
||||||
|
var extraMenuView: XCUIElement {get{return XCUIApplication._extraMenuView}}
|
||||||
|
var numpadCallView: XCUIElement {get{return XCUIApplication._numpadCallView}}
|
||||||
|
var pauseCallView: XCUIElement {get{return XCUIApplication._pauseCallView}}
|
||||||
|
|
||||||
|
//MainViews
|
||||||
|
private static let _activeCallView = _mainView.otherElements["active_call_view"]
|
||||||
|
private static let _assistantLinkView = _mainView.otherElements["assistant_link_view"]
|
||||||
|
private static let _assistantView = _mainView.otherElements["assistant_view"]
|
||||||
|
private static let _callView = _mainView.otherElements["IO_call_view"]
|
||||||
|
private static let _callsListView = _mainView.otherElements["calls_list_view"]
|
||||||
|
private static let _chatsListView = _mainView.otherElements["chats_list_view"]
|
||||||
|
private static let _dialerView = _mainView.otherElements["dialer_view"]
|
||||||
|
private static let _loginView = _mainView.otherElements["assistant_login_view"]
|
||||||
|
private static let _loginWarningView = _mainView.otherElements["assistant_login_warning_view"]
|
||||||
|
private static let _settingsView = _mainView.otherElements["settings_view"]
|
||||||
|
|
||||||
|
var activeCallView: XCUIElement {get{return XCUIApplication._activeCallView}}
|
||||||
|
var assistantLinkView: XCUIElement {get{return XCUIApplication._assistantLinkView}}
|
||||||
|
var assistantView: XCUIElement {get{return XCUIApplication._assistantView}}
|
||||||
|
var callView: XCUIElement {get{return XCUIApplication._callView}}
|
||||||
|
var callsListView: XCUIElement {get{return XCUIApplication._callsListView}}
|
||||||
|
var chatsListView: XCUIElement {get{return XCUIApplication._chatsListView}}
|
||||||
|
var dialerView: XCUIElement {get{return XCUIApplication._dialerView}}
|
||||||
|
var loginView: XCUIElement {get{return XCUIApplication._loginView}}
|
||||||
|
var loginWarningView: XCUIElement {get{return XCUIApplication._loginWarningView}}
|
||||||
|
var settingsView: XCUIElement {get{return XCUIApplication._settingsView}}
|
||||||
|
|
||||||
|
//StatusBar
|
||||||
|
private static let _statusBar = _phoneView.otherElements["status_bar"]
|
||||||
|
var statusBar: XCUIElement {get{return XCUIApplication._statusBar}}
|
||||||
|
|
||||||
|
//TabBar
|
||||||
|
private static let _tabBar = _phoneView.otherElements["tab_bar"]
|
||||||
|
var tabBar: XCUIElement {get{return XCUIApplication._tabBar}}
|
||||||
|
|
||||||
|
//SideMenuView
|
||||||
|
private static let _sideMenuView: XCUIElement = _phoneView.otherElements["side_menu_view"]
|
||||||
|
var sideMenuView: XCUIElement {get{return XCUIApplication._sideMenuView}}
|
||||||
|
|
||||||
|
//AlertPopups
|
||||||
|
private static let _callFailedView: XCUIElement = XCUIApplication().otherElements["call_failed_error_view"]
|
||||||
|
|
||||||
|
var callFailedView: XCUIElement {get{return XCUIApplication._callFailedView}}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class UITestsUtils {
|
||||||
|
static let app = XCUIApplication()
|
||||||
|
|
||||||
|
// function which is launched before every tests to setup
|
||||||
|
// it checks and fix account connection status and checks the view displayed (Dialer View)
|
||||||
|
static func testAppSetup() {
|
||||||
|
if (app.state != .runningForeground && !app.sideMenuView.staticTexts["side_menu_view_sip_adress"].exists) {
|
||||||
|
app.launch()
|
||||||
|
}
|
||||||
|
if (!rightAccountConnected() || !accountIsConnected()) {
|
||||||
|
deleteApp() // easiest methods to clear configured accounts and reset the app
|
||||||
|
app.launch()
|
||||||
|
removeSystemAlerts() // accept all initial permissions
|
||||||
|
connectAccount()
|
||||||
|
XCTAssert(accountIsConnected(), "registration state on the Status Bar is still not : Connected after 5 seconds")
|
||||||
|
}
|
||||||
|
|
||||||
|
//app.representation.reMake()
|
||||||
|
//app.dialerView.representation.reMake()
|
||||||
|
app.representationWithElements.mainView = app.dialerView
|
||||||
|
app.representationWithElements.withElementVariations(mainView: [], statusBar: [], tabBar: []).check()
|
||||||
|
}
|
||||||
|
|
||||||
|
static func accountIsConnected() -> Bool {
|
||||||
|
XCTContext.runActivity(named: "Check connection state") { _ in
|
||||||
|
let connection = app.statusBar.buttons["status_bar_registration_state"]
|
||||||
|
for i in 1...5 {
|
||||||
|
if (connection.value as? String == "Connected") {return true}
|
||||||
|
if (connection.value as? String == "Connecté") {app.launch()} //relauch the app if it is in French to fix (happen when the app is launch manually)
|
||||||
|
else if (i>1 && connection.value as? String != "Connection in progress") {break} // wait only if connection is in progress
|
||||||
|
_ = XCTWaiter.wait(for: [XCTestExpectation()], timeout: 1)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func rightAccountConnected() -> Bool {
|
||||||
|
let manager = UITestsCoreManager.instance
|
||||||
|
return XCTContext.runActivity(named: "Check connected adress") { _ -> Bool in
|
||||||
|
let sipAdress = "sip:\(manager.appAccountAuthInfo.username)@\(manager.appAccountAuthInfo.domain)"
|
||||||
|
let sipLabel = app.sideMenuView.staticTexts["side_menu_view_sip_adress"].label
|
||||||
|
XCTContext.runActivity(named: "expected adress : \(sipAdress) \nfound adress: \(sipLabel)") {_ in}
|
||||||
|
return sipLabel == sipAdress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func connectAccount() {
|
||||||
|
let manager = UITestsCoreManager.instance
|
||||||
|
XCTContext.runActivity(named: "Login \(manager.appAccountAuthInfo.username) in \(app)") { _ in
|
||||||
|
manager.accountsReset()
|
||||||
|
|
||||||
|
let sideMenu = app.statusBar.buttons["side_menu_button"]
|
||||||
|
sideMenu.tap()
|
||||||
|
app.sideMenuView.staticTexts["Settings"].tap()
|
||||||
|
app.settingsView.staticTexts["Network"].tap()
|
||||||
|
app.settingsView.tables.cells.containing(.staticText, identifier:"DNS Server").children(matching: .textField).element.fillTextField(manager.dnsServer)
|
||||||
|
app.settingsView.buttons["settings_view_back"].tap()
|
||||||
|
|
||||||
|
sideMenu.tap()
|
||||||
|
app.sideMenuView.staticTexts["Assistant"].tap()
|
||||||
|
app.assistantView.buttons["assistant_view_accept"].tap()
|
||||||
|
app.assistantView.buttons["assistant_view_sip_login"].tap()
|
||||||
|
app.loginWarningView.buttons["assistant_login_warning_view_skip"].tap()
|
||||||
|
app.loginView.textFields["assistant_login_view_username_field"].fillTextField(manager.appAccountAuthInfo.username)
|
||||||
|
app.loginView.secureTextFields["assistant_login_view_password_field"].fillTextField(manager.appAccountAuthInfo.password)
|
||||||
|
app.loginView.textFields["assistant_login_view_domain_field"].fillTextField(manager.appAccountAuthInfo.domain)
|
||||||
|
app.loginView.buttons["TCP"].tap()
|
||||||
|
app.loginView.buttons["assistant_login_view_login"].tap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func deleteApp() {
|
||||||
|
XCTContext.runActivity(named: "Delete \(app)") { _ in
|
||||||
|
app.terminate()
|
||||||
|
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
|
||||||
|
let linphoneApp = springboard/*@START_MENU_TOKEN@*/.icons["Linphone"]/*[[".otherElements[\"Home screen icons\"]",".icons.icons[\"Linphone\"]",".icons[\"Linphone\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/
|
||||||
|
if (linphoneApp.waitForExistence(timeout: 2)) {
|
||||||
|
linphoneApp.press(forDuration: 2)
|
||||||
|
for i in [2,0,1] {
|
||||||
|
let button = springboard.buttons.element(boundBy: i)
|
||||||
|
if (button.exists || button.waitForExistence(timeout: 2)) {
|
||||||
|
button.tap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func removeSystemAlerts() {
|
||||||
|
XCTContext.runActivity(named: "Remove all system alerts \(app)") { _ in
|
||||||
|
var alertsEnd = false
|
||||||
|
while (!alertsEnd) {
|
||||||
|
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
|
||||||
|
let alertAllowButton = springboard.buttons.element(boundBy: 1)
|
||||||
|
if (alertAllowButton.exists || alertAllowButton.waitForExistence(timeout: 3)) {
|
||||||
|
alertAllowButton.tap()
|
||||||
|
} else {
|
||||||
|
alertsEnd = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Adding some features to XCUIElement like an UITestsScreenshots object called "representaion"
|
||||||
|
// to simplify the screenshot comparison integration, a custom and complete fillTextFill methods
|
||||||
|
// and the opposite of the native method XCUIElement.waitForExistence(timeout: TimeInterval) -> Bool
|
||||||
|
//
|
||||||
|
extension XCUIElement {
|
||||||
|
|
||||||
|
func fillTextField(_ text: String) {
|
||||||
|
tap()
|
||||||
|
let initValue = String(value as? String ?? "")
|
||||||
|
if (initValue != text) {
|
||||||
|
let deleteString = (0..<initValue.count).map{_ in XCUIKeyboardKey.delete.rawValue}.joined(separator: "")
|
||||||
|
typeText(deleteString)
|
||||||
|
typeText(text)
|
||||||
|
}
|
||||||
|
typeText(XCUIKeyboardKey.return.rawValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForNonExistence(timeout: TimeInterval) -> Bool {
|
||||||
|
let doesNotExistPredicate = NSPredicate(format: "exists == false")
|
||||||
|
let exept = XCTNSPredicateExpectation(predicate: doesNotExistPredicate, object: self)
|
||||||
|
let result = XCTWaiter.wait(for: [exept], timeout: timeout)
|
||||||
|
return result == .completed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
191
UITests/Screenshots/IO_call_view.svg
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="1170.0"
|
||||||
|
height="2532.0"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 1170.0 2532.0"
|
||||||
|
id="svg141"
|
||||||
|
sodipodi:docname="IO_call_view.svg"
|
||||||
|
inkscape:version="1.2.1 (9c6d41e, 2022-07-14)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview143"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="0.37282781"
|
||||||
|
inkscape:cx="-417.08262"
|
||||||
|
inkscape:cy="1051.4237"
|
||||||
|
inkscape:window-width="1835"
|
||||||
|
inkscape:window-height="1046"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="25"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="mask" />
|
||||||
|
<g
|
||||||
|
id="reference"
|
||||||
|
sodipodi:insensitive="true">
|
||||||
|
<image
|
||||||
|
id="IO_call_view"
|
||||||
|
x="0.0"
|
||||||
|
y="231.0"
|
||||||
|
width="1170.0"
|
||||||
|
height="2301.0"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/IO_call_view.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
</g>
|
||||||
|
<defs
|
||||||
|
id="defs135">
|
||||||
|
<clipPath
|
||||||
|
id="clipPath">
|
||||||
|
<use
|
||||||
|
xlink:href="#speaker"
|
||||||
|
id="use1181" />
|
||||||
|
<use
|
||||||
|
xlink:href="#mute"
|
||||||
|
id="use1183" />
|
||||||
|
<use
|
||||||
|
xlink:href="#outgoing"
|
||||||
|
id="use1185" />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
id="variations"
|
||||||
|
clip-path="url(#clipPath)">
|
||||||
|
<g
|
||||||
|
id="speaker"
|
||||||
|
display="none"
|
||||||
|
fill="none"
|
||||||
|
stroke="#0000ff"
|
||||||
|
stroke-width="3">
|
||||||
|
<image
|
||||||
|
id="IO_call_view_speaker"
|
||||||
|
x="0"
|
||||||
|
y="231"
|
||||||
|
width="1170"
|
||||||
|
height="2301"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/IO_call_view_speaker.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<rect
|
||||||
|
x="630"
|
||||||
|
y="2332"
|
||||||
|
width="73"
|
||||||
|
height="72"
|
||||||
|
id="rect1190" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="mute"
|
||||||
|
display="none"
|
||||||
|
fill="none"
|
||||||
|
stroke="#0000ff"
|
||||||
|
stroke-width="3">
|
||||||
|
<image
|
||||||
|
id="IO_call_view_mute"
|
||||||
|
x="0"
|
||||||
|
y="231"
|
||||||
|
width="1170"
|
||||||
|
height="2301"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/IO_call_view_mute.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<rect
|
||||||
|
x="465"
|
||||||
|
y="2322"
|
||||||
|
width="72"
|
||||||
|
height="92"
|
||||||
|
id="rect1194" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="outgoing"
|
||||||
|
display="none"
|
||||||
|
fill="none"
|
||||||
|
stroke="#0000ff"
|
||||||
|
stroke-width="3">
|
||||||
|
<image
|
||||||
|
id="IO_call_view_outgoing"
|
||||||
|
x="0"
|
||||||
|
y="231"
|
||||||
|
width="1170"
|
||||||
|
height="2301"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/IO_call_view_outgoing.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<rect
|
||||||
|
x="421"
|
||||||
|
y="585"
|
||||||
|
width="327"
|
||||||
|
height="53"
|
||||||
|
id="rect778" />
|
||||||
|
<rect
|
||||||
|
x="635"
|
||||||
|
y="698"
|
||||||
|
width="1"
|
||||||
|
height="5"
|
||||||
|
id="rect780" />
|
||||||
|
<rect
|
||||||
|
x="36"
|
||||||
|
y="2292"
|
||||||
|
width="195"
|
||||||
|
height="150"
|
||||||
|
id="rect782" />
|
||||||
|
<rect
|
||||||
|
x="374"
|
||||||
|
y="2292"
|
||||||
|
width="423"
|
||||||
|
height="150"
|
||||||
|
id="rect784" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="mask"
|
||||||
|
opacity="0.4"
|
||||||
|
fill="#000"
|
||||||
|
stroke="none">
|
||||||
|
<rect
|
||||||
|
x="376.0"
|
||||||
|
y="2492.0"
|
||||||
|
width="418.0"
|
||||||
|
height="16.0"
|
||||||
|
sodipodi:insensitive="true"
|
||||||
|
id="rect138" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:3"
|
||||||
|
id="rect364"
|
||||||
|
width="105.26157"
|
||||||
|
height="105.26154"
|
||||||
|
x="533.41992"
|
||||||
|
y="416.30463" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:3.10529"
|
||||||
|
id="rect367"
|
||||||
|
width="50.29134"
|
||||||
|
height="39.227234"
|
||||||
|
x="588.40833"
|
||||||
|
y="674.23889" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:3"
|
||||||
|
id="rect369"
|
||||||
|
width="159.59109"
|
||||||
|
height="49.956039"
|
||||||
|
x="609.86603"
|
||||||
|
y="1725.9979" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:3"
|
||||||
|
id="rect371"
|
||||||
|
width="120.02858"
|
||||||
|
height="38.221382"
|
||||||
|
x="469.72086"
|
||||||
|
y="1803.4464" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.4 KiB |
83
UITests/Screenshots/Linphone.svg
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="1170.0"
|
||||||
|
height="2532.0"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 1170.0 2532.0"
|
||||||
|
id="svg141"
|
||||||
|
sodipodi:docname="Linphone.svg"
|
||||||
|
inkscape:version="1.2.1 (9c6d41e, 2022-07-14)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview143"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="1.0545163"
|
||||||
|
inkscape:cx="834.0317"
|
||||||
|
inkscape:cy="116.64116"
|
||||||
|
inkscape:window-width="1463"
|
||||||
|
inkscape:window-height="456"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="25"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="mask" />
|
||||||
|
<g
|
||||||
|
id="reference"
|
||||||
|
sodipodi:insensitive="true">
|
||||||
|
<image
|
||||||
|
id="Linphone"
|
||||||
|
x="0.0"
|
||||||
|
y="0.0"
|
||||||
|
width="1170.0"
|
||||||
|
height="2532.0"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/Linphone.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
</g>
|
||||||
|
<defs
|
||||||
|
id="defs135">
|
||||||
|
<clipPath
|
||||||
|
id="clipPath" />
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
id="variations"
|
||||||
|
clip-path="url(#clipPath)" />
|
||||||
|
<g
|
||||||
|
id="mask"
|
||||||
|
opacity="0.4"
|
||||||
|
fill="#000"
|
||||||
|
stroke="none">
|
||||||
|
<rect
|
||||||
|
x="376.0"
|
||||||
|
y="2492.0"
|
||||||
|
width="418.0"
|
||||||
|
height="16.0"
|
||||||
|
sodipodi:insensitive="true"
|
||||||
|
id="rect138"
|
||||||
|
inkscape:label="rect138" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:3.98292"
|
||||||
|
id="rect364-7"
|
||||||
|
width="277.85251"
|
||||||
|
height="57.104916"
|
||||||
|
x="868.64471"
|
||||||
|
y="41.621895" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:3.98292"
|
||||||
|
id="rect364-7-8"
|
||||||
|
width="277.85251"
|
||||||
|
height="57.104916"
|
||||||
|
x="20.388498"
|
||||||
|
y="41.621895" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
369
UITests/Screenshots/active_call_view.svg
Normal file
|
|
@ -0,0 +1,369 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="1170.0"
|
||||||
|
height="2532.0"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 1170.0 2532.0"
|
||||||
|
id="svg375"
|
||||||
|
sodipodi:docname="active_call_view.svg"
|
||||||
|
inkscape:version="1.2.1 (9c6d41e, 2022-07-14)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview377"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="0.26362907"
|
||||||
|
inkscape:cx="-544.3254"
|
||||||
|
inkscape:cy="1331.4161"
|
||||||
|
inkscape:window-width="1463"
|
||||||
|
inkscape:window-height="456"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="25"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="mask" />
|
||||||
|
<g
|
||||||
|
id="reference"
|
||||||
|
sodipodi:insensitive="true">
|
||||||
|
<image
|
||||||
|
id="active_call_view"
|
||||||
|
x="0.0"
|
||||||
|
y="231.0"
|
||||||
|
width="1170.0"
|
||||||
|
height="2301.0"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/active_call_view.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
</g>
|
||||||
|
<defs
|
||||||
|
id="defs369">
|
||||||
|
<clipPath
|
||||||
|
id="clipPath">
|
||||||
|
<use
|
||||||
|
xlink:href="#extra_menu"
|
||||||
|
id="use439" />
|
||||||
|
<use
|
||||||
|
xlink:href="#mute"
|
||||||
|
id="use441" />
|
||||||
|
<use
|
||||||
|
xlink:href="#speaker"
|
||||||
|
id="use443" />
|
||||||
|
<use
|
||||||
|
xlink:href="#remote_pause"
|
||||||
|
id="use6400" />
|
||||||
|
<use
|
||||||
|
xlink:href="#pause"
|
||||||
|
id="use5615" />
|
||||||
|
<use
|
||||||
|
xlink:href="#pause_shadow"
|
||||||
|
id="use5617" />
|
||||||
|
<use
|
||||||
|
xlink:href="#record"
|
||||||
|
id="use4517" />
|
||||||
|
<use
|
||||||
|
xlink:href="#remote_record"
|
||||||
|
id="use4519" />
|
||||||
|
<use
|
||||||
|
xlink:href="#shadow"
|
||||||
|
id="use4523" />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
id="variations"
|
||||||
|
clip-path="url(#clipPath)"
|
||||||
|
style="display:inline">
|
||||||
|
<g
|
||||||
|
id="extra_menu"
|
||||||
|
display="none"
|
||||||
|
fill="none"
|
||||||
|
stroke="#0000ff"
|
||||||
|
stroke-width="3">
|
||||||
|
<image
|
||||||
|
id="active_call_view_extra_menu"
|
||||||
|
x="0"
|
||||||
|
y="231"
|
||||||
|
width="1170"
|
||||||
|
height="2301"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/active_call_view_extra_menu.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<rect
|
||||||
|
x="36"
|
||||||
|
y="1842"
|
||||||
|
width="1098"
|
||||||
|
height="645"
|
||||||
|
id="rect493" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="mute"
|
||||||
|
display="none"
|
||||||
|
fill="none"
|
||||||
|
stroke="#0000ff"
|
||||||
|
stroke-width="3">
|
||||||
|
<image
|
||||||
|
id="active_call_view_mute"
|
||||||
|
x="0"
|
||||||
|
y="231"
|
||||||
|
width="1170"
|
||||||
|
height="2301"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/active_call_view_mute.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<rect
|
||||||
|
x="382"
|
||||||
|
y="2322"
|
||||||
|
width="72"
|
||||||
|
height="92"
|
||||||
|
id="rect497" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="speaker"
|
||||||
|
display="none"
|
||||||
|
fill="none"
|
||||||
|
stroke="#0000ff"
|
||||||
|
stroke-width="3">
|
||||||
|
<image
|
||||||
|
id="active_call_view_speaker"
|
||||||
|
x="0"
|
||||||
|
y="231"
|
||||||
|
width="1170"
|
||||||
|
height="2301"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/active_call_view_speaker.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<rect
|
||||||
|
x="547"
|
||||||
|
y="2332"
|
||||||
|
width="73"
|
||||||
|
height="72"
|
||||||
|
id="rect501" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="remote_pause"
|
||||||
|
display="none"
|
||||||
|
fill="none"
|
||||||
|
stroke="#0000ff"
|
||||||
|
stroke-width="3">
|
||||||
|
<image
|
||||||
|
id="active_call_view_remote_pause"
|
||||||
|
x="0"
|
||||||
|
y="231"
|
||||||
|
width="1170"
|
||||||
|
height="2301"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/active_call_view_remote_pause.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<rect
|
||||||
|
x="285"
|
||||||
|
y="804"
|
||||||
|
width="600"
|
||||||
|
height="600"
|
||||||
|
id="rect6448" />
|
||||||
|
<rect
|
||||||
|
x="153.75529"
|
||||||
|
y="1480.1888"
|
||||||
|
width="856.05585"
|
||||||
|
height="192.62233"
|
||||||
|
id="rect6452"
|
||||||
|
style="stroke-width:3.37767" />
|
||||||
|
<rect
|
||||||
|
x="675"
|
||||||
|
y="2292"
|
||||||
|
width="150"
|
||||||
|
height="150"
|
||||||
|
id="rect6454" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="pause"
|
||||||
|
display="none"
|
||||||
|
fill="none"
|
||||||
|
stroke="#0000ff"
|
||||||
|
stroke-width="3">
|
||||||
|
<image
|
||||||
|
id="active_call_view_pause"
|
||||||
|
x="0"
|
||||||
|
y="231"
|
||||||
|
width="1170"
|
||||||
|
height="2301"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/active_call_view_pause.png"
|
||||||
|
sodipodi:insensitive="true"
|
||||||
|
style="display:inline" />
|
||||||
|
<rect
|
||||||
|
x="984"
|
||||||
|
y="488"
|
||||||
|
width="120"
|
||||||
|
height="120"
|
||||||
|
id="rect5663" />
|
||||||
|
<rect
|
||||||
|
x="285"
|
||||||
|
y="821"
|
||||||
|
width="600"
|
||||||
|
height="600"
|
||||||
|
id="rect5665" />
|
||||||
|
<rect
|
||||||
|
x="70"
|
||||||
|
y="1496"
|
||||||
|
width="1023"
|
||||||
|
height="160"
|
||||||
|
id="rect5667" />
|
||||||
|
<rect
|
||||||
|
x="675"
|
||||||
|
y="2292"
|
||||||
|
width="150"
|
||||||
|
height="150"
|
||||||
|
id="rect5669" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="pause_shadow"
|
||||||
|
display="none"
|
||||||
|
fill="none"
|
||||||
|
stroke="#0000ff"
|
||||||
|
stroke-width="3">
|
||||||
|
<image
|
||||||
|
id="active_call_view_pause_shadow"
|
||||||
|
x="0"
|
||||||
|
y="231"
|
||||||
|
width="1170"
|
||||||
|
height="2301"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/active_call_view_pause_shadow.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<rect
|
||||||
|
x="0"
|
||||||
|
y="231"
|
||||||
|
width="1170"
|
||||||
|
height="2016"
|
||||||
|
id="rect5673" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="record"
|
||||||
|
display="none"
|
||||||
|
fill="none"
|
||||||
|
stroke="#0000ff"
|
||||||
|
stroke-width="3">
|
||||||
|
<image
|
||||||
|
id="active_call_view_record"
|
||||||
|
x="0"
|
||||||
|
y="231"
|
||||||
|
width="1170"
|
||||||
|
height="2301"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/active_call_view_record.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<rect
|
||||||
|
x="66"
|
||||||
|
y="488"
|
||||||
|
width="120"
|
||||||
|
height="120"
|
||||||
|
id="rect4555" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="remote_record"
|
||||||
|
display="none"
|
||||||
|
fill="none"
|
||||||
|
stroke="#0000ff"
|
||||||
|
stroke-width="3">
|
||||||
|
<image
|
||||||
|
id="active_call_view_remote_record"
|
||||||
|
x="0"
|
||||||
|
y="231"
|
||||||
|
width="1170"
|
||||||
|
height="2301"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/active_call_view_remote_record.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<rect
|
||||||
|
x="36"
|
||||||
|
y="458"
|
||||||
|
width="1098"
|
||||||
|
height="285"
|
||||||
|
id="rect4559" />
|
||||||
|
<rect
|
||||||
|
x="299"
|
||||||
|
y="1066"
|
||||||
|
width="573"
|
||||||
|
height="641"
|
||||||
|
id="rect4561" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="shadow"
|
||||||
|
display="none"
|
||||||
|
fill="none"
|
||||||
|
stroke="#0000ff"
|
||||||
|
stroke-width="3">
|
||||||
|
<image
|
||||||
|
id="active_call_view_shadow"
|
||||||
|
x="0"
|
||||||
|
y="231"
|
||||||
|
width="1170"
|
||||||
|
height="2301"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/active_call_view_shadow.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<rect
|
||||||
|
x="0"
|
||||||
|
y="231"
|
||||||
|
width="1170"
|
||||||
|
height="2301"
|
||||||
|
id="rect4569" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="mask"
|
||||||
|
opacity="0.4"
|
||||||
|
fill="#000"
|
||||||
|
stroke="none">
|
||||||
|
<rect
|
||||||
|
x="376.0"
|
||||||
|
y="2492.0"
|
||||||
|
width="418.0"
|
||||||
|
height="16.0"
|
||||||
|
sodipodi:insensitive="true"
|
||||||
|
id="rect372" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:3"
|
||||||
|
id="rect548"
|
||||||
|
width="147.46097"
|
||||||
|
height="45.518494"
|
||||||
|
x="228.5408"
|
||||||
|
y="296.81857" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:3"
|
||||||
|
id="rect551"
|
||||||
|
width="57.846436"
|
||||||
|
height="45.518494"
|
||||||
|
x="483.63406"
|
||||||
|
y="296.81857" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:3"
|
||||||
|
id="rect553"
|
||||||
|
width="57.846439"
|
||||||
|
height="45.518494"
|
||||||
|
x="413.93387"
|
||||||
|
y="296.81857" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:3"
|
||||||
|
id="rect555"
|
||||||
|
width="119.96021"
|
||||||
|
height="38.880386"
|
||||||
|
x="259.83478"
|
||||||
|
y="366.99292" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:3"
|
||||||
|
id="rect557"
|
||||||
|
width="155.52155"
|
||||||
|
height="49.311703"
|
||||||
|
x="275.9559"
|
||||||
|
y="2159.2839" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 8.4 KiB |
103
UITests/Screenshots/call_failed_error_view.svg
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="1170.0"
|
||||||
|
height="2532.0"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 1170.0 2532.0"
|
||||||
|
id="svg941"
|
||||||
|
sodipodi:docname="call_failed_error_view.svg"
|
||||||
|
inkscape:version="1.2.1 (9c6d41e, 2022-07-14)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview943"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="0.52725813"
|
||||||
|
inkscape:cx="703.64017"
|
||||||
|
inkscape:cy="595.53373"
|
||||||
|
inkscape:window-width="1624"
|
||||||
|
inkscape:window-height="804"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="241"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="mask" />
|
||||||
|
<g
|
||||||
|
id="reference"
|
||||||
|
sodipodi:insensitive="true">
|
||||||
|
<image
|
||||||
|
id="call_failed_error_view"
|
||||||
|
x="180.0"
|
||||||
|
y="1075.0"
|
||||||
|
width="810.0"
|
||||||
|
height="421.0000000000001"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/call_failed_error_view.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
</g>
|
||||||
|
<defs
|
||||||
|
id="defs935">
|
||||||
|
<clipPath
|
||||||
|
id="clipPath" />
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
id="variations"
|
||||||
|
clip-path="url(#clipPath)" />
|
||||||
|
<g
|
||||||
|
id="mask"
|
||||||
|
opacity="0.4"
|
||||||
|
fill="#000"
|
||||||
|
stroke="none">
|
||||||
|
<rect
|
||||||
|
x="376.0"
|
||||||
|
y="2492.0"
|
||||||
|
width="418.0"
|
||||||
|
height="16.0"
|
||||||
|
sodipodi:insensitive="true"
|
||||||
|
id="rect938" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:2.9485"
|
||||||
|
id="rect1062"
|
||||||
|
width="55"
|
||||||
|
height="55"
|
||||||
|
x="180"
|
||||||
|
y="1075" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:2.9485"
|
||||||
|
id="rect1062-4"
|
||||||
|
width="55"
|
||||||
|
height="55"
|
||||||
|
x="935"
|
||||||
|
y="1075" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:2.9485"
|
||||||
|
id="rect1062-4-8"
|
||||||
|
width="55"
|
||||||
|
height="55"
|
||||||
|
x="935"
|
||||||
|
y="1441" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:2.9485"
|
||||||
|
id="rect1062-4-3"
|
||||||
|
width="55"
|
||||||
|
height="55"
|
||||||
|
x="180"
|
||||||
|
y="1441" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:3"
|
||||||
|
id="rect365"
|
||||||
|
width="513.97974"
|
||||||
|
height="49.31171"
|
||||||
|
x="326.21594"
|
||||||
|
y="1204.3436" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.5 KiB |
75
UITests/Screenshots/call_numpad_view.svg
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="1170.0"
|
||||||
|
height="2532.0"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 1170.0 2532.0"
|
||||||
|
id="svg141"
|
||||||
|
sodipodi:docname="call_numpad_view.svg"
|
||||||
|
inkscape:version="1.2.1 (9c6d41e, 2022-07-14)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview143"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="2.9826224"
|
||||||
|
inkscape:cx="300.23915"
|
||||||
|
inkscape:cy="2174.9317"
|
||||||
|
inkscape:window-width="1717"
|
||||||
|
inkscape:window-height="852"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="25"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="mask" />
|
||||||
|
<g
|
||||||
|
id="reference"
|
||||||
|
sodipodi:insensitive="true">
|
||||||
|
<image
|
||||||
|
id="call_numpad_view"
|
||||||
|
x="30.0"
|
||||||
|
y="458.00000000000006"
|
||||||
|
width="1110.0"
|
||||||
|
height="2074.0"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/call_numpad_view.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
</g>
|
||||||
|
<defs
|
||||||
|
id="defs135">
|
||||||
|
<clipPath
|
||||||
|
id="clipPath" />
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
id="variations"
|
||||||
|
clip-path="url(#clipPath)" />
|
||||||
|
<g
|
||||||
|
id="mask"
|
||||||
|
opacity="0.4"
|
||||||
|
fill="#000"
|
||||||
|
stroke="none">
|
||||||
|
<rect
|
||||||
|
x="376.0"
|
||||||
|
y="2492.0"
|
||||||
|
width="418.0"
|
||||||
|
height="16.0"
|
||||||
|
sodipodi:insensitive="true"
|
||||||
|
id="rect138" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:2.29653"
|
||||||
|
id="rect364"
|
||||||
|
width="158.58528"
|
||||||
|
height="55.990997"
|
||||||
|
x="271.57312"
|
||||||
|
y="2155.8208" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
160
UITests/Screenshots/call_stats_view.svg
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="1170.0"
|
||||||
|
height="2532.0"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 1170.0 2532.0"
|
||||||
|
id="svg3938"
|
||||||
|
sodipodi:docname="call_stats_view.svg"
|
||||||
|
inkscape:version="1.2.1 (9c6d41e4, 2022-07-14)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview3940"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="1.0545163"
|
||||||
|
inkscape:cx="415.83046"
|
||||||
|
inkscape:cy="1161.67"
|
||||||
|
inkscape:window-width="1440"
|
||||||
|
inkscape:window-height="766"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="25"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="mask" />
|
||||||
|
<g
|
||||||
|
id="reference"
|
||||||
|
sodipodi:insensitive="true">
|
||||||
|
<image
|
||||||
|
id="call_stats_view"
|
||||||
|
x="30.0"
|
||||||
|
y="458.00000000000006"
|
||||||
|
width="1110.0"
|
||||||
|
height="2074.0"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/call_stats_view.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
</g>
|
||||||
|
<defs
|
||||||
|
id="defs3932">
|
||||||
|
<clipPath
|
||||||
|
id="clipPath">
|
||||||
|
<use
|
||||||
|
xlink:href="#remote_pause"
|
||||||
|
id="use135" />
|
||||||
|
<use
|
||||||
|
xlink:href="#pause"
|
||||||
|
id="use137" />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
id="variations"
|
||||||
|
clip-path="url(#clipPath)">
|
||||||
|
<g
|
||||||
|
id="remote_pause"
|
||||||
|
display="none"
|
||||||
|
fill="none"
|
||||||
|
stroke="#00f"
|
||||||
|
stroke-width="3">
|
||||||
|
<image
|
||||||
|
id="call_stats_view_remote_pause"
|
||||||
|
x="30.0"
|
||||||
|
y="458.00000000000006"
|
||||||
|
width="1110.0"
|
||||||
|
height="2074.0"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/call_stats_view_remote_pause.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<rect
|
||||||
|
x="30.0"
|
||||||
|
y="458.0"
|
||||||
|
width="1110.0"
|
||||||
|
height="1789.0"
|
||||||
|
id="rect142" />
|
||||||
|
<rect
|
||||||
|
x="675.0"
|
||||||
|
y="2292.0"
|
||||||
|
width="150.0"
|
||||||
|
height="150.0"
|
||||||
|
id="rect144" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="pause"
|
||||||
|
display="none"
|
||||||
|
fill="none"
|
||||||
|
stroke="#00f"
|
||||||
|
stroke-width="3">
|
||||||
|
<image
|
||||||
|
id="call_stats_view_pause"
|
||||||
|
x="30.0"
|
||||||
|
y="458.00000000000006"
|
||||||
|
width="1110.0"
|
||||||
|
height="2074.0"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/call_stats_view_pause.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<rect
|
||||||
|
x="30.0"
|
||||||
|
y="458.0"
|
||||||
|
width="1110.0"
|
||||||
|
height="1789.0"
|
||||||
|
id="rect148" />
|
||||||
|
<rect
|
||||||
|
x="675.0"
|
||||||
|
y="2292.0"
|
||||||
|
width="150.0"
|
||||||
|
height="150.0"
|
||||||
|
id="rect150" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="mask"
|
||||||
|
opacity="0.4"
|
||||||
|
fill="#000"
|
||||||
|
stroke="none">
|
||||||
|
<rect
|
||||||
|
x="376.0"
|
||||||
|
y="2492.0"
|
||||||
|
width="418.0"
|
||||||
|
height="16.0"
|
||||||
|
sodipodi:insensitive="true"
|
||||||
|
id="rect3935" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:4.13671"
|
||||||
|
id="rect4059"
|
||||||
|
width="838.10724"
|
||||||
|
height="35.804604"
|
||||||
|
x="189.54741"
|
||||||
|
y="928.61865" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:4.39858"
|
||||||
|
id="rect4059-0"
|
||||||
|
width="836.76611"
|
||||||
|
height="40.546116"
|
||||||
|
x="190.81631"
|
||||||
|
y="971.17676" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:2.25609"
|
||||||
|
id="rect4059-0-3"
|
||||||
|
width="163.53305"
|
||||||
|
height="54.580029"
|
||||||
|
x="272.95486"
|
||||||
|
y="2156.0237" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000"
|
||||||
|
id="rect180"
|
||||||
|
width="23.707523"
|
||||||
|
height="36.035645"
|
||||||
|
x="676.1394"
|
||||||
|
y="1054.512" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.8 KiB |
76
UITests/Screenshots/dialer_view.svg
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="1170.0"
|
||||||
|
height="2532.0"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 1170.0 2532.0"
|
||||||
|
id="svg436"
|
||||||
|
sodipodi:docname="dialer_view.svg"
|
||||||
|
inkscape:version="1.2.1 (9c6d41e, 2022-07-14)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview438"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="2.1090326"
|
||||||
|
inkscape:cx="922.935"
|
||||||
|
inkscape:cy="329.53497"
|
||||||
|
inkscape:window-width="1755"
|
||||||
|
inkscape:window-height="958"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="25"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg436" />
|
||||||
|
<g
|
||||||
|
id="reference"
|
||||||
|
sodipodi:insensitive="true">
|
||||||
|
<image
|
||||||
|
id="dialer_view"
|
||||||
|
x="0.0"
|
||||||
|
y="231.0"
|
||||||
|
width="1170.0"
|
||||||
|
height="2103.0"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xlink:href="images/dialer_view.png"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
</g>
|
||||||
|
<defs
|
||||||
|
id="defs430">
|
||||||
|
<clipPath
|
||||||
|
id="clipPath">
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
id="variations"
|
||||||
|
clip-path="url(#clipPath)" />
|
||||||
|
<g
|
||||||
|
id="mask"
|
||||||
|
opacity="0.4"
|
||||||
|
fill="#000"
|
||||||
|
stroke="none">
|
||||||
|
<rect
|
||||||
|
x="376.0"
|
||||||
|
y="2492.0"
|
||||||
|
width="418.0"
|
||||||
|
height="16.0"
|
||||||
|
sodipodi:insensitive="true"
|
||||||
|
id="rect433" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:3.16263"
|
||||||
|
id="rect609"
|
||||||
|
width="946.40552"
|
||||||
|
height="117.58946"
|
||||||
|
x="47.415104"
|
||||||
|
y="271.21439" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
BIN
UITests/Screenshots/images/IO_call_view.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
UITests/Screenshots/images/IO_call_view_mute.png
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
UITests/Screenshots/images/IO_call_view_outgoing.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
UITests/Screenshots/images/IO_call_view_speaker.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
UITests/Screenshots/images/Linphone.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
UITests/Screenshots/images/active_call_view.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
UITests/Screenshots/images/active_call_view_call_stats.png
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
UITests/Screenshots/images/active_call_view_extra_menu.png
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
UITests/Screenshots/images/active_call_view_mute.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
BIN
UITests/Screenshots/images/active_call_view_pause.png
Normal file
|
After Width: | Height: | Size: 159 KiB |
BIN
UITests/Screenshots/images/active_call_view_pause_shadow.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
UITests/Screenshots/images/active_call_view_record.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
UITests/Screenshots/images/active_call_view_remote_pause.png
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
UITests/Screenshots/images/active_call_view_remote_record.png
Normal file
|
After Width: | Height: | Size: 119 KiB |
BIN
UITests/Screenshots/images/active_call_view_shadow.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
UITests/Screenshots/images/active_call_view_speaker.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
UITests/Screenshots/images/call_failed_error_view.png
Normal file
|
After Width: | Height: | Size: 221 KiB |
BIN
UITests/Screenshots/images/call_numpad_view.png
Normal file
|
After Width: | Height: | Size: 137 KiB |
BIN
UITests/Screenshots/images/call_stats_view.png
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
UITests/Screenshots/images/call_stats_view_pause.png
Normal file
|
After Width: | Height: | Size: 193 KiB |
BIN
UITests/Screenshots/images/call_stats_view_remote_pause.png
Normal file
|
After Width: | Height: | Size: 186 KiB |