diff --git a/Resources/VLCTimeNavigationTitleView.xib b/Resources/VLCTimeNavigationTitleView.xib index 874f63c32485c644fa6209b9c2866e8ddda3db88..311c597fc392eb52a17c7c9aa6d1b6ec825e63f2 100644 --- a/Resources/VLCTimeNavigationTitleView.xib +++ b/Resources/VLCTimeNavigationTitleView.xib @@ -1,11 +1,11 @@ <?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"/> diff --git a/Resources/en.lproj/Localizable.strings b/Resources/en.lproj/Localizable.strings index 0561dea86adb4a6153c5ce6800a5e1f8e7b55b68..37e233cfe1f6333631a80dcfd0cc8a3e9cbc7fd0 100644 --- a/Resources/en.lproj/Localizable.strings +++ b/Resources/en.lproj/Localizable.strings @@ -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"; @@ -128,6 +132,7 @@ "SHARING_SUCCESS_CAMERA_ROLL" = "File was successfully saved to the Camera Roll"; "SECTION_HEADER_LIBRARY" = "Media Library"; +"HEADER_TITLE_RENDERER" = "Select a casting device"; "SECTION_HEADER_NETWORK" = "Network"; "LOCAL_NETWORK" = "Local Network"; diff --git a/Sources/VLCActionSheet/VLCActionSheet.swift b/Sources/VLCActionSheet/VLCActionSheet.swift new file mode 100644 index 0000000000000000000000000000000000000000..61abb3d052e557e68c8b5e5186aa56a527321506 --- /dev/null +++ b/Sources/VLCActionSheet/VLCActionSheet.swift @@ -0,0 +1,265 @@ +/***************************************************************************** + * 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 = .white + 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 = .black + headerView.backgroundColor = .white + headerView.translatesAutoresizingMaskIntoConstraints = false + return headerView + }() + + lazy var bottomBackgroundView: UIView = { + let bottomBackgroundView = UIView() + bottomBackgroundView.backgroundColor = .white + 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") + } +} diff --git a/Sources/VLCActionSheet/VLCActionSheetCell.swift b/Sources/VLCActionSheet/VLCActionSheetCell.swift new file mode 100644 index 0000000000000000000000000000000000000000..96aa3c10705c0d13a24fb286b7347bb08c95fa3b --- /dev/null +++ b/Sources/VLCActionSheet/VLCActionSheetCell.swift @@ -0,0 +1,75 @@ +/***************************************************************************** + * 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 = .black + 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 = .white + + 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) + ]) + } +} diff --git a/Sources/VLCActionSheet/VLCActionSheetSectionHeader.swift b/Sources/VLCActionSheet/VLCActionSheetSectionHeader.swift new file mode 100644 index 0000000000000000000000000000000000000000..1eb9b2e8404dc9ea21bbd835488a14ec5250a2f8 --- /dev/null +++ b/Sources/VLCActionSheet/VLCActionSheetSectionHeader.swift @@ -0,0 +1,70 @@ +/***************************************************************************** + * 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) + ]) + } +} diff --git a/Sources/VLCLibraryViewController.m b/Sources/VLCLibraryViewController.m index ddc649da2115847e22846fb7649c1be0ffee1f84..298c28ee347cfe5152d0e3071441fed7e32d784f 100644 --- a/Sources/VLCLibraryViewController.m +++ b/Sources/VLCLibraryViewController.m @@ -72,6 +72,7 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData"; UIBarButtonItem *_shareBarButtonItem; UIBarButtonItem *_removeFromFolderBarButtonItem; UIBarButtonItem *_deleteSelectedBarButtonItem; + UIBarButtonItem *_rendererBarButton; NSObject *dragAndDropManager; } @@ -247,6 +248,7 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData"; self.edgesForExtendedLayout = UIRectEdgeNone; [self setupSearchController]; + _rendererBarButton = [[UIBarButtonItem alloc] initWithCustomView:[VLCRendererDiscovererManager.sharedInstance setupRendererButton]]; } - (void)setupSearchController @@ -268,6 +270,13 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData"; [self.collectionView.collectionViewLayout invalidateLayout]; [self setViewFromDeviceOrientation]; [self updateViewsForCurrentDisplayMode]; + + VLCRendererDiscovererManager *manager = VLCRendererDiscovererManager.sharedInstance; + if (manager.discoverers || manager.discoverers.count) { + // No discoverers has yet been started + [manager start]; + } + manager.presentingViewController = self; } - (void)viewDidAppear:(BOOL)animated @@ -408,7 +417,7 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData"; self.navigationItem.rightBarButtonItems = @[toggleDisplayedView, self.editButtonItem]; self.displayModeBarButtonItem = toggleDisplayedView; } else { - self.navigationItem.rightBarButtonItem = self.editButtonItem; + self.navigationItem.rightBarButtonItems = @[self.editButtonItem, _rendererBarButton]; } } if (self.usingTableViewToShowData) { @@ -1032,13 +1041,20 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData"; _isSelected = NO; + UIBarButtonItem *editButton = self.editButtonItem; editButton.tintColor = [UIColor whiteColor]; - if (!editing && self.navigationItem.rightBarButtonItems.lastObject == _selectAllBarButtonItem) + if (!editing && self.navigationItem.rightBarButtonItems.lastObject == _selectAllBarButtonItem) { [self.navigationItem setRightBarButtonItems: [self.navigationItem.rightBarButtonItems subarrayWithRange:NSMakeRange(0, self.navigationItem.rightBarButtonItems.count - 1)]]; - else + [self.navigationItem setRightBarButtonItems: [self.navigationItem.rightBarButtonItems arrayByAddingObject:_rendererBarButton]]; + } + else { + // ugly workaround since the stackview doesn't seems to be working properly + // setRightBarButtonItem doesn't reset it correctly + [self.navigationItem setRightBarButtonItems:@[editButton]]; [self.navigationItem setRightBarButtonItems:editing ? [self.navigationItem.rightBarButtonItems arrayByAddingObject:_selectAllBarButtonItem] : [self.navigationItem rightBarButtonItems] animated:YES]; + } [self setSearchBar:!editing resetContent:!editing]; self.tableView.allowsMultipleSelectionDuringEditing = editing; diff --git a/Sources/VLCMovieViewController.h b/Sources/VLCMovieViewController.h index 15f11ed5bf8646f13e2b41ad149f9af83201440c..a1355330c8fd462078b98b2d799a0fa5f5c81be4 100644 --- a/Sources/VLCMovieViewController.h +++ b/Sources/VLCMovieViewController.h @@ -96,4 +96,6 @@ typedef NS_ENUM(NSInteger, VLCMovieJumpState) { - (void)toggleChapterAndTitleSelector; - (void)hideMenu; +- (void)setupCastWithCurrentRenderer; + @end diff --git a/Sources/VLCMovieViewController.m b/Sources/VLCMovieViewController.m index c871df084a99de78f8f4f769d9669b0b806a3909..6241ed8557590799376bbc9bf627de782f0e2f60 100644 --- a/Sources/VLCMovieViewController.m +++ b/Sources/VLCMovieViewController.m @@ -55,7 +55,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; @@ -116,6 +116,9 @@ 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; @@ -193,8 +196,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]; @@ -241,7 +242,7 @@ typedef NS_ENUM(NSInteger, VLCPanType) { _screenPixelSize = CGSizeMake(screenBounds.size.width, screenBounds.size.height); [self setupConstraints]; - + [self setupRendererDiscovererManager]; } - (void)setupGestureRecognizers @@ -360,7 +361,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 addTarget:self action:@selector(closePlayback:) forControlEvents:UIControlEventTouchUpInside]; [_doneButton setTitle:NSLocalizedString(@"BUTTON_DONE", nil) forState:UIControlStateNormal]; @@ -370,21 +370,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 @@ -417,6 +430,12 @@ typedef NS_ENUM(NSInteger, VLCPanType) { [self updateDefaults]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateDefaults) name:NSUserDefaultsDidChangeNotification object:nil]; + + VLCRendererDiscovererManager *manager = [VLCRendererDiscovererManager sharedInstance]; + manager.presentingViewController = self; + manager.delegate = self; + + [self hidePlayingExternallyViewForRendererIfNeeded]; } - (void)viewDidAppear:(BOOL)animated @@ -433,6 +452,7 @@ typedef NS_ENUM(NSInteger, VLCPanType) { //Media is loaded in the media player, checking the projection type and configuring accordingly. [self setupForMediaProjection]; + [VLCRendererDiscovererManager.sharedInstance start]; } - (void)viewDidLayoutSubviews @@ -633,7 +653,8 @@ typedef NS_ENUM(NSInteger, VLCPanType) { _multiSelectionView.chapterSelectorButton, _multiSelectionView.repeatButton, _multiSelectionView.shuffleButton, - _controllerPanel.volumeView]]; + _controllerPanel.volumeView, + _rendererButton]]; [[UIDevice currentDevice] isiPhoneX] ? [items addObject:_tapToToggleiPhoneXRatioRecognizer] : [items addObject:_tapToSeekRecognizer]; @@ -874,6 +895,7 @@ typedef NS_ENUM(NSInteger, VLCPanType) { - (IBAction)closePlayback:(id)sender { _playbackWillClose = YES; + [self hidePlayingExternallyViewForRendererIfNeeded]; [_vpc stopPlayback]; } @@ -1058,6 +1080,10 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom [_controllerPanel updateButtons]; _audioOnly = metadata.isAudioOnly; + if (_audioOnly) { + // fixme: _playingExternallyView should be shown in audioOnly as well + _playingExternallyView.hidden = YES; + } } - (IBAction)playPause @@ -1675,6 +1701,9 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom self.playingExternallyView.hidden = NO; self.externalWindow.screen = screen; self.externalWindow.hidden = NO; + + _playingExternallyTitle.text = NSLocalizedString(@"PLAYING_EXTERNALLY_TITLE", nil); + _playingExternallyDescription.text = NSLocalizedString(@"PLAYING_EXTERNALLY_DESC", nil); } - (void)hideFromExternalDisplay @@ -1698,4 +1727,47 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom [self hideFromExternalDisplay]; } +#pragma mark - Renderers + + +/** + * Checks if playingExternallyView needs to be hidden. + * If not, playingExternallyView will be shown with the current renderer name + */ +- (void)hidePlayingExternallyViewForRendererIfNeeded +{ + VLCRendererItem *renderer = _vpc.renderer; + + if (renderer != nil) { + // TODO: Have a better/prettier transition between local playback frame and playingExternallyView + _playingExternallyView.hidden = NO; + _playingExternallyTitle.text = NSLocalizedString(@"PLAYING_EXTERNALLY_TITLE_CHROMECAST", nil); + _playingExternallyDescription.text = renderer.name; + } else { + _playingExternallyView.hidden = YES; + } +} + +- (void)setupCastWithCurrentRenderer +{ + [self hidePlayingExternallyViewForRendererIfNeeded]; + [_vpc mediaPlayerSetRenderer:_vpc.renderer]; +} + +- (void)setupRendererDiscovererManager +{ + // Create a renderer button for VLCMovieViewController + _rendererButton = [VLCRendererDiscovererManager.sharedInstance setupRendererButton]; + [VLCRendererDiscovererManager.sharedInstance addSelectionHandlerWithSelectionHandler:^(VLCRendererItem * _Nonnull item) { + [self setupCastWithCurrentRenderer]; + }]; +} + +#pragma mark - VLCRendererDiscovererManagerDelegate + +- (void)removedCurrentRendererItem:(VLCRendererItem *)item +{ + [self hidePlayingExternallyViewForRendererIfNeeded]; +} + @end diff --git a/Sources/VLCPlaybackController.h b/Sources/VLCPlaybackController.h index e48120ab6e2488d43fb36304d8d2c941a772f397..637a046e5b25749bad1039fbc8176cfd06300348 100644 --- a/Sources/VLCPlaybackController.h +++ b/Sources/VLCPlaybackController.h @@ -93,6 +93,8 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom @property (nonatomic, readonly) NSDictionary *mediaOptionsDictionary; @property (nonatomic, readonly) NSTimer* sleepTimer; +@property (nonatomic) VLCRendererItem *renderer; + + (VLCPlaybackController *)sharedInstance; - (VLCTime *)playedTime; #pragma mark - playback @@ -134,4 +136,6 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom - (void)playMediaList:(VLCMediaList *)mediaList firstIndex:(NSInteger)index subtitlesFilePath:(NSString *)subsFilePath; - (void)openVideoSubTitlesFromFile:(NSString *)pathToFile; +- (void)mediaPlayerSetRenderer:(VLCRendererItem *)renderer; + @end diff --git a/Sources/VLCPlaybackController.m b/Sources/VLCPlaybackController.m index 02b79fefc04593b2b1816f077e63cc86076e8b4f..d7ab7001c898b6c66e5fd4127ef9bc194d801036 100644 --- a/Sources/VLCPlaybackController.m +++ b/Sources/VLCPlaybackController.m @@ -238,6 +238,8 @@ typedef NS_ENUM(NSUInteger, VLCAspectRatio) { [_mediaPlayer addObserver:self forKeyPath:@"time" options:0 context:nil]; [_mediaPlayer addObserver:self forKeyPath:@"remainingTime" options:0 context:nil]; + [_mediaPlayer setRendererItem:_renderer]; + [_listPlayer playItemAtNumber:@(_itemInMediaListToBePlayedFirst)]; if ([self.delegate respondsToSelector:@selector(prepareForMediaPlayback:)]) @@ -1232,7 +1234,7 @@ typedef NS_ENUM(NSUInteger, VLCAspectRatio) { { _preBackgroundWrapperView = _videoOutputViewWrapper; - if (_mediaPlayer.audioTrackIndexes.count > 0) + if (!_renderer && _mediaPlayer.audioTrackIndexes.count > 0) [self setVideoTrackEnabled:false]; } @@ -1323,4 +1325,11 @@ typedef NS_ENUM(NSUInteger, VLCAspectRatio) { kVLCSettingHardwareDecoding : [defaults objectForKey:kVLCSettingHardwareDecoding]}; } +#pragma mark - Renderer + +- (void)mediaPlayerSetRenderer:(VLCRendererItem *)renderer +{ + [_mediaPlayer setRendererItem:renderer]; +} + @end diff --git a/Sources/VLCRendererDiscovererManager.swift b/Sources/VLCRendererDiscovererManager.swift new file mode 100644 index 0000000000000000000000000000000000000000..15f94dbf9c4da00dcc2b234c71d0fae9821cccaa --- /dev/null +++ b/Sources/VLCRendererDiscovererManager.swift @@ -0,0 +1,261 @@ +/***************************************************************************** + * VLCRendererDiscovererManager.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. + *****************************************************************************/ + +@objc protocol VLCRendererDiscovererManagerDelegate { + @objc(removedCurrentRendererItem:) + optional func removedCurrentRendererItem(item: VLCRendererItem) +} + +class VLCRendererDiscovererManager: NSObject { + @objc static let sharedInstance = VLCRendererDiscovererManager(presentingViewController: nil) + + // Array of RendererDiscoverers(Chromecast, UPnP, ...) + @objc var discoverers: [VLCRendererDiscoverer] = [VLCRendererDiscoverer]() + + @objc weak var delegate: VLCRendererDiscovererManagerDelegate? + + @objc lazy var actionSheet: VLCActionSheet = { + let actionSheet = VLCActionSheet() + actionSheet.delegate = self + actionSheet.dataSource = self + actionSheet.modalPresentationStyle = .custom + actionSheet.setAction { [weak self] (item) in + if let rendererItem = item as? VLCRendererItem { + self?.setRendererItem(rendererItem: rendererItem) + } + } + return actionSheet + }() + + @objc var presentingViewController: UIViewController? + + @objc var rendererButtons: [UIButton] = [UIButton]() + + fileprivate init(presentingViewController: UIViewController?) { + self.presentingViewController = presentingViewController + super.init() + } + + // Returns renderers of *all* discoverers + @objc func getAllRenderers() -> [VLCRendererItem] { + return discoverers.flatMap { $0.renderers } + } + + fileprivate func isDuplicateDiscoverer(with description: VLCRendererDiscovererDescription) -> Bool { + for discoverer in discoverers where discoverer.name == description.name { + return true + } + return false + } + + @objc func start() { + // Gather potential renderer discoverers + guard let tmpDiscoverersDescription: [VLCRendererDiscovererDescription] = VLCRendererDiscoverer.list() else { + print("VLCRendererDiscovererManager: Unable to retrieve list of VLCRendererDiscovererDescription") + return + } + for discovererDescription in tmpDiscoverersDescription where !isDuplicateDiscoverer(with: discovererDescription) { + guard let rendererDiscoverer = VLCRendererDiscoverer(name: discovererDescription.name) else { + print("VLCRendererDiscovererManager: Unable to instanciate renderer discoverer with name: \(discovererDescription.name)") + continue + } + guard rendererDiscoverer.start() else { + print("VLCRendererDiscovererManager: Unable to start renderer discoverer with name: \(rendererDiscoverer.name)") + continue + } + rendererDiscoverer.delegate = self + discoverers.append(rendererDiscoverer) + } + } + + @objc func stop() { + for discoverer in discoverers { + discoverer.stop() + } + discoverers.removeAll() + } + + // MARK: VLCActionSheet + @objc fileprivate func displayActionSheet() { + guard let presentingViewController = presentingViewController else { + assertionFailure("VLCRendererDiscovererManager: Cannot display actionSheet, no viewController setted") + return + } + // If only one renderer, choose it automatically + if getAllRenderers().count == 1, let rendererItem = getAllRenderers().first { + let indexPath = IndexPath(row: 0, section: 0) + actionSheet.collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredVertically) + actionSheet(collectionView: actionSheet.collectionView, cellForItemAt: indexPath) + actionSheet.action?(rendererItem) + } else { + presentingViewController.present(actionSheet, animated: false, completion: nil) + } + } + + fileprivate func setRendererItem(rendererItem: VLCRendererItem) { + let vpcRenderer = VLCPlaybackController.sharedInstance().renderer + var finalRendererItem: VLCRendererItem? = nil + var isSelected: Bool = false + + if vpcRenderer != rendererItem { + finalRendererItem = rendererItem + isSelected = true + } + + VLCPlaybackController.sharedInstance().renderer = finalRendererItem + for button in rendererButtons { + button.isSelected = isSelected + } + } + + @objc func addSelectionHandler(selectionHandler: ((_ rendererItem: VLCRendererItem) -> Void)?) { + actionSheet.setAction { [weak self] (item) in + if let rendererItem = item as? VLCRendererItem { + self?.setRendererItem(rendererItem: rendererItem) + if let handler = selectionHandler { + handler(rendererItem) + } + } + } + } + + /// Add the given button to VLCRendererDiscovererManager. + /// The button state will be handled by the manager. + /// + /// - Returns: New `UIButton` + @objc func setupRendererButton() -> UIButton { + let button = UIButton() + button.isHidden = getAllRenderers().isEmpty + button.setImage(UIImage(named: "renderer"), for: .normal) + button.setImage(UIImage(named: "rendererFull"), for: .selected) + button.addTarget(self, action: #selector(displayActionSheet), for: .touchUpInside) + button.accessibilityLabel = NSLocalizedString("BUTTON_RENDERER", comment: "") + button.accessibilityHint = NSLocalizedString("BUTTON_RENDERER_HINT", comment: "") + rendererButtons.append(button) + return button + } +} + +// MARK: VLCRendererDiscovererDelegate +extension VLCRendererDiscovererManager: VLCRendererDiscovererDelegate { + func rendererDiscovererItemAdded(_ rendererDiscoverer: VLCRendererDiscoverer, item: VLCRendererItem) { + for button in rendererButtons { + UIView.animate(withDuration: 0.1) { + button.isHidden = false + } + } + + if actionSheet.viewIfLoaded?.window != nil { + actionSheet.collectionView.reloadData() + actionSheet.updateViewConstraints() + } + } + + func rendererDiscovererItemDeleted(_ rendererDiscoverer: VLCRendererDiscoverer, item: VLCRendererItem) { + if let playbackController = VLCPlaybackController.sharedInstance() { + // Current renderer has been removed + if playbackController.renderer == item { + playbackController.renderer = nil + if playbackController.isPlaying { + // If playing, fall back to local playback + playbackController.mediaPlayerSetRenderer(nil) + } + delegate?.removedCurrentRendererItem?(item: item) + // Reset buttons state + for button in rendererButtons { + button.isSelected = false + } + } + if actionSheet.viewIfLoaded?.window != nil { + actionSheet.collectionView.reloadData() + actionSheet.updateViewConstraints() + } + } + + // No more renderers to show + if getAllRenderers().isEmpty { + for button in rendererButtons { + UIView.animate(withDuration: 0.1) { + button.isHidden = true + } + } + actionSheet.removeActionSheet() + } + } + + fileprivate func updateCollectionViewCellApparence(cell: VLCActionSheetCell, highlighted: Bool) { + var image = UIImage(named: "rendererGray") + var textColor: UIColor = .black + + if highlighted { + image = UIImage(named: "rendererOrangeFull") + textColor = UIColor.vlcOrangeTint() + } + + cell.icon.image = image + cell.name.textColor = textColor + } +} + +// MARK: VLCActionSheetDelegate +extension VLCRendererDiscovererManager: VLCActionSheetDelegate { + func headerViewTitle() -> String? { + return NSLocalizedString("HEADER_TITLE_RENDERER", comment: "") + } + + func itemAtIndexPath(_ indexPath: IndexPath) -> Any? { + let renderers = getAllRenderers() + if indexPath.row < renderers.count { + return renderers[indexPath.row] + } + assertionFailure("VLCRendererDiscovererManager: VLCActionSheetDelegate: IndexPath out of range") + return nil + } + + func actionSheet(collectionView: UICollectionView, didSelectItem item: Any, At indexPath: IndexPath) { + guard let renderer = item as? VLCRendererItem, + let cell = collectionView.cellForItem(at: indexPath) as? VLCActionSheetCell else { + assertionFailure("VLCRendererDiscovererManager: VLCActionSheetDelegate: Cell is not a VLCActionSheetCell") + return + } + let isCurrentlySelectedRenderer = renderer == VLCPlaybackController.sharedInstance().renderer + + if !isCurrentlySelectedRenderer { + collectionView.reloadData() + } + updateCollectionViewCellApparence(cell: cell, highlighted: isCurrentlySelectedRenderer) + } +} + +// MARK: VLCActionSheetDataSource +extension VLCRendererDiscovererManager: VLCActionSheetDataSource { + func numberOfRows() -> Int { + return getAllRenderers().count + } + + @discardableResult + func actionSheet(collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let cell = collectionView.dequeueReusableCell( + withReuseIdentifier: VLCActionSheetCell.identifier, for: indexPath) as? VLCActionSheetCell else { + assertionFailure("VLCRendererDiscovererManager: VLCActionSheetDataSource: Unable to dequeue reusable cell") + return UICollectionViewCell() + } + let renderers = getAllRenderers() + if indexPath.row < renderers.count { + cell.name.text = renderers[indexPath.row].name + let isSelectedRenderer = renderers[indexPath.row] == VLCPlaybackController.sharedInstance().renderer ? true : false + updateCollectionViewCellApparence(cell: cell, highlighted: isSelectedRenderer) + } else { + assertionFailure("VLCRendererDiscovererManager: VLCActionSheetDataSource: IndexPath out of range") + } + return cell + } +} diff --git a/VLC-iOS-Bridging-Header.h b/VLC-iOS-Bridging-Header.h index a9ab5316e86871a99d63d90c2f6dc652b775166b..ed05ed6431524b5c44b33d603efe99eeb233e468 100644 --- a/VLC-iOS-Bridging-Header.h +++ b/VLC-iOS-Bridging-Header.h @@ -3,9 +3,12 @@ // #import <MediaLibraryKit/MediaLibraryKit.h> +#import <MobileVLCKit/MobileVLCKit.h> #import "VLCPlaylistTableViewCell.h" #import "VLCMediaDataSource.h" #import "VLCLibraryViewController.h" #import <PAPasscode/PAPasscodeViewController.h> #import <XKKeychain/XKKeychain.h> #import "VLCConstants.h" +#import "VLCPlaybackController.h" +#import "UIColor+Presets.h" diff --git a/VLC.xcodeproj/project.pbxproj b/VLC.xcodeproj/project.pbxproj index 4d77843db7e9d50f120f1159f15f14376b390a20..d93c067c99e006362d185d54333c1bd2dbeac538 100644 --- a/VLC.xcodeproj/project.pbxproj +++ b/VLC.xcodeproj/project.pbxproj @@ -454,6 +454,10 @@ 7DF90B4B1BE7A8110059C0E3 /* IASKSpecifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF90B491BE7A8110059C0E3 /* IASKSpecifier.m */; }; 7DF9352F1958AB0600E60FD4 /* UIColor+Presets.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF9352E1958AB0600E60FD4 /* UIColor+Presets.m */; }; 7DFFD4071D42436B00A41B0A /* VLCExtensionDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFFD4061D42436B00A41B0A /* VLCExtensionDelegate.m */; }; + 8D43712D2056AF1600F36458 /* VLCRendererDiscovererManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D43712C2056AF1600F36458 /* VLCRendererDiscovererManager.swift */; }; + 8D437154205808FF00F36458 /* VLCActionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D437153205808FF00F36458 /* VLCActionSheet.swift */; }; + 8DD651BA208F6AF00052EE68 /* VLCActionSheetCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DD651B9208F6AF00052EE68 /* VLCActionSheetCell.swift */; }; + 8DD651C4208F786F0052EE68 /* VLCActionSheetSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DD651C3208F786F0052EE68 /* VLCActionSheetSectionHeader.swift */; }; 8F91EC79195CEC7900F5BCBA /* VLCOpenInActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F91EC78195CEC7900F5BCBA /* VLCOpenInActivity.m */; }; 8F91EC7F195E1DAB00F5BCBA /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8F91EC7E195E1DAB00F5BCBA /* AssetsLibrary.framework */; }; 9B088308183D7BEC004B5C2A /* VLCCloudStorageTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B088307183D7BEC004B5C2A /* VLCCloudStorageTableViewController.m */; }; @@ -1200,6 +1204,10 @@ 8939257D0D04F9AFF766DEA5 /* libPods-VLC-TV.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-VLC-TV.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 8B9DD09C453D2346D109D586 /* Pods-VLC-TV.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VLC-TV.debug.xcconfig"; path = "Pods/Target Support Files/Pods-VLC-TV/Pods-VLC-TV.debug.xcconfig"; sourceTree = "<group>"; }; 8C707B9BB2C5681D50CC9B99 /* Pods-VLC-tvOS-Debug.distribution.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VLC-tvOS-Debug.distribution.xcconfig"; path = "Pods/Target Support Files/Pods-VLC-tvOS-Debug/Pods-VLC-tvOS-Debug.distribution.xcconfig"; sourceTree = "<group>"; }; + 8D43712C2056AF1600F36458 /* VLCRendererDiscovererManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = VLCRendererDiscovererManager.swift; path = Sources/VLCRendererDiscovererManager.swift; sourceTree = "<group>"; }; + 8D437153205808FF00F36458 /* VLCActionSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VLCActionSheet.swift; sourceTree = "<group>"; }; + 8DD651B9208F6AF00052EE68 /* VLCActionSheetCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VLCActionSheetCell.swift; sourceTree = "<group>"; }; + 8DD651C3208F786F0052EE68 /* VLCActionSheetSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VLCActionSheetSectionHeader.swift; sourceTree = "<group>"; }; 8DEAD87A672248D0A6790405 /* libPods-vlc-ios.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-vlc-ios.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 8F91EC77195CEC7900F5BCBA /* VLCOpenInActivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCOpenInActivity.h; path = Sources/VLCOpenInActivity.h; sourceTree = SOURCE_ROOT; }; 8F91EC78195CEC7900F5BCBA /* VLCOpenInActivity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCOpenInActivity.m; path = Sources/VLCOpenInActivity.m; sourceTree = SOURCE_ROOT; }; @@ -1781,6 +1789,7 @@ DDC10BE31AEE8EA700890DC3 /* VLCTimeNavigationTitleView.m */, DD1CB0581BBAC549006EDDE6 /* VLCVolumeView.h */, DD1CB0591BBAC549006EDDE6 /* VLCVolumeView.m */, + 8DD651B0208F62B70052EE68 /* VLCActionSheet */, ); name = "UI Elements"; sourceTree = "<group>"; @@ -1909,6 +1918,7 @@ DDAD5C2D1BB9A1E6006AFD3B /* VLCMovieViewControlPanelView.m */, 41F9BC7A1F4F20E400268461 /* VLCTrackSelectorView.h */, 41F9BC7B1F4F20E400268461 /* VLCTrackSelectorView.m */, + 8D43712C2056AF1600F36458 /* VLCRendererDiscovererManager.swift */, ); name = Playback; sourceTree = "<group>"; @@ -2421,6 +2431,17 @@ name = Dropbox; sourceTree = "<group>"; }; + 8DD651B0208F62B70052EE68 /* VLCActionSheet */ = { + isa = PBXGroup; + children = ( + 8D437153205808FF00F36458 /* VLCActionSheet.swift */, + 8DD651B9208F6AF00052EE68 /* VLCActionSheetCell.swift */, + 8DD651C3208F786F0052EE68 /* VLCActionSheetSectionHeader.swift */, + ); + name = VLCActionSheet; + path = Sources/VLCActionSheet; + sourceTree = "<group>"; + }; 9B51719A17EDEC8900F8FBA7 /* GoogleDrive */ = { isa = PBXGroup; children = ( @@ -3893,6 +3914,7 @@ 8F91EC79195CEC7900F5BCBA /* VLCOpenInActivity.m in Sources */, 7D37848F183A98B6009EE944 /* VLCMovieViewController.m in Sources */, DD3EFF4D1BDEBCE500B68579 /* VLCNetworkServerBrowserPlex.m in Sources */, + 8D437154205808FF00F36458 /* VLCActionSheet.swift in Sources */, DDF908E41CFCD97400108B70 /* VLCNetworkLoginDataSourceProtocol.m in Sources */, 7D378492183A98BF009EE944 /* VLCExternalDisplayController.m in Sources */, 41F9BC7C1F4F20E400268461 /* VLCTrackSelectorView.m in Sources */, @@ -3902,11 +3924,13 @@ DD3EFF551BDEBCE500B68579 /* VLCLocalNetworkServiceBrowserDSM.m in Sources */, 7D37849A183A98D1009EE944 /* VLCPlaylistTableViewCell.m in Sources */, 7D37849B183A98D1009EE944 /* VLCLibraryViewController.m in Sources */, + 8DD651C4208F786F0052EE68 /* VLCActionSheetSectionHeader.swift in Sources */, 7D37849E183A98DD009EE944 /* VLCThumbnailsCache.m in Sources */, DD3EFF411BDEBCE500B68579 /* VLCNetworkServerBrowserSharedLibrary.m in Sources */, 7D3784A1183A98EB009EE944 /* VLCBugreporter.m in Sources */, 7D3784A6183A98F5009EE944 /* VLCAboutViewController.m in Sources */, 7D3784A7183A98F5009EE944 /* VLCSettingsController.m in Sources */, + 8D43712D2056AF1600F36458 /* VLCRendererDiscovererManager.swift in Sources */, 7DC19AE41868C8EC00810BF7 /* VLCFirstStepsFirstPageViewController.m in Sources */, 7D3784AD183A9906009EE944 /* VLCDropboxController.m in Sources */, 7D3784AE183A9906009EE944 /* VLCDropboxTableViewController.m in Sources */, @@ -3930,6 +3954,7 @@ 7D3784C8183A9972009EE944 /* NSString+SupportedMedia.m in Sources */, 417E68B91F321EFF00DB9BB2 /* VLCActivityViewControllerVendor.m in Sources */, DD3EFF5B1BDEBCE500B68579 /* VLCNetworkServerBrowserUPnP.m in Sources */, + 8DD651BA208F6AF00052EE68 /* VLCActionSheetCell.swift in Sources */, DD3EABF81BE14BD6003668DA /* BasicUPnPDevice+VLC.m in Sources */, DD3EAC091BE2192A003668DA /* VLCServerBrowsingController.m in Sources */, 7D3784C9183A9972009EE944 /* UIDevice+VLC.m in Sources */, diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/Contents.json b/vlc-ios/Images.xcassets/Movie View/Renderer/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..da4a164c918651cdd1e11dca5cc62c333f097601 --- /dev/null +++ b/vlc-ios/Images.xcassets/Movie View/Renderer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/renderer.imageset/Contents.json b/vlc-ios/Images.xcassets/Movie View/Renderer/renderer.imageset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..3f07431c362bfb7b083309669c9677d985267df0 --- /dev/null +++ b/vlc-ios/Images.xcassets/Movie View/Renderer/renderer.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "renderer_normal.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "renderer_normal@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "renderer_normal@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/renderer.imageset/renderer_normal.png b/vlc-ios/Images.xcassets/Movie View/Renderer/renderer.imageset/renderer_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..7e4f8653da305d937f0fc1deab93a9c364a0ccde Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/renderer.imageset/renderer_normal.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/renderer.imageset/renderer_normal@2x.png b/vlc-ios/Images.xcassets/Movie View/Renderer/renderer.imageset/renderer_normal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..6a2aa5daee697c90839a45327c3b6044e923cfb0 Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/renderer.imageset/renderer_normal@2x.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/renderer.imageset/renderer_normal@3x.png b/vlc-ios/Images.xcassets/Movie View/Renderer/renderer.imageset/renderer_normal@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..8c86e612d3623717dc58eee066814e0417339e24 Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/renderer.imageset/renderer_normal@3x.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlack.imageset/Contents.json b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlack.imageset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..7550aeef5e0ed06f17f40f018f1e1daaf80b4ca1 --- /dev/null +++ b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlack.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "renderer_normal_black.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "renderer_normal_black@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "renderer_normal_black@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlack.imageset/renderer_normal_black.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlack.imageset/renderer_normal_black.png new file mode 100644 index 0000000000000000000000000000000000000000..aa74dfa038bfd95a18610d61d63eec4eccbc3e2d Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlack.imageset/renderer_normal_black.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlack.imageset/renderer_normal_black@2x.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlack.imageset/renderer_normal_black@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..79d4073862f81cf89a3d6ed8fc9bb9b797ce24e6 Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlack.imageset/renderer_normal_black@2x.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlack.imageset/renderer_normal_black@3x.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlack.imageset/renderer_normal_black@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..44e33fdc50de155cf26e947098b328dfab2fb470 Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlack.imageset/renderer_normal_black@3x.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlackFull.imageset/Contents.json b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlackFull.imageset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..20a0a13b99f54296c85551b95c8cc5617a6080b5 --- /dev/null +++ b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlackFull.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "renderer_full_normal_black.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "renderer_full_normal_black@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "renderer_full_normal_black@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlackFull.imageset/renderer_full_normal_black.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlackFull.imageset/renderer_full_normal_black.png new file mode 100644 index 0000000000000000000000000000000000000000..239838f55ba98e965fa1c9704bd65b0ef39dadb5 Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlackFull.imageset/renderer_full_normal_black.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlackFull.imageset/renderer_full_normal_black@2x.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlackFull.imageset/renderer_full_normal_black@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..607c25bbab094e24e5310a4eadb5bf2a6984ace4 Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlackFull.imageset/renderer_full_normal_black@2x.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlackFull.imageset/renderer_full_normal_black@3x.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlackFull.imageset/renderer_full_normal_black@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..c3f547f3977094d2974a78ecbeb42ba6fd682c86 Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererBlackFull.imageset/renderer_full_normal_black@3x.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererFull.imageset/Contents.json b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererFull.imageset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..20a0dd794c855ec0b2c31add9243c62edbef2ce2 --- /dev/null +++ b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererFull.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "renderer_full_normal.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "renderer_full_normal@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "renderer_full_normal@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererFull.imageset/renderer_full_normal.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererFull.imageset/renderer_full_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..99cf3b0077f8dd5f7f029dc6a94f94cb7737db97 Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererFull.imageset/renderer_full_normal.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererFull.imageset/renderer_full_normal@2x.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererFull.imageset/renderer_full_normal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..db861e61561b2611f4bfa57a65040b1757cebb55 Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererFull.imageset/renderer_full_normal@2x.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererFull.imageset/renderer_full_normal@3x.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererFull.imageset/renderer_full_normal@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..d1f0f4e0bf2ec3ad19a7b0a838f46a89c19d96d4 Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererFull.imageset/renderer_full_normal@3x.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererGray.imageset/Contents.json b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererGray.imageset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..c2f01e735a8b8419b9c9c9461bc0c0f8632ec43d --- /dev/null +++ b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererGray.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "group95.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "group95@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "group95@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererGray.imageset/group95.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererGray.imageset/group95.png new file mode 100644 index 0000000000000000000000000000000000000000..00e30e9d3a61d589b83aad44a9c319ce3c24903f Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererGray.imageset/group95.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererGray.imageset/group95@2x.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererGray.imageset/group95@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ea642317fc4409f9345c475ddafa58d0861bf32e Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererGray.imageset/group95@2x.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererGray.imageset/group95@3x.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererGray.imageset/group95@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..33207b9c08a7a5ea428abcf3c8da80257792449b Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererGray.imageset/group95@3x.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererOrangeFull.imageset/Contents.json b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererOrangeFull.imageset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..fac31c43e9aa9f55c106cd7098659ad139f7324f --- /dev/null +++ b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererOrangeFull.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icRemoveCircleWhite24Dp.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "icRemoveCircleWhite24Dp@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "icRemoveCircleWhite24Dp@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererOrangeFull.imageset/icRemoveCircleWhite24Dp.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererOrangeFull.imageset/icRemoveCircleWhite24Dp.png new file mode 100644 index 0000000000000000000000000000000000000000..cc3567ac995e8b4530221b1987e7f989fa612835 Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererOrangeFull.imageset/icRemoveCircleWhite24Dp.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererOrangeFull.imageset/icRemoveCircleWhite24Dp@2x.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererOrangeFull.imageset/icRemoveCircleWhite24Dp@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..80c92dff542a3f7ba73b8fe2af651ea703eb8f9d Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererOrangeFull.imageset/icRemoveCircleWhite24Dp@2x.png differ diff --git a/vlc-ios/Images.xcassets/Movie View/Renderer/rendererOrangeFull.imageset/icRemoveCircleWhite24Dp@3x.png b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererOrangeFull.imageset/icRemoveCircleWhite24Dp@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..82cb57faba1834ddb6707977d0582b6ce1c135c4 Binary files /dev/null and b/vlc-ios/Images.xcassets/Movie View/Renderer/rendererOrangeFull.imageset/icRemoveCircleWhite24Dp@3x.png differ