Commit 258b149b authored by Tobias's avatar Tobias

Implement special gesture recognizer for Siri Remote which can detect the...

Implement special gesture recognizer for Siri Remote which can detect the touch location and select short and long presses
Both the SiriRemote recognizer and the pan gesture recognizer work with the same touches.

Possible improvements to think about:
An improvement in user experience might be to cancel the SiriRemote recognizer instead of updating the touch location if the touch moved to much.
But then we have the problem that the hint does not update to the other location until the user lifts the finger and puts it down again.
parent e7d2299a
......@@ -14,6 +14,7 @@
#import "VLCPlaybackInfoTVAnimators.h"
#import "VLCIRTVTapGestureRecognizer.h"
#import "VLCHTTPUploaderController.h"
#import "VLCSiriRemoteGestureRecognizer.h"
typedef NS_ENUM(NSInteger, VLCPlayerScanState)
{
......@@ -71,6 +72,7 @@ typedef NS_ENUM(NSInteger, VLCPlayerScanState)
// Panning and Swiping
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGesture:)];
panGestureRecognizer.delegate = self;
[self.view addGestureRecognizer:panGestureRecognizer];
// Button presses
......@@ -78,10 +80,6 @@ typedef NS_ENUM(NSInteger, VLCPlayerScanState)
playpauseGesture.allowedPressTypes = @[@(UIPressTypePlayPause)];
[self.view addGestureRecognizer:playpauseGesture];
UITapGestureRecognizer *selectTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(selectButtonPressed:)];
selectTapGestureRecognizer.allowedPressTypes = @[@(UIPressTypeSelect)];
[self.view addGestureRecognizer:selectTapGestureRecognizer];
UITapGestureRecognizer *menuTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(menuButtonPressed:)];
menuTapGestureRecognizer.allowedPressTypes = @[@(UIPressTypeMenu)];
menuTapGestureRecognizer.delegate = self;
......@@ -99,6 +97,12 @@ typedef NS_ENUM(NSInteger, VLCPlayerScanState)
UITapGestureRecognizer *rightArrowRecognizer = [[VLCIRTVTapGestureRecognizer alloc] initWithTarget:self action:@selector(handleIRPressRight)];
rightArrowRecognizer.allowedPressTypes = @[@(UIPressTypeRightArrow)];
[self.view addGestureRecognizer:rightArrowRecognizer];
// Siri remote arrow presses
VLCSiriRemoteGestureRecognizer *siriArrowRecognizer = [[VLCSiriRemoteGestureRecognizer alloc] initWithTarget:self action:@selector(handleSiriRemote:)];
siriArrowRecognizer.delegate = self;
[self.view addGestureRecognizer:siriArrowRecognizer];
}
- (void)didReceiveMemoryWarning
......@@ -162,7 +166,7 @@ typedef NS_ENUM(NSInteger, VLCPlayerScanState)
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
if (self.transportBar.scrubbing) {
[self selectButtonPressed:nil];
[self selectButtonPressed];
} else {
[vpc playPause];
}
......@@ -195,6 +199,7 @@ typedef NS_ENUM(NSInteger, VLCPlayerScanState)
return;
}
}
[self showPlaybackControlsIfNeededForUserInteraction];
[self setScanState:VLCPlayerScanStateNone];
......@@ -222,7 +227,7 @@ typedef NS_ENUM(NSInteger, VLCPlayerScanState)
[self updateTimeLabelsForScrubbingFraction:scrubbingFraction];
}
- (void)selectButtonPressed:(UITapGestureRecognizer *)recognizer
- (void)selectButtonPressed
{
[self showPlaybackControlsIfNeededForUserInteraction];
[self setScanState:VLCPlayerScanStateNone];
......@@ -286,18 +291,88 @@ typedef NS_ENUM(NSInteger, VLCPlayerScanState)
}
}
- (void)handleSiriRemote:(VLCSiriRemoteGestureRecognizer *)recognizer
{
[self showPlaybackControlsIfNeededForUserInteraction];
VLCTransportBarHint hint = self.transportBar.hint;
switch (recognizer.state) {
case UIGestureRecognizerStateBegan:
case UIGestureRecognizerStateChanged:
if (recognizer.isLongPress) {
if (recognizer.touchLocation == VLCSiriRemoteTouchLocationRight) {
[self setScanState:VLCPlayerScanStateForward2];
return;
}
} else {
switch (recognizer.touchLocation) {
case VLCSiriRemoteTouchLocationLeft:
hint = VLCTransportBarHintJumpBackward10;
break;
case VLCSiriRemoteTouchLocationRight:
hint = VLCTransportBarHintJumpForward10;
break;
default:
hint = VLCTransportBarHintNone;
break;
}
}
break;
case UIGestureRecognizerStateEnded:
if (recognizer.isClick && !recognizer.isLongPress) {
[self handleSiriPressUpAtLocation:recognizer.touchLocation];
}
[self setScanState:VLCPlayerScanStateNone];
break;
case UIGestureRecognizerStateCancelled:
hint = VLCTransportBarHintNone;
[self setScanState:VLCPlayerScanStateNone];
break;
default:
break;
}
self.transportBar.hint = hint;
}
- (void)handleSiriPressUpAtLocation:(VLCSiriRemoteTouchLocation)location
{
switch (location) {
case VLCSiriRemoteTouchLocationLeft:
[self jumpBackward];
break;
case VLCSiriRemoteTouchLocationRight:
[self jumpForward];
default:
[self selectButtonPressed];
break;
}
}
#pragma mark -
static const NSInteger VLCJumpInterval = 10000; // 10 seconds
- (void)jumpForward
{
[self jumpInterval:VLCJumpInterval];
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
VLCMediaPlayer *player = vpc.mediaPlayer;
if (player.isPlaying) {
[player jumpForward:VLCJumpInterval];
} else {
[self scrubbingJumpInterval:VLCJumpInterval];
}
}
- (void)jumpBackward
{
[self jumpInterval:-VLCJumpInterval];
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
VLCMediaPlayer *player = vpc.mediaPlayer;
if (player.isPlaying) {
[player jumpBackward:VLCJumpInterval];
} else {
[self scrubbingJumpInterval:-VLCJumpInterval];
}
}
- (void)jumpInterval:(NSInteger)interval
- (void)scrubbingJumpInterval:(NSInteger)interval
{
NSInteger duration = [VLCPlaybackController sharedInstance].mediaDuration;
if (duration==0) {
......@@ -351,6 +426,10 @@ static const NSInteger VLCJumpInterval = 10000; // 10 seconds
- (void)setScanState:(VLCPlayerScanState)scanState
{
if (_scanState == scanState) {
return;
}
if (_scanState == VLCPlayerScanStateNone) {
self.scanSavedPlaybackRate = @([VLCPlaybackController sharedInstance].playbackRate);
}
......@@ -489,6 +568,8 @@ static const NSInteger VLCJumpInterval = 10000; // 10 seconds
return _infoViewController;
}
#pragma mark - playback controller delegation
- (void)prepareForMediaPlayback:(VLCPlaybackController *)controller
......@@ -555,7 +636,10 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
}
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
@end
......
......@@ -22,7 +22,10 @@
- (BOOL)vlc_isSynthetic
{
/*Attention we are using private API here
/*
* !!! Attention: We are using private API !!!
* !!! Might break in any future release !!!
*
* For internal name changes the press might wrongly detected as non-synthetic.
* Since we us it to filter for only non-synthetic presses arrow taps
* on the Siri remote might be additionally be detected.
......
/*****************************************************************************
* VLC for iOS
*****************************************************************************
* Copyright (c) 2015 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Tobias Conradi <videolan # tobias-conradi.de>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger, VLCSiriRemoteTouchLocation){
VLCSiriRemoteTouchLocationUnknown,
VLCSiriRemoteTouchLocationLeft,
VLCSiriRemoteTouchLocationRight,
};
@interface VLCSiriRemoteGestureRecognizer : UIGestureRecognizer
@property (nonatomic) NSTimeInterval minLongPressDuration; // default = 0.5
@property (nonatomic, readonly, getter=isLongPress) BOOL longPress;
@property (nonatomic, readonly, getter=isClick) BOOL click;
@property (nonatomic, readonly) VLCSiriRemoteTouchLocation touchLocation;
@end
/*****************************************************************************
* VLC for iOS
*****************************************************************************
* Copyright (c) 2015 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Tobias Conradi <videolan # tobias-conradi.de>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import "VLCSiriRemoteGestureRecognizer.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
@interface UIEvent (VLCDigitizerLocation)
- (CGPoint)vlc_digitizerLocation;
@end
@interface VLCSiriRemoteGestureRecognizer ()
{
NSTimer *_longPressTimer;
}
@end
@implementation VLCSiriRemoteGestureRecognizer
@dynamic delegate;
- (instancetype)initWithTarget:(id)target action:(SEL)action
{
self = [super initWithTarget:target action:action];
if (self) {
self.allowedTouchTypes = @[@(UITouchTypeIndirect)];
self.allowedPressTypes = @[@(UIPressTypeSelect)];
self.minLongPressDuration = 0.5;
self.cancelsTouchesInView = NO;
}
return self;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.state = UIGestureRecognizerStateBegan;
[self updateTouchLocationWithEvent:event];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self updateTouchLocationWithEvent:event];
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self updateTouchLocation:VLCSiriRemoteTouchLocationUnknown];
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self updateTouchLocation:VLCSiriRemoteTouchLocationUnknown];
}
- (void)updateTouchLocationWithEvent:(UIEvent *)event
{
CGPoint digitizerLocation = [event vlc_digitizerLocation];
VLCSiriRemoteTouchLocation location = VLCSiriRemoteTouchLocationUnknown;
if (digitizerLocation.x <= 0.2) {
location = VLCSiriRemoteTouchLocationLeft;
} else if (0.8 <= digitizerLocation.x) {
location = VLCSiriRemoteTouchLocationRight;
}
[self updateTouchLocation:location];
}
- (void)updateTouchLocation:(VLCSiriRemoteTouchLocation)location
{
if (_touchLocation == location) {
return;
}
_touchLocation = location;
self.state = UIGestureRecognizerStateChanged;
}
- (void)reset
{
_click = NO;
_touchLocation = VLCSiriRemoteTouchLocationUnknown;
_longPress = NO;
[_longPressTimer invalidate];
_longPressTimer = nil;
[super reset];
}
- (void)longPressTimerFired
{
if (_click && (self.state == UIGestureRecognizerStateBegan || self.state == UIGestureRecognizerStateChanged)) {
_longPress = YES;
self.state = UIGestureRecognizerStateChanged;
}
}
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{
if ([self.allowedPressTypes containsObject:@(presses.anyObject.type)]) {
_click = YES;
_longPressTimer = [NSTimer scheduledTimerWithTimeInterval:self.minLongPressDuration target:self selector:@selector(longPressTimerFired) userInfo:nil repeats:NO];
self.state = UIGestureRecognizerStateChanged;
}
}
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{
self.state = UIGestureRecognizerStateChanged;
}
- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{
self.state = UIGestureRecognizerStateCancelled;
}
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{
if (_click) {
self.state = UIGestureRecognizerStateEnded;
}
}
@end
@implementation UIEvent (VLCDigitizerLocation)
- (CGPoint)vlc_digitizerLocation
{
/*
* !!! Attention: We are using private API !!!
* !!! Might break in any future release !!!
*
* The digitizer location is the absolut location of the touch on the touch pad.
* The location is in a 0,0 (top left) to 1,1 (bottom right) coordinate system.
*/
NSString *key = [@"digitiz" stringByAppendingString:@"erLocation"];
NSNumber *value = [self valueForKey:key];
if ([value isKindOfClass:[NSValue class]]) {
return [value CGPointValue];
}
// default to center position as undefined position
return CGPointMake(0.5,0.5);
}
@end
\ No newline at end of file
......@@ -30,7 +30,7 @@ IB_DESIGNABLE @interface VLCTransportBar : UIView
@property (nonatomic, readonly) UILabel *markerTimeLabel;
@property (nonatomic, readonly) UILabel *remainingTimeLabel;
-(void)setHint:(VLCTransportBarHint)hint;
@property (nonatomic) VLCTransportBarHint hint;
@end
NS_ASSUME_NONNULL_END
\ No newline at end of file
......@@ -147,6 +147,7 @@ static inline void sharedSetup(VLCTransportBar *self) {
}
- (void)setHint:(VLCTransportBarHint)hint
{
_hint = hint;
UIImage *leftImage = nil;
UIImage *rightImage = nil;
switch (hint) {
......
......@@ -312,6 +312,7 @@
DD3EFF5D1BDEBCE500B68579 /* VLCLocalServerDiscoveryController.m in Sources */ = {isa = PBXBuildFile; fileRef = DD3EFF2B1BDEBCE500B68579 /* VLCLocalServerDiscoveryController.m */; };
DD3EFF5E1BDEBCE500B68579 /* VLCLocalServerDiscoveryController.m in Sources */ = {isa = PBXBuildFile; fileRef = DD3EFF2B1BDEBCE500B68579 /* VLCLocalServerDiscoveryController.m */; };
DD490B171BE6BA580010F335 /* VLCIRTVTapGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = DD490B161BE6BA580010F335 /* VLCIRTVTapGestureRecognizer.m */; };
DD490B1F1BE95B5C0010F335 /* VLCSiriRemoteGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = DD490B1E1BE95B5C0010F335 /* VLCSiriRemoteGestureRecognizer.m */; };
DD510B701B14E564003BA71C /* VLCPlayerDisplayController.m in Sources */ = {isa = PBXBuildFile; fileRef = DD510B6F1B14E564003BA71C /* VLCPlayerDisplayController.m */; };
DD7110F01AF38B2B00854776 /* MLMediaLibrary+playlist.m in Sources */ = {isa = PBXBuildFile; fileRef = DD7110EF1AF38B2B00854776 /* MLMediaLibrary+playlist.m */; };
DD7BA2631B680C8E002D9F54 /* MediaLibraryKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD7BA2601B680C1B002D9F54 /* MediaLibraryKit.framework */; };
......@@ -931,6 +932,8 @@
DD3EFF2C1BDEBCE500B68579 /* VLCNetworkServerBrowser-Protocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "VLCNetworkServerBrowser-Protocol.h"; sourceTree = "<group>"; };
DD490B151BE6BA580010F335 /* VLCIRTVTapGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCIRTVTapGestureRecognizer.h; sourceTree = "<group>"; };
DD490B161BE6BA580010F335 /* VLCIRTVTapGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCIRTVTapGestureRecognizer.m; sourceTree = "<group>"; };
DD490B1D1BE95B5C0010F335 /* VLCSiriRemoteGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCSiriRemoteGestureRecognizer.h; sourceTree = "<group>"; };
DD490B1E1BE95B5C0010F335 /* VLCSiriRemoteGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCSiriRemoteGestureRecognizer.m; sourceTree = "<group>"; };
DD510B6E1B14E564003BA71C /* VLCPlayerDisplayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCPlayerDisplayController.h; path = Sources/VLCPlayerDisplayController.h; sourceTree = SOURCE_ROOT; };
DD510B6F1B14E564003BA71C /* VLCPlayerDisplayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCPlayerDisplayController.m; path = Sources/VLCPlayerDisplayController.m; sourceTree = SOURCE_ROOT; };
DD7110EE1AF38B2B00854776 /* MLMediaLibrary+playlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MLMediaLibrary+playlist.h"; sourceTree = "<group>"; };
......@@ -1737,6 +1740,8 @@
7DEC8BDC1BD67899006E1093 /* VLCFullscreenMovieTVViewController.m */,
DD490B151BE6BA580010F335 /* VLCIRTVTapGestureRecognizer.h */,
DD490B161BE6BA580010F335 /* VLCIRTVTapGestureRecognizer.m */,
DD490B1D1BE95B5C0010F335 /* VLCSiriRemoteGestureRecognizer.h */,
DD490B1E1BE95B5C0010F335 /* VLCSiriRemoteGestureRecognizer.m */,
DD8095FA1BE628800065D8E1 /* Playback Info */,
);
path = Playback;
......@@ -2624,6 +2629,7 @@
7D0EDE061BE774BF00363AA1 /* WhiteRaccoon.m in Sources */,
7D60696B1BD93AC800AB765C /* VLCDropboxTableViewController.m in Sources */,
7D405ED01BEA11C1006ED886 /* VLCHTTPConnection.m in Sources */,
DD490B1F1BE95B5C0010F335 /* VLCSiriRemoteGestureRecognizer.m in Sources */,
DD3EFF3C1BDEBCE500B68579 /* VLCNetworkServerBrowserVLCMedia.m in Sources */,
7D1334801BE132F10012E919 /* VLCNetworkServerBrowserUPnP.m in Sources */,
DDEAECC71BDEC79D00756C83 /* VLCLocalNetworkServiceBrowserSAP.m in Sources */,
......
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