Commit d59277d7 authored by Robert Gordon's avatar Robert Gordon Committed by Soomin Lee

MediaMoreOptionsActionSheet: Centralize MoreOptionsActionSheet for VLCMovieViewController

parent 3235a361
......@@ -378,3 +378,7 @@
"MORE_OPTIONS_HINT" = "View more option controls";
"REPEAT_MODE_HINT" = "Change repeat mode of current item";
"VIDEO_ASPECT_RATIO_HINT" = "Change the aspect ratio of the current video";
/* MediaMoreOptionsActionSheet */
"EQUALIZER_CELL_TITLE" = "Equalizer";
"MORE_OPTIONS_HEADER_TITLE" = "Video Options";
......@@ -208,6 +208,10 @@ class ActionSheet: UIViewController {
}
collectionView.layoutIfNeeded()
}
func addChildToStackView(_ child: UIView) {
mainStackView.addSubview(child)
}
}
// MARK: Private setup methods
......
......@@ -9,8 +9,8 @@
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
enum ActionSheetCellAccessoryType: Equatable {
case none
enum ActionSheetCellAccessoryType {
case toggleSwitch
case checkmark
case disclosureChevron
}
......@@ -33,9 +33,46 @@ class ActionSheetCellImageView: UIImageView {
}
}
/// Model that determines the layout presentation of the ActionSheetCell.
@objc (VLCActionSheetCellModel)
@objcMembers class ActionSheetCellModel: NSObject {
var title: String
var iconImage: UIImage?
var viewToPresent: UIView?
var accessoryType: ActionSheetCellAccessoryType
var cellIdentifier: MediaPlayerActionSheetCellIdentifier?
init(
title: String,
imageIdentifier: String,
accessoryType: ActionSheetCellAccessoryType = .checkmark,
viewToPresent: UIView? = nil,
cellIdentifier: MediaPlayerActionSheetCellIdentifier? = nil) {
self.title = title
iconImage = UIImage(named: imageIdentifier)?.withRenderingMode(.alwaysTemplate)
self.accessoryType = accessoryType
self.viewToPresent = viewToPresent
self.cellIdentifier = cellIdentifier
}
}
@objc (VLCActionSheetCellDelegate)
protocol ActionSheetCellDelegate {
func actionSheetCellShouldUpdateColors() -> Bool
func actionSheetCellDidToggleSwitch(for cell: ActionSheetCell, state: Bool)
}
@objc(VLCActionSheetCell)
class ActionSheetCell: UICollectionViewCell {
/// UIViewController to present on cell selection
weak var viewToPresent: UIView?
/// Rightmost accessory view that the cell should use. Default `checkmark`.
/// If `viewControllerToPresent` is set, defaults to `disclosureChevron`, otherwise `checkmark` is main default.
private(set) var accessoryView = UIView ()
weak var delegate: ActionSheetCellDelegate?
var identifier: MediaPlayerActionSheetCellIdentifier?
@objc static var identifier: String {
return String(describing: self)
}
......@@ -44,13 +81,16 @@ class ActionSheetCell: UICollectionViewCell {
didSet {
updateColors()
// only checkmarks should be hidden if they arent selected
accessoryTypeImageView.isHidden = !isSelected && accessoryType == .checkmark
if accessoryType == .checkmark {
accessoryView.isHidden = !isSelected
}
}
}
let icon: ActionSheetCellImageView = {
let icon = ActionSheetCellImageView()
icon.translatesAutoresizingMaskIntoConstraints = false
icon.setContentHuggingPriority(.required, for: .horizontal)
icon.contentMode = .scaleAspectFit
return icon
}()
......@@ -60,31 +100,42 @@ class ActionSheetCell: UICollectionViewCell {
name.textColor = PresentationTheme.current.colors.cellTextColor
name.font = UIFont.systemFont(ofSize: 15)
name.translatesAutoresizingMaskIntoConstraints = false
name.setContentHuggingPriority(.defaultLow, for: .horizontal)
return name
}()
private var accessoryTypeImageView: UIImageView = {
lazy private var accessoryTypeImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.backgroundColor = .none
imageView.tintColor = PresentationTheme.current.colors.cellDetailTextColor
imageView.setContentHuggingPriority(.required, for: .horizontal)
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
lazy private var toggleSwitch: UISwitch = {
let toggleSwitch = UISwitch()
toggleSwitch.onTintColor = .orange
toggleSwitch.translatesAutoresizingMaskIntoConstraints = false
toggleSwitch.addTarget(self, action: #selector(switchToggled(_:)), for: .valueChanged)
return toggleSwitch
}()
var accessoryType: ActionSheetCellAccessoryType = .checkmark {
private(set) var accessoryType: ActionSheetCellAccessoryType = .checkmark {
didSet {
switch accessoryType {
case .checkmark:
accessoryTypeImageView.image = UIImage(named: "checkmark")?.withRenderingMode(.alwaysTemplate)
accessoryTypeImageView.isHidden = !isSelected
add(view: accessoryTypeImageView, to: accessoryView)
case .disclosureChevron:
accessoryTypeImageView.image = UIImage(named: "disclosureChevron")?.withRenderingMode(.alwaysTemplate)
accessoryTypeImageView.isHidden = false
case .none:
accessoryTypeImageView.image = nil
accessoryTypeImageView.isHidden = true
add(view: accessoryTypeImageView, to: accessoryView)
case .toggleSwitch:
add(view: toggleSwitch, to: accessoryView)
}
if accessoryType == .checkmark {
accessoryView.isHidden = !isSelected
} else {
accessoryView.isHidden = false
}
}
}
......@@ -107,43 +158,85 @@ class ActionSheetCell: UICollectionViewCell {
super.init(coder: aDecoder)
setupViews()
}
convenience init(withCellModel model: ActionSheetCellModel) {
self.init()
configure(withModel: model)
setupViews()
}
private func updateColors() {
let shouldUpdateColors = delegate?.actionSheetCellShouldUpdateColors() ?? true
let colors = PresentationTheme.current.colors
name.textColor = isSelected ? colors.orangeUI : colors.cellTextColor
tintColor = isSelected ? colors.orangeUI : colors.cellDetailTextColor
if accessoryType == .checkmark {
let defaultColor = PresentationTheme.current.colors.cellDetailTextColor
accessoryTypeImageView.tintColor = isSelected ? .orange : defaultColor
if shouldUpdateColors {
name.textColor = isSelected ? colors.orangeUI : colors.cellTextColor
tintColor = isSelected ? colors.orangeUI : colors.cellDetailTextColor
}
if accessoryType != .toggleSwitch {
accessoryView.tintColor = isSelected && accessoryType == .checkmark ? colors.orangeUI : colors.cellDetailTextColor
}
}
@objc private func switchToggled(_ sender: UISwitch) {
delegate?.actionSheetCellDidToggleSwitch(for: self, state: sender.isOn)
}
override func prepareForReuse() {
super.prepareForReuse()
toggleSwitch.removeFromSuperview()
accessoryType = .checkmark
updateColors()
}
private func add(view: UIView, to parentView: UIView) {
view.translatesAutoresizingMaskIntoConstraints = false
parentView.subviews.forEach { $0.removeFromSuperview() }
parentView.addSubview(view)
NSLayoutConstraint.activate([
view.topAnchor.constraint(equalTo: parentView.topAnchor),
view.bottomAnchor.constraint(equalTo: parentView.bottomAnchor),
view.leadingAnchor.constraint(equalTo: parentView.leadingAnchor),
view.trailingAnchor.constraint(equalTo: parentView.trailingAnchor)
])
}
func configure(withModel model: ActionSheetCellModel) {
if model.accessoryType == .disclosureChevron {
assert(model.viewToPresent != nil, "ActionSheetCell: Cell with disclosure chevron must have accompanying presentable UIView")
}
name.text = model.title
icon.image = model.iconImage
viewToPresent = model.viewToPresent
identifier = model.cellIdentifier
// disclosure chevron is set as the default accessoryView if a viewController is present
accessoryType = model.viewToPresent != nil ? .disclosureChevron : model.accessoryType
}
func setToggleSwitch(state: Bool) {
if accessoryType == .toggleSwitch {
toggleSwitch.isOn = state
}
}
private func setupViews() {
backgroundColor = PresentationTheme.current.colors.background
// property observers only trigger after the first time the values are set.
// allow the didSet to set the checkmark image
accessoryType = .checkmark
stackView.addArrangedSubview(icon)
stackView.addArrangedSubview(name)
stackView.addArrangedSubview(accessoryTypeImageView)
stackView.addArrangedSubview(accessoryView)
addSubview(stackView)
// property observers only trigger after the first time the values are set.
// allow the didSet to set the checkmark image
accessoryType = .checkmark
var guide: LayoutAnchorContainer = self
if #available(iOS 11.0, *) {
guide = safeAreaLayoutGuide
}
NSLayoutConstraint.activate([
icon.heightAnchor.constraint(equalToConstant: 25),
icon.widthAnchor.constraint(equalTo: icon.heightAnchor),
stackView.leadingAnchor.constraint(equalTo: guide.leadingAnchor, constant: 20),
stackView.trailingAnchor.constraint(equalTo: guide.trailingAnchor, constant: -20),
stackView.heightAnchor.constraint(equalTo: heightAnchor),
......
/*****************************************************************************
* MediaMoreOptionsActionSheet.swift
*
* Copyright © 2019 VLC authors and VideoLAN
*
* Authors: Robert Gordon <robwaynegordon@gmail.com>
*
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
enum MediaPlayerActionSheetCellIdentifier: String, CustomStringConvertible, CaseIterable {
case filter
case playback
case equalizer
case sleepTimer
case interfaceLock
var description: String {
switch self {
case .filter:
return NSLocalizedString("VIDEO_FILTER", comment: "")
case .playback:
return NSLocalizedString("PLAYBACK_SPEED", comment: "")
case .equalizer:
return NSLocalizedString("EQUALIZER_CELL_TITLE", comment: "")
case .sleepTimer:
return NSLocalizedString("BUTTON_SLEEP_TIMER", comment: "")
case .interfaceLock:
return NSLocalizedString("INTERFACE_LOCK_BUTTON", comment: "")
}
}
}
@objc (VLCMediaMoreOptionsActionSheetDelegate)
protocol MediaMoreOptionsActionSheetDelegate {
func mediaMoreOptionsDidToggleInterfaceLock(state: Bool)
}
@objc (VLCMediaMoreOptionsActionSheet)
class MediaMoreOptionsActionSheet: ActionSheet {
// MARK: Private Instance Properties
private weak var currentChildView: UIView?
@objc weak var moreOptionsDelegate: MediaMoreOptionsActionSheetDelegate?
@objc var interfaceDisabled: Bool = false {
didSet {
collectionView.visibleCells.forEach {
if let cell = $0 as? ActionSheetCell, let id = cell.identifier {
if id == .interfaceLock {
cell.setToggleSwitch(state: interfaceDisabled)
} else {
cell.alpha = interfaceDisabled ? 0.5 : 1
}
}
}
collectionView.allowsSelection = !interfaceDisabled
}
}
private var offScreenFrame: CGRect {
let y = collectionView.frame.origin.y + headerView.cellHeight
let w = collectionView.frame.size.width
let h = collectionView.frame.size.height
return CGRect(x: w, y: y, width: w, height: h)
}
private var leftToRightGesture: UIPanGestureRecognizer {
let leftToRight = UIPanGestureRecognizer(target: self, action: #selector(draggedRight(panGesture:)))
return leftToRight
}
// To be removed when Designs are done for the Filters, Equalizer etc views are added to Figma
lazy private var mockView: UIView = {
let v = UIView()
v.backgroundColor = .green
v.frame = offScreenFrame
return v
}()
lazy private var cellModels: [ActionSheetCellModel] = {
var models: [ActionSheetCellModel] = []
MediaPlayerActionSheetCellIdentifier.allCases.forEach {
var cellModel = ActionSheetCellModel(
title: String(describing: $0),
imageIdentifier: $0.rawValue,
viewToPresent: mockView,
cellIdentifier: $0
)
if $0 == .interfaceLock {
cellModel.accessoryType = .toggleSwitch
cellModel.viewToPresent = nil
}
models.append(cellModel)
}
return models
}()
// MARK: Private Methods
private func add(childView child: UIView) {
UIView.animate(withDuration: 0.3, animations: {
child.frame = self.collectionView.frame
self.addChildToStackView(child)
}) {
(completed) in
child.addGestureRecognizer(self.leftToRightGesture)
self.currentChildView = child
}
}
private func remove(childView child: UIView) {
UIView.animate(withDuration: 0.3, animations: {
child.frame = self.offScreenFrame
}) { (completed) in
child.removeFromSuperview()
child.removeGestureRecognizer(self.leftToRightGesture)
}
}
@objc func removeCurrentChild() {
if let current = currentChildView {
remove(childView: current)
}
}
func setTheme() {
let darkColors = PresentationTheme.darkTheme.colors
collectionView.backgroundColor = darkColors.background
headerView.backgroundColor = darkColors.background
headerView.title.textColor = darkColors.cellTextColor
for cell in collectionView.visibleCells {
if let cell = cell as? ActionSheetCell {
cell.backgroundColor = darkColors.background
cell.name.textColor = darkColors.cellTextColor
cell.icon.tintColor = .orange
// toggleSwitch's tintColor should not be changed
if cell.accessoryType == .disclosureChevron {
cell.accessoryView.tintColor = darkColors.cellDetailTextColor
} else if cell.accessoryType == .checkmark {
cell.accessoryView.tintColor = .orange
}
}
}
collectionView.layoutIfNeeded()
}
/// Animates the removal of the `currentChildViewController` when it is dragged from its left edge to the right
@objc private func draggedRight(panGesture: UIPanGestureRecognizer) {
if let current = currentChildView {
let translation = panGesture.translation(in: view)
let x = translation.x + current.center.x
let halfWidth = current.frame.size.width / 2
panGesture.setTranslation(.zero, in: view)
if panGesture.state == .began || panGesture.state == .changed {
// only enable left-to-right drags
if current.frame.minX + translation.x >= 0 {
current.center = CGPoint(x: x, y: current.center.y)
}
} else if panGesture.state == .ended {
if current.frame.minX > halfWidth {
removeCurrentChild()
} else {
UIView.animate(withDuration: 0.3) {
current.frame = self.collectionView.frame
}
}
}
}
}
// MARK: Overridden superclass methods
// Removed the automatic dismissal of the view when a cell is selected
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let delegate = delegate {
if let item = delegate.itemAtIndexPath(indexPath) {
delegate.actionSheet?(collectionView: collectionView, didSelectItem: item, At: indexPath)
action?(item)
}
if let cell = collectionView.cellForItem(at: indexPath) as? ActionSheetCell, cell.accessoryType == .checkmark {
removeActionSheet()
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Remove the themeDidChangeNotification set in the superclass
// MovieViewController Video Options should be dark at all times
NotificationCenter.default.removeObserver(self, name: .VLCThemeDidChangeNotification, object: nil)
setTheme()
}
// MARK: Initializers
override init() {
super.init()
delegate = self
dataSource = self
modalPresentationStyle = .custom
setAction { (item) in
if let item = item as? UIView {
self.add(childView: item)
} else {
preconditionFailure("MediaMoreOptionsActionSheet: Cell item could not be casted as UIView")
}
}
setTheme()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension MediaMoreOptionsActionSheet: ActionSheetDataSource {
func numberOfRows() -> Int {
return cellModels.count
}
func actionSheet(collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard indexPath.row < cellModels.count else {
assertionFailure("MediaMoreOptionsActionSheet: Out of range.")
return ActionSheetCell()
}
var sheetCell: ActionSheetCell
if let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: ActionSheetCell.identifier,
for: indexPath) as? ActionSheetCell {
sheetCell = cell
sheetCell.configure(withModel: cellModels[indexPath.row])
} else {
assertionFailure("MediaMoreOptionsActionSheet: Could not dequeue reusable cell")
sheetCell = ActionSheetCell(withCellModel: cellModels[indexPath.row])
}
sheetCell.accessoryView.tintColor = PresentationTheme.darkTheme.colors.cellDetailTextColor
sheetCell.delegate = self
return sheetCell
}
}
extension MediaMoreOptionsActionSheet: ActionSheetDelegate {
func itemAtIndexPath(_ indexPath: IndexPath) -> Any? {
if indexPath.row < cellModels.count {
return cellModels[indexPath.row].viewToPresent
}
return nil
}
func headerViewTitle() -> String? {
return NSLocalizedString("MORE_OPTIONS_HEADER_TITLE", comment: "")
}
}
extension MediaMoreOptionsActionSheet: ActionSheetCellDelegate {
func actionSheetCellShouldUpdateColors() -> Bool {
return false
}
func actionSheetCellDidToggleSwitch(for cell: ActionSheetCell, state: Bool) {
assert(moreOptionsDelegate != nil, "MediaMoreOptionsActionSheet: Delegate not set.")
if let identifier = cell.identifier {
if identifier == .interfaceLock {
moreOptionsDelegate?.mediaMoreOptionsDidToggleInterfaceLock(state: state)
}
}
}
}
......@@ -54,7 +54,7 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
VLCPanTypeProjection
};
@interface VLCMovieViewController () <UIGestureRecognizerDelegate, VLCMultiSelectionViewDelegate, VLCEqualizerViewUIDelegate, VLCPlaybackControllerDelegate, VLCDeviceMotionDelegate, VLCRendererDiscovererManagerDelegate, PlaybackSpeedViewDelegate, VLCVideoOptionsControlBarDelegate>
@interface VLCMovieViewController () <UIGestureRecognizerDelegate, VLCMultiSelectionViewDelegate, VLCEqualizerViewUIDelegate, VLCPlaybackControllerDelegate, VLCDeviceMotionDelegate, VLCRendererDiscovererManagerDelegate, PlaybackSpeedViewDelegate, VLCVideoOptionsControlBarDelegate, VLCMediaMoreOptionsActionSheetDelegate>
{
BOOL _controlsHidden;
BOOL _videoFiltersHidden;
......@@ -98,6 +98,7 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
VLCEqualizerView *_equalizerView;
VLCMultiSelectionMenuView *_multiSelectionView;
VLCVideoOptionsControlBar *_videoOptionsControlBar;
VLCMediaMoreOptionsActionSheet *_moreOptionsActionSheet;
VLCPlaybackController *_vpc;
......@@ -171,6 +172,8 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
[self setupMultiSelectionView];
#else
[self setupVideoOptionsControlBar];
_moreOptionsActionSheet = [[VLCMediaMoreOptionsActionSheet alloc] init];
_moreOptionsActionSheet.moreOptionsDelegate = self;
#endif
_scrubHelpLabel.text = NSLocalizedString(@"PLAYBACK_SCRUB_HELP", nil);
......@@ -256,7 +259,6 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
{
_videoOptionsControlBar = [[VLCVideoOptionsControlBar alloc] init];
_videoOptionsControlBar.delegate = self;
_videoOptionsControlBar.hidden = YES;
_videoOptionsControlBar.repeatMode = _vpc.repeatMode;
[self.view addSubview:_videoOptionsControlBar];
}
......@@ -704,7 +706,6 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
return [arr arrayByAddingObjectsFromArray:
@[_videoOptionsControlBar.toggleFullScreenButton,
_videoOptionsControlBar.selectSubtitleButton,
_videoOptionsControlBar.moreOptionsButton,
_videoOptionsControlBar.repeatButton]];
#endif
}
......@@ -813,7 +814,7 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
#if !NEW_UI
self->_multiSelectionView.hidden = YES;
#else
self->_videoOptionsControlBar.hidden = YES;
self->_videoOptionsControlBar.hidden = NO;
#endif
......@@ -1346,25 +1347,10 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
completion:nil];
}
- (void) toggleVideoOptionsBar
{
CGFloat alpha = _videoOptionsControlBar.hidden ? 1.0f : 0.0f;
BOOL hidden = !_videoOptionsControlBar.hidden;
[UIView animateWithDuration:.3
animations:^{
self->_videoOptionsControlBar.alpha = alpha;
self->_videoOptionsControlBar.hidden = hidden;
}
completion:nil];
}
- (void)moreActions:(UIButton *)sender
{
#if !NEW_UI
[self toggleMultiSelectionView:sender];
#else
[self toggleVideoOptionsBar];
#endif
[self _resetIdleTimer];
}
......@@ -1401,6 +1387,7 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
_multiSelectionView.displayLock = _interfaceIsLocked;
#else
_videoOptionsControlBar.interfaceDisabled = _interfaceIsLocked;
_moreOptionsActionSheet.interfaceDisabled = _interfaceIsLocked;
#endif
}
......@@ -1483,8 +1470,7 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
self->_videoOptionsControlBar.hidden = YES;
#endif
}
completion:^(BOOL finished){
}];
completion:nil];
[self _resetIdleTimer];
}
......@@ -1873,7 +1859,7 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
#pragma mark - VLCVideoOptionsControlBarDelegate
- (void)didSelectMoreOptions:(VLCVideoOptionsControlBar * _Nonnull)optionsBar {
[self moreActions:optionsBar.moreOptionsButton];
[self toggleMoreOptionsActionSheet];
}
- (void)didSelectSubtitle:(VLCVideoOptionsControlBar * _Nonnull)optionsBar {
......@@ -1892,4 +1878,17 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
[self toggleRepeatMode];
}
- (void)toggleMoreOptionsActionSheet
{
[self presentViewController:_moreOptionsActionSheet animated:false completion:^{
self->_moreOptionsActionSheet.interfaceDisabled = self->_interfaceIsLocked;
}];
}
#pragma mark - VLCMediaMoreOptionsActionSheetDelegate
- (void) mediaMoreOptionsDidToggleInterfaceLockWithState:(BOOL)state
{
[self toggleUILock];
}
@end
......@@ -384,6 +384,7 @@
DDF908E01CF4E04A00108B70 /* VLCNetworkLoginDataSourceSavedLogins.m in Sources */ = {isa = PBXBuildFile; fileRef = DDF908DF1CF4E04A00108B70 /* VLCNetworkLoginDataSourceSavedLogins.m */; };
DDF908E41CFCD97400108B70 /* VLCNetworkLoginDataSourceProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = DDF908E31CFCD97400108B70 /* VLCNetworkLoginDataSourceProtocol.m */; };
E03DECA622BEE27E00F44A05 /* MediaNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E03DECA522BEE27E00F44A05 /* MediaNavigationBar.swift */; };
E03F36B122ED8DBB00057525 /* MediaMoreOptionsActionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = E03F36B022ED8DBA00057525 /* MediaMoreOptionsActionSheet.swift */; };
E0539E8C22E5E2EC009317CB /* VideoOptionsControlBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0539E8B22E5E2EC009317CB /* VideoOptionsControlBar.swift */; };
E0BA21B922D7C8C700937CFD /* MediaPlaybackControlToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0BA21B822D7C8C700937CFD /* MediaPlaybackControlToolbar.swift */; };
E0C04F951A25B4410080331A /* VLCDocumentPickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E0C04F941A25B4410080331A /* VLCDocumentPickerController.m */; };
......@@ -1022,6 +1023,7 @@
DDF908E21CFCD97400108B70 /* VLCNetworkLoginDataSourceProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCNetworkLoginDataSourceProtocol.h; path = Sources/LocalNetworkConnectivity/VLCNetworkLoginDataSourceProtocol.h; sourceTree = SOURCE_ROOT; };
DDF908E31CFCD97400108B70 /* VLCNetworkLoginDataSourceProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCNetworkLoginDataSourceProtocol.m; path = Sources/LocalNetworkConnectivity/VLCNetworkLoginDataSourceProtocol.m; sourceTree = SOURCE_ROOT; };
E03DECA522BEE27E00F44A05 /* MediaNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MediaNavigationBar.swift; path = Sources/MediaNavigationBar.swift; sourceTree = "<group>"; };
E03F36B022ED8DBA00057525 /* MediaMoreOptionsActionSheet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MediaMoreOptionsActionSheet.swift; path = Sources/MediaMoreOptionsActionSheet.swift; sourceTree = "<group>"; };
E0539E8B22E5E2EC009317CB /* VideoOptionsControlBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = VideoOptionsControlBar.swift; path = Sources/VideoOptionsControlBar.swift; sourceTree = "<group>"; };
E0BA21B822D7C8C700937CFD /* MediaPlaybackControlToolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MediaPlaybackControlToolbar.swift; path = Sources/MediaPlaybackControlToolbar.swift; sourceTree = "<group>"; };
E0C04F931A25B4410080331A /* VLCDocumentPickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCDocumentPickerController.h; path = Sources/VLCDocumentPickerController.h; sourceTree = SOURCE_ROOT; };
......@@ -1406,6 +1408,7 @@
isa = PBXGroup;
children = (
E0BA21B822D7C8C700937CFD /* MediaPlaybackControlToolbar.swift */,
E03F36B022ED8DBA00057525 /* MediaMoreOptionsActionSheet.swift */,
8D144D6122298E5800984C46 /* MiniPlayer */,
416443852048419E00CAC646 /* DeviceMotion.swift */,
DD8F842F1B00EB3B0009138A /* VLCPlaybackController+MediaLibrary.h */,
......@@ -2960,6 +2963,7 @@
DD3EFF5D1BDEBCE500B68579 /* VLCLocalServerDiscoveryController.m in Sources */,
E0539E8C22E5E2EC009317CB /* VideoOptionsControlBar.swift in Sources */,
D6E034ED1CC284FC0037F516 /* VLCStreamingHistoryCell.m in Sources */,
E03F36B122ED8DBB00057525 /* MediaMoreOptionsActionSheet.swift in Sources */,
DD3EFEED1BDEBA3800B68579 /* VLCNetworkServerBrowserViewController.m in Sources */,
8DF9669D2113317E00D0FCD6 /* EditToolbar.swift in Sources */,
416443862048419E00CAC646 /* DeviceMotion.swift in Sources */,
......
{
"images" : [
{
"idiom" : "universal",
"filename" : "subtitlesIcon-new.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "subtitlesIcon-new@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "subtitlesIcon-new@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment