Initial commit: SimVision tvOS streaming app
Features: - VOD library with movie grouping and version detection - TV show library with season/episode organization - TMDB integration for trending shows and recently aired episodes - Recent releases section with TMDB release date sorting - Watch history tracking with continue watching - Playlist caching (12-hour TTL) for offline support - M3U playlist parsing with XStream API support - Authentication with credential storage Technical: - SwiftUI for tvOS - Actor-based services for thread safety - Persistent caching for playlists, TMDB data, and watch history - KSPlayer integration for video playback Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// PlayerTransitionAnimator.swift
|
||||
// KSPlayer
|
||||
//
|
||||
// Created by kintan on 2021/8/20.
|
||||
//
|
||||
|
||||
#if canImport(UIKit)
|
||||
import UIKit
|
||||
|
||||
class PlayerTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
|
||||
private let isDismiss: Bool
|
||||
private let containerView: UIView
|
||||
private let animationView: UIView
|
||||
private let fromCenter: CGPoint
|
||||
init(containerView: UIView, animationView: UIView, isDismiss: Bool = false) {
|
||||
self.containerView = containerView
|
||||
self.animationView = animationView
|
||||
self.isDismiss = isDismiss
|
||||
fromCenter = containerView.superview?.convert(containerView.center, to: nil) ?? .zero
|
||||
super.init()
|
||||
}
|
||||
|
||||
func transitionDuration(using _: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||
0.3
|
||||
}
|
||||
|
||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||
let animationSuperView = animationView.superview
|
||||
let animationViewIndex = animationSuperView?.subviews.firstIndex(of: animationView) ?? 0
|
||||
let initSize = animationView.frame.size
|
||||
let animationFrameConstraints = animationView.frameConstraints
|
||||
guard let presentedView = transitionContext.view(forKey: isDismiss ? .from : .to) else {
|
||||
return
|
||||
}
|
||||
if isDismiss {
|
||||
containerView.layoutIfNeeded()
|
||||
presentedView.bounds = containerView.bounds
|
||||
presentedView.removeFromSuperview()
|
||||
} else {
|
||||
if let viewController = transitionContext.viewController(forKey: .to) {
|
||||
presentedView.frame = transitionContext.finalFrame(for: viewController)
|
||||
}
|
||||
}
|
||||
presentedView.layoutIfNeeded()
|
||||
transitionContext.containerView.addSubview(animationView)
|
||||
animationView.translatesAutoresizingMaskIntoConstraints = true
|
||||
guard let transform = transitionContext.viewController(forKey: .from)?.view.transform else {
|
||||
return
|
||||
}
|
||||
animationView.transform = CGAffineTransform(scaleX: initSize.width / animationView.frame.size.width, y: initSize.height / animationView.frame.size.height).concatenating(transform)
|
||||
let toCenter = transitionContext.containerView.center
|
||||
let fromCenter = transform == .identity ? fromCenter : fromCenter.reverse
|
||||
animationView.center = isDismiss ? toCenter : fromCenter
|
||||
UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, options: .curveEaseInOut) {
|
||||
self.animationView.transform = .identity
|
||||
self.animationView.center = self.isDismiss ? fromCenter : toCenter
|
||||
} completion: { _ in
|
||||
animationSuperView?.insertSubview(self.animationView, at: animationViewIndex)
|
||||
if !animationFrameConstraints.isEmpty {
|
||||
self.animationView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate(animationFrameConstraints)
|
||||
}
|
||||
if !self.isDismiss {
|
||||
transitionContext.containerView.addSubview(presentedView)
|
||||
}
|
||||
transitionContext.completeTransition(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user