feat: make media indicator view hide when playing video
This commit is contained in:
parent
6a8dee037f
commit
5b45224f7b
|
@ -143,6 +143,7 @@
|
||||||
DB45FB0F25CA87D0005A8AC7 /* AuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB45FB0E25CA87D0005A8AC7 /* AuthenticationService.swift */; };
|
DB45FB0F25CA87D0005A8AC7 /* AuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB45FB0E25CA87D0005A8AC7 /* AuthenticationService.swift */; };
|
||||||
DB45FB1D25CA9D23005A8AC7 /* APIService+HomeTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB45FB1C25CA9D23005A8AC7 /* APIService+HomeTimeline.swift */; };
|
DB45FB1D25CA9D23005A8AC7 /* APIService+HomeTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB45FB1C25CA9D23005A8AC7 /* APIService+HomeTimeline.swift */; };
|
||||||
DB47229725F9EFAD00DA7F53 /* NSManagedObjectContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB47229625F9EFAD00DA7F53 /* NSManagedObjectContext.swift */; };
|
DB47229725F9EFAD00DA7F53 /* NSManagedObjectContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB47229625F9EFAD00DA7F53 /* NSManagedObjectContext.swift */; };
|
||||||
|
DB49A63D25FF609300B98345 /* PlayerContainerView+MediaTypeIndicotorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB49A63C25FF609300B98345 /* PlayerContainerView+MediaTypeIndicotorView.swift */; };
|
||||||
DB5086A525CC0B7000C2C187 /* AvatarBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5086A425CC0B7000C2C187 /* AvatarBarButtonItem.swift */; };
|
DB5086A525CC0B7000C2C187 /* AvatarBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5086A425CC0B7000C2C187 /* AvatarBarButtonItem.swift */; };
|
||||||
DB5086AB25CC0BBB00C2C187 /* AvatarConfigurableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5086AA25CC0BBB00C2C187 /* AvatarConfigurableView.swift */; };
|
DB5086AB25CC0BBB00C2C187 /* AvatarConfigurableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5086AA25CC0BBB00C2C187 /* AvatarConfigurableView.swift */; };
|
||||||
DB5086B825CC0D6400C2C187 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = DB5086B725CC0D6400C2C187 /* Kingfisher */; };
|
DB5086B825CC0D6400C2C187 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = DB5086B725CC0D6400C2C187 /* Kingfisher */; };
|
||||||
|
@ -400,6 +401,7 @@
|
||||||
DB45FB0E25CA87D0005A8AC7 /* AuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationService.swift; sourceTree = "<group>"; };
|
DB45FB0E25CA87D0005A8AC7 /* AuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationService.swift; sourceTree = "<group>"; };
|
||||||
DB45FB1C25CA9D23005A8AC7 /* APIService+HomeTimeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+HomeTimeline.swift"; sourceTree = "<group>"; };
|
DB45FB1C25CA9D23005A8AC7 /* APIService+HomeTimeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+HomeTimeline.swift"; sourceTree = "<group>"; };
|
||||||
DB47229625F9EFAD00DA7F53 /* NSManagedObjectContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSManagedObjectContext.swift; sourceTree = "<group>"; };
|
DB47229625F9EFAD00DA7F53 /* NSManagedObjectContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSManagedObjectContext.swift; sourceTree = "<group>"; };
|
||||||
|
DB49A63C25FF609300B98345 /* PlayerContainerView+MediaTypeIndicotorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PlayerContainerView+MediaTypeIndicotorView.swift"; sourceTree = "<group>"; };
|
||||||
DB5086A425CC0B7000C2C187 /* AvatarBarButtonItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarBarButtonItem.swift; sourceTree = "<group>"; };
|
DB5086A425CC0B7000C2C187 /* AvatarBarButtonItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarBarButtonItem.swift; sourceTree = "<group>"; };
|
||||||
DB5086AA25CC0BBB00C2C187 /* AvatarConfigurableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarConfigurableView.swift; sourceTree = "<group>"; };
|
DB5086AA25CC0BBB00C2C187 /* AvatarConfigurableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarConfigurableView.swift; sourceTree = "<group>"; };
|
||||||
DB5086BD25CC0D9900C2C187 /* SplashPreference.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplashPreference.swift; sourceTree = "<group>"; };
|
DB5086BD25CC0D9900C2C187 /* SplashPreference.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplashPreference.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1190,6 +1192,7 @@
|
||||||
DB9D6C0D25E4F9780051B173 /* MosaicImageViewContainer.swift */,
|
DB9D6C0D25E4F9780051B173 /* MosaicImageViewContainer.swift */,
|
||||||
2D206B7125F5D27F00143C56 /* AudioContainerView.swift */,
|
2D206B7125F5D27F00143C56 /* AudioContainerView.swift */,
|
||||||
5DF1057825F88A1D00D6C0D4 /* PlayerContainerView.swift */,
|
5DF1057825F88A1D00D6C0D4 /* PlayerContainerView.swift */,
|
||||||
|
DB49A63C25FF609300B98345 /* PlayerContainerView+MediaTypeIndicotorView.swift */,
|
||||||
5DF1057E25F88A4100D6C0D4 /* TouchBlockingView.swift */,
|
5DF1057E25F88A4100D6C0D4 /* TouchBlockingView.swift */,
|
||||||
);
|
);
|
||||||
path = Container;
|
path = Container;
|
||||||
|
@ -1675,6 +1678,7 @@
|
||||||
DB45FADD25CA6F6B005A8AC7 /* APIService+CoreData+MastodonUser.swift in Sources */,
|
DB45FADD25CA6F6B005A8AC7 /* APIService+CoreData+MastodonUser.swift in Sources */,
|
||||||
2D32EABA25CB9B0500C9ED86 /* UIView.swift in Sources */,
|
2D32EABA25CB9B0500C9ED86 /* UIView.swift in Sources */,
|
||||||
2D38F20825CD491300561493 /* DisposeBagCollectable.swift in Sources */,
|
2D38F20825CD491300561493 /* DisposeBagCollectable.swift in Sources */,
|
||||||
|
DB49A63D25FF609300B98345 /* PlayerContainerView+MediaTypeIndicotorView.swift in Sources */,
|
||||||
DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */,
|
DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */,
|
||||||
DB44384F25E8C1FA008912A2 /* CALayer.swift in Sources */,
|
DB44384F25E8C1FA008912A2 /* CALayer.swift in Sources */,
|
||||||
2D206B8625F5FB0900143C56 /* Double.swift in Sources */,
|
2D206B8625F5FB0900143C56 /* Double.swift in Sources */,
|
||||||
|
|
|
@ -222,6 +222,23 @@ extension StatusSection {
|
||||||
playerViewController.player = videoPlayerViewModel.player
|
playerViewController.player = videoPlayerViewModel.player
|
||||||
playerViewController.showsPlaybackControls = videoPlayerViewModel.videoKind != .gif
|
playerViewController.showsPlaybackControls = videoPlayerViewModel.videoKind != .gif
|
||||||
playerContainerView.setMediaKind(kind: videoPlayerViewModel.videoKind)
|
playerContainerView.setMediaKind(kind: videoPlayerViewModel.videoKind)
|
||||||
|
if videoPlayerViewModel.videoKind == .gif {
|
||||||
|
playerContainerView.setMediaIndicator(isHidden: false)
|
||||||
|
} else {
|
||||||
|
videoPlayerViewModel.timeControlStatus.sink { timeControlStatus in
|
||||||
|
UIView.animate(withDuration: 0.33) {
|
||||||
|
switch timeControlStatus {
|
||||||
|
case .playing:
|
||||||
|
playerContainerView.setMediaIndicator(isHidden: true)
|
||||||
|
case .paused, .waitingToPlayAtSpecifiedRate:
|
||||||
|
playerContainerView.setMediaIndicator(isHidden: false)
|
||||||
|
@unknown default:
|
||||||
|
assertionFailure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cell.disposeBag)
|
||||||
|
}
|
||||||
playerContainerView.isHidden = false
|
playerContainerView.isHidden = false
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -5,4 +5,95 @@
|
||||||
// Created by MainasuK Cirno on 2021-3-15.
|
// Created by MainasuK Cirno on 2021-3-15.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import UIKit
|
||||||
|
|
||||||
|
extension PlayerContainerView {
|
||||||
|
|
||||||
|
final class MediaTypeIndicotorView: UIView {
|
||||||
|
|
||||||
|
static let indicatorViewSize = CGSize(width: 47, height: 25)
|
||||||
|
|
||||||
|
let maskLayer = CAShapeLayer()
|
||||||
|
|
||||||
|
let label: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.textColor = .white
|
||||||
|
label.textAlignment = .right
|
||||||
|
label.adjustsFontSizeToFitWidth = true
|
||||||
|
label.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func layoutSubviews() {
|
||||||
|
super.layoutSubviews()
|
||||||
|
|
||||||
|
let path = UIBezierPath()
|
||||||
|
path.move(to: CGPoint(x: bounds.width, y: bounds.height))
|
||||||
|
path.addLine(to: CGPoint(x: bounds.width, y: 0))
|
||||||
|
path.addLine(to: CGPoint(x: bounds.width * 0.5, y: 0))
|
||||||
|
path.addCurve(
|
||||||
|
to: CGPoint(x: 0, y: bounds.height),
|
||||||
|
controlPoint1: CGPoint(x: bounds.width * 0.2, y: 0),
|
||||||
|
controlPoint2: CGPoint(x: 0, y: bounds.height * 0.3)
|
||||||
|
)
|
||||||
|
path.close()
|
||||||
|
|
||||||
|
maskLayer.frame = bounds
|
||||||
|
maskLayer.path = path.cgPath
|
||||||
|
layer.mask = maskLayer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PlayerContainerView.MediaTypeIndicotorView {
|
||||||
|
|
||||||
|
private func _init() {
|
||||||
|
backgroundColor = Asset.Colors.Background.mediaTypeIndicotor.color
|
||||||
|
layoutMargins = UIEdgeInsets(top: 3, left: 13, bottom: 0, right: 6)
|
||||||
|
|
||||||
|
addSubview(label)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor),
|
||||||
|
label.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
|
||||||
|
label.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
|
||||||
|
label.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func roundedFont(weight: UIFont.Weight,fontSize: CGFloat) -> UIFont {
|
||||||
|
let systemFont = UIFont.systemFont(ofSize: fontSize, weight: weight)
|
||||||
|
guard let descriptor = systemFont.fontDescriptor.withDesign(.rounded) else { return systemFont }
|
||||||
|
let roundedFont = UIFont(descriptor: descriptor, size: fontSize)
|
||||||
|
return roundedFont
|
||||||
|
}
|
||||||
|
|
||||||
|
func setMediaKind(kind: VideoPlayerViewModel.Kind) {
|
||||||
|
let fontSize: CGFloat = 18
|
||||||
|
|
||||||
|
switch kind {
|
||||||
|
case .gif:
|
||||||
|
label.font = PlayerContainerView.MediaTypeIndicotorView.roundedFont(weight: .heavy, fontSize: fontSize)
|
||||||
|
label.text = "GIF"
|
||||||
|
case .video:
|
||||||
|
let configuration = UIImage.SymbolConfiguration(font: PlayerContainerView.MediaTypeIndicotorView.roundedFont(weight: .regular, fontSize: fontSize))
|
||||||
|
let image = UIImage(systemName: "video.fill", withConfiguration: configuration)!
|
||||||
|
let attachment = NSTextAttachment()
|
||||||
|
attachment.image = image.withTintColor(.white)
|
||||||
|
label.attributedText = NSAttributedString(attachment: attachment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,26 +26,8 @@ final class PlayerContainerView: UIView {
|
||||||
|
|
||||||
let playerViewController = AVPlayerViewController()
|
let playerViewController = AVPlayerViewController()
|
||||||
|
|
||||||
let mediaTypeIndicotorLabel: UILabel = {
|
let mediaTypeIndicotorView = MediaTypeIndicotorView()
|
||||||
let label = UILabel()
|
let mediaTypeIndicotorViewInContentWarningOverlay = MediaTypeIndicotorView()
|
||||||
label.textColor = .white
|
|
||||||
label.textAlignment = .right
|
|
||||||
label.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
return label
|
|
||||||
}()
|
|
||||||
|
|
||||||
let mediaTypeIndicotorView: UIView = {
|
|
||||||
let view = UIView()
|
|
||||||
view.backgroundColor = Asset.Colors.Background.mediaTypeIndicotor.color
|
|
||||||
view.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
let rect = CGRect(x: 0, y: 0, width: 47, height: 50)
|
|
||||||
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: [.topLeft], cornerRadii: CGSize(width: 50, height: 50))
|
|
||||||
let maskLayer = CAShapeLayer()
|
|
||||||
maskLayer.frame = rect
|
|
||||||
maskLayer.path = path.cgPath
|
|
||||||
view.layer.mask = maskLayer
|
|
||||||
return view
|
|
||||||
}()
|
|
||||||
|
|
||||||
weak var delegate: PlayerContainerViewDelegate?
|
weak var delegate: PlayerContainerViewDelegate?
|
||||||
|
|
||||||
|
@ -78,6 +60,16 @@ extension PlayerContainerView {
|
||||||
playerViewController.view.layer.cornerRadius = PlayerContainerView.cornerRadius
|
playerViewController.view.layer.cornerRadius = PlayerContainerView.cornerRadius
|
||||||
playerViewController.view.layer.cornerCurve = .continuous
|
playerViewController.view.layer.cornerCurve = .continuous
|
||||||
|
|
||||||
|
// mediaType
|
||||||
|
mediaTypeIndicotorView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
playerViewController.contentOverlayView!.addSubview(mediaTypeIndicotorView)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
mediaTypeIndicotorView.bottomAnchor.constraint(equalTo: playerViewController.contentOverlayView!.bottomAnchor),
|
||||||
|
mediaTypeIndicotorView.trailingAnchor.constraint(equalTo: playerViewController.contentOverlayView!.trailingAnchor),
|
||||||
|
mediaTypeIndicotorView.heightAnchor.constraint(equalToConstant: 25).priority(.defaultHigh),
|
||||||
|
mediaTypeIndicotorView.widthAnchor.constraint(equalToConstant: 47).priority(.defaultHigh),
|
||||||
|
])
|
||||||
|
|
||||||
addSubview(contentWarningOverlayView)
|
addSubview(contentWarningOverlayView)
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
contentWarningOverlayView.topAnchor.constraint(equalTo: topAnchor),
|
contentWarningOverlayView.topAnchor.constraint(equalTo: topAnchor),
|
||||||
|
@ -87,21 +79,13 @@ extension PlayerContainerView {
|
||||||
])
|
])
|
||||||
contentWarningOverlayView.delegate = self
|
contentWarningOverlayView.delegate = self
|
||||||
|
|
||||||
// mediaType
|
mediaTypeIndicotorViewInContentWarningOverlay.translatesAutoresizingMaskIntoConstraints = false
|
||||||
addSubview(mediaTypeIndicotorView)
|
contentWarningOverlayView.addSubview(mediaTypeIndicotorViewInContentWarningOverlay)
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
mediaTypeIndicotorView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
mediaTypeIndicotorViewInContentWarningOverlay.bottomAnchor.constraint(equalTo: contentWarningOverlayView.bottomAnchor),
|
||||||
mediaTypeIndicotorView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
mediaTypeIndicotorViewInContentWarningOverlay.trailingAnchor.constraint(equalTo: contentWarningOverlayView.trailingAnchor),
|
||||||
mediaTypeIndicotorView.heightAnchor.constraint(equalToConstant: 25),
|
mediaTypeIndicotorViewInContentWarningOverlay.heightAnchor.constraint(equalToConstant: 25).priority(.defaultHigh),
|
||||||
mediaTypeIndicotorView.widthAnchor.constraint(equalToConstant: 47)
|
mediaTypeIndicotorViewInContentWarningOverlay.widthAnchor.constraint(equalToConstant: 47).priority(.defaultHigh),
|
||||||
])
|
|
||||||
|
|
||||||
mediaTypeIndicotorView.addSubview(mediaTypeIndicotorLabel)
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
mediaTypeIndicotorLabel.topAnchor.constraint(equalTo: mediaTypeIndicotorView.topAnchor),
|
|
||||||
mediaTypeIndicotorLabel.leadingAnchor.constraint(equalTo: mediaTypeIndicotorView.leadingAnchor),
|
|
||||||
mediaTypeIndicotorLabel.bottomAnchor.constraint(equalTo: mediaTypeIndicotorView.bottomAnchor),
|
|
||||||
mediaTypeIndicotorView.trailingAnchor.constraint(equalTo: mediaTypeIndicotorLabel.trailingAnchor, constant: 8)
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,25 +145,14 @@ extension PlayerContainerView {
|
||||||
return playerViewController
|
return playerViewController
|
||||||
}
|
}
|
||||||
|
|
||||||
func roundedFont(weight: UIFont.Weight,fontSize: CGFloat) -> UIFont {
|
|
||||||
let systemFont = UIFont.systemFont(ofSize: fontSize, weight: weight)
|
|
||||||
guard let descriptor = systemFont.fontDescriptor.withDesign(.rounded) else { return systemFont }
|
|
||||||
let roundedFont = UIFont(descriptor: descriptor, size: fontSize)
|
|
||||||
return roundedFont
|
|
||||||
}
|
|
||||||
func setMediaKind(kind: VideoPlayerViewModel.Kind) {
|
func setMediaKind(kind: VideoPlayerViewModel.Kind) {
|
||||||
let fontSize: CGFloat = 18
|
mediaTypeIndicotorView.setMediaKind(kind: kind)
|
||||||
|
mediaTypeIndicotorViewInContentWarningOverlay.setMediaKind(kind: kind)
|
||||||
switch kind {
|
|
||||||
case .gif:
|
|
||||||
mediaTypeIndicotorLabel.font = roundedFont(weight: .heavy, fontSize: fontSize)
|
|
||||||
mediaTypeIndicotorLabel.text = "GIF"
|
|
||||||
case .video:
|
|
||||||
let configuration = UIImage.SymbolConfiguration(font: roundedFont(weight: .regular, fontSize: fontSize))
|
|
||||||
let image = UIImage(systemName: "video.fill", withConfiguration: configuration)!
|
|
||||||
let attachment = NSTextAttachment()
|
|
||||||
attachment.image = image.withTintColor(.white)
|
|
||||||
mediaTypeIndicotorLabel.attributedText = NSAttributedString(attachment: attachment)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setMediaIndicator(isHidden: Bool) {
|
||||||
|
mediaTypeIndicotorView.alpha = isHidden ? 0 : 1
|
||||||
|
mediaTypeIndicotorViewInContentWarningOverlay.alpha = isHidden ? 0 : 1
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue