Commit cb77dc7e authored by Soomin Lee's avatar Soomin Lee

Chromecast: Initial integration

parent 6c02f625
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13189.4" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13165.3"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
......@@ -21,7 +21,7 @@
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Sdb-a5-RTT">
<rect key="frame" x="662" y="5" width="30" height="30"/>
<rect key="frame" x="670" y="5" width="30" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="Ap6-VL-6UH"/>
<constraint firstAttribute="width" constant="30" id="dEx-l7-vH3"/>
......@@ -40,7 +40,7 @@
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="x1t-3m-s0G">
<rect key="frame" x="618" y="5" width="44" height="30"/>
<rect key="frame" x="626" y="5" width="44" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="fv5-Cp-MOv"/>
</constraints>
......@@ -76,7 +76,7 @@
</connections>
</button>
<slider opaque="NO" contentMode="scaleToFill" semanticContentAttribute="playback" insetsLayoutMarginsFromSafeArea="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="axb-6M-lSX" userLabel="Position Slider" customClass="VLCOBSlider">
<rect key="frame" x="28" y="5" width="584" height="31"/>
<rect key="frame" x="28" y="5" width="592" height="31"/>
<accessibility key="accessibilityConfiguration">
<accessibilityTraits key="traits" updatesFrequently="YES"/>
</accessibility>
......@@ -99,7 +99,7 @@
<constraint firstItem="axb-6M-lSX" firstAttribute="trailing" secondItem="x1t-3m-s0G" secondAttribute="leading" constant="-8" id="l05-q4-Dha"/>
<constraint firstItem="x1t-3m-s0G" firstAttribute="centerY" secondItem="SbC-6V-aXT" secondAttribute="centerY" id="mIZ-5x-1r6"/>
<constraint firstItem="SBq-Am-6MD" firstAttribute="leading" secondItem="SbC-6V-aXT" secondAttribute="leading" id="mf3-NF-cwy"/>
<constraint firstAttribute="trailing" secondItem="Sdb-a5-RTT" secondAttribute="trailing" constant="8" id="uI1-3o-gyT"/>
<constraint firstAttribute="trailing" secondItem="Sdb-a5-RTT" secondAttribute="trailing" id="uI1-3o-gyT"/>
<constraint firstItem="axb-6M-lSX" firstAttribute="leading" secondItem="SBq-Am-6MD" secondAttribute="trailing" id="zQP-Wv-QPC"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
......
......@@ -25,6 +25,7 @@
"ONE_SPU_TRACK" = "One subtitles track";
"PLAYING_EXTERNALLY_TITLE" = "TV Connected";
"PLAYING_EXTERNALLY_TITLE_CHROMECAST" = "Chromecast Connected";
"PLAYING_EXTERNALLY_DESC" = "This video is playing on the TV";
"VFILTER_HUE" = "Hue";
......@@ -70,6 +71,9 @@
"PRIVATE_PLAYBACK_TOGGLE" = "Private Playback";
"SCAN_SUBTITLE_TOGGLE" = "Scan for Subtitles (http-only)";
"BUTTON_RENDERER" = "Casting devices";
"BUTTON_RENDERER_HINT" = "Show a menu of available casting devices";
"UPGRADING_LIBRARY" = "Upgrading Media Library";
"UNTITLED_SHOW" = "Untitled Show";
"UNKNOWN" = "Unknown";
......@@ -115,6 +119,7 @@
"SECTION_HEADER_LIBRARY" = "Media Library";
"STREAMVC_DETAILTEXT" = "Play streams directly without downloading";
"DOWNLOADVC_DETAILTEXT" = "Download files directly to your device";
"HEADER_TITLE_RENDERER" = "Select a casting device";
"LOCAL_NETWORK" = "Local Network";
"CONNECT_TO_SERVER" = "Connect to Server";
......
......@@ -14,6 +14,7 @@ import Foundation
@objc(VLCService)
public class Services: NSObject {
@objc let mediaDataSource = VLCMediaDataSource()
@objc let rendererDiscovererManager = VLCRendererDiscovererManager(presentingViewController: nil)
}
@objc class AppCoordinator: NSObject {
......
......@@ -24,6 +24,8 @@ public class VLCMediaViewController: UICollectionViewController, UISearchResults
private var searchController: UISearchController?
private let searchDataSource = VLCLibrarySearchDisplayDataSource()
private var mediaType: VLCMediaType
private var rendererButton: UIButton
public weak var delegate: VLCMediaViewControllerDelegate?
@available(iOS 11.0, *)
......@@ -49,6 +51,7 @@ public class VLCMediaViewController: UICollectionViewController, UISearchResults
init(services: Services, type: VLCMediaType) {
self.services = services
mediaType = type
self.rendererButton = services.rendererDiscovererManager.setupRendererButton()
super.init(collectionViewLayout: UICollectionViewFlowLayout())
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .VLCThemeDidChangeNotification, object: nil)
if mediaType.category == .video {
......@@ -73,9 +76,20 @@ public class VLCMediaViewController: UICollectionViewController, UISearchResults
setupCollectionView()
setupSearchController()
setupNavigationBar()
setupRendererButton()
_ = (MLMediaLibrary.sharedMediaLibrary() as! MLMediaLibrary).libraryDidAppear()
}
public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let manager = services.rendererDiscovererManager
if manager.discoverers.isEmpty {
// Either didn't start or stopped before
manager.start()
}
manager.presentingViewController = self
}
@objc func themeDidChange() {
collectionView?.backgroundColor = PresentationTheme.current.colors.background
}
......@@ -128,6 +142,11 @@ public class VLCMediaViewController: UICollectionViewController, UISearchResults
collectionView?.backgroundView = collectionView?.numberOfItems(inSection: 0) == 0 ? emptyView : nil
}
// MARK: Renderer
private func setupRendererButton() {
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: rendererButton)
}
@objc func sort() {
delegate?.mediaViewControllerDidSelectSort(self)
}
......@@ -154,5 +173,4 @@ public class VLCMediaViewController: UICollectionViewController, UISearchResults
public func didDismissSearchController(_ searchController: UISearchController) {
collectionView?.dataSource = mediaDataSourceAndDelegate
}
}
/*****************************************************************************
* VLCActionSheet.swift
*
* Copyright © 2018 VLC authors and VideoLAN
* Copyright © 2018 Videolabs
*
* Authors: Soomin Lee <bubu@mikan.io>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
import Foundation
import UIKit
@objc protocol VLCActionSheetDataSource {
@objc func numberOfRows() -> Int
@objc func actionSheet(collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
}
@objc protocol VLCActionSheetDelegate {
@objc optional func headerViewTitle() -> String?
@objc func itemAtIndexPath(_ indexPath: IndexPath) -> Any?
@objc func actionSheet(collectionView: UICollectionView, didSelectItem item: Any, At indexPath: IndexPath)
}
// MARK: VLCActionSheet
class VLCActionSheet: UIViewController {
private let cellHeight: CGFloat = 50
@objc weak var dataSource: VLCActionSheetDataSource?
@objc weak var delegate: VLCActionSheetDelegate?
var action: ((_ item: Any) -> Void)?
lazy var backgroundView: UIView = {
let backgroundView = UIView()
backgroundView.isHidden = true
backgroundView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
backgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.6)
backgroundView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.removeActionSheet)))
return backgroundView
}()
lazy var collectionViewLayout: UICollectionViewFlowLayout = {
let collectionViewLayout = UICollectionViewFlowLayout()
collectionViewLayout.minimumLineSpacing = 1
collectionViewLayout.minimumInteritemSpacing = 0
return collectionViewLayout
}()
lazy var collectionView: UICollectionView = {
let collectionView = UICollectionView(frame: UIScreen.main.bounds, collectionViewLayout: collectionViewLayout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.backgroundColor = PresentationTheme.current.colors.background
collectionView.alwaysBounceVertical = true
collectionView.showsVerticalScrollIndicator = false
collectionView.register(VLCActionSheetCell.self, forCellWithReuseIdentifier: VLCActionSheetCell.identifier)
collectionView.translatesAutoresizingMaskIntoConstraints = false
return collectionView
}()
lazy var headerView: VLCActionSheetSectionHeader = {
let headerView = VLCActionSheetSectionHeader()
headerView.title.text = delegate?.headerViewTitle?() ?? "Default header title"
headerView.title.textColor = PresentationTheme.current.colors.cellTextColor
headerView.backgroundColor = PresentationTheme.current.colors.background
headerView.translatesAutoresizingMaskIntoConstraints = false
return headerView
}()
lazy var bottomBackgroundView: UIView = {
let bottomBackgroundView = UIView()
bottomBackgroundView.backgroundColor = PresentationTheme.current.colors.background
bottomBackgroundView.translatesAutoresizingMaskIntoConstraints = false
return bottomBackgroundView
}()
lazy var mainStackView: UIStackView = {
let mainStackView = UIStackView()
mainStackView.spacing = 0
mainStackView.axis = .vertical
mainStackView.alignment = .center
mainStackView.translatesAutoresizingMaskIntoConstraints = false
return mainStackView
}()
fileprivate lazy var maxCollectionViewHeightConstraint: NSLayoutConstraint = {
let maxCollectionViewHeightConstraint = collectionView.heightAnchor.constraint(
lessThanOrEqualToConstant: (view.bounds.height / 2) - cellHeight)
return maxCollectionViewHeightConstraint
}()
fileprivate lazy var collectionViewHeightConstraint: NSLayoutConstraint = {
guard let dataSource = dataSource else {
preconditionFailure("VLCActionSheet: Data source not set correctly!")
}
let collectionViewHeightConstraint = collectionView.heightAnchor.constraint(
equalToConstant: CGFloat(dataSource.numberOfRows()) * cellHeight)
collectionViewHeightConstraint.priority = .required - 1
return collectionViewHeightConstraint
}()
fileprivate lazy var bottomBackgroundViewHeightConstraint: NSLayoutConstraint = {
let bottomBackgroundViewHeightConstraint = bottomBackgroundView.heightAnchor.constraint(equalToConstant: cellHeight)
return bottomBackgroundViewHeightConstraint
}()
@objc func removeActionSheet() {
UIView.transition(with: backgroundView, duration: 0.01, options: .transitionCrossDissolve, animations: {
[weak self] in
self?.backgroundView.isHidden = true
}, completion: { [weak self] finished in
self?.presentingViewController?.dismiss(animated: true, completion: nil)
})
}
// MARK: Private methods
fileprivate func setuplHeaderViewConstraints() {
NSLayoutConstraint.activate([
headerView.heightAnchor.constraint(equalToConstant: cellHeight),
headerView.widthAnchor.constraint(equalTo: view.widthAnchor),
])
}
fileprivate func setupCollectionViewConstraints() {
NSLayoutConstraint.activate([
collectionViewHeightConstraint,
maxCollectionViewHeightConstraint,
collectionView.widthAnchor.constraint(equalTo: view.widthAnchor),
])
}
fileprivate func setupBottomBackgroundView() {
NSLayoutConstraint.activate([
bottomBackgroundViewHeightConstraint,
bottomBackgroundView.widthAnchor.constraint(equalTo: view.widthAnchor)
])
}
fileprivate func setupMainStackViewConstraints() {
NSLayoutConstraint.activate([
mainStackView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
mainStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
mainStackView.widthAnchor.constraint(equalTo: view.widthAnchor),
mainStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
}
override func updateViewConstraints() {
super.updateViewConstraints()
if let presentingViewController = presentingViewController, let dataSource = dataSource {
collectionViewHeightConstraint.constant = CGFloat(dataSource.numberOfRows()) * cellHeight
maxCollectionViewHeightConstraint.constant = presentingViewController.view.frame.size.height / 2
collectionView.setNeedsLayout()
collectionView.layoutIfNeeded()
}
}
@available(iOS 11.0, *)
override func viewSafeAreaInsetsDidChange() {
bottomBackgroundViewHeightConstraint.constant = view.safeAreaInsets.bottom
}
// MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(backgroundView)
view.addSubview(mainStackView)
mainStackView.addArrangedSubview(headerView)
mainStackView.addArrangedSubview(collectionView)
mainStackView.addArrangedSubview(bottomBackgroundView)
backgroundView.frame = UIScreen.main.bounds
setupMainStackViewConstraints()
setupCollectionViewConstraints()
setuplHeaderViewConstraints()
setupBottomBackgroundView()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
mainStackView.isHidden = true
collectionView.reloadData()
updateViewConstraints()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// This is to avoid a horrible visual glitch!
mainStackView.isHidden = false
UIView.transition(with: backgroundView, duration: 0.2, options: .transitionCrossDissolve, animations: { [weak self] in
self?.backgroundView.isHidden = false
}, completion: nil)
let realMainStackView = mainStackView.frame
mainStackView.frame.origin.y += mainStackView.frame.origin.y
UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: .curveEaseOut, animations: {
[mainStackView] in
mainStackView.frame = realMainStackView
}, completion: nil)
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { [weak self] _ in
self?.maxCollectionViewHeightConstraint.constant = size.height / 2
self?.collectionView.layoutIfNeeded()
})
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
collectionView.collectionViewLayout.invalidateLayout()
}
@objc func setAction(closure action: @escaping (_ item: Any) -> Void) {
self.action = action
}
}
// MARK: UICollectionViewDelegateFlowLayout
extension VLCActionSheet: UICollectionViewDelegateFlowLayout {
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width, height: cellHeight)
}
}
// MARK: UICollectionViewDelegate
extension VLCActionSheet: UICollectionViewDelegate {
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let delegate = delegate, let item = delegate.itemAtIndexPath(indexPath) {
delegate.actionSheet(collectionView: collectionView, didSelectItem: item, At: indexPath)
action?(item)
}
removeActionSheet()
}
}
// MARK: UICollectionViewDataSource
extension VLCActionSheet: UICollectionViewDataSource {
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let dataSource = dataSource {
return dataSource.numberOfRows()
}
preconditionFailure("VLCActionSheet: No data source")
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let dataSource = dataSource {
return dataSource.actionSheet(collectionView: collectionView, cellForItemAt: indexPath)
}
preconditionFailure("VLCActionSheet: No data source")
}
}
/*****************************************************************************
* VLCActionSheetCell.swift
*
* Copyright © 2018 VLC authors and VideoLAN
* Copyright © 2018 Videolabs
*
* Authors: Soomin Lee <bubu@mikan.io>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
class VLCActionSheetCell: UICollectionViewCell {
static let identifier = "VLCActionSheetCell"
let icon: UIImageView = {
let icon = UIImageView()
icon.translatesAutoresizingMaskIntoConstraints = false
icon.contentMode = .scaleAspectFit
return icon
}()
let name: UILabel = {
let name = UILabel()
name.textColor = PresentationTheme.current.colors.cellTextColor
name.font = UIFont.systemFont(ofSize: 15)
name.translatesAutoresizingMaskIntoConstraints = false
return name
}()
let stackView: UIStackView = {
let stackView = UIStackView()
stackView.spacing = 15.0
stackView.axis = .horizontal
stackView.alignment = .center
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupViews()
}
private func setupViews() {
backgroundColor = PresentationTheme.current.colors.background
stackView.addArrangedSubview(icon)
stackView.addArrangedSubview(name)
addSubview(stackView)
var guide: LayoutAnchorContainer = self
if #available(iOS 11.0, *) {
guide = safeAreaLayoutGuide
}
NSLayoutConstraint.activate([
icon.heightAnchor.constraint(equalToConstant: 25),
icon.widthAnchor.constraint(equalTo: icon.heightAnchor),
name.trailingAnchor.constraint(equalTo: stackView.trailingAnchor),
name.centerYAnchor.constraint(equalTo: stackView.centerYAnchor),
stackView.leadingAnchor.constraint(equalTo: guide.leadingAnchor, constant: 20),
stackView.trailingAnchor.constraint(equalTo: guide.trailingAnchor, constant: -20),
stackView.heightAnchor.constraint(equalTo: heightAnchor),
stackView.topAnchor.constraint(equalTo: topAnchor)
])
}
}
/*****************************************************************************
* VLCActionSheetSectionHeader.swift
*
* Copyright © 2018 VLC authors and VideoLAN
* Copyright © 2018 Videolabs
*
* Authors: Soomin Lee <bubu@mikan.io>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
class VLCActionSheetSectionHeader: UIView {
static let identifier = "VLCActionSheetSectionHeader"
let title: UILabel = {
let title = UILabel()
title.font = UIFont.systemFont(ofSize: 13)
title.translatesAutoresizingMaskIntoConstraints = false
return title
}()
let separator: UIView = {
let separator = UIView()
separator.backgroundColor = .lightGray
separator.translatesAutoresizingMaskIntoConstraints = false
return separator
}()
lazy var guide: LayoutAnchorContainer = {
var guide: LayoutAnchorContainer = self
if #available(iOS 11.0, *) {
guide = safeAreaLayoutGuide
}
return guide
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupTitle()
setupSeparator()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupTitle()
setupSeparator()
}
fileprivate func setupSeparator() {
addSubview(separator)
NSLayoutConstraint.activate([
separator.leadingAnchor.constraint(equalTo: guide.leadingAnchor, constant: 20),
separator.trailingAnchor.constraint(equalTo: guide.trailingAnchor, constant: -20),
separator.heightAnchor.constraint(equalToConstant: 0.5),
separator.topAnchor.constraint(equalTo: bottomAnchor, constant: -1)
])
}
fileprivate func setupTitle() {
addSubview(title)
NSLayoutConstraint.activate([
title.leadingAnchor.constraint(equalTo: guide.leadingAnchor, constant: 20),
title.centerYAnchor.constraint(equalTo: centerYAnchor),
title.centerXAnchor.constraint(equalTo: centerXAnchor),
title.topAnchor.constraint(equalTo: topAnchor)
])
}
}
......@@ -16,6 +16,7 @@
#import "VLCPlaybackController.h"
@class OBSlider;
@class VLCService;
@class VLCStatusLabel;
@class VLCVerticalSwipeGestureRecognizer;
@class VLCTimeNavigationTitleView;
......@@ -80,6 +81,8 @@ typedef NS_ENUM(NSInteger, VLCMovieJumpState) {
@property (nonatomic, weak) id<VLCMovieViewControllerDelegate> delegate;
- (instancetype)initWithServices:(VLCService *)services;
- (IBAction)closePlayback:(id)sender;
- (IBAction)minimizePlayback:(id)sender;
......@@ -102,5 +105,6 @@ typedef NS_ENUM(NSInteger, VLCMovieJumpState) {
- (void)toggleUILock;
- (void)toggleChapterAndTitleSelector;
- (void)hideMenu;
- (void)setupCastWithCurrentRenderer;
@end
......@@ -54,7 +54,7 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
VLCPanTypeProjection
};
@interface VLCMovieViewController () <UIGestureRecognizerDelegate, VLCMultiSelectionViewDelegate, VLCEqualizerViewUIDelegate, VLCPlaybackControllerDelegate, VLCDeviceMotionDelegate>
@interface VLCMovieViewController () <UIGestureRecognizerDelegate, VLCMultiSelectionViewDelegate, VLCEqualizerViewUIDelegate, VLCPlaybackControllerDelegate, VLCDeviceMotionDelegate, VLCRendererDiscovererManagerDelegate>
{
BOOL _controlsHidden;
BOOL _videoFiltersHidden;
......@@ -115,10 +115,15 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
CGPoint _saveLocation;
CGSize _screenPixelSize;
UIInterfaceOrientation _lockedOrientation;
UIStackView *_navigationBarStackView;
UIButton *_rendererButton;
}
@property (nonatomic, strong) VLCMovieViewControlPanelView *controllerPanel;
@property (nonatomic, strong) UIPopoverController *masterPopoverController;
@property (nonatomic, strong) UIWindow *externalWindow;
@property (nonatomic, strong) VLCService *services;
@end
@implementation VLCMovieViewController
......@@ -130,6 +135,16 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
[defaults registerDefaults:appDefaults];
}
- (instancetype)initWithServices:(VLCService *)services
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
NSAssert([services isKindOfClass:[VLCService class]], @"VLCPlayerDisplayController: Injected services class issue");
_services = services;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
......@@ -187,8 +202,6 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
name:VLCPlaybackControllerPlaybackDidStop
object:nil];
_playingExternallyTitle.text = NSLocalizedString(@"PLAYING_EXTERNALLY_TITLE", nil);
_playingExternallyDescription.text = NSLocalizedString(@"PLAYING_EXTERNALLY_DESC", nil);
if ([[UIDevice currentDevice] VLCHasExternalDisplay])
[self showOnExternalDisplay];
......@@ -236,7 +249,7 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
_screenPixelSize = CGSizeMake(screenBounds.size.width, screenBounds.size.height);
[self setupConstraints];
[self setupRendererDiscovererManager];
}
- (void)setupGestureRecognizers
......@@ -355,7 +368,6 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
- (void)setupNavigationbar
{
//Needs to be a UIButton since we need it to work with constraints
_doneButton = [[UIButton alloc] initWithFrame:CGRectZero];
[_doneButton setAccessibilityIdentifier:@"Done"];
[_doneButton addTarget:self action:@selector(closePlayback:) forControlEvents:UIControlEventTouchUpInside];
......@@ -366,21 +378,34 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
self.timeNavigationTitleView = [[[NSBundle mainBundle] loadNibNamed:@"VLCTimeNavigationTitleView" owner:self options:nil] objectAtIndex:0];
self.timeNavigationTitleView.translatesAutoresizingMaskIntoConstraints = NO;
[self.navigationController.navigationBar addSubview:self.timeNavigationTitleView];
[self.navigationController.navigationBar addSubview:_doneButton];
if (_vpc.renderer != nil) {
[_rendererButton setSelected:YES];
}
_navigationBarStackView = [[UIStackView alloc] init];
_navigationBarStackView.translatesAutoresizingMaskIntoConstraints = NO;
_navigationBarStackView.spacing = 8;
_navigationBarStackView.axis = UILayoutConstraintAxisHorizontal;
_navigationBarStackView.alignment = UIStackViewAlignmentCenter;
[_navigationBarStackView addArrangedSubview:_doneButton];
[_navigationBarStackView addArrangedSubview:_timeNavigationTitleView];
[_navigationBarStackView addArrangedSubview:_rendererButton];
[self.navigationController.navigationBar addSubview:_navigationBarStackView];
NSObject *guide = self.navigationController.navigationBar;
if (@available(iOS 11.0, *)) {
guide = self.navigationController.navigationBar.safeAreaLayoutGuide;
}
[self.navigationController.view addConstraints: @[
[NSLayoutConstraint constraintWithItem:_doneButton attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:guide attribute:NSLayoutAttributeLeft multiplier:1 constant:8],
[NSLayoutConstraint constraintWithItem:_doneButton attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.navigationController.navigationBar attribute:NSLayoutAttributeCenterY multiplier:1 constant:0],
[NSLayoutConstraint constraintWithItem:self.timeNavigationTitleView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:_doneButton attribute:NSLayoutAttributeRight multiplier:1 constant:0],
[NSLayoutConstraint constraintWithItem:self.timeNavigationTitleView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:guide attribute:NSLayoutAttributeRight multiplier:1 constant:0],
[NSLayoutConstraint constraintWithItem:self.timeNavigationTitleView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.navigationController.navigationBar attribute:NSLayoutAttributeTop multiplier:1 constant:0],
[NSLayoutConstraint constraintWithItem:self.timeNavigationTitleView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.navigationController.navigationBar attribute:NSLayoutAttributeBottom multiplier:1 constant:0],
]];
[NSLayoutConstraint activateConstraints:@[
[NSLayoutConstraint constraintWithItem:_navigationBarStackView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.navigationController.navigationBar attribute:NSLayoutAttributeCenterY multiplier:1 constant:0],
[NSLayoutConstraint constraintWithItem:_navigationBarStackView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:guide attribute:NSLayoutAttributeLeft multiplier:1 constant:8],
[NSLayoutConstraint constraintWithItem:_navigationBarStackView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:guide attribute:NSLayoutAttributeRight multiplier:1 constant:-8],
[NSLayoutConstraint constraintWithItem:_navigationBarStackView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.navigationController.navigationBar attribute:NSLayoutAttributeTop multiplier:1 constant:0],
[NSLayoutConstraint constraintWithItem:_navigationBarStackView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.navigationController.navigationBar attribute:NSLayoutAttributeBottom multiplier:1 constant:0],
[NSLayoutConstraint constraintWithItem:_timeNavigationTitleView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:_navigationBarStackView attribute:NSLayoutAttributeHeight multiplier:1 constant:0]
]];
}
- (void)resetVideoFiltersSliders
......@@ -413,6 +438,13 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
[self updateDefaults];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateDefaults) name:NSUserDefaultsDidChangeNotification object:nil];
VLCRendererDiscovererManager *manager = _services.rendererDiscove