Commit 672a2146 authored by Jose Blaya's avatar Jose Blaya
Browse files

- Updated VPN connection button to PIAX

- Animations for connecting, connected and disconnected status
parent a66bc418
......@@ -158,6 +158,8 @@
5E6B7667C4B1E6590A54A69E /* Pods_PIA_VPN_dev.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0E3B16D09433B9FD02705DB /* Pods_PIA_VPN_dev.framework */; };
DD1AA4962180AD92005116D7 /* CustomDNSSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1AA4952180AD92005116D7 /* CustomDNSSettingsViewController.swift */; };
DD1AA4972180AD92005116D7 /* CustomDNSSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1AA4952180AD92005116D7 /* CustomDNSSettingsViewController.swift */; };
DD58F4BF21B12CFE00D043F7 /* PIAConnectionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD58F4BE21B12CFE00D043F7 /* PIAConnectionButton.swift */; };
DD58F4C021B12CFE00D043F7 /* PIAConnectionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD58F4BE21B12CFE00D043F7 /* PIAConnectionButton.swift */; };
DD746957217F070700B7BD73 /* DNS.plist in Resources */ = {isa = PBXBuildFile; fileRef = DD746956217F070700B7BD73 /* DNS.plist */; };
DD746958217F070700B7BD73 /* DNS.plist in Resources */ = {isa = PBXBuildFile; fileRef = DD746956217F070700B7BD73 /* DNS.plist */; };
DD74695A217F07AC00B7BD73 /* DNSList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD746959217F07AC00B7BD73 /* DNSList.swift */; };
......@@ -409,6 +411,7 @@
CD77859A2939E107EEAF5D00 /* Pods-PIA VPN.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PIA VPN.release.xcconfig"; path = "Pods/Target Support Files/Pods-PIA VPN/Pods-PIA VPN.release.xcconfig"; sourceTree = "<group>"; };
D0E3B16D09433B9FD02705DB /* Pods_PIA_VPN_dev.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PIA_VPN_dev.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DD1AA4952180AD92005116D7 /* CustomDNSSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDNSSettingsViewController.swift; sourceTree = "<group>"; };
DD58F4BE21B12CFE00D043F7 /* PIAConnectionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIAConnectionButton.swift; sourceTree = "<group>"; };
DD746956217F070700B7BD73 /* DNS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = DNS.plist; sourceTree = "<group>"; };
DD746959217F07AC00B7BD73 /* DNSList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSList.swift; sourceTree = "<group>"; };
DDC8124B2176185000CB290C /* SwiftGen+SeguesStoryboards.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SwiftGen+SeguesStoryboards.swift"; sourceTree = "<group>"; };
......@@ -772,6 +775,7 @@
DDC8124B2176185000CB290C /* SwiftGen+SeguesStoryboards.swift */,
DDC8124E21761B0B00CB290C /* SwiftGen+ScenesStoryboards.swift */,
0E2215C820084CD700F5FB4D /* SwiftGen+Strings.swift */,
DD58F4BE21B12CFE00D043F7 /* PIAConnectionButton.swift */,
);
name = Shared;
sourceTree = "<group>";
......@@ -1385,6 +1389,7 @@
0E3A35291FD9A960000B0F99 /* DashboardViewController.swift in Sources */,
0E9452A61FDB578400891948 /* RegionCell.swift in Sources */,
0EFDC1ED1FE4B9DC007C0B9B /* AppConstants.swift in Sources */,
DD58F4C021B12CFE00D043F7 /* PIAConnectionButton.swift in Sources */,
0EE14D131FF129AF008D9AC2 /* PIASwitch.m in Sources */,
0E2215CA2008BA9100F5FB4D /* SwiftGen+Strings.swift in Sources */,
0EFDC1C71FE35B78007C0B9B /* Macros+App.swift in Sources */,
......@@ -1469,6 +1474,7 @@
0E3A35281FD9A960000B0F99 /* DashboardViewController.swift in Sources */,
0E9452A51FDB578400891948 /* RegionCell.swift in Sources */,
0EFDC1EC1FE4B9DC007C0B9B /* AppConstants.swift in Sources */,
DD58F4BF21B12CFE00D043F7 /* PIAConnectionButton.swift in Sources */,
0EE14D121FF12991008D9AC2 /* PIASwitch.m in Sources */,
0E2215C920084CD700F5FB4D /* SwiftGen+Strings.swift in Sources */,
0EFDC1C61FE35B78007C0B9B /* Macros+App.swift in Sources */,
......
......@@ -24,11 +24,7 @@ class DashboardViewController: AutolayoutViewController {
@IBOutlet private weak var viewConnection: UIView!
@IBOutlet private weak var toggleConnection: PIASwitch!
@IBOutlet private weak var labelStatusCaption: UILabel!
@IBOutlet private weak var labelStatus: UILabel!
@IBOutlet private weak var toggleConnection: PIAConnectionButton!
@IBOutlet private weak var viewFooterSeparator: UIView!
......@@ -74,14 +70,12 @@ class DashboardViewController: AutolayoutViewController {
viewContent.isHidden = true
viewRows.isHidden = true
labelStatusCaption.text = L10n.Dashboard.status
labelRegionCaption.text = L10n.Dashboard.Connection.Region.caption
buttonChangeRegion.setTitle(L10n.Dashboard.Connection.Region.change, for: .normal)
labelPublicIPCaption.text = L10n.Dashboard.Connection.Ip.caption
currentPageIndex = 0
toggleConnection.addTarget(self, action: #selector(toggleMoved(_:)), for: .valueChanged)
buttonChangeRegion.accessibilityIdentifier = "uitests.main.pick_region";
SideMenuManager.default.menuLeftNavigationController = StoryboardScene.Main.sideMenuNavigationController.instantiate()
......@@ -202,8 +196,8 @@ class DashboardViewController: AutolayoutViewController {
perform(segue: StoryboardSegue.Main.menuSegueIdentifier)
}
@objc private func toggleMoved(_ sender: Any?) {
if toggleConnection.isOn {
@IBAction func vpnButtonClicked(_ sender: Any?) {
if !toggleConnection.isOn {
Client.providers.vpnProvider.connect(nil)
} else {
Client.providers.vpnProvider.disconnect(nil)
......@@ -271,28 +265,32 @@ class DashboardViewController: AutolayoutViewController {
@objc private func updateCurrentStatusWithUserInfo(_ userInfo: [AnyHashable: Any]?) {
currentStatus = Client.providers.vpnProvider.vpnStatus
Theme.current.applyVPNStatus(labelStatus, forStatus: currentStatus)
//Theme.current.applyVPNStatus(labelStatus, forStatus: currentStatus)
switch currentStatus {
case .connected:
toggleConnection.isOn = true
toggleConnection.isIndeterminate = false
labelStatus.text = L10n.Dashboard.Vpn.connected
toggleConnection.stopButtonAnimation()
// labelStatus.text = L10n.Dashboard.Vpn.connected
case .disconnected:
toggleConnection.isOn = false
toggleConnection.isIndeterminate = false
labelStatus.text = L10n.Dashboard.Vpn.disconnected
toggleConnection.stopButtonAnimation()
// labelStatus.text = L10n.Dashboard.Vpn.disconnected
case .connecting:
toggleConnection.isOn = true
toggleConnection.isIndeterminate = true
labelStatus.text = L10n.Dashboard.Vpn.connecting
toggleConnection.startButtonAnimation()
// labelStatus.text = L10n.Dashboard.Vpn.connecting
case .disconnecting:
toggleConnection.isOn = true
toggleConnection.isIndeterminate = true
labelStatus.text = L10n.Dashboard.Vpn.disconnecting
toggleConnection.startButtonAnimation()
// labelStatus.text = L10n.Dashboard.Vpn.disconnecting
// case .changingServer:
// powerConnection.powerState = .pending
......@@ -304,7 +302,7 @@ class DashboardViewController: AutolayoutViewController {
imvRegion.setImage(fromServer: server.flagServer(forStatus: currentStatus))
// XXX hack to suppress "ellipsis"
viewConnectionArea.accessibilityLabel = labelStatus.text
//viewConnectionArea.accessibilityLabel = labelStatus.text
viewConnectionArea.accessibilityLabel = viewConnectionArea.accessibilityLabel?.replacingOccurrences(of: "...", with: "")
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, viewConnectionArea)
......@@ -351,14 +349,12 @@ class DashboardViewController: AutolayoutViewController {
navigationItem.titleView = NavigationLogoView()
Theme.current.applyLightNavigationBar(navigationController!.navigationBar)
Theme.current.applyTitle(labelStatusCaption, appearance: .dark)
Theme.current.applyCaption(labelPublicIPCaption, appearance: .dark)
Theme.current.applyTitle(labelPublicIP, appearance: .dark)
Theme.current.applyCaption(labelRegionCaption, appearance: .dark)
Theme.current.applyTitle(labelRegion, appearance: .dark)
Theme.current.applyCaption(buttonChangeRegion, appearance: .emphasis)
Theme.current.applyTextButton(buttonChangeRegion)
Theme.current.applyToggle(toggleConnection)
// XXX: emulate native UITableView separator
Theme.current.applyDividerToSeparator(tableRows)
......
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
{
"images" : [
{
"idiom" : "universal",
"filename" : "connected.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
//
// PIAConnectionButton.swift
// PIA VPN
//
// Created by Jose Antonio Blaya Garcia on 30/11/2018.
// Copyright © 2018 London Trust Media. All rights reserved.
//
import Foundation
private struct PIAConnectionButtonSettings {
static let outsideBorderWidth: CGFloat = 10.0
static let animatedShapeWidth: CGFloat = 2.0
static let startAngle: CGFloat = -0.25 * 2 * .pi
static let endAngle: CGFloat = PIAConnectionButtonSettings.startAngle + 2 * .pi
static let udpateColorAnimationDuration = 0.3
static let shapeAnimationDuration = 2
static let shapeEndAnimationDuration = 0.3
static let timingFunction = CAMediaTimingFunction(controlPoints: 0.2, 0.88, 0.09, 0.99)
}
class PIAConnectionButton: UIButton {
private var isAnimating: Bool = false
var isOn: Bool = false
var isIndeterminate: Bool = false
private let circlePathLayer = CAShapeLayer()
private var circleRadius: CGFloat!
private var currenStrokeEnd: CGFloat!
private var displayLink: CADisplayLink!
override init(frame: CGRect) {
super.init(frame: frame)
self.setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupView()
}
private func setupView() {
displayLink = CADisplayLink(target: self, selector: #selector(redrawUpdate))
//Configure the button static color
self.layer.cornerRadius = self.frame.width/2
self.layer.borderWidth = PIAConnectionButtonSettings.outsideBorderWidth
self.layer.borderColor = UIColor.piaGrey2.cgColor
//Configure the Bezierpath to animate
self.circlePathLayer.strokeEnd = 1
self.circlePathLayer.frame = bounds
self.circlePathLayer.lineWidth = PIAConnectionButtonSettings.animatedShapeWidth
self.circlePathLayer.fillColor = UIColor.clear.cgColor
self.updateColors()
self.layer.addSublayer(circlePathLayer)
self.clipsToBounds = true
//Image
let vpnImage = Asset.Piax.Dashboard.vpnButton.image.withRenderingMode(.alwaysTemplate)
self.setImage(vpnImage, for: [])
}
private func circleAnimationPath() -> UIBezierPath {
self.circleRadius = (self.frame.width - (self.layer.borderWidth*2))/2
let center = CGPoint(x: self.bounds.width/2,
y: self.bounds.height/2)
return UIBezierPath(arcCenter: center,
radius: self.circleRadius,
startAngle: PIAConnectionButtonSettings.startAngle,
endAngle: PIAConnectionButtonSettings.endAngle,
clockwise: true)
}
private func updateColors() {
UIView.animate(withDuration: PIAConnectionButtonSettings.udpateColorAnimationDuration) { [weak self] in
if let weakSelf = self {
if weakSelf.isOn {
weakSelf.circlePathLayer.strokeColor = UIColor.piaGreen.cgColor
weakSelf.tintColor = UIColor.piaGreen
} else {
weakSelf.circlePathLayer.strokeColor = UIColor.piaRedDark.cgColor
weakSelf.tintColor = UIColor.piaRedDark
}
if weakSelf.isIndeterminate {
weakSelf.circlePathLayer.strokeColor = UIColor.piaYellowDark.cgColor
weakSelf.tintColor = UIColor.piaYellowDark
}
}
}
}
override func layoutSubviews() {
super.layoutSubviews()
circlePathLayer.frame = bounds
circlePathLayer.path = circleAnimationPath().cgPath
}
func startButtonAnimation() {
displayLink.add(to: .current, forMode: .commonModes)
self.updateColors()
let duration: CFTimeInterval = CFTimeInterval(PIAConnectionButtonSettings.shapeAnimationDuration)
let end = CABasicAnimation(keyPath: "strokeEnd")
end.fromValue = 0
end.toValue = 1
end.beginTime = 0
end.duration = duration * 0.75
end.timingFunction = PIAConnectionButtonSettings.timingFunction
end.fillMode = kCAFillModeForwards
let begin = CABasicAnimation(keyPath: "strokeStart")
begin.fromValue = 0
begin.toValue = 1
begin.beginTime = duration * 0.15
begin.duration = duration * 0.85
begin.timingFunction = PIAConnectionButtonSettings.timingFunction
begin.fillMode = kCAFillModeBackwards
let opacity = CABasicAnimation(keyPath: "opacity")
opacity.fromValue = 0
opacity.toValue = 1
opacity.beginTime = 0
opacity.duration = duration * 0.75
opacity.timingFunction = PIAConnectionButtonSettings.timingFunction
opacity.fillMode = kCAFillModeForwards
let group = CAAnimationGroup()
group.animations = [end, begin, opacity]
group.duration = duration
group.repeatCount = .infinity
group.isRemovedOnCompletion = false
self.circlePathLayer.add(group, forKey: "move")
isAnimating = true
}
func stopButtonAnimation() {
self.updateColors()
self.circlePathLayer.removeAllAnimations()
self.circlePathLayer.strokeEnd = 1
self.circlePathLayer.strokeStart = 0
if isAnimating {
let ending = CABasicAnimation(keyPath: "strokeEnd")
ending.fromValue = self.currenStrokeEnd
ending.toValue = 1
ending.duration = PIAConnectionButtonSettings.shapeEndAnimationDuration
ending.fillMode = kCAFillModeForwards
self.circlePathLayer.add(ending, forKey: "move")
displayLink.remove(from: .current, forMode: .commonModes)
}
isAnimating = false
}
@objc func redrawUpdate() {
if let layer = self.circlePathLayer.presentation() {
if let value = layer.value(forKey: "strokeEnd") as? CGFloat {
self.currenStrokeEnd = value
}
}
}
}
......@@ -45,6 +45,9 @@ struct ColorAsset {
// swiftlint:disable identifier_name line_length nesting type_body_length type_name
enum Asset {
enum Piax {
enum Dashboard {
static let vpnButton = ImageAsset(name: "vpn-button")
}
enum Global {
static let iconBack = ImageAsset(name: "icon-back")
static let pagecontrolSelectedDot = ImageAsset(name: "pagecontrol-selected-dot")
......@@ -314,6 +317,7 @@ enum Asset {
static let allColors: [ColorAsset] = [
]
static let allImages: [ImageAsset] = [
Piax.Dashboard.vpnButton,
Piax.Global.iconBack,
Piax.Global.pagecontrolSelectedDot,
Piax.Global.pagecontrolUnselectedDot,
......
......@@ -502,39 +502,26 @@
<rect key="frame" x="0.0" y="0.0" width="359" height="533.66666666666663"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hkt-DN-kZZ">
<rect key="frame" x="0.0" y="199" width="359" height="135.66666666666663"/>
<rect key="frame" x="0.0" y="100" width="359" height="150"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Status" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BmT-10-tRN">
<rect key="frame" x="155" y="0.0" width="49.333333333333343" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Connected to VPN" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="g6c-8P-2tV">
<rect key="frame" x="110.66666666666667" y="26" width="137.66666666666663" height="19.666666666666671"/>
<accessibility key="accessibilityConfiguration">
<bool key="isElement" value="NO"/>
</accessibility>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="i8m-Ed-q8t">
<rect key="frame" x="104.66666666666669" y="60.666666666666686" width="150" height="75"/>
<rect key="frame" x="104.66666666666669" y="0.0" width="150" height="150"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3ro-hb-UxF" customClass="PIASwitch">
<rect key="frame" x="0.0" y="0.0" width="150" height="75"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3ro-hb-UxF" customClass="PIAConnectionButton" customModule="PIA_VPN" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="150" height="150"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="150" id="Iiv-TX-jPz"/>
<constraint firstAttribute="width" secondItem="3ro-hb-UxF" secondAttribute="height" multiplier="2" id="Ph6-xL-Od0"/>
<constraint firstAttribute="height" constant="75" id="eKt-70-tGa"/>
<constraint firstAttribute="height" constant="150" id="eKt-70-tGa"/>
</constraints>
<connections>
<action selector="vpnButtonClicked:" destination="CEm-fv-KfP" eventType="touchUpInside" id="pco-w4-4qa"/>
</connections>
</view>
</subviews>
<constraints>
<constraint firstItem="3ro-hb-UxF" firstAttribute="leading" secondItem="i8m-Ed-q8t" secondAttribute="leading" id="5bt-6r-Jbf"/>
<constraint firstItem="3ro-hb-UxF" firstAttribute="top" secondItem="i8m-Ed-q8t" secondAttribute="top" id="c3U-TQ-o4n"/>
<constraint firstItem="3ro-hb-UxF" firstAttribute="top" secondItem="i8m-Ed-q8t" secondAttribute="top" id="nkx-ZJ-cKV"/>
<constraint firstAttribute="bottom" secondItem="3ro-hb-UxF" secondAttribute="bottom" id="p4g-hu-lWy"/>
<constraint firstAttribute="trailing" secondItem="3ro-hb-UxF" secondAttribute="trailing" id="xmF-rw-eQE"/>
</constraints>
......@@ -544,20 +531,16 @@
<bool key="isElement" value="YES"/>
</accessibility>
<constraints>
<constraint firstItem="g6c-8P-2tV" firstAttribute="top" secondItem="BmT-10-tRN" secondAttribute="bottom" constant="5" id="EOl-y9-XOP"/>
<constraint firstItem="i8m-Ed-q8t" firstAttribute="top" secondItem="g6c-8P-2tV" secondAttribute="bottom" constant="15" id="GXS-c6-tNL"/>
<constraint firstItem="g6c-8P-2tV" firstAttribute="centerX" secondItem="hkt-DN-kZZ" secondAttribute="centerX" id="N0o-04-wK9"/>
<constraint firstItem="BmT-10-tRN" firstAttribute="top" secondItem="hkt-DN-kZZ" secondAttribute="top" id="OJM-BB-4lf"/>
<constraint firstItem="i8m-Ed-q8t" firstAttribute="top" secondItem="hkt-DN-kZZ" secondAttribute="top" id="HNX-OK-29L"/>
<constraint firstItem="i8m-Ed-q8t" firstAttribute="centerX" secondItem="hkt-DN-kZZ" secondAttribute="centerX" id="Vqm-8a-ADZ"/>
<constraint firstAttribute="bottom" secondItem="i8m-Ed-q8t" secondAttribute="bottom" id="gYI-5C-nFq"/>
<constraint firstItem="i8m-Ed-q8t" firstAttribute="centerX" secondItem="hkt-DN-kZZ" secondAttribute="centerX" id="uEP-qX-HO9"/>
<constraint firstItem="BmT-10-tRN" firstAttribute="centerX" secondItem="hkt-DN-kZZ" secondAttribute="centerX" id="vfd-al-qVa"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="hkt-DN-kZZ" secondAttribute="trailing" id="80S-hq-L3e"/>
<constraint firstItem="hkt-DN-kZZ" firstAttribute="centerY" secondItem="LIx-5E-b9S" secondAttribute="centerY" id="ari-ho-JEi"/>
<constraint firstItem="hkt-DN-kZZ" firstAttribute="leading" secondItem="LIx-5E-b9S" secondAttribute="leading" id="dPQ-fq-gUX"/>
<constraint firstItem="hkt-DN-kZZ" firstAttribute="top" secondItem="LIx-5E-b9S" secondAttribute="top" constant="100" id="tA8-8c-sxT"/>
</constraints>
</view>
</subviews>
......@@ -883,10 +866,8 @@
<outlet property="labelPublicIPCaption" destination="yXc-oo-hmb" id="jCD-dp-s7z"/>
<outlet property="labelRegion" destination="9YW-9Y-9ST" id="IsD-bK-xbd"/>
<outlet property="labelRegionCaption" destination="drf-oR-mWL" id="MJh-Lz-BZj"/>
<outlet property="labelStatus" destination="g6c-8P-2tV" id="mLX-wi-o0w"/>
<outlet property="labelStatusCaption" destination="BmT-10-tRN" id="YWC-9c-I3y"/>
<outlet property="tableRows" destination="iCQ-g6-3OE" id="LyA-m0-EPg"/>
<outlet property="toggleConnection" destination="3ro-hb-UxF" id="xL7-iV-IQs"/>
<outlet property="toggleConnection" destination="3ro-hb-UxF" id="DOc-d5-qxe"/>
<outlet property="viewConnection" destination="i8m-Ed-q8t" id="Kif-fW-fcJ"/>
<outlet property="viewConnectionArea" destination="hkt-DN-kZZ" id="uaD-2U-nMv"/>
<outlet property="viewContainer" destination="R8e-Ar-VG6" id="TS5-TK-5QP"/>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment