Prechádzať zdrojové kódy

iOS: Add navigation bar animation on scroll on the LibraryView

Signed-off-by: Jean-Baptiste Kempf <jb@videolan.org>
Soomin Lee 8 rokov pred
rodič
commit
ebd67be984

+ 52 - 0
Sources/GTScrollNavigationBar.h

@@ -0,0 +1,52 @@
+/*  This file is adapted from GTScrollNavigationBar - https://github.com/luugiathuy/GTScrollNavigationBar
+ *  3-clause BSD License
+ *
+ *  Copyright (c) 2013, Luu Gia Thuy
+ *
+ *  Redistribution and use in source and binary forms, with or without modification,
+ *  are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice, this
+ *  list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice, this
+ *  list of conditions and the following disclaimer in the documentation and/or
+ *  other materials provided with the distribution.
+ *
+ *  * Neither the name of the {organization} nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+#import <UIKit/UIKit.h>
+
+typedef NS_ENUM(NSInteger, GTScrollNavigationBarState) {
+    GTScrollNavigationBarStateNone,
+    GTScrollNavigationBarStateScrollingDown,
+    GTScrollNavigationBarStateScrollingUp
+};
+
+@interface GTScrollNavigationBar : UINavigationBar
+
+@property (strong, nonatomic) UIScrollView *scrollView;
+@property (assign, nonatomic) GTScrollNavigationBarState scrollState;
+
+- (void)resetToDefaultPositionWithAnimation:(BOOL)animated;
+
+@end
+
+@interface UINavigationController (GTScrollNavigationBarAdditions)
+
+@property(strong, nonatomic, readonly) GTScrollNavigationBar *scrollNavigationBar;
+
+@end

+ 252 - 0
Sources/GTScrollNavigationBar.m

@@ -0,0 +1,252 @@
+/*  This file is adapted from GTScrollNavigationBar - https://github.com/luugiathuy/GTScrollNavigationBar
+ *  3-clause BSD License
+ *
+ *  Copyright (c) 2013, Luu Gia Thuy
+ *
+ *  Redistribution and use in source and binary forms, with or without modification,
+ *  are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice, this
+ *  list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice, this
+ *  list of conditions and the following disclaimer in the documentation and/or
+ *  other materials provided with the distribution.
+ *
+ *  * Neither the name of the {organization} nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+#import "GTScrollNavigationBar.h"
+
+#define kNearZero 0.000001f
+
+@interface GTScrollNavigationBar () <UIGestureRecognizerDelegate>
+
+@property (strong, nonatomic) UIPanGestureRecognizer* panGesture;
+@property (assign, nonatomic) CGFloat lastContentOffsetY;
+
+@end
+
+@implementation GTScrollNavigationBar
+
+- (id)initWithCoder:(NSCoder *)aDecoder {
+    self = [super initWithCoder:aDecoder];
+    if (self) {
+        [self setup];
+    }
+    return self;
+}
+
+- (id)initWithFrame:(CGRect)frame
+{
+    self = [super initWithFrame:frame];
+    if (self) {
+        [self setup];
+    }
+    return self;
+}
+
+- (void)setup
+{
+    self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self
+                                                              action:@selector(handlePan:)];
+    self.panGesture.delegate = self;
+    self.panGesture.cancelsTouchesInView = NO;
+
+    NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
+
+    [defaultCenter addObserver:self
+                   selector:@selector(applicationDidBecomeActive)
+                   name:UIApplicationDidBecomeActiveNotification
+                   object:nil];
+
+    [defaultCenter addObserver:self
+                   selector:@selector(statusBarOrientationDidChange)
+                   name:UIApplicationDidChangeStatusBarOrientationNotification
+                   object:nil];
+}
+
+- (void)dealloc
+{
+    if (!SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9.0")) {
+        [[NSNotificationCenter defaultCenter] removeObserver:self];
+    }
+}
+
+#pragma mark - Properties
+- (void)setScrollView:(UIScrollView*)scrollView
+{
+    [self resetToDefaultPositionWithAnimation:NO];
+
+    _scrollView = scrollView;
+
+    // remove gesture from current panGesture's view
+    if (self.panGesture.view) {
+        [self.panGesture.view removeGestureRecognizer:self.panGesture];
+    }
+
+    if (scrollView) {
+        [scrollView addGestureRecognizer:self.panGesture];
+    }
+}
+
+#pragma mark - Public methods
+- (void)resetToDefaultPositionWithAnimation:(BOOL)animated
+{
+    self.scrollState = GTScrollNavigationBarStateNone;
+    CGRect frame = self.frame;
+    frame.origin.y = [self statusBarTopOffset];
+    [self setFrame:frame alpha:1.0f animated:animated];
+}
+
+#pragma mark - Notifications
+- (void)statusBarOrientationDidChange
+{
+    [self resetToDefaultPositionWithAnimation:NO];
+}
+
+- (void)applicationDidBecomeActive
+{
+    [self resetToDefaultPositionWithAnimation:NO];
+}
+
+#pragma mark - UIGestureRecognizerDelegate
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
+shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
+{
+    return YES;
+}
+
+#pragma mark - panGesture handler
+- (void)handlePan:(UIPanGestureRecognizer*)gesture
+{
+    if (!self.scrollView || gesture.view != self.scrollView) {
+        return;
+    }
+
+    // Don't try to scroll navigation bar if there's not enough room
+    if (self.scrollView.frame.size.height + (self.bounds.size.height * 2) >=
+        self.scrollView.contentSize.height) {
+        return;
+    }
+
+    CGFloat contentOffsetY = self.scrollView.contentOffset.y;
+
+    // Reset scrollState when the gesture began
+    if (gesture.state == UIGestureRecognizerStateBegan) {
+        self.scrollState = GTScrollNavigationBarStateNone;
+        self.lastContentOffsetY = contentOffsetY;
+        return;
+    }
+
+    CGFloat deltaY = contentOffsetY - self.lastContentOffsetY;
+    if (deltaY < 0.0f) {
+        self.scrollState = GTScrollNavigationBarStateScrollingDown;
+    } else if (deltaY > 0.0f) {
+        self.scrollState = GTScrollNavigationBarStateScrollingUp;
+    }
+
+    CGRect frame = self.frame;
+    CGFloat alpha = 1.0f;
+    CGFloat maxY = [self statusBarTopOffset];
+    CGFloat minY = maxY - CGRectGetHeight(frame) + 1.0f;
+    // NOTE: plus 1px to prevent the navigation bar disappears in iOS < 7
+
+    CGFloat contentInsetTop = self.scrollView.contentInset.top;
+    bool isBouncePastTopEdge = contentOffsetY < -contentInsetTop;
+    if (isBouncePastTopEdge && CGRectGetMinY(frame) == maxY) {
+        self.lastContentOffsetY = contentOffsetY;
+        return;
+    }
+
+    bool isScrolling = (self.scrollState == GTScrollNavigationBarStateScrollingUp ||
+                        self.scrollState == GTScrollNavigationBarStateScrollingDown);
+
+    bool gestureIsActive = (gesture.state != UIGestureRecognizerStateEnded &&
+                            gesture.state != UIGestureRecognizerStateCancelled);
+
+    if (isScrolling && !gestureIsActive) {
+        // Animate navigation bar to end position
+        if (self.scrollState == GTScrollNavigationBarStateScrollingDown) {
+            frame.origin.y = maxY;
+            alpha = 1.0f;
+        }
+        else if (self.scrollState == GTScrollNavigationBarStateScrollingUp) {
+            frame.origin.y = minY;
+            alpha = kNearZero;
+        }
+        [self setFrame:frame alpha:alpha animated:YES];
+    }
+    // When panning down at beginning of scrollView and the bar is expanding, do not update lastContentOffsetY
+    if (!isBouncePastTopEdge && CGRectGetMinY(frame) == maxY) {
+        self.lastContentOffsetY = contentOffsetY;
+    }
+}
+
+#pragma mark - helper methods
+- (CGFloat)statusBarTopOffset
+{
+    CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
+    CGFloat topOffset = MIN(CGRectGetMaxX(statusBarFrame), CGRectGetMaxY(statusBarFrame));
+    bool isInCallStatusBar = topOffset == 40.0f;
+    if (isInCallStatusBar) {
+        topOffset -= 20.0f;
+    }
+    return topOffset;
+}
+
+- (void)setFrame:(CGRect)frame alpha:(CGFloat)alpha animated:(BOOL)animated
+{
+    if (animated) {
+        [UIView beginAnimations:@"GTScrollNavigationBarAnimation" context:nil];
+    }
+
+    CGFloat offsetY = CGRectGetMinY(frame) - CGRectGetMinY(self.frame);
+    UIView *firstView = [self.subviews firstObject];
+
+    for (UIView *view in self.subviews) {
+        bool isBackgroundView = view == firstView;
+        bool isViewHidden = view.hidden || view.alpha == 0.0f;
+        if (isBackgroundView || isViewHidden)
+            continue;
+        view.alpha = alpha;
+    }
+    self.frame = frame;
+
+
+    if (self.scrollView) {
+        CGRect parentViewFrame = self.scrollView.superview.frame;
+        parentViewFrame.origin.y += offsetY;
+        parentViewFrame.size.height -= offsetY;
+        self.scrollView.superview.frame = parentViewFrame;
+    }
+
+    if (animated) {
+        [UIView commitAnimations];
+    }
+}
+
+@end
+
+@implementation UINavigationController (GTScrollNavigationBarAdditions)
+
+@dynamic scrollNavigationBar;
+
+- (GTScrollNavigationBar *)scrollNavigationBar
+{
+    return (GTScrollNavigationBar *)self.navigationBar;
+}
+
+@end

+ 4 - 1
Sources/VLCAppDelegate.m

@@ -33,6 +33,7 @@
 #import "VLCSidebarController.h"
 #import "VLCKeychainCoordinator.h"
 #import "VLCActivityManager.h"
+#import "GTScrollNavigationBar.h"
 
 NSString *const VLCDropboxSessionWasAuthorized = @"VLCDropboxSessionWasAuthorized";
 
@@ -127,7 +128,9 @@ NSString *const VLCDropboxSessionWasAuthorized = @"VLCDropboxSessionWasAuthorize
     void (^setupBlock)() = ^{
         _libraryViewController = [[VLCLibraryViewController alloc] init];
         VLCSidebarController *sidebarVC = [VLCSidebarController sharedInstance];
-        VLCNavigationController *navCon = [[VLCNavigationController alloc] initWithRootViewController:_libraryViewController];
+        VLCNavigationController *navCon = [[VLCNavigationController alloc] initWithNavigationBarClass: [GTScrollNavigationBar class] toolbarClass:nil];
+        [navCon setViewControllers:@[_libraryViewController] animated:NO];
+
         sidebarVC.contentViewController = navCon;
 
         VLCPlayerDisplayController *playerDisplayController = [VLCPlayerDisplayController sharedInstance];

+ 25 - 0
Sources/VLCLibraryViewController.m

@@ -28,6 +28,7 @@
 #import "VLCNavigationController.h"
 #import "VLCPlaybackController+MediaLibrary.h"
 #import "VLCKeychainCoordinator.h"
+#import "GTScrollNavigationBar.h"
 
 #import <AssetsLibrary/AssetsLibrary.h>
 #import <CoreSpotlight/CoreSpotlight.h>
@@ -131,6 +132,8 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
             _tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
             _tableView.tableHeaderView = _searchBar;
             _tableView.tableFooterView = [UIView new];
+            self.navigationController.scrollNavigationBar.scrollView = self.tableView;
+
         }
         _tableView.frame = contentView.bounds;
         [contentView addSubview:_tableView];
@@ -149,6 +152,7 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
             _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_collectionViewHandleLongPressGesture:)];
             [_collectionView addGestureRecognizer:_longPressGestureRecognizer];
             [_collectionView registerNib:[UINib nibWithNibName:@"VLCPlaylistCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:@"PlaylistCell"];
+            self.navigationController.scrollNavigationBar.scrollView = self.collectionView;
         }
         _collectionView.frame = contentView.bounds;
         [contentView addSubview:_collectionView];
@@ -254,6 +258,7 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
     [super viewWillAppear:animated];
     [self.collectionView.collectionViewLayout invalidateLayout];
     [self _displayEmptyLibraryViewIfNeeded];
+    [self enableNavigationBarAnimation:YES resetPositionWithAnimation:YES];
 }
 
 - (void)viewDidAppear:(BOOL)animated
@@ -308,6 +313,7 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
     } else if ([mediaObject isKindOfClass:[MLLabel class]]) {
         MLLabel *folder = (MLLabel*) mediaObject;
         _inFolder = YES;
+        [self.navigationController.scrollNavigationBar resetToDefaultPositionWithAnimation:YES];
         if (!self.usingTableViewToShowData) {
             if (![self.collectionView.collectionViewLayout isEqual:_reorderLayout]) {
                 for (UIGestureRecognizer *recognizer in _collectionView.gestureRecognizers) {
@@ -494,7 +500,11 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
         UIDevice *currentDevice = [UIDevice currentDevice];
         BOOL isPortrait = UIDeviceOrientationIsPortrait(currentDevice.orientation);
 
+        if (self.isEditing) {
+            [self setEditing:NO animated:NO];
+        }
         [self setUsingTableViewToShowData:isPortrait];
+        [self enableNavigationBarAnimation:YES resetPositionWithAnimation:YES];
     }
 }
 
@@ -511,6 +521,19 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
     }
 }
 
+- (void)enableNavigationBarAnimation:(BOOL)enable resetPositionWithAnimation:(BOOL)resetPositionWithAnimation
+{
+    if (!enable) {
+        self.navigationController.scrollNavigationBar.scrollView = nil;
+    } else {
+        self.navigationController.scrollNavigationBar.scrollView = self.usingTableViewToShowData ? self.tableView : self.collectionView;
+    }
+
+    if (resetPositionWithAnimation) {
+        [self.navigationController.scrollNavigationBar resetToDefaultPositionWithAnimation:YES];
+    }
+}
+
 - (void)libraryUpgradeComplete
 {
     self.title = NSLocalizedString(@"LIBRARY_ALL_FILES", nil);
@@ -1272,6 +1295,8 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
     UIBarButtonItem *editButton = self.editButtonItem;
     editButton.tintColor = [UIColor whiteColor];
 
+    [self enableNavigationBarAnimation:!editing resetPositionWithAnimation:NO];
+
     if (!editing && self.navigationItem.rightBarButtonItems.lastObject == _selectAllBarButtonItem)
         [self.navigationItem setRightBarButtonItems: [self.navigationItem.rightBarButtonItems subarrayWithRange:NSMakeRange(0, self.navigationItem.rightBarButtonItems.count - 1)]];
     else

+ 6 - 0
VLC.xcodeproj/project.pbxproj

@@ -756,6 +756,7 @@
 		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 */; };
+		8DDE705F1E49DAD400452F85 /* GTScrollNavigationBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DDE705E1E49DAD400452F85 /* GTScrollNavigationBar.m */; };
 		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 */; };
@@ -1485,6 +1486,8 @@
 		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>"; };
+		8DDE705E1E49DAD400452F85 /* GTScrollNavigationBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GTScrollNavigationBar.m; path = Sources/GTScrollNavigationBar.m; sourceTree = SOURCE_ROOT; };
+		8DDE70601E49DAF800452F85 /* GTScrollNavigationBar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GTScrollNavigationBar.h; path = Sources/GTScrollNavigationBar.h; sourceTree = SOURCE_ROOT; };
 		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; };
@@ -2106,6 +2109,8 @@
 				DDC10BE31AEE8EA700890DC3 /* VLCTimeNavigationTitleView.m */,
 				DD1CB0581BBAC549006EDDE6 /* VLCVolumeView.h */,
 				DD1CB0591BBAC549006EDDE6 /* VLCVolumeView.m */,
+				8DDE70601E49DAF800452F85 /* GTScrollNavigationBar.h */,
+				8DDE705E1E49DAD400452F85 /* GTScrollNavigationBar.m */,
 			);
 			name = "UI Elements";
 			sourceTree = "<group>";
@@ -4418,6 +4423,7 @@
 				D6E034ED1CC284FC0037F516 /* VLCStreamingHistoryCell.m in Sources */,
 				7DC19B0C1868D21800810BF7 /* VLCFirstStepsSixthPageViewController.m in Sources */,
 				DD3EFEED1BDEBA3800B68579 /* VLCNetworkServerBrowserViewController.m in Sources */,
+				8DDE705F1E49DAD400452F85 /* GTScrollNavigationBar.m in Sources */,
 				DD3EABFC1BE14C4B003668DA /* UIViewController+VLCAlert.m in Sources */,
 				7D9289751877459B009108FD /* VLCFirstStepsThirdPageViewController.m in Sources */,
 				7D95610B1AF3E9E800779745 /* VLCMiniPlaybackView.m in Sources */,