mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-20 16:42:44 +02:00
Create slider view
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class ArrowsAnimationView: UIView {
|
||||
|
||||
private enum Constants {
|
||||
static let numberOfArrows: Int = 3
|
||||
static let arrowSize: CGSize = CGSize(width: 14, height: 14)
|
||||
static let gradientAnimationKey: String = "gradient"
|
||||
static let gradientRatios: [CGFloat] = [1.0, 0.3, 0.2]
|
||||
}
|
||||
|
||||
private var gradientLayer: CAGradientLayer!
|
||||
private lazy var gradientAnimation: CABasicAnimation = {
|
||||
let animation = CABasicAnimation(keyPath: "locations")
|
||||
animation.fromValue = [0.0, 0.0, 0.25]
|
||||
animation.toValue = [0.75, 1.0, 1.0]
|
||||
animation.repeatCount = .infinity
|
||||
animation.duration = 1
|
||||
return animation
|
||||
}()
|
||||
private var theme: Theme = ThemeService.shared().theme
|
||||
private var arrowImageViews: [UIImageView] = []
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
setup()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
setup()
|
||||
}
|
||||
|
||||
private func setup() {
|
||||
let arrowImage = Asset.Images.disclosureIcon.image
|
||||
for i in 0..<Constants.numberOfArrows {
|
||||
let totalSpace = frame.width - CGFloat(Constants.numberOfArrows) * Constants.arrowSize.width
|
||||
let oneSpace = totalSpace / CGFloat(Constants.numberOfArrows - 1)
|
||||
let x = CGFloat(i) * (oneSpace + Constants.arrowSize.width)
|
||||
let y = (frame.height - Constants.arrowSize.height) / 2
|
||||
let imageView = UIImageView(frame: CGRect(origin: CGPoint(x: x, y: y),
|
||||
size: Constants.arrowSize))
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
imageView.tintColor = theme.tabBarUnselectedItemTintColor
|
||||
imageView.image = arrowImage
|
||||
addSubview(imageView)
|
||||
|
||||
arrowImageViews.append(imageView)
|
||||
}
|
||||
|
||||
gradientLayer = CAGradientLayer()
|
||||
gradientLayer.frame = bounds
|
||||
gradientLayer.locations = [0.25, 0.5, 0.75]
|
||||
gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
|
||||
gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
|
||||
// this color doesn't have to come from the theme, it's only used as a mask
|
||||
let color = UIColor.black
|
||||
let colors = Constants.gradientRatios.map({ color.withAlphaComponent($0) })
|
||||
gradientLayer.colors = colors.map({ $0.cgColor })
|
||||
|
||||
layer.mask = gradientLayer
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
gradientLayer.frame = bounds
|
||||
}
|
||||
|
||||
// MARK: - API
|
||||
|
||||
var isAnimating: Bool = false {
|
||||
didSet {
|
||||
if isAnimating {
|
||||
if gradientLayer.animation(forKey: Constants.gradientAnimationKey) == nil {
|
||||
gradientLayer.add(gradientAnimation,
|
||||
forKey: Constants.gradientAnimationKey)
|
||||
}
|
||||
} else {
|
||||
if gradientLayer.animation(forKey: Constants.gradientAnimationKey) != nil {
|
||||
gradientLayer.removeAnimation(forKey: Constants.gradientAnimationKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Themable
|
||||
|
||||
extension ArrowsAnimationView: Themable {
|
||||
|
||||
func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
|
||||
arrowImageViews.forEach({ $0.tintColor = theme.tabBarUnselectedItemTintColor })
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Reusable
|
||||
|
||||
@objcMembers
|
||||
class RemoveJitsiWidgetView: UIView {
|
||||
|
||||
private enum Constants {
|
||||
static let activationThreshold: CGFloat = 0.5
|
||||
}
|
||||
|
||||
private enum State: Equatable {
|
||||
case notStarted
|
||||
case sliding(percentage: CGFloat)
|
||||
case completed
|
||||
|
||||
static func == (lhs: State, rhs: State) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case (.notStarted, .notStarted):
|
||||
return true
|
||||
case (let .sliding(percentage1), let .sliding(percentage2)):
|
||||
return percentage1 == percentage2
|
||||
case (.completed, .completed):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet private weak var slidingViewLeadingConstraint: NSLayoutConstraint!
|
||||
@IBOutlet private weak var slidingView: UIView!
|
||||
@IBOutlet private weak var slidingViewLabel: UILabel! {
|
||||
didSet {
|
||||
slidingViewLabel.text = VectorL10n.roomSlideToEndGroupCall
|
||||
}
|
||||
}
|
||||
@IBOutlet private weak var arrowsView: ArrowsAnimationView!
|
||||
@IBOutlet private weak var hangupView: UIView!
|
||||
@IBOutlet private weak var hangupImage: UIImageView!
|
||||
@IBOutlet private weak var topSeparatorView: UIView!
|
||||
@IBOutlet private weak var bottomSeparatorView: UIView!
|
||||
|
||||
private var state: State = .notStarted
|
||||
private var theme: Theme = ThemeService.shared().theme
|
||||
|
||||
// MARK - Private
|
||||
|
||||
private func configure(withState state: State) {
|
||||
switch state {
|
||||
case .notStarted:
|
||||
arrowsView.isAnimating = false
|
||||
hangupView.backgroundColor = .clear
|
||||
hangupImage.tintColor = theme.noticeColor
|
||||
slidingViewLeadingConstraint.constant = 0
|
||||
case .sliding(let percentage):
|
||||
arrowsView.isAnimating = true
|
||||
if percentage < Constants.activationThreshold {
|
||||
hangupView.backgroundColor = .clear
|
||||
hangupImage.tintColor = theme.noticeColor
|
||||
} else {
|
||||
hangupView.backgroundColor = theme.noticeColor
|
||||
hangupImage.tintColor = theme.backgroundColor
|
||||
}
|
||||
slidingViewLeadingConstraint.constant = percentage * slidingView.frame.width
|
||||
case .completed:
|
||||
arrowsView.isAnimating = false
|
||||
hangupView.backgroundColor = theme.noticeColor
|
||||
hangupImage.tintColor = theme.backgroundColor
|
||||
}
|
||||
}
|
||||
|
||||
private func updateState(to newState: State) {
|
||||
guard newState != state else {
|
||||
return
|
||||
}
|
||||
configure(withState: newState)
|
||||
state = newState
|
||||
|
||||
if state == .completed {
|
||||
delegate?.removeJitsiWidgetViewDidCompleteSliding(self)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Touch Handling
|
||||
|
||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
super.touchesBegan(touches, with: event)
|
||||
|
||||
if state == .notStarted {
|
||||
updateState(to: .sliding(percentage: 0))
|
||||
}
|
||||
}
|
||||
|
||||
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
super.touchesMoved(touches, with: event)
|
||||
|
||||
switch state {
|
||||
case .sliding:
|
||||
if let touch = touches.first {
|
||||
let touchLocation = touch.location(in: self)
|
||||
if frame.contains(touchLocation) {
|
||||
let percentage = touchLocation.x / frame.width
|
||||
updateState(to: .sliding(percentage: percentage))
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
super.touchesEnded(touches, with: event)
|
||||
|
||||
switch state {
|
||||
case .sliding(let percentage):
|
||||
if percentage < Constants.activationThreshold {
|
||||
updateState(to: .notStarted)
|
||||
} else {
|
||||
updateState(to: .completed)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
super.touchesCancelled(touches, with: event)
|
||||
|
||||
switch state {
|
||||
case .sliding(let percentage):
|
||||
if percentage < Constants.activationThreshold {
|
||||
updateState(to: .notStarted)
|
||||
} else {
|
||||
updateState(to: .completed)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - API
|
||||
|
||||
weak var delegate: RemoveJitsiWidgetViewDelegate?
|
||||
|
||||
static func instantiate() -> RemoveJitsiWidgetView {
|
||||
let view = RemoveJitsiWidgetView.loadFromNib()
|
||||
view.update(theme: ThemeService.shared().theme)
|
||||
return view
|
||||
}
|
||||
|
||||
func reset() {
|
||||
updateState(to: .notStarted)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - NibLoadable
|
||||
|
||||
extension RemoveJitsiWidgetView: NibLoadable { }
|
||||
|
||||
// MARK: - Themable
|
||||
|
||||
extension RemoveJitsiWidgetView: Themable {
|
||||
|
||||
func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
|
||||
self.backgroundColor = theme.headerBackgroundColor
|
||||
|
||||
slidingViewLabel.textColor = theme.textPrimaryColor
|
||||
arrowsView.update(theme: theme)
|
||||
topSeparatorView.backgroundColor = theme.lineBreakColor
|
||||
bottomSeparatorView.backgroundColor = theme.lineBreakColor
|
||||
|
||||
configure(withState: state)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="RemoveJitsiWidgetView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="55"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kKF-lQ-ZyI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="236.5" height="55"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Slide to end the call for everyone " textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dT6-Xr-WEJ">
|
||||
<rect key="frame" x="24" y="0.0" width="202.5" height="55"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="dT6-Xr-WEJ" secondAttribute="trailing" constant="10" id="EbF-GZ-NzF"/>
|
||||
<constraint firstItem="dT6-Xr-WEJ" firstAttribute="top" secondItem="kKF-lQ-ZyI" secondAttribute="top" id="Qu0-Ik-PYy"/>
|
||||
<constraint firstItem="dT6-Xr-WEJ" firstAttribute="leading" secondItem="kKF-lQ-ZyI" secondAttribute="leading" constant="24" id="aJj-xS-5HE"/>
|
||||
<constraint firstAttribute="bottom" secondItem="dT6-Xr-WEJ" secondAttribute="bottom" id="n5n-Ky-ncI"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bi1-rF-LRz" customClass="ArrowsAnimationView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="236.5" y="0.0" width="50.5" height="55"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="50" id="sKo-iu-uGJ"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="PIa-uP-1J7">
|
||||
<rect key="frame" x="295" y="0.0" width="80" height="55"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="voice_call_hangup_icon" translatesAutoresizingMaskIntoConstraints="NO" id="bWv-EC-L99">
|
||||
<rect key="frame" x="28" y="15.5" width="24" height="24"/>
|
||||
<color key="tintColor" systemColor="systemRedColor"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="bWv-EC-L99" firstAttribute="centerY" secondItem="PIa-uP-1J7" secondAttribute="centerY" id="2Vl-CE-QUT"/>
|
||||
<constraint firstItem="bWv-EC-L99" firstAttribute="centerX" secondItem="PIa-uP-1J7" secondAttribute="centerX" id="9vE-r4-Nje"/>
|
||||
<constraint firstAttribute="width" constant="80" id="NW6-rp-ycN"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ntn-XH-RxI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="1"/>
|
||||
<color key="backgroundColor" systemColor="systemGrayColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="yX4-ag-LWD"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bLk-fK-yz0">
|
||||
<rect key="frame" x="0.0" y="54" width="375" height="1"/>
|
||||
<color key="backgroundColor" systemColor="systemGrayColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="LsE-CW-ztj"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="PIa-uP-1J7" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="41n-Yu-G3I"/>
|
||||
<constraint firstItem="kKF-lQ-ZyI" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="Ciw-a7-Pct"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Ntn-XH-RxI" secondAttribute="trailing" id="E9k-gw-h02"/>
|
||||
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="bLk-fK-yz0" secondAttribute="trailing" id="ERx-So-ce7"/>
|
||||
<constraint firstAttribute="bottom" secondItem="bLk-fK-yz0" secondAttribute="bottom" id="I42-n7-cBJ"/>
|
||||
<constraint firstItem="bi1-rF-LRz" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="Iyl-NN-rCe"/>
|
||||
<constraint firstItem="bLk-fK-yz0" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="Oj8-Jf-cWi"/>
|
||||
<constraint firstItem="PIa-uP-1J7" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="XJo-0J-fte"/>
|
||||
<constraint firstItem="kKF-lQ-ZyI" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="aUb-po-3Dw"/>
|
||||
<constraint firstItem="PIa-uP-1J7" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="fn9-gi-1Fo"/>
|
||||
<constraint firstItem="bi1-rF-LRz" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="gbK-bh-J3T"/>
|
||||
<constraint firstItem="bi1-rF-LRz" firstAttribute="leading" secondItem="kKF-lQ-ZyI" secondAttribute="trailing" priority="750" id="hWc-xf-WTt"/>
|
||||
<constraint firstItem="kKF-lQ-ZyI" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="k9f-Tc-VQw"/>
|
||||
<constraint firstItem="Ntn-XH-RxI" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="lzw-UG-Zeh"/>
|
||||
<constraint firstItem="PIa-uP-1J7" firstAttribute="leading" secondItem="bi1-rF-LRz" secondAttribute="trailing" constant="8" id="sSR-kg-guw"/>
|
||||
<constraint firstItem="Ntn-XH-RxI" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="vJc-3a-yWr"/>
|
||||
</constraints>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
<outlet property="arrowsView" destination="bi1-rF-LRz" id="9NK-yt-cXa"/>
|
||||
<outlet property="bottomSeparatorView" destination="bLk-fK-yz0" id="6Fn-W3-VTa"/>
|
||||
<outlet property="hangupImage" destination="bWv-EC-L99" id="UAz-cI-2ai"/>
|
||||
<outlet property="hangupView" destination="PIa-uP-1J7" id="Qd0-It-bFg"/>
|
||||
<outlet property="slidingView" destination="kKF-lQ-ZyI" id="bLF-Aa-1Oy"/>
|
||||
<outlet property="slidingViewLabel" destination="dT6-Xr-WEJ" id="OSR-IL-92L"/>
|
||||
<outlet property="slidingViewLeadingConstraint" destination="aUb-po-3Dw" id="R7j-74-W4J"/>
|
||||
<outlet property="topSeparatorView" destination="Ntn-XH-RxI" id="nRw-nh-427"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="110.86956521739131" y="-142.96875"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="voice_call_hangup_icon" width="24" height="24"/>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemGrayColor">
|
||||
<color red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemRedColor">
|
||||
<color red="1" green="0.23137254901960785" blue="0.18823529411764706" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc
|
||||
protocol RemoveJitsiWidgetViewDelegate: class {
|
||||
|
||||
/// Tells the delegate that the user complete sliding on the view
|
||||
/// - Parameter view: The view instance
|
||||
func removeJitsiWidgetViewDidCompleteSliding(_ view: RemoveJitsiWidgetView)
|
||||
}
|
||||
Reference in New Issue
Block a user