"Fossies" - the Fresh Open Source Software Archive

Member "jitsi-meet-5079/ios/sdk/src/picture-in-picture/DragGestureController.swift" (17 Jun 2021, 4274 Bytes) of package /linux/misc/jitsi-meet-5079.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Swift source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * Copyright @ 2017-present Atlassian Pty Ltd
    3  *
    4  * Licensed under the Apache License, Version 2.0 (the "License");
    5  * you may not use this file except in compliance with the License.
    6  * You may obtain a copy of the License at
    7  *
    8  *     http://www.apache.org/licenses/LICENSE-2.0
    9  *
   10  * Unless required by applicable law or agreed to in writing, software
   11  * distributed under the License is distributed on an "AS IS" BASIS,
   12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13  * See the License for the specific language governing permissions and
   14  * limitations under the License.
   15  */
   16 
   17 import UIKit
   18 
   19 final class DragGestureController {
   20 
   21     var insets: UIEdgeInsets = UIEdgeInsets.zero
   22 
   23     private var frameBeforeDragging: CGRect = CGRect.zero
   24     private weak var view: UIView?
   25     private lazy var panGesture: UIPanGestureRecognizer = {
   26         return UIPanGestureRecognizer(target: self,
   27                                       action: #selector(handlePan(gesture:)))
   28     }()
   29 
   30     func startDragListener(inView view: UIView) {
   31         self.view = view
   32         view.addGestureRecognizer(panGesture)
   33         panGesture.isEnabled = true
   34     }
   35 
   36     func stopDragListener() {
   37         panGesture.isEnabled = false
   38         view?.removeGestureRecognizer(panGesture)
   39         view = nil
   40     }
   41 
   42     @objc private func handlePan(gesture: UIPanGestureRecognizer) {
   43         guard let view = self.view else { return }
   44 
   45         let translation = gesture.translation(in: view.superview)
   46         let velocity = gesture.velocity(in: view.superview)
   47         var frame = frameBeforeDragging
   48 
   49         switch gesture.state {
   50         case .began:
   51             frameBeforeDragging = view.frame
   52 
   53         case .changed:
   54             frame.origin.x = floor(frame.origin.x + translation.x)
   55             frame.origin.y = floor(frame.origin.y + translation.y)
   56             view.frame = frame
   57 
   58         case .ended:
   59             let currentPos = view.frame.origin
   60             let finalPos = calculateFinalPosition()
   61 
   62             let distance = CGPoint(x: currentPos.x - finalPos.x,
   63                                    y: currentPos.y - finalPos.y)
   64             let distanceMagnitude = magnitude(vector: distance)
   65             let velocityMagnitude = magnitude(vector: velocity)
   66             let animationDuration = 0.5
   67             let initialSpringVelocity =
   68                 velocityMagnitude / distanceMagnitude / CGFloat(animationDuration)
   69 
   70             frame.origin = CGPoint(x: finalPos.x, y: finalPos.y)
   71 
   72             UIView.animate(withDuration: animationDuration,
   73                            delay: 0,
   74                            usingSpringWithDamping: 0.9,
   75                            initialSpringVelocity: initialSpringVelocity,
   76                            options: .curveLinear,
   77                            animations: {
   78                             view.frame = frame
   79             }, completion: nil)
   80 
   81         default:
   82             break
   83         }
   84     }
   85 
   86     private func calculateFinalPosition() -> CGPoint {
   87         guard
   88             let view = self.view,
   89             let bounds = view.superview?.frame
   90             else { return CGPoint.zero }
   91 
   92         let currentSize = view.frame.size
   93         let adjustedBounds = bounds.inset(by: insets)
   94         let threshold: CGFloat = 20.0
   95         let velocity = panGesture.velocity(in: view.superview)
   96         let location = panGesture.location(in: view.superview)
   97 
   98         let goLeft: Bool
   99         if abs(velocity.x) > threshold {
  100             goLeft = velocity.x < -threshold
  101         } else {
  102             goLeft = location.x < bounds.midX
  103         }
  104 
  105         let goUp: Bool
  106         if abs(velocity.y) > threshold {
  107             goUp = velocity.y < -threshold
  108         } else {
  109             goUp = location.y < bounds.midY
  110         }
  111 
  112         let finalPosX: CGFloat =
  113             goLeft
  114                 ? adjustedBounds.origin.x
  115                 : bounds.size.width - insets.right  - currentSize.width
  116         let finalPosY: CGFloat =
  117             goUp
  118                 ? adjustedBounds.origin.y
  119                 : bounds.size.height - insets.bottom - currentSize.height
  120 
  121         return CGPoint(x: finalPosX, y: finalPosY)
  122     }
  123 
  124     private func magnitude(vector: CGPoint) -> CGFloat {
  125         return sqrt(pow(vector.x, 2) + pow(vector.y, 2))
  126     }
  127 }