Browse Source

iOS: Add shuffle feature

Signed-off-by: Jean-Baptiste Kempf <jb@videolan.org>
Soomin Lee 8 years ago
parent
commit
b47269ec5b

+ 1 - 0
NEWS

@@ -2,6 +2,7 @@ iOS 2.8.0:
 ----------
 * Added support for NFS shares
 * Added Bonjour discovery for SMB shares
+* Added shuffle feature
 * Improved search bar discovery method
 
 iOS 2.7.7:

+ 1 - 0
Sources/VLCMovieViewController.h

@@ -94,6 +94,7 @@
 - (IBAction)videoDimensionAction:(id)sender;
 
 - (void)toggleRepeatMode;
+- (void)toggleShuffleMode;
 - (void)toggleEqualizer;
 - (void)toggleUILock;
 - (void)toggleChapterAndTitleSelector;

+ 8 - 0
Sources/VLCMovieViewController.m

@@ -450,6 +450,7 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
     _vpc.videoOutputView = nil;
     _vpc.videoOutputView = self.movieView;
     _multiSelectionView.repeatMode = _vpc.repeatMode;
+    _multiSelectionView.shuffleMode = _vpc.isShuffleMode;
 
     //Media is loaded in the media player, checking the projection type and configuring accordingly.
     _fov = 0.f;
@@ -1153,6 +1154,13 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
     _multiSelectionView.repeatMode = nextRepeatMode;
 }
 
+- (void)toggleShuffleMode
+{
+    LOCKCHECK;
+    _vpc.shuffleMode = !_vpc.isShuffleMode;
+    _multiSelectionView.shuffleMode = _vpc.isShuffleMode;
+}
+
 - (void)hideMenu
 {
     [UIView animateWithDuration:.2

+ 3 - 0
Sources/VLCMultiSelectionMenuView.h

@@ -15,6 +15,7 @@
 - (void)toggleEqualizer;
 - (void)toggleChapterAndTitleSelector;
 - (void)toggleRepeatMode;
+- (void)toggleShuffleMode;
 - (void)hideMenu;
 
 @end
@@ -27,6 +28,8 @@
 @property (readwrite, assign) BOOL mediaHasChapters;
 
 @property (nonatomic, assign) VLCRepeatMode repeatMode;
+@property (nonatomic, assign) BOOL shuffleMode;
+
 
 - (void)setDisplayLock:(BOOL)displayLock;
 - (CGSize)proposedDisplaySize;

+ 37 - 4
Sources/VLCMultiSelectionMenuView.m

@@ -18,6 +18,7 @@
     UIButton *_chapterSelectorButton;
     UIButton *_repeatButton;
     UIButton *_lockButton;
+    UIButton *_shuffleButton;
 
     BOOL _showsEQ;
 }
@@ -60,6 +61,13 @@
         [_lockButton addTarget:self action:@selector(lockAction:) forControlEvents:UIControlEventTouchUpInside];
         _lockButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
         [self addSubview:_lockButton];
+
+        _shuffleButton = [UIButton buttonWithType:UIButtonTypeCustom];
+        [_shuffleButton setImage:[UIImage imageNamed:@"shuffle"] forState:UIControlStateNormal];
+        _shuffleButton.frame = CGRectMake(spacer, spacer * 3 + buttonHeight * 3, buttonWidth, buttonHeight);
+        [_shuffleButton addTarget:self action:@selector(shuffleAction:) forControlEvents:UIControlEventTouchUpInside];
+        _shuffleButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
+        [self addSubview:_shuffleButton];
     }
     return self;
 }
@@ -74,7 +82,7 @@
 
     if (_showsEqualizer) {
         if (_mediaHasChapters) {
-            height = 6. * spacer + 5. * buttonHeight;
+            height = 7. * spacer + 6. * buttonHeight;
             workFrame = _equalizerButton.frame;
             workFrame.origin.y = spacer;
             _equalizerButton.frame = workFrame;
@@ -89,8 +97,11 @@
             workFrame = _lockButton.frame;
             workFrame.origin.y = spacer * 4. + buttonHeight * 3.;
             _lockButton.frame = workFrame;
+            workFrame = _shuffleButton.frame;
+            workFrame.origin.y = spacer * 5. + buttonHeight * 4.;
+            _shuffleButton.frame = workFrame;
         } else {
-            height = 4. * spacer + 3. * buttonHeight;
+            height = 5. * spacer + 4. * buttonHeight;
             workFrame = _equalizerButton.frame;
             workFrame.origin.y = spacer;
             _equalizerButton.frame = workFrame;
@@ -102,10 +113,13 @@
             workFrame = _lockButton.frame;
             workFrame.origin.y = spacer * 3. + buttonHeight * 2.;
             _lockButton.frame = workFrame;
+            workFrame = _shuffleButton.frame;
+            workFrame.origin.y = spacer * 4. + buttonHeight * 3;
+            _shuffleButton.frame = workFrame;
         }
     } else {
         if (_mediaHasChapters) {
-            height = 4. * spacer + 3. * buttonHeight;
+            height = 5. * spacer + 4. * buttonHeight;
             _equalizerButton.hidden = YES;
             workFrame = _chapterSelectorButton.frame;
             workFrame.origin.y = spacer;
@@ -117,8 +131,11 @@
             workFrame = _lockButton.frame;
             workFrame.origin.y = spacer * 3. + buttonHeight * 2.;
             _lockButton.frame = workFrame;
+            workFrame = _shuffleButton.frame;
+            workFrame.origin.y = spacer * 4. + buttonHeight * 3;
+            _shuffleButton.frame = workFrame;
         } else {
-            height = 3. * spacer + 2. * buttonHeight;
+            height = 4. * spacer + 3. * buttonHeight;
             _equalizerButton.hidden = YES;
             _chapterSelectorButton.hidden = YES;
             workFrame = _repeatButton.frame;
@@ -127,6 +144,9 @@
             workFrame = _lockButton.frame;
             workFrame.origin.y = spacer * 2. + buttonHeight;
             _lockButton.frame = workFrame;
+            workFrame = _shuffleButton.frame;
+            workFrame.origin.y = spacer * 3. + buttonHeight * 2;
+            _shuffleButton.frame = workFrame;
         }
     }
 
@@ -158,6 +178,14 @@
         [_lockButton setBackgroundColor:[UIColor clearColor]];
 }
 
+- (void)setShuffleMode:(BOOL)shuffleMode
+{
+    if (shuffleMode)
+        [_shuffleButton setBackgroundColor:[UIColor VLCOrangeTintColor]];
+    else
+        [_shuffleButton setBackgroundColor:[UIColor clearColor]];
+}
+
 - (void)equalizerAction:(id)sender
 {
     [self.delegate toggleEqualizer];
@@ -180,4 +208,9 @@
     [self.delegate toggleUILock];
 }
 
+- (void)shuffleAction:(id)sender
+{
+    [self.delegate toggleShuffleMode];
+}
+
 @end

+ 1 - 0
Sources/VLCPlaybackController.h

@@ -70,6 +70,7 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
 @property (nonatomic, readonly) NSInteger mediaDuration;
 @property (nonatomic, readonly) BOOL isPlaying;
 @property (nonatomic, readwrite) VLCRepeatMode repeatMode;
+@property (nonatomic, assign, getter=isShuffleMode) BOOL shuffleMode;
 @property (nonatomic, readwrite) float playbackRate; // default = 1.0
 @property (nonatomic, readwrite) float audioDelay; // in seconds, default = 0.0
 @property (nonatomic, readwrite) float subtitleDelay; // in seconds, default = 0.0

+ 31 - 1
Sources/VLCPlaybackController.m

@@ -74,6 +74,8 @@ VLCMediaDelegate>
     NSLock *_playbackSessionManagementLock;
 
     VLCDialogProvider *_dialogProvider;
+
+    NSMutableArray *_shuffleStack;
 }
 
 @end
@@ -118,6 +120,8 @@ VLCMediaDelegate>
         _dialogProvider = [[VLCDialogProvider alloc] initWithLibrary:[VLCLibrary sharedLibrary] customUI:NO];
 
         _playbackSessionManagementLock = [[NSLock alloc] init];
+        _shuffleMode = NO;
+        _shuffleStack = [[NSMutableArray alloc] init];
     }
     return self;
 }
@@ -403,6 +407,7 @@ VLCMediaDelegate>
         }
     }
     _playerIsSetup = NO;
+    [_shuffleStack removeAllObjects];
 
     if (self.errorCallback && _playbackFailed && !_sessionWillRestart)
         [[UIApplication sharedApplication] openURL:self.errorCallback];
@@ -672,7 +677,32 @@ VLCMediaDelegate>
 
 - (void)forward
 {
-    if (_mediaList.count > 1) {
+    NSInteger mediaListCount = _mediaList.count;
+
+    if (mediaListCount > 2 && _shuffleMode) {
+
+        NSNumber *nextIndex;
+        NSUInteger currentIndex = [_mediaList indexOfMedia:_listPlayer.mediaPlayer.media];
+
+        //Reached end of playlist
+        if (_shuffleStack.count + 1 == mediaListCount) {
+            if ([self repeatMode] == VLCDoNotRepeat)
+                return;
+            [_shuffleStack removeAllObjects];
+        }
+
+        [_shuffleStack addObject:[NSNumber numberWithUnsignedInteger:currentIndex]];
+        do {
+            nextIndex = [NSNumber numberWithUnsignedInt:arc4random_uniform((uint32_t)mediaListCount)];
+        } while (currentIndex == nextIndex.unsignedIntegerValue || [_shuffleStack containsObject:nextIndex]);
+
+        [_listPlayer playItemAtNumber:[NSNumber numberWithUnsignedInteger:nextIndex.unsignedIntegerValue]];
+        [[NSNotificationCenter defaultCenter] postNotificationName:VLCPlaybackControllerPlaybackMetadataDidChange object:self];
+
+        return;
+    }
+
+    if (mediaListCount > 1) {
         [_listPlayer next];
         [[NSNotificationCenter defaultCenter] postNotificationName:VLCPlaybackControllerPlaybackMetadataDidChange object:self];
     } else {

+ 20 - 0
vlc-ios/Images.xcassets/AppIcon.appiconset/Contents.json

@@ -1,6 +1,16 @@
 {
   "images" : [
     {
+      "idiom" : "iphone",
+      "size" : "20x20",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "20x20",
+      "scale" : "3x"
+    },
+    {
       "size" : "29x29",
       "idiom" : "iphone",
       "filename" : "AppIcon29x29@2x-1.png",
@@ -37,6 +47,16 @@
       "scale" : "3x"
     },
     {
+      "idiom" : "ipad",
+      "size" : "20x20",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "20x20",
+      "scale" : "2x"
+    },
+    {
       "size" : "29x29",
       "idiom" : "ipad",
       "filename" : "AppIcon29x29.png",

+ 6 - 0
vlc-ios/Images.xcassets/menu/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

+ 12 - 0
vlc-ios/Images.xcassets/menu/shuffle.imageset/Contents.json

@@ -0,0 +1,12 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "shuffle_white.pdf"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
vlc-ios/Images.xcassets/menu/shuffle.imageset/shuffle_white.pdf